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 // }