github.com/ipld/go-ipld-prime@v0.21.0/node/basicnode/map.go (about)

     1  package basicnode
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/ipld/go-ipld-prime/datamodel"
     7  	"github.com/ipld/go-ipld-prime/node/mixins"
     8  )
     9  
    10  var (
    11  	_ datamodel.Node          = &plainMap{}
    12  	_ datamodel.NodePrototype = Prototype__Map{}
    13  	_ datamodel.NodeBuilder   = &plainMap__Builder{}
    14  	_ datamodel.NodeAssembler = &plainMap__Assembler{}
    15  )
    16  
    17  // plainMap is a concrete type that provides a map-kind datamodel.Node.
    18  // It can contain any kind of value.
    19  // plainMap is also embedded in the 'any' struct and usable from there.
    20  type plainMap struct {
    21  	m map[string]datamodel.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  
    25  type plainMap__Entry struct {
    26  	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  	v datamodel.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.)
    28  	// 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.
    29  }
    30  
    31  // -- Node interface methods -->
    32  
    33  func (plainMap) Kind() datamodel.Kind {
    34  	return datamodel.Kind_Map
    35  }
    36  func (n *plainMap) LookupByString(key string) (datamodel.Node, error) {
    37  	v, exists := n.m[key]
    38  	if !exists {
    39  		return nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}
    40  	}
    41  	return v, nil
    42  }
    43  func (n *plainMap) LookupByNode(key datamodel.Node) (datamodel.Node, error) {
    44  	ks, err := key.AsString()
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	return n.LookupByString(ks)
    49  }
    50  func (plainMap) LookupByIndex(idx int64) (datamodel.Node, error) {
    51  	return mixins.Map{TypeName: "map"}.LookupByIndex(0)
    52  }
    53  func (n *plainMap) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {
    54  	return n.LookupByString(seg.String())
    55  }
    56  func (n *plainMap) MapIterator() datamodel.MapIterator {
    57  	return &plainMap_MapIterator{n, 0}
    58  }
    59  func (plainMap) ListIterator() datamodel.ListIterator {
    60  	return nil
    61  }
    62  func (n *plainMap) Length() int64 {
    63  	return int64(len(n.t))
    64  }
    65  func (plainMap) IsAbsent() bool {
    66  	return false
    67  }
    68  func (plainMap) IsNull() bool {
    69  	return false
    70  }
    71  func (plainMap) AsBool() (bool, error) {
    72  	return mixins.Map{TypeName: "map"}.AsBool()
    73  }
    74  func (plainMap) AsInt() (int64, error) {
    75  	return mixins.Map{TypeName: "map"}.AsInt()
    76  }
    77  func (plainMap) AsFloat() (float64, error) {
    78  	return mixins.Map{TypeName: "map"}.AsFloat()
    79  }
    80  func (plainMap) AsString() (string, error) {
    81  	return mixins.Map{TypeName: "map"}.AsString()
    82  }
    83  func (plainMap) AsBytes() ([]byte, error) {
    84  	return mixins.Map{TypeName: "map"}.AsBytes()
    85  }
    86  func (plainMap) AsLink() (datamodel.Link, error) {
    87  	return mixins.Map{TypeName: "map"}.AsLink()
    88  }
    89  func (plainMap) Prototype() datamodel.NodePrototype {
    90  	return Prototype.Map
    91  }
    92  
    93  type plainMap_MapIterator struct {
    94  	n   *plainMap
    95  	idx int
    96  }
    97  
    98  func (itr *plainMap_MapIterator) Next() (k datamodel.Node, v datamodel.Node, _ error) {
    99  	if itr.Done() {
   100  		return nil, nil, datamodel.ErrIteratorOverread{}
   101  	}
   102  	k = &itr.n.t[itr.idx].k
   103  	v = itr.n.t[itr.idx].v
   104  	itr.idx++
   105  	return
   106  }
   107  func (itr *plainMap_MapIterator) Done() bool {
   108  	return itr.idx >= len(itr.n.t)
   109  }
   110  
   111  // -- NodePrototype -->
   112  
   113  type Prototype__Map struct{}
   114  
   115  func (Prototype__Map) NewBuilder() datamodel.NodeBuilder {
   116  	return &plainMap__Builder{plainMap__Assembler{w: &plainMap{}}}
   117  }
   118  
   119  // -- NodeBuilder -->
   120  
   121  type plainMap__Builder struct {
   122  	plainMap__Assembler
   123  }
   124  
   125  func (nb *plainMap__Builder) Build() datamodel.Node {
   126  	if nb.state != maState_finished {
   127  		panic("invalid state: assembler must be 'finished' before Build can be called!")
   128  	}
   129  	return nb.w
   130  }
   131  func (nb *plainMap__Builder) Reset() {
   132  	*nb = plainMap__Builder{}
   133  	nb.w = &plainMap{}
   134  }
   135  
   136  // -- NodeAssembler -->
   137  
   138  type plainMap__Assembler struct {
   139  	w *plainMap
   140  
   141  	ka plainMap__KeyAssembler
   142  	va plainMap__ValueAssembler
   143  
   144  	state maState
   145  }
   146  type plainMap__KeyAssembler struct {
   147  	ma *plainMap__Assembler
   148  }
   149  type plainMap__ValueAssembler struct {
   150  	ma *plainMap__Assembler
   151  }
   152  
   153  // maState is an enum of the state machine for a map assembler.
   154  // (this might be something to export reusably, but it's also very much an impl detail that need not be seen, so, dubious.)
   155  type maState uint8
   156  
   157  const (
   158  	maState_initial     maState = iota // also the 'expect key or finish' state
   159  	maState_midKey                     // waiting for a 'finished' state in the KeyAssembler.
   160  	maState_expectValue                // 'AssembleValue' is the only valid next step
   161  	maState_midValue                   // waiting for a 'finished' state in the ValueAssembler.
   162  	maState_finished                   // 'w' will also be nil, but this is a politer statement
   163  )
   164  
   165  func (na *plainMap__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {
   166  	if sizeHint < 0 {
   167  		sizeHint = 0
   168  	}
   169  	// Allocate storage space.
   170  	na.w.t = make([]plainMap__Entry, 0, sizeHint)
   171  	na.w.m = make(map[string]datamodel.Node, sizeHint)
   172  	// That's it; return self as the MapAssembler.  We already have all the right methods on this structure.
   173  	return na, nil
   174  }
   175  func (plainMap__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {
   176  	return mixins.MapAssembler{TypeName: "map"}.BeginList(0)
   177  }
   178  func (plainMap__Assembler) AssignNull() error {
   179  	return mixins.MapAssembler{TypeName: "map"}.AssignNull()
   180  }
   181  func (plainMap__Assembler) AssignBool(bool) error {
   182  	return mixins.MapAssembler{TypeName: "map"}.AssignBool(false)
   183  }
   184  func (plainMap__Assembler) AssignInt(int64) error {
   185  	return mixins.MapAssembler{TypeName: "map"}.AssignInt(0)
   186  }
   187  func (plainMap__Assembler) AssignFloat(float64) error {
   188  	return mixins.MapAssembler{TypeName: "map"}.AssignFloat(0)
   189  }
   190  func (plainMap__Assembler) AssignString(string) error {
   191  	return mixins.MapAssembler{TypeName: "map"}.AssignString("")
   192  }
   193  func (plainMap__Assembler) AssignBytes([]byte) error {
   194  	return mixins.MapAssembler{TypeName: "map"}.AssignBytes(nil)
   195  }
   196  func (plainMap__Assembler) AssignLink(datamodel.Link) error {
   197  	return mixins.MapAssembler{TypeName: "map"}.AssignLink(nil)
   198  }
   199  func (na *plainMap__Assembler) AssignNode(v datamodel.Node) error {
   200  	// Sanity check assembler state.
   201  	//  Update of state to 'finished' comes later; where exactly depends on if shortcuts apply.
   202  	if na.state != maState_initial {
   203  		panic("misuse")
   204  	}
   205  	// Copy the content.
   206  	if v2, ok := v.(*plainMap); ok { // if our own type: shortcut.
   207  		// Copy the structure by value.
   208  		//  This means we'll have pointers into the same internal maps and slices;
   209  		//   this is okay, because the Node type promises it's immutable, and we are going to instantly finish ourselves to also maintain that.
   210  		// FIXME: the shortcut behaves differently than the long way: it discards any existing progress.  Doesn't violate immut, but is odd.
   211  		*na.w = *v2
   212  		na.state = maState_finished
   213  		return nil
   214  	}
   215  	// If the above shortcut didn't work, resort to a generic copy.
   216  	//  We call AssignNode for all the child values, giving them a chance to hit shortcuts even if we didn't.
   217  	if v.Kind() != datamodel.Kind_Map {
   218  		return datamodel.ErrWrongKind{TypeName: "map", MethodName: "AssignNode", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()}
   219  	}
   220  	itr := v.MapIterator()
   221  	for !itr.Done() {
   222  		k, v, err := itr.Next()
   223  		if err != nil {
   224  			return err
   225  		}
   226  		if err := na.AssembleKey().AssignNode(k); err != nil {
   227  			return err
   228  		}
   229  		if err := na.AssembleValue().AssignNode(v); err != nil {
   230  			return err
   231  		}
   232  	}
   233  	return na.Finish()
   234  }
   235  func (plainMap__Assembler) Prototype() datamodel.NodePrototype {
   236  	return Prototype.Map
   237  }
   238  
   239  // -- MapAssembler -->
   240  
   241  // AssembleEntry is part of conforming to MapAssembler, which we do on
   242  // plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.
   243  func (ma *plainMap__Assembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {
   244  	// Sanity check assembler state.
   245  	//  Update of state comes after possible key rejection.
   246  	if ma.state != maState_initial {
   247  		panic("misuse")
   248  	}
   249  	// Check for dup keys; error if so.
   250  	_, exists := ma.w.m[k]
   251  	if exists {
   252  		return nil, datamodel.ErrRepeatedMapKey{Key: plainString(k)}
   253  	}
   254  	ma.state = maState_midValue
   255  	ma.w.t = append(ma.w.t, plainMap__Entry{k: plainString(k)})
   256  	// Make value assembler valid by giving it pointer back to whole 'ma'; yield it.
   257  	ma.va.ma = ma
   258  	return &ma.va, nil
   259  }
   260  
   261  // AssembleKey is part of conforming to MapAssembler, which we do on
   262  // plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.
   263  func (ma *plainMap__Assembler) AssembleKey() datamodel.NodeAssembler {
   264  	// Sanity check, then update, assembler state.
   265  	if ma.state != maState_initial {
   266  		panic("misuse")
   267  	}
   268  	ma.state = maState_midKey
   269  	// Make key assembler valid by giving it pointer back to whole 'ma'; yield it.
   270  	ma.ka.ma = ma
   271  	return &ma.ka
   272  }
   273  
   274  // AssembleValue is part of conforming to MapAssembler, which we do on
   275  // plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.
   276  func (ma *plainMap__Assembler) AssembleValue() datamodel.NodeAssembler {
   277  	// Sanity check, then update, assembler state.
   278  	if ma.state != maState_expectValue {
   279  		panic("misuse")
   280  	}
   281  	ma.state = maState_midValue
   282  	// Make value assembler valid by giving it pointer back to whole 'ma'; yield it.
   283  	ma.va.ma = ma
   284  	return &ma.va
   285  }
   286  
   287  // Finish is part of conforming to MapAssembler, which we do on
   288  // plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.
   289  func (ma *plainMap__Assembler) Finish() error {
   290  	// Sanity check, then update, assembler state.
   291  	if ma.state != maState_initial {
   292  		panic("misuse")
   293  	}
   294  	ma.state = maState_finished
   295  	// validators could run and report errors promptly, if this type had any.
   296  	return nil
   297  }
   298  func (plainMap__Assembler) KeyPrototype() datamodel.NodePrototype {
   299  	return Prototype__String{}
   300  }
   301  func (plainMap__Assembler) ValuePrototype(_ string) datamodel.NodePrototype {
   302  	return Prototype.Any
   303  }
   304  
   305  // -- MapAssembler.KeyAssembler -->
   306  
   307  func (plainMap__KeyAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {
   308  	return mixins.StringAssembler{TypeName: "string"}.BeginMap(0)
   309  }
   310  func (plainMap__KeyAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {
   311  	return mixins.StringAssembler{TypeName: "string"}.BeginList(0)
   312  }
   313  func (plainMap__KeyAssembler) AssignNull() error {
   314  	return mixins.StringAssembler{TypeName: "string"}.AssignNull()
   315  }
   316  func (plainMap__KeyAssembler) AssignBool(bool) error {
   317  	return mixins.StringAssembler{TypeName: "string"}.AssignBool(false)
   318  }
   319  func (plainMap__KeyAssembler) AssignInt(int64) error {
   320  	return mixins.StringAssembler{TypeName: "string"}.AssignInt(0)
   321  }
   322  func (plainMap__KeyAssembler) AssignFloat(float64) error {
   323  	return mixins.StringAssembler{TypeName: "string"}.AssignFloat(0)
   324  }
   325  func (mka *plainMap__KeyAssembler) AssignString(v string) error {
   326  	// Check for dup keys; error if so.
   327  	//  (And, backtrack state to accepting keys again so we don't get eternally wedged here.)
   328  	_, exists := mka.ma.w.m[v]
   329  	if exists {
   330  		mka.ma.state = maState_initial
   331  		mka.ma = nil // invalidate self to prevent further incorrect use.
   332  		return datamodel.ErrRepeatedMapKey{Key: plainString(v)}
   333  	}
   334  	// Assign the key into the end of the entry table;
   335  	//  we'll be doing map insertions after we get the value in hand.
   336  	//  (There's no need to delegate to another assembler for the key type,
   337  	//   because we're just at Data Model level here, which only regards plain strings.)
   338  	mka.ma.w.t = append(mka.ma.w.t, plainMap__Entry{})
   339  	mka.ma.w.t[len(mka.ma.w.t)-1].k = plainString(v)
   340  	// Update parent assembler state: clear to proceed.
   341  	mka.ma.state = maState_expectValue
   342  	mka.ma = nil // invalidate self to prevent further incorrect use.
   343  	return nil
   344  }
   345  func (plainMap__KeyAssembler) AssignBytes([]byte) error {
   346  	return mixins.StringAssembler{TypeName: "string"}.AssignBytes(nil)
   347  }
   348  func (plainMap__KeyAssembler) AssignLink(datamodel.Link) error {
   349  	return mixins.StringAssembler{TypeName: "string"}.AssignLink(nil)
   350  }
   351  func (mka *plainMap__KeyAssembler) AssignNode(v datamodel.Node) error {
   352  	vs, err := v.AsString()
   353  	if err != nil {
   354  		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?
   355  	}
   356  	return mka.AssignString(vs)
   357  }
   358  func (plainMap__KeyAssembler) Prototype() datamodel.NodePrototype {
   359  	return Prototype__String{}
   360  }
   361  
   362  // -- MapAssembler.ValueAssembler -->
   363  
   364  func (mva *plainMap__ValueAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {
   365  	ma := plainMap__ValueAssemblerMap{}
   366  	ma.ca.w = &plainMap{}
   367  	ma.p = mva.ma
   368  	_, err := ma.ca.BeginMap(sizeHint)
   369  	return &ma, err
   370  }
   371  func (mva *plainMap__ValueAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {
   372  	la := plainMap__ValueAssemblerList{}
   373  	la.ca.w = &plainList{}
   374  	la.p = mva.ma
   375  	_, err := la.ca.BeginList(sizeHint)
   376  	return &la, err
   377  }
   378  func (mva *plainMap__ValueAssembler) AssignNull() error {
   379  	return mva.AssignNode(datamodel.Null)
   380  }
   381  func (mva *plainMap__ValueAssembler) AssignBool(v bool) error {
   382  	vb := plainBool(v)
   383  	return mva.AssignNode(&vb)
   384  }
   385  func (mva *plainMap__ValueAssembler) AssignInt(v int64) error {
   386  	vb := plainInt(v)
   387  	return mva.AssignNode(&vb)
   388  }
   389  func (mva *plainMap__ValueAssembler) AssignFloat(v float64) error {
   390  	vb := plainFloat(v)
   391  	return mva.AssignNode(&vb)
   392  }
   393  func (mva *plainMap__ValueAssembler) AssignString(v string) error {
   394  	vb := plainString(v)
   395  	return mva.AssignNode(&vb)
   396  }
   397  func (mva *plainMap__ValueAssembler) AssignBytes(v []byte) error {
   398  	vb := plainBytes(v)
   399  	return mva.AssignNode(&vb)
   400  }
   401  func (mva *plainMap__ValueAssembler) AssignLink(v datamodel.Link) error {
   402  	vb := plainLink{v}
   403  	return mva.AssignNode(&vb)
   404  }
   405  func (mva *plainMap__ValueAssembler) AssignNode(v datamodel.Node) error {
   406  	l := len(mva.ma.w.t) - 1
   407  	mva.ma.w.t[l].v = v
   408  	mva.ma.w.m[string(mva.ma.w.t[l].k)] = v
   409  	mva.ma.state = maState_initial
   410  	mva.ma = nil // invalidate self to prevent further incorrect use.
   411  	return nil
   412  }
   413  func (plainMap__ValueAssembler) Prototype() datamodel.NodePrototype {
   414  	return Prototype.Any
   415  }
   416  
   417  type plainMap__ValueAssemblerMap struct {
   418  	ca plainMap__Assembler
   419  	p  *plainMap__Assembler // pointer back to parent, for final insert and state bump
   420  }
   421  
   422  // we briefly state only the methods we need to delegate here.
   423  // just embedding plainMap__Assembler also behaves correctly,
   424  //  but causes a lot of unnecessary autogenerated functions in the final binary.
   425  
   426  func (ma *plainMap__ValueAssemblerMap) AssembleEntry(k string) (datamodel.NodeAssembler, error) {
   427  	return ma.ca.AssembleEntry(k)
   428  }
   429  func (ma *plainMap__ValueAssemblerMap) AssembleKey() datamodel.NodeAssembler {
   430  	return ma.ca.AssembleKey()
   431  }
   432  func (ma *plainMap__ValueAssemblerMap) AssembleValue() datamodel.NodeAssembler {
   433  	return ma.ca.AssembleValue()
   434  }
   435  func (plainMap__ValueAssemblerMap) KeyPrototype() datamodel.NodePrototype {
   436  	return Prototype__String{}
   437  }
   438  func (plainMap__ValueAssemblerMap) ValuePrototype(_ string) datamodel.NodePrototype {
   439  	return Prototype.Any
   440  }
   441  
   442  func (ma *plainMap__ValueAssemblerMap) Finish() error {
   443  	if err := ma.ca.Finish(); err != nil {
   444  		return err
   445  	}
   446  	w := ma.ca.w
   447  	ma.ca.w = nil
   448  	return ma.p.va.AssignNode(w)
   449  }
   450  
   451  type plainMap__ValueAssemblerList struct {
   452  	ca plainList__Assembler
   453  	p  *plainMap__Assembler // pointer back to parent, for final insert and state bump
   454  }
   455  
   456  // we briefly state only the methods we need to delegate here.
   457  // just embedding plainList__Assembler also behaves correctly,
   458  //  but causes a lot of unnecessary autogenerated functions in the final binary.
   459  
   460  func (la *plainMap__ValueAssemblerList) AssembleValue() datamodel.NodeAssembler {
   461  	return la.ca.AssembleValue()
   462  }
   463  func (plainMap__ValueAssemblerList) ValuePrototype(_ int64) datamodel.NodePrototype {
   464  	return Prototype.Any
   465  }
   466  
   467  func (la *plainMap__ValueAssemblerList) Finish() error {
   468  	if err := la.ca.Finish(); err != nil {
   469  		return err
   470  	}
   471  	w := la.ca.w
   472  	la.ca.w = nil
   473  	return la.p.va.AssignNode(w)
   474  }