github.com/ipld/go-ipld-prime@v0.21.0/node/basicnode/list.go (about) 1 package basicnode 2 3 import ( 4 "github.com/ipld/go-ipld-prime/datamodel" 5 "github.com/ipld/go-ipld-prime/node/mixins" 6 ) 7 8 var ( 9 _ datamodel.Node = &plainList{} 10 _ datamodel.NodePrototype = Prototype__List{} 11 _ datamodel.NodeBuilder = &plainList__Builder{} 12 _ datamodel.NodeAssembler = &plainList__Assembler{} 13 ) 14 15 // plainList is a concrete type that provides a list-kind datamodel.Node. 16 // It can contain any kind of value. 17 // plainList is also embedded in the 'any' struct and usable from there. 18 type plainList struct { 19 x []datamodel.Node 20 } 21 22 // -- Node interface methods --> 23 24 func (plainList) Kind() datamodel.Kind { 25 return datamodel.Kind_List 26 } 27 func (plainList) LookupByString(string) (datamodel.Node, error) { 28 return mixins.List{TypeName: "list"}.LookupByString("") 29 } 30 func (plainList) LookupByNode(datamodel.Node) (datamodel.Node, error) { 31 return mixins.List{TypeName: "list"}.LookupByNode(nil) 32 } 33 func (n *plainList) LookupByIndex(idx int64) (datamodel.Node, error) { 34 if n.Length() <= idx { 35 return nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfInt(idx)} 36 } 37 return n.x[idx], nil 38 } 39 func (n *plainList) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) { 40 idx, err := seg.Index() 41 if err != nil { 42 return nil, datamodel.ErrInvalidSegmentForList{TroubleSegment: seg, Reason: err} 43 } 44 return n.LookupByIndex(idx) 45 } 46 func (plainList) MapIterator() datamodel.MapIterator { 47 return nil 48 } 49 func (n *plainList) ListIterator() datamodel.ListIterator { 50 return &plainList_ListIterator{n, 0} 51 } 52 func (n *plainList) Length() int64 { 53 return int64(len(n.x)) 54 } 55 func (plainList) IsAbsent() bool { 56 return false 57 } 58 func (plainList) IsNull() bool { 59 return false 60 } 61 func (plainList) AsBool() (bool, error) { 62 return mixins.List{TypeName: "list"}.AsBool() 63 } 64 func (plainList) AsInt() (int64, error) { 65 return mixins.List{TypeName: "list"}.AsInt() 66 } 67 func (plainList) AsFloat() (float64, error) { 68 return mixins.List{TypeName: "list"}.AsFloat() 69 } 70 func (plainList) AsString() (string, error) { 71 return mixins.List{TypeName: "list"}.AsString() 72 } 73 func (plainList) AsBytes() ([]byte, error) { 74 return mixins.List{TypeName: "list"}.AsBytes() 75 } 76 func (plainList) AsLink() (datamodel.Link, error) { 77 return mixins.List{TypeName: "list"}.AsLink() 78 } 79 func (plainList) Prototype() datamodel.NodePrototype { 80 return Prototype.List 81 } 82 83 type plainList_ListIterator struct { 84 n *plainList 85 idx int 86 } 87 88 func (itr *plainList_ListIterator) Next() (idx int64, v datamodel.Node, _ error) { 89 if itr.Done() { 90 return -1, nil, datamodel.ErrIteratorOverread{} 91 } 92 v = itr.n.x[itr.idx] 93 idx = int64(itr.idx) 94 itr.idx++ 95 return 96 } 97 func (itr *plainList_ListIterator) Done() bool { 98 return itr.idx >= len(itr.n.x) 99 } 100 101 // -- NodePrototype --> 102 103 type Prototype__List struct{} 104 105 func (Prototype__List) NewBuilder() datamodel.NodeBuilder { 106 return &plainList__Builder{plainList__Assembler{w: &plainList{}}} 107 } 108 109 // -- NodeBuilder --> 110 111 type plainList__Builder struct { 112 plainList__Assembler 113 } 114 115 func (nb *plainList__Builder) Build() datamodel.Node { 116 if nb.state != laState_finished { 117 panic("invalid state: assembler must be 'finished' before Build can be called!") 118 } 119 return nb.w 120 } 121 func (nb *plainList__Builder) Reset() { 122 *nb = plainList__Builder{} 123 nb.w = &plainList{} 124 } 125 126 // -- NodeAssembler --> 127 128 type plainList__Assembler struct { 129 w *plainList 130 131 va plainList__ValueAssembler 132 133 state laState 134 } 135 type plainList__ValueAssembler struct { 136 la *plainList__Assembler 137 } 138 139 // laState is an enum of the state machine for a list assembler. 140 // (this might be something to export reusably, but it's also very much an impl detail that need not be seen, so, dubious.) 141 // it's similar to maState for maps, but has fewer states because we never have keys to assemble. 142 type laState uint8 143 144 const ( 145 laState_initial laState = iota // also the 'expect value or finish' state 146 laState_midValue // waiting for a 'finished' state in the ValueAssembler. 147 laState_finished // 'w' will also be nil, but this is a politer statement 148 ) 149 150 func (plainList__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) { 151 return mixins.ListAssembler{TypeName: "list"}.BeginMap(0) 152 } 153 func (na *plainList__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) { 154 if sizeHint < 0 { 155 sizeHint = 0 156 } 157 // Allocate storage space. 158 na.w.x = make([]datamodel.Node, 0, sizeHint) 159 // That's it; return self as the ListAssembler. We already have all the right methods on this structure. 160 return na, nil 161 } 162 func (plainList__Assembler) AssignNull() error { 163 return mixins.ListAssembler{TypeName: "list"}.AssignNull() 164 } 165 func (plainList__Assembler) AssignBool(bool) error { 166 return mixins.ListAssembler{TypeName: "list"}.AssignBool(false) 167 } 168 func (plainList__Assembler) AssignInt(int64) error { 169 return mixins.ListAssembler{TypeName: "list"}.AssignInt(0) 170 } 171 func (plainList__Assembler) AssignFloat(float64) error { 172 return mixins.ListAssembler{TypeName: "list"}.AssignFloat(0) 173 } 174 func (plainList__Assembler) AssignString(string) error { 175 return mixins.ListAssembler{TypeName: "list"}.AssignString("") 176 } 177 func (plainList__Assembler) AssignBytes([]byte) error { 178 return mixins.ListAssembler{TypeName: "list"}.AssignBytes(nil) 179 } 180 func (plainList__Assembler) AssignLink(datamodel.Link) error { 181 return mixins.ListAssembler{TypeName: "list"}.AssignLink(nil) 182 } 183 func (na *plainList__Assembler) AssignNode(v datamodel.Node) error { 184 // Sanity check, then update, assembler state. 185 // Update of state to 'finished' comes later; where exactly depends on if shortcuts apply. 186 if na.state != laState_initial { 187 panic("misuse") 188 } 189 // Copy the content. 190 if v2, ok := v.(*plainList); ok { // if our own type: shortcut. 191 // Copy the structure by value. 192 // This means we'll have pointers into the same internal maps and slices; 193 // this is okay, because the Node type promises it's immutable, and we are going to instantly finish ourselves to also maintain that. 194 // FIXME: the shortcut behaves differently than the long way: it discards any existing progress. Doesn't violate immut, but is odd. 195 *na.w = *v2 196 na.state = laState_finished 197 return nil 198 } 199 // If the above shortcut didn't work, resort to a generic copy. 200 // We call AssignNode for all the child values, giving them a chance to hit shortcuts even if we didn't. 201 if v.Kind() != datamodel.Kind_List { 202 return datamodel.ErrWrongKind{TypeName: "list", MethodName: "AssignNode", AppropriateKind: datamodel.KindSet_JustList, ActualKind: v.Kind()} 203 } 204 itr := v.ListIterator() 205 for !itr.Done() { 206 _, v, err := itr.Next() 207 if err != nil { 208 return err 209 } 210 if err := na.AssembleValue().AssignNode(v); err != nil { 211 return err 212 } 213 } 214 return na.Finish() 215 } 216 func (plainList__Assembler) Prototype() datamodel.NodePrototype { 217 return Prototype.List 218 } 219 220 // -- ListAssembler --> 221 222 // AssembleValue is part of conforming to ListAssembler, which we do on 223 // plainList__Assembler so that BeginList can just return a retyped pointer rather than new object. 224 func (la *plainList__Assembler) AssembleValue() datamodel.NodeAssembler { 225 // Sanity check, then update, assembler state. 226 if la.state != laState_initial { 227 panic("misuse") 228 } 229 la.state = laState_midValue 230 // Make value assembler valid by giving it pointer back to whole 'la'; yield it. 231 la.va.la = la 232 return &la.va 233 } 234 235 // Finish is part of conforming to ListAssembler, which we do on 236 // plainList__Assembler so that BeginList can just return a retyped pointer rather than new object. 237 func (la *plainList__Assembler) Finish() error { 238 // Sanity check, then update, assembler state. 239 if la.state != laState_initial { 240 panic("misuse") 241 } 242 la.state = laState_finished 243 // validators could run and report errors promptly, if this type had any. 244 return nil 245 } 246 func (plainList__Assembler) ValuePrototype(_ int64) datamodel.NodePrototype { 247 return Prototype.Any 248 } 249 250 // -- ListAssembler.ValueAssembler --> 251 252 func (lva *plainList__ValueAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) { 253 ma := plainList__ValueAssemblerMap{} 254 ma.ca.w = &plainMap{} 255 ma.p = lva.la 256 _, err := ma.ca.BeginMap(sizeHint) 257 return &ma, err 258 } 259 func (lva *plainList__ValueAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) { 260 la := plainList__ValueAssemblerList{} 261 la.ca.w = &plainList{} 262 la.p = lva.la 263 _, err := la.ca.BeginList(sizeHint) 264 return &la, err 265 } 266 func (lva *plainList__ValueAssembler) AssignNull() error { 267 return lva.AssignNode(datamodel.Null) 268 } 269 func (lva *plainList__ValueAssembler) AssignBool(v bool) error { 270 vb := plainBool(v) 271 return lva.AssignNode(&vb) 272 } 273 func (lva *plainList__ValueAssembler) AssignInt(v int64) error { 274 vb := plainInt(v) 275 return lva.AssignNode(&vb) 276 } 277 func (lva *plainList__ValueAssembler) AssignFloat(v float64) error { 278 vb := plainFloat(v) 279 return lva.AssignNode(&vb) 280 } 281 func (lva *plainList__ValueAssembler) AssignString(v string) error { 282 vb := plainString(v) 283 return lva.AssignNode(&vb) 284 } 285 func (lva *plainList__ValueAssembler) AssignBytes(v []byte) error { 286 vb := plainBytes(v) 287 return lva.AssignNode(&vb) 288 } 289 func (lva *plainList__ValueAssembler) AssignLink(v datamodel.Link) error { 290 vb := plainLink{v} 291 return lva.AssignNode(&vb) 292 } 293 func (lva *plainList__ValueAssembler) AssignNode(v datamodel.Node) error { 294 lva.la.w.x = append(lva.la.w.x, v) 295 lva.la.state = laState_initial 296 lva.la = nil // invalidate self to prevent further incorrect use. 297 return nil 298 } 299 func (plainList__ValueAssembler) Prototype() datamodel.NodePrototype { 300 return Prototype.Any 301 } 302 303 type plainList__ValueAssemblerMap struct { 304 ca plainMap__Assembler 305 p *plainList__Assembler // pointer back to parent, for final insert and state bump 306 } 307 308 // we briefly state only the methods we need to delegate here. 309 // just embedding plainMap__Assembler also behaves correctly, 310 // but causes a lot of unnecessary autogenerated functions in the final binary. 311 312 func (ma *plainList__ValueAssemblerMap) AssembleEntry(k string) (datamodel.NodeAssembler, error) { 313 return ma.ca.AssembleEntry(k) 314 } 315 func (ma *plainList__ValueAssemblerMap) AssembleKey() datamodel.NodeAssembler { 316 return ma.ca.AssembleKey() 317 } 318 func (ma *plainList__ValueAssemblerMap) AssembleValue() datamodel.NodeAssembler { 319 return ma.ca.AssembleValue() 320 } 321 func (plainList__ValueAssemblerMap) KeyPrototype() datamodel.NodePrototype { 322 return Prototype__String{} 323 } 324 func (plainList__ValueAssemblerMap) ValuePrototype(_ string) datamodel.NodePrototype { 325 return Prototype.Any 326 } 327 328 func (ma *plainList__ValueAssemblerMap) Finish() error { 329 if err := ma.ca.Finish(); err != nil { 330 return err 331 } 332 w := ma.ca.w 333 ma.ca.w = nil 334 return ma.p.va.AssignNode(w) 335 } 336 337 type plainList__ValueAssemblerList struct { 338 ca plainList__Assembler 339 p *plainList__Assembler // pointer back to parent, for final insert and state bump 340 } 341 342 // we briefly state only the methods we need to delegate here. 343 // just embedding plainList__Assembler also behaves correctly, 344 // but causes a lot of unnecessary autogenerated functions in the final binary. 345 346 func (la *plainList__ValueAssemblerList) AssembleValue() datamodel.NodeAssembler { 347 return la.ca.AssembleValue() 348 } 349 func (plainList__ValueAssemblerList) ValuePrototype(_ int64) datamodel.NodePrototype { 350 return Prototype.Any 351 } 352 353 func (la *plainList__ValueAssemblerList) Finish() error { 354 if err := la.ca.Finish(); err != nil { 355 return err 356 } 357 w := la.ca.w 358 la.ca.w = nil 359 return la.p.va.AssignNode(w) 360 }