map.go 14 KB
Newer Older
1
package basicnode
2 3 4 5

import (
	"fmt"

6 7
	ipld "github.com/ipld/go-ipld-prime"
	"github.com/ipld/go-ipld-prime/node/mixins"
8 9
)

10 11 12 13 14 15 16
var (
	_ ipld.Node          = &plainMap{}
	_ ipld.NodeStyle     = Style__Map{}
	_ ipld.NodeBuilder   = &plainMap__Builder{}
	_ ipld.NodeAssembler = &plainMap__Assembler{}
)

17 18 19
// plainMap is a concrete type that provides a map-kind ipld.Node.
// It can contain any kind of value.
// plainMap is also embedded in the 'any' struct and usable from there.
Eric Myhre's avatar
Eric Myhre committed
20
type plainMap struct {
21
	m map[string]ipld.Node // string key -- even if a runtime schema wrapper is using us for storage, we must have a comparable type here, and string is all we know.
22
	t []plainMap__Entry    // table for fast iteration, order keeping, and yielding pointers to enable alloc/conv amortization.
23 24
}

Eric Myhre's avatar
Eric Myhre committed
25 26
type plainMap__Entry struct {
	k plainString // address of this used when we return keys as nodes, such as in iterators.  Need in one place to amortize shifts to heap when ptr'ing for iface.
27 28
	v ipld.Node   // identical to map values.  keeping them here simplifies iteration.  (in codegen'd maps, this position is also part of amortization, but in this implementation, that's less useful.)
	// note on alternate implementations: 'v' could also use the 'any' type, and thus amortize value allocations.  the memory size trade would be large however, so we don't, here.
Eric Myhre's avatar
Eric Myhre committed
29 30
}

31 32
// -- Node interface methods -->

Eric Myhre's avatar
Eric Myhre committed
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
func (plainMap) ReprKind() ipld.ReprKind {
	return ipld.ReprKind_Map
}
func (n *plainMap) LookupString(key string) (ipld.Node, error) {
	v, exists := n.m[key]
	if !exists {
		return nil, ipld.ErrNotExists{ipld.PathSegmentOfString(key)}
	}
	return v, nil
}
func (n *plainMap) Lookup(key ipld.Node) (ipld.Node, error) {
	ks, err := key.AsString()
	if err != nil {
		return nil, err
	}
	return n.LookupString(ks)
}
func (plainMap) LookupIndex(idx int) (ipld.Node, error) {
51
	return mixins.Map{"map"}.LookupIndex(0)
Eric Myhre's avatar
Eric Myhre committed
52 53 54 55 56 57 58 59
}
func (n *plainMap) LookupSegment(seg ipld.PathSegment) (ipld.Node, error) {
	return n.LookupString(seg.String())
}
func (n *plainMap) MapIterator() ipld.MapIterator {
	return &plainMap_MapIterator{n, 0}
}
func (plainMap) ListIterator() ipld.ListIterator {
60
	return nil
Eric Myhre's avatar
Eric Myhre committed
61 62 63 64 65 66 67 68 69 70 71
}
func (n *plainMap) Length() int {
	return len(n.t)
}
func (plainMap) IsUndefined() bool {
	return false
}
func (plainMap) IsNull() bool {
	return false
}
func (plainMap) AsBool() (bool, error) {
72
	return mixins.Map{"map"}.AsBool()
Eric Myhre's avatar
Eric Myhre committed
73 74
}
func (plainMap) AsInt() (int, error) {
75
	return mixins.Map{"map"}.AsInt()
Eric Myhre's avatar
Eric Myhre committed
76 77
}
func (plainMap) AsFloat() (float64, error) {
78
	return mixins.Map{"map"}.AsFloat()
Eric Myhre's avatar
Eric Myhre committed
79 80
}
func (plainMap) AsString() (string, error) {
81
	return mixins.Map{"map"}.AsString()
Eric Myhre's avatar
Eric Myhre committed
82 83
}
func (plainMap) AsBytes() ([]byte, error) {
84
	return mixins.Map{"map"}.AsBytes()
Eric Myhre's avatar
Eric Myhre committed
85 86
}
func (plainMap) AsLink() (ipld.Link, error) {
87
	return mixins.Map{"map"}.AsLink()
Eric Myhre's avatar
Eric Myhre committed
88 89
}
func (plainMap) Style() ipld.NodeStyle {
90
	return Style__Map{}
Eric Myhre's avatar
Eric Myhre committed
91 92 93 94 95
}

type plainMap_MapIterator struct {
	n   *plainMap
	idx int
96 97
}

Eric Myhre's avatar
Eric Myhre committed
98 99 100 101 102 103 104 105 106 107 108 109 110
func (itr *plainMap_MapIterator) Next() (k ipld.Node, v ipld.Node, _ error) {
	if itr.Done() {
		return nil, nil, ipld.ErrIteratorOverread{}
	}
	k = &itr.n.t[itr.idx].k
	v = itr.n.t[itr.idx].v
	itr.idx++
	return
}
func (itr *plainMap_MapIterator) Done() bool {
	return itr.idx >= len(itr.n.t)
}

111 112
// -- NodeStyle -->

Eric Myhre's avatar
Eric Myhre committed
113 114 115 116 117 118
type Style__Map struct{}

func (Style__Map) NewBuilder() ipld.NodeBuilder {
	return &plainMap__Builder{plainMap__Assembler{w: &plainMap{}}}
}

119
// -- NodeBuilder -->
120

Eric Myhre's avatar
Eric Myhre committed
121 122 123 124
type plainMap__Builder struct {
	plainMap__Assembler
}

125
func (nb *plainMap__Builder) Build() ipld.Node {
126 127
	if nb.state != maState_finished {
		panic("invalid state: assembler must be 'finished' before Build can be called!")
128
	}
129
	return nb.w
Eric Myhre's avatar
Eric Myhre committed
130 131 132 133 134 135
}
func (nb *plainMap__Builder) Reset() {
	*nb = plainMap__Builder{}
	nb.w = &plainMap{}
}

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
// -- NodeAssembler -->

type plainMap__Assembler struct {
	w *plainMap

	ka plainMap__KeyAssembler
	va plainMap__ValueAssembler

	state maState
}
type plainMap__KeyAssembler struct {
	ma *plainMap__Assembler
}
type plainMap__ValueAssembler struct {
	ma *plainMap__Assembler
}

// maState is an enum of the state machine for a map assembler.
// (this might be something to export reusably, but it's also very much an impl detail that need not be seen, so, dubious.)
type maState uint8

const (
158 159
	maState_initial     maState = iota // also the 'expect key or finish' state
	maState_midKey                     // waiting for a 'finished' state in the KeyAssembler.
160
	maState_expectValue                // 'AssembleValue' is the only valid next step
161 162
	maState_midValue                   // waiting for a 'finished' state in the ValueAssembler.
	maState_finished                   // 'w' will also be nil, but this is a politer statement
163 164
)

Eric Myhre's avatar
Eric Myhre committed
165
func (na *plainMap__Assembler) BeginMap(sizeHint int) (ipld.MapNodeAssembler, error) {
166 167 168
	if sizeHint < 0 {
		sizeHint = 0
	}
Eric Myhre's avatar
Eric Myhre committed
169 170 171 172 173 174
	// Allocate storage space.
	na.w.t = make([]plainMap__Entry, 0, sizeHint)
	na.w.m = make(map[string]ipld.Node, sizeHint)
	// That's it; return self as the MapNodeAssembler.  We already have all the right methods on this structure.
	return na, nil
}
Eric Myhre's avatar
Eric Myhre committed
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
func (plainMap__Assembler) BeginList(sizeHint int) (ipld.ListNodeAssembler, error) {
	return mixins.MapAssembler{"map"}.BeginList(0)
}
func (plainMap__Assembler) AssignNull() error {
	return mixins.MapAssembler{"map"}.AssignNull()
}
func (plainMap__Assembler) AssignBool(bool) error {
	return mixins.MapAssembler{"map"}.AssignBool(false)
}
func (plainMap__Assembler) AssignInt(int) error {
	return mixins.MapAssembler{"map"}.AssignInt(0)
}
func (plainMap__Assembler) AssignFloat(float64) error {
	return mixins.MapAssembler{"map"}.AssignFloat(0)
}
func (plainMap__Assembler) AssignString(string) error {
	return mixins.MapAssembler{"map"}.AssignString("")
}
func (plainMap__Assembler) AssignBytes([]byte) error {
	return mixins.MapAssembler{"map"}.AssignBytes(nil)
}
Eric Myhre's avatar
Eric Myhre committed
196 197 198
func (plainMap__Assembler) AssignLink(ipld.Link) error {
	return mixins.MapAssembler{"map"}.AssignLink(nil)
}
Eric Myhre's avatar
Eric Myhre committed
199
func (na *plainMap__Assembler) AssignNode(v ipld.Node) error {
Eric Myhre's avatar
Eric Myhre committed
200 201 202
	// 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'.)
203
	//   (wait... actually, probably we can?  'Assign' is a "finish" method.  we can&should invalidate the wip pointer here.)
Eric Myhre's avatar
Eric Myhre committed
204 205
	panic("later")
}
206 207 208
func (plainMap__Assembler) Style() ipld.NodeStyle {
	return Style__Map{}
}
209

210 211 212 213
// -- MapNodeAssembler -->

// AssembleDirectly is part of conforming to MapAssembler, which we do on
// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.
Eric Myhre's avatar
Eric Myhre committed
214
func (ma *plainMap__Assembler) AssembleDirectly(k string) (ipld.NodeAssembler, error) {
215 216
	// Sanity check, then update, assembler state.
	if ma.state != maState_initial {
217 218
		panic("misuse")
	}
219 220
	ma.state = maState_midValue
	// Check for dup keys; error if so.
221 222
	_, exists := ma.w.m[k]
	if exists {
223
		return nil, ipld.ErrRepeatedMapKey{plainString(k)}
224
	}
Eric Myhre's avatar
Eric Myhre committed
225
	ma.w.t = append(ma.w.t, plainMap__Entry{k: plainString(k)})
226 227
	// Make value assembler valid by giving it pointer back to whole 'ma'; yield it.
	ma.va.ma = ma
228
	return &ma.va, nil
229 230
}

Eric Myhre's avatar
Eric Myhre committed
231
// AssembleKey is part of conforming to MapNodeAssembler, which we do on
232
// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.
Eric Myhre's avatar
Eric Myhre committed
233
func (ma *plainMap__Assembler) AssembleKey() ipld.NodeAssembler {
234 235
	// Sanity check, then update, assembler state.
	if ma.state != maState_initial {
Eric Myhre's avatar
Eric Myhre committed
236 237
		panic("misuse")
	}
238 239
	ma.state = maState_midKey
	// Extend entry table.
Eric Myhre's avatar
Eric Myhre committed
240
	ma.w.t = append(ma.w.t, plainMap__Entry{})
241 242
	// Make key assembler valid by giving it pointer back to whole 'ma'; yield it.
	ma.ka.ma = ma
Eric Myhre's avatar
Eric Myhre committed
243
	return &ma.ka
244
}
245

Eric Myhre's avatar
Eric Myhre committed
246
// AssembleValue is part of conforming to MapNodeAssembler, which we do on
247
// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.
Eric Myhre's avatar
Eric Myhre committed
248
func (ma *plainMap__Assembler) AssembleValue() ipld.NodeAssembler {
249 250
	// Sanity check, then update, assembler state.
	if ma.state != maState_expectValue {
Eric Myhre's avatar
Eric Myhre committed
251 252
		panic("misuse")
	}
253
	ma.state = maState_midValue
254 255
	// Make value assembler valid by giving it pointer back to whole 'ma'; yield it.
	ma.va.ma = ma
Eric Myhre's avatar
Eric Myhre committed
256
	return &ma.va
257
}
258

Eric Myhre's avatar
Eric Myhre committed
259
// Finish is part of conforming to MapNodeAssembler, which we do on
260
// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.
261
func (ma *plainMap__Assembler) Finish() error {
262 263
	// Sanity check, then update, assembler state.
	if ma.state != maState_initial {
264 265
		panic("misuse")
	}
266
	ma.state = maState_finished
267
	// validators could run and report errors promptly, if this type had any.
Eric Myhre's avatar
Eric Myhre committed
268 269
	return nil
}
270 271 272
func (plainMap__Assembler) KeyStyle() ipld.NodeStyle {
	return Style__String{}
}
273
func (plainMap__Assembler) ValueStyle(_ string) ipld.NodeStyle {
274 275
	return Style__Any{}
}
Eric Myhre's avatar
Eric Myhre committed
276

277 278
// -- MapNodeAssembler.KeyAssembler -->

279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
func (plainMap__KeyAssembler) BeginMap(sizeHint int) (ipld.MapNodeAssembler, error) {
	return mixins.StringAssembler{"string"}.BeginMap(0)
}
func (plainMap__KeyAssembler) BeginList(sizeHint int) (ipld.ListNodeAssembler, error) {
	return mixins.StringAssembler{"string"}.BeginList(0)
}
func (plainMap__KeyAssembler) AssignNull() error {
	return mixins.StringAssembler{"string"}.AssignNull()
}
func (plainMap__KeyAssembler) AssignBool(bool) error {
	return mixins.StringAssembler{"string"}.AssignBool(false)
}
func (plainMap__KeyAssembler) AssignInt(int) error {
	return mixins.StringAssembler{"string"}.AssignInt(0)
}
func (plainMap__KeyAssembler) AssignFloat(float64) error {
	return mixins.StringAssembler{"string"}.AssignFloat(0)
}
Eric Myhre's avatar
Eric Myhre committed
297
func (mka *plainMap__KeyAssembler) AssignString(v string) error {
298
	// Check for dup keys; error if so.
Eric Myhre's avatar
Eric Myhre committed
299
	_, exists := mka.ma.w.m[v]
300
	if exists {
301
		return ipld.ErrRepeatedMapKey{plainString(v)}
302
	}
303 304 305 306
	// Assign the key into the end of the entry table;
	//  we'll be doing map insertions after we get the value in hand.
	//  (There's no need to delegate to another assembler for the key type,
	//   because we're just at Data Model level here, which only regards plain strings.)
Eric Myhre's avatar
Eric Myhre committed
307
	mka.ma.w.t[len(mka.ma.w.t)-1].k = plainString(v)
308 309
	// Update parent assembler state: clear to proceed.
	mka.ma.state = maState_expectValue
310
	mka.ma = nil // invalidate self to prevent further incorrect use.
311 312
	return nil
}
313 314 315
func (plainMap__KeyAssembler) AssignBytes([]byte) error {
	return mixins.StringAssembler{"string"}.AssignBytes(nil)
}
316 317 318
func (plainMap__KeyAssembler) AssignLink(ipld.Link) error {
	return mixins.StringAssembler{"string"}.AssignLink(nil)
}
Eric Myhre's avatar
Eric Myhre committed
319
func (mka *plainMap__KeyAssembler) AssignNode(v ipld.Node) error {
320 321 322 323 324 325
	vs, err := v.AsString()
	if err != nil {
		return fmt.Errorf("cannot assign non-string node into map key assembler") // FIXME:errors: this doesn't quite fit in ErrWrongKind cleanly; new error type?
	}
	return mka.AssignString(vs)
}
326 327 328
func (plainMap__KeyAssembler) Style() ipld.NodeStyle {
	return Style__String{}
}
329

330 331
// -- MapNodeAssembler.ValueAssembler -->

Eric Myhre's avatar
Eric Myhre committed
332
func (mva *plainMap__ValueAssembler) BeginMap(sizeHint int) (ipld.MapNodeAssembler, error) {
333
	ma := plainMap__ValueAssemblerMap{}
334
	ma.ca.w = &plainMap{}
335
	ma.p = mva.ma
336
	_, err := ma.ca.BeginMap(sizeHint)
337
	return &ma, err
338
}
Eric Myhre's avatar
Eric Myhre committed
339
func (mva *plainMap__ValueAssembler) BeginList(sizeHint int) (ipld.ListNodeAssembler, error) {
340 341 342 343 344 345 346 347 348 349 350 351
	la := plainMap__ValueAssemblerList{}
	la.ca.w = &plainList{}
	la.p = mva.ma
	_, err := la.ca.BeginList(sizeHint)
	return &la, err
}
func (mva *plainMap__ValueAssembler) AssignNull() error {
	return mva.AssignNode(ipld.Null)
}
func (mva *plainMap__ValueAssembler) AssignBool(v bool) error {
	vb := plainBool(v)
	return mva.AssignNode(&vb)
352
}
Eric Myhre's avatar
Eric Myhre committed
353 354
func (mva *plainMap__ValueAssembler) AssignInt(v int) error {
	vb := plainInt(v)
Eric Myhre's avatar
Eric Myhre committed
355
	return mva.AssignNode(&vb)
356
}
357 358 359 360
func (mva *plainMap__ValueAssembler) AssignFloat(v float64) error {
	vb := plainFloat(v)
	return mva.AssignNode(&vb)
}
361 362
func (mva *plainMap__ValueAssembler) AssignString(v string) error {
	vb := plainString(v)
Eric Myhre's avatar
Eric Myhre committed
363
	return mva.AssignNode(&vb)
364
}
365 366 367 368 369 370 371 372
func (mva *plainMap__ValueAssembler) AssignBytes(v []byte) error {
	vb := plainBytes(v)
	return mva.AssignNode(&vb)
}
func (mva *plainMap__ValueAssembler) AssignLink(v ipld.Link) error {
	vb := plainLink{v}
	return mva.AssignNode(&vb)
}
Eric Myhre's avatar
Eric Myhre committed
373
func (mva *plainMap__ValueAssembler) AssignNode(v ipld.Node) error {
Eric Myhre's avatar
Eric Myhre committed
374 375 376
	l := len(mva.ma.w.t) - 1
	mva.ma.w.t[l].v = v
	mva.ma.w.m[string(mva.ma.w.t[l].k)] = v
377
	mva.ma.state = maState_initial
378
	mva.ma = nil // invalidate self to prevent further incorrect use.
379 380
	return nil
}
381 382 383
func (plainMap__ValueAssembler) Style() ipld.NodeStyle {
	return Style__Any{}
}
384 385

type plainMap__ValueAssemblerMap struct {
386 387 388 389
	ca plainMap__Assembler
	p  *plainMap__Assembler // pointer back to parent, for final insert and state bump
}

Eric Myhre's avatar
Eric Myhre committed
390 391 392
// 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.
393 394 395 396 397 398 399 400 401

func (ma *plainMap__ValueAssemblerMap) AssembleDirectly(k string) (ipld.NodeAssembler, error) {
	return ma.ca.AssembleDirectly(k)
}
func (ma *plainMap__ValueAssemblerMap) AssembleKey() ipld.NodeAssembler {
	return ma.ca.AssembleKey()
}
func (ma *plainMap__ValueAssemblerMap) AssembleValue() ipld.NodeAssembler {
	return ma.ca.AssembleValue()
402
}
403 404 405
func (plainMap__ValueAssemblerMap) KeyStyle() ipld.NodeStyle {
	return Style__String{}
}
406
func (plainMap__ValueAssemblerMap) ValueStyle(_ string) ipld.NodeStyle {
407 408
	return Style__Any{}
}
409

410 411
func (ma *plainMap__ValueAssemblerMap) Finish() error {
	if err := ma.ca.Finish(); err != nil {
412 413
		return err
	}
414 415 416
	w := ma.ca.w
	ma.ca.w = nil
	return ma.p.va.AssignNode(w)
417
}
418 419 420 421 422 423 424 425 426 427 428 429 430

type plainMap__ValueAssemblerList struct {
	ca plainList__Assembler
	p  *plainMap__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 *plainMap__ValueAssemblerList) AssembleValue() ipld.NodeAssembler {
	return la.ca.AssembleValue()
}
431 432 433
func (plainMap__ValueAssemblerList) ValueStyle() ipld.NodeStyle {
	return Style__Any{}
}
434 435 436 437 438 439 440 441 442

func (la *plainMap__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)
}