{{if .IsG2 -}}
//go:build g2

{{end -}}
package {{.PackageName}}
{{if .IsScalar}}
{{- template "scalar_field_c_imports" . -}}
{{end}}
import (
	"encoding/binary"
	"fmt"
	{{- if .IsScalar}}
	{{- template "scalar_field_go_imports" -}}
	{{end}}
)

const (
	{{if .IsScalar}}SCALAR{{else}}{{if .IsG2}}G2_{{end}}BASE{{end}}_LIMBS int8 = {{if .IsScalar}}{{.ScalarLimbsNum}}{{else}}{{if .IsG2}}{{.G2BaseLimbsNum}}{{else}}{{.BaseLimbsNum}}{{end}}{{end}}
)

type {{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field struct {
	limbs [{{- if .IsScalar}}SCALAR{{else}}{{if .IsG2}}G2_{{end}}BASE{{end}}_LIMBS]uint32
}

func (f {{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field) Len() int {
	return int({{- if .IsScalar}}SCALAR{{else}}{{if .IsG2}}G2_{{end}}BASE{{end}}_LIMBS)
}

func (f {{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field) Size() int {
	return int({{- if .IsScalar}}SCALAR{{else}}{{if .IsG2}}G2_{{end}}BASE{{end}}_LIMBS * 4)
}

func (f {{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field) GetLimbs() []uint32 {
	return f.limbs[:]
}

func (f {{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field) AsPointer() *uint32 {
	return &f.limbs[0]
}

func (f *{{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field) FromLimbs(limbs []uint32) {{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field {
	if len(limbs) != f.Len() {
		panic("Called FromLimbs with limbs of different length than field")
	}
	for i := range f.limbs {
		f.limbs[i] = limbs[i]
	}

	return *f
}

func (f *{{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field) Zero() {{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field {
	for i := range f.limbs {
		f.limbs[i] = 0
	}

	return *f
}

func (f *{{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field) One() {{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field {
	for i := range f.limbs {
		f.limbs[i] = 0
	}
	f.limbs[0] = 1

	return *f
}

func (f *{{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field) FromBytesLittleEndian(bytes []byte) {{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field {
	if len(bytes)/4 != f.Len() {
		panic(fmt.Sprintf("Called FromBytesLittleEndian with incorrect bytes length; expected %d - got %d", f.Len()*4, len(bytes)))
	}

	for i := range f.limbs {
		f.limbs[i] = binary.LittleEndian.Uint32(bytes[i*4 : i*4+4])
	}

	return *f
}

func (f {{if .IsMock}}Mock{{else}}{{if .IsG2}}G2{{end}}{{- if .IsScalar}}Scalar{{else}}Base{{end}}{{end}}Field) ToBytesLittleEndian() []byte {
	bytes := make([]byte, f.Len()*4)
	for i, v := range f.limbs {
		binary.LittleEndian.PutUint32(bytes[i*4:], v)
	}

	return bytes
}
{{- if .IsScalar}}
{{template "scalar_field_funcs" . }}{{end}}
