Commit 41aed25d authored by Eric Myhre's avatar Eric Myhre

Add generateKindStruct.EmitNodeMethodMapIterator.

A bit fun; wish there was a way to compress that block of ifdefs about
optional vs nullable stuff, but so far nothing clearer has emerged.

Added ErrIteratorOverread while at it.  Should refactoring other node
types to use it too, I suppose.  But perhaps we'll just accumlate those
todos for a while, since there's already one other error refactor with
a chain of blocks in front of it.
parent 6802ea10
......@@ -45,3 +45,11 @@ type ErrNotExists struct {
func (e ErrNotExists) Error() string {
return fmt.Sprintf("key not found: %q", e.Segment)
}
// ErrIteratorOverread is returned when calling 'Next' on a MapIterator or
// ListIterator when it is already done.
type ErrIteratorOverread struct{}
func (e ErrIteratorOverread) Error() string {
return "iterator overread"
}
......@@ -29,7 +29,7 @@ func TestScalarUnmarshal(t *testing.T) {
tb := &TokenSourceBucket{tokens: []tok.Token{
{Type: tok.TString, Str: "zooooom"},
}}
nb := Strang__NodeBuilder{}
nb := String__NodeBuilder{}
n, err := encoding.Unmarshal(nb, tb)
Wish(t, err, ShouldEqual, nil)
Wish(t, n.ReprKind(), ShouldEqual, ipld.ReprKind_String)
......
......@@ -82,9 +82,55 @@ func (gk generateKindStruct) EmitNodeMethodTraverseField(w io.Writer) {
func (gk generateKindStruct) EmitNodeMethodMapIterator(w io.Writer) {
doTemplate(`
func ({{ .Type.Name }}) MapIterator() ipld.MapIterator {
return nil // TODO EmitNodeMethodMapIterator
func (x {{ .Type.Name }}) MapIterator() ipld.MapIterator {
return &_{{ .Type.Name }}__itr{&x, 0}
}
type _{{ .Type.Name }}__itr struct {
node *{{ .Type.Name }}
idx int
}
func (itr *_{{ .Type.Name }}__itr) Next() (k ipld.Node, v ipld.Node, _ error) {
if itr.idx >= {{ len .Type.Fields }} {
return nil, nil, ipld.ErrIteratorOverread{}
}
switch itr.idx {
{{- range $i, $field := .Type.Fields }}
case {{ $i }}:
k = String{"{{ $field.Name }}"}
{{- if and $field.IsOptional $field.IsNullable }}
if !itr.node.{{ $field.Name }}__exists {
v = ipld.Undef
break
}
if itr.node.{{ $field.Name }} == nil {
v = ipld.Null
break
}
{{- else if $field.IsOptional }}
if itr.node.{{ $field.Name }} == nil {
v = ipld.Undef
break
}
{{- else if $field.IsNullable }}
if itr.node.{{ $field.Name }} == nil {
v = ipld.Null
break
}
{{- end}}
v = itr.node.{{ $field.Name }}
{{- end}}
default:
panic("unreachable")
}
itr.idx++
return
}
func (itr *_{{ .Type.Name }}__itr) Done() bool {
return itr.idx >= {{ len .Type.Fields }}
}
`, w, gk)
}
......
......@@ -23,4 +23,11 @@ func (itr mapIteratorReject) Done() bool { return false
func (itr listIteratorReject) Next() (int, ipld.Node, error) { return -1, nil, itr.err }
func (itr listIteratorReject) Done() bool { return false }
`))
// Box type for map keys.
// f.Write([]byte(`
// type boxedString struct { x string }
// `))
//
// ... nevermind; we already need strings in the prelude. Use em.
}
......@@ -40,29 +40,29 @@ func TestNuevo(t *testing.T) {
f := openOrPanic("_test/minima.go")
emitMinima(f)
tStrang := schema.SpawnString("Strang")
tString := schema.SpawnString("String")
tStract := schema.SpawnStruct("Stract",
[]schema.StructField{schema.SpawnStructField(
"aField", tStrang, false, false,
"aField", tString, false, false,
)},
schema.StructRepresentation_Map{},
)
tStract2 := schema.SpawnStruct("Stract2",
[]schema.StructField{schema.SpawnStructField(
"nulble", tStrang, false, true,
"nulble", tString, false, true,
)},
schema.StructRepresentation_Map{},
)
tStract3 := schema.SpawnStruct("Stract3",
[]schema.StructField{schema.SpawnStructField(
"noptble", tStrang, true, true,
"noptble", tString, true, true,
)},
schema.StructRepresentation_Map{},
)
f = openOrPanic("_test/tStrang.go")
f = openOrPanic("_test/tString.go")
emitFileHeader(f)
emitType(NewGeneratorForKindString(tStrang), f)
emitType(NewGeneratorForKindString(tString), f)
f = openOrPanic("_test/Stract.go")
emitFileHeader(f)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment