package basicnode import ( ipld "github.com/ipld/go-ipld-prime" "github.com/ipld/go-ipld-prime/node/mixins" ) var ( _ ipld.Node = &plainList{} _ ipld.NodeStyle = Style__List{} _ ipld.NodeBuilder = &plainList__Builder{} _ ipld.NodeAssembler = &plainList__Assembler{} ) // plainList is a concrete type that provides a list-kind ipld.Node. // It can contain any kind of value. // plainList is also embedded in the 'any' struct and usable from there. type plainList struct { x []ipld.Node } // -- Node interface methods --> func (plainList) ReprKind() ipld.ReprKind { return ipld.ReprKind_List } func (plainList) LookupString(string) (ipld.Node, error) { return mixins.List{"list"}.LookupString("") } func (plainList) Lookup(ipld.Node) (ipld.Node, error) { return mixins.List{"list"}.Lookup(nil) } func (n *plainList) LookupIndex(idx int) (ipld.Node, error) { if n.Length() <= idx { return nil, ipld.ErrNotExists{ipld.PathSegmentOfInt(idx)} } return n.x[idx], nil } func (n *plainList) LookupSegment(seg ipld.PathSegment) (ipld.Node, error) { idx, err := seg.Index() if err != nil { panic("todo name this kind of error") } return n.LookupIndex(idx) } func (plainList) MapIterator() ipld.MapIterator { return nil } func (n *plainList) ListIterator() ipld.ListIterator { return &plainList_ListIterator{n, 0} } func (n *plainList) Length() int { return len(n.x) } func (plainList) IsUndefined() bool { return false } func (plainList) IsNull() bool { return false } func (plainList) AsBool() (bool, error) { return mixins.List{"list"}.AsBool() } func (plainList) AsInt() (int, error) { return mixins.List{"list"}.AsInt() } func (plainList) AsFloat() (float64, error) { return mixins.List{"list"}.AsFloat() } func (plainList) AsString() (string, error) { return mixins.List{"list"}.AsString() } func (plainList) AsBytes() ([]byte, error) { return mixins.List{"list"}.AsBytes() } func (plainList) AsLink() (ipld.Link, error) { return mixins.List{"list"}.AsLink() } func (plainList) Style() ipld.NodeStyle { return Style__List{} } type plainList_ListIterator struct { n *plainList idx int } func (itr *plainList_ListIterator) Next() (idx int, v ipld.Node, _ error) { if itr.Done() { return -1, nil, ipld.ErrIteratorOverread{} } v = itr.n.x[itr.idx] idx = itr.idx itr.idx++ return } func (itr *plainList_ListIterator) Done() bool { return itr.idx >= len(itr.n.x) } // -- NodeStyle --> type Style__List struct{} func (Style__List) NewBuilder() ipld.NodeBuilder { return &plainList__Builder{plainList__Assembler{w: &plainList{}}} } // -- NodeBuilder --> type plainList__Builder struct { plainList__Assembler } func (nb *plainList__Builder) Build() ipld.Node { if nb.state != laState_finished { panic("invalid state: assembler must be 'finished' before Build can be called!") } return nb.w } func (nb *plainList__Builder) Reset() { *nb = plainList__Builder{} nb.w = &plainList{} } // -- NodeAssembler --> type plainList__Assembler struct { w *plainList va plainList__ValueAssembler state laState } type plainList__ValueAssembler struct { la *plainList__Assembler } // laState is an enum of the state machine for a list assembler. // (this might be something to export reusably, but it's also very much an impl detail that need not be seen, so, dubious.) // it's similar to maState for maps, but has fewer states because we never have keys to assemble. type laState uint8 const ( laState_initial laState = iota // also the 'expect value or finish' state laState_midValue // waiting for a 'finished' state in the ValueAssembler. laState_finished // 'w' will also be nil, but this is a politer statement ) func (plainList__Assembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { return mixins.ListAssembler{"list"}.BeginMap(0) } func (na *plainList__Assembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { if sizeHint < 0 { sizeHint = 0 } // Allocate storage space. na.w.x = make([]ipld.Node, 0, sizeHint) // That's it; return self as the ListAssembler. We already have all the right methods on this structure. return na, nil } func (plainList__Assembler) AssignNull() error { return mixins.ListAssembler{"list"}.AssignNull() } func (plainList__Assembler) AssignBool(bool) error { return mixins.ListAssembler{"list"}.AssignBool(false) } func (plainList__Assembler) AssignInt(int) error { return mixins.ListAssembler{"list"}.AssignInt(0) } func (plainList__Assembler) AssignFloat(float64) error { return mixins.ListAssembler{"list"}.AssignFloat(0) } func (plainList__Assembler) AssignString(string) error { return mixins.ListAssembler{"list"}.AssignString("") } func (plainList__Assembler) AssignBytes([]byte) error { return mixins.ListAssembler{"list"}.AssignBytes(nil) } func (plainList__Assembler) AssignLink(ipld.Link) error { return mixins.ListAssembler{"list"}.AssignLink(nil) } func (na *plainList__Assembler) AssignNode(v ipld.Node) error { // todo: apply a generic 'copy' function. // todo: probably can also shortcut to copying na.t and na.m if it's our same concrete type? // (can't quite just `na.w = v`, because we don't have 'freeze' features, and we don't wanna open door to mutation of 'v'.) // (wait... actually, probably we can? 'Assign' is a "finish" method. we can&should invalidate the wip pointer here.) panic("later") } func (plainList__Assembler) Style() ipld.NodeStyle { return Style__List{} } // -- ListAssembler --> // AssembleValue is part of conforming to ListAssembler, which we do on // plainList__Assembler so that BeginList can just return a retyped pointer rather than new object. func (la *plainList__Assembler) AssembleValue() ipld.NodeAssembler { // Sanity check, then update, assembler state. if la.state != laState_initial { panic("misuse") } la.state = laState_midValue // Make value assembler valid by giving it pointer back to whole 'la'; yield it. la.va.la = la return &la.va } // Finish is part of conforming to ListAssembler, which we do on // plainList__Assembler so that BeginList can just return a retyped pointer rather than new object. func (la *plainList__Assembler) Finish() error { // Sanity check, then update, assembler state. if la.state != laState_initial { panic("misuse") } la.state = laState_finished // validators could run and report errors promptly, if this type had any. return nil } func (plainList__Assembler) ValueStyle(_ int) ipld.NodeStyle { return Style__Any{} } // -- ListAssembler.ValueAssembler --> func (lva *plainList__ValueAssembler) BeginMap(sizeHint int) (ipld.MapAssembler, error) { ma := plainList__ValueAssemblerMap{} ma.ca.w = &plainMap{} ma.p = lva.la _, err := ma.ca.BeginMap(sizeHint) return &ma, err } func (lva *plainList__ValueAssembler) BeginList(sizeHint int) (ipld.ListAssembler, error) { la := plainList__ValueAssemblerList{} la.ca.w = &plainList{} la.p = lva.la _, err := la.ca.BeginList(sizeHint) return &la, err } func (lva *plainList__ValueAssembler) AssignNull() error { return lva.AssignNode(ipld.Null) } func (lva *plainList__ValueAssembler) AssignBool(v bool) error { vb := plainBool(v) return lva.AssignNode(&vb) } func (lva *plainList__ValueAssembler) AssignInt(v int) error { vb := plainInt(v) return lva.AssignNode(&vb) } func (lva *plainList__ValueAssembler) AssignFloat(v float64) error { vb := plainFloat(v) return lva.AssignNode(&vb) } func (lva *plainList__ValueAssembler) AssignString(v string) error { vb := plainString(v) return lva.AssignNode(&vb) } func (lva *plainList__ValueAssembler) AssignBytes(v []byte) error { vb := plainBytes(v) return lva.AssignNode(&vb) } func (lva *plainList__ValueAssembler) AssignLink(v ipld.Link) error { vb := plainLink{v} return lva.AssignNode(&vb) } func (lva *plainList__ValueAssembler) AssignNode(v ipld.Node) error { lva.la.w.x = append(lva.la.w.x, v) lva.la.state = laState_initial lva.la = nil // invalidate self to prevent further incorrect use. return nil } func (plainList__ValueAssembler) Style() ipld.NodeStyle { return Style__Any{} } type plainList__ValueAssemblerMap struct { ca plainMap__Assembler p *plainList__Assembler // pointer back to parent, for final insert and state bump } // we briefly state only the methods we need to delegate here. // just embedding plainMap__Assembler also behaves correctly, // but causes a lot of unnecessary autogenerated functions in the final binary. func (ma *plainList__ValueAssemblerMap) AssembleDirectly(k string) (ipld.NodeAssembler, error) { return ma.ca.AssembleDirectly(k) } func (ma *plainList__ValueAssemblerMap) AssembleKey() ipld.NodeAssembler { return ma.ca.AssembleKey() } func (ma *plainList__ValueAssemblerMap) AssembleValue() ipld.NodeAssembler { return ma.ca.AssembleValue() } func (plainList__ValueAssemblerMap) KeyStyle() ipld.NodeStyle { return Style__String{} } func (plainList__ValueAssemblerMap) ValueStyle(_ string) ipld.NodeStyle { return Style__Any{} } func (ma *plainList__ValueAssemblerMap) Finish() error { if err := ma.ca.Finish(); err != nil { return err } w := ma.ca.w ma.ca.w = nil return ma.p.va.AssignNode(w) } type plainList__ValueAssemblerList struct { ca plainList__Assembler p *plainList__Assembler // pointer back to parent, for final insert and state bump } // we briefly state only the methods we need to delegate here. // just embedding plainList__Assembler also behaves correctly, // but causes a lot of unnecessary autogenerated functions in the final binary. func (la *plainList__ValueAssemblerList) AssembleValue() ipld.NodeAssembler { return la.ca.AssembleValue() } func (plainList__ValueAssemblerList) ValueStyle(_ int) ipld.NodeStyle { return Style__Any{} } func (la *plainList__ValueAssemblerList) Finish() error { if err := la.ca.Finish(); err != nil { return err } w := la.ca.w la.ca.w = nil return la.p.va.AssignNode(w) }