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

     1  package basicnode
     2  
     3  import (
     4  	"github.com/ipld/go-ipld-prime/datamodel"
     5  	"github.com/ipld/go-ipld-prime/linking"
     6  )
     7  
     8  var (
     9  	//_ datamodel.Node          = &anyNode{}
    10  	_ datamodel.NodePrototype = Prototype__Any{}
    11  	_ datamodel.NodeBuilder   = &anyBuilder{}
    12  	//_ datamodel.NodeAssembler = &anyAssembler{}
    13  )
    14  
    15  // Note that we don't use a "var _" declaration to assert that Chooser
    16  // implements traversal.LinkTargetNodePrototypeChooser, to keep basicnode's
    17  // dependencies fairly light.
    18  
    19  // Chooser implements traversal.LinkTargetNodePrototypeChooser.
    20  //
    21  // It can be used directly when loading links into the "any" prototype,
    22  // or with another chooser layer on top, such as:
    23  //
    24  //	prototypeChooser := dagpb.AddSupportToChooser(basicnode.Chooser)
    25  func Chooser(_ datamodel.Link, _ linking.LinkContext) (datamodel.NodePrototype, error) {
    26  	return Prototype.Any, nil
    27  }
    28  
    29  // -- Node interface methods -->
    30  
    31  // Unimplemented at present -- see "REVIEW" comment on anyNode.
    32  
    33  // -- NodePrototype -->
    34  
    35  type Prototype__Any struct{}
    36  
    37  func (Prototype__Any) NewBuilder() datamodel.NodeBuilder {
    38  	return &anyBuilder{}
    39  }
    40  
    41  // -- NodeBuilder -->
    42  
    43  // anyBuilder is a builder for any kind of node.
    44  //
    45  // anyBuilder is a little unusual in its internal workings:
    46  // unlike most builders, it doesn't embed the corresponding assembler,
    47  // nor will it end up using anyNode,
    48  // but instead embeds a builder for each of the kinds it might contain.
    49  // This is because we want a more granular return at the end:
    50  // if we used anyNode, and returned a pointer to just the relevant part of it,
    51  // we'd have all the extra bytes of anyNode still reachable in GC terms
    52  // for as long as that handle to the interior of it remains live.
    53  type anyBuilder struct {
    54  	// kind is set on first interaction, and used to select which builder to delegate 'Build' to!
    55  	// As soon as it's been set to a value other than zero (being "Invalid"), all other Assign/Begin calls will fail since something is already in progress.
    56  	// May also be set to the magic value '99', which means "i dunno, I'm just carrying another node of unknown prototype".
    57  	kind datamodel.Kind
    58  
    59  	// Only one of the following ends up being used...
    60  	//  but we don't know in advance which one, so all are embeded here.
    61  	//   This uses excessive space, but amortizes allocations, and all will be
    62  	//    freed as soon as the builder is done.
    63  	// Builders are only used for recursives;
    64  	//  scalars are simple enough we just do them directly.
    65  	// 'scalarNode' may also hold another Node of unknown prototype (possibly not even from this package),
    66  	//  in which case this is indicated by 'kind==99'.
    67  
    68  	mapBuilder  plainMap__Builder
    69  	listBuilder plainList__Builder
    70  	scalarNode  datamodel.Node
    71  }
    72  
    73  func (nb *anyBuilder) Reset() {
    74  	*nb = anyBuilder{}
    75  }
    76  
    77  func (nb *anyBuilder) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {
    78  	if nb.kind != datamodel.Kind_Invalid {
    79  		panic("misuse")
    80  	}
    81  	nb.kind = datamodel.Kind_Map
    82  	nb.mapBuilder.w = &plainMap{}
    83  	return nb.mapBuilder.BeginMap(sizeHint)
    84  }
    85  func (nb *anyBuilder) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {
    86  	if nb.kind != datamodel.Kind_Invalid {
    87  		panic("misuse")
    88  	}
    89  	nb.kind = datamodel.Kind_List
    90  	nb.listBuilder.w = &plainList{}
    91  	return nb.listBuilder.BeginList(sizeHint)
    92  }
    93  func (nb *anyBuilder) AssignNull() error {
    94  	if nb.kind != datamodel.Kind_Invalid {
    95  		panic("misuse")
    96  	}
    97  	nb.kind = datamodel.Kind_Null
    98  	return nil
    99  }
   100  func (nb *anyBuilder) AssignBool(v bool) error {
   101  	if nb.kind != datamodel.Kind_Invalid {
   102  		panic("misuse")
   103  	}
   104  	nb.kind = datamodel.Kind_Bool
   105  	nb.scalarNode = NewBool(v)
   106  	return nil
   107  }
   108  func (nb *anyBuilder) AssignInt(v int64) error {
   109  	if nb.kind != datamodel.Kind_Invalid {
   110  		panic("misuse")
   111  	}
   112  	nb.kind = datamodel.Kind_Int
   113  	nb.scalarNode = NewInt(v)
   114  	return nil
   115  }
   116  func (nb *anyBuilder) AssignFloat(v float64) error {
   117  	if nb.kind != datamodel.Kind_Invalid {
   118  		panic("misuse")
   119  	}
   120  	nb.kind = datamodel.Kind_Float
   121  	nb.scalarNode = NewFloat(v)
   122  	return nil
   123  }
   124  func (nb *anyBuilder) AssignString(v string) error {
   125  	if nb.kind != datamodel.Kind_Invalid {
   126  		panic("misuse")
   127  	}
   128  	nb.kind = datamodel.Kind_String
   129  	nb.scalarNode = NewString(v)
   130  	return nil
   131  }
   132  func (nb *anyBuilder) AssignBytes(v []byte) error {
   133  	if nb.kind != datamodel.Kind_Invalid {
   134  		panic("misuse")
   135  	}
   136  	nb.kind = datamodel.Kind_Bytes
   137  	nb.scalarNode = NewBytes(v)
   138  	return nil
   139  }
   140  func (nb *anyBuilder) AssignLink(v datamodel.Link) error {
   141  	if nb.kind != datamodel.Kind_Invalid {
   142  		panic("misuse")
   143  	}
   144  	nb.kind = datamodel.Kind_Link
   145  	nb.scalarNode = NewLink(v)
   146  	return nil
   147  }
   148  func (nb *anyBuilder) AssignNode(v datamodel.Node) error {
   149  	if nb.kind != datamodel.Kind_Invalid {
   150  		panic("misuse")
   151  	}
   152  	nb.kind = 99
   153  	nb.scalarNode = v
   154  	return nil
   155  }
   156  func (anyBuilder) Prototype() datamodel.NodePrototype {
   157  	return Prototype.Any
   158  }
   159  
   160  func (nb *anyBuilder) Build() datamodel.Node {
   161  	switch nb.kind {
   162  	case datamodel.Kind_Invalid:
   163  		panic("misuse")
   164  	case datamodel.Kind_Map:
   165  		return nb.mapBuilder.Build()
   166  	case datamodel.Kind_List:
   167  		return nb.listBuilder.Build()
   168  	case datamodel.Kind_Null:
   169  		return datamodel.Null
   170  	case datamodel.Kind_Bool:
   171  		return nb.scalarNode
   172  	case datamodel.Kind_Int:
   173  		return nb.scalarNode
   174  	case datamodel.Kind_Float:
   175  		return nb.scalarNode
   176  	case datamodel.Kind_String:
   177  		return nb.scalarNode
   178  	case datamodel.Kind_Bytes:
   179  		return nb.scalarNode
   180  	case datamodel.Kind_Link:
   181  		return nb.scalarNode
   182  	case 99:
   183  		return nb.scalarNode
   184  	default:
   185  		panic("unreachable")
   186  	}
   187  }
   188  
   189  // -- NodeAssembler -->
   190  
   191  // ... oddly enough, we seem to be able to put off implementing this
   192  //  until we also implement something that goes full-hog on amortization
   193  //   and actually has a slab of `anyNode`.  Which so far, nothing does.
   194  //    See "REVIEW" comment on anyNode.
   195  // type anyAssembler struct {
   196  // 	w *anyNode
   197  // }