github.com/ipld/go-ipld-prime@v0.21.0/adl/rot13adl/example_test.go (about) 1 package rot13adl_test 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "strings" 8 9 "github.com/ipfs/go-cid" 10 11 "github.com/ipld/go-ipld-prime/adl/rot13adl" 12 "github.com/ipld/go-ipld-prime/codec/dagjson" 13 "github.com/ipld/go-ipld-prime/datamodel" 14 "github.com/ipld/go-ipld-prime/linking" 15 cidlink "github.com/ipld/go-ipld-prime/linking/cid" 16 "github.com/ipld/go-ipld-prime/must" 17 "github.com/ipld/go-ipld-prime/storage/memstore" 18 ) 19 20 func ExampleReify_unmarshallingToADL() { 21 // Create a NodeBuilder for the ADL's substrate. 22 // Unmarshalling into this memory structure is optimal, 23 // because it immediately puts data into the right memory layout for the ADL code to work on, 24 // but you could use any other kind of NodeBuilder just as well and still get correct results. 25 nb := rot13adl.Prototype.SubstrateRoot.NewBuilder() 26 27 // Unmarshal -- using the substrate's nodebuilder just like you'd unmarshal with any other nodebuilder. 28 err := dagjson.Decode(nb, strings.NewReader(`"n pbby fgevat"`)) 29 fmt.Printf("unmarshal error: %v\n", err) 30 31 // Use `Reify` to get the synthetic high-level view of the ADL data. 32 substrateNode := nb.Build() 33 syntheticView, err := rot13adl.Reify(substrateNode) 34 fmt.Printf("reify error: %v\n", err) 35 36 // We can inspect the synthetic ADL node like any other node! 37 fmt.Printf("adl node kind: %v\n", syntheticView.Kind()) 38 fmt.Printf("adl view value: %q\n", must.String(syntheticView)) 39 40 // Output: 41 // unmarshal error: <nil> 42 // reify error: <nil> 43 // adl node kind: string 44 // adl view value: "a cool string" 45 } 46 func ExampleReify_loadingToADL() { 47 48 // Create a NodeBuilder for the ADL's substrate. 49 // Unmarshalling into this memory structure is optimal, 50 // because it immediately puts data into the right memory layout for the ADL code to work on, 51 // but you could use any other kind of NodeBuilder just as well and still get correct results. 52 nb := rot13adl.Prototype.SubstrateRoot.NewBuilder() 53 54 // Unmarshal -- using the substrate's nodebuilder just like you'd unmarshal with any other nodebuilder. 55 err := dagjson.Decode(nb, strings.NewReader(`"n pbby fgevat"`)) 56 fmt.Printf("unmarshal error: %v\n", err) 57 58 substrateNode := nb.Build() 59 // now save the node to storage 60 lp := cidlink.LinkPrototype{Prefix: cid.Prefix{ 61 Version: 1, 62 Codec: 0x129, 63 MhType: 0x13, 64 MhLength: 4, 65 }} 66 linkSystem := cidlink.DefaultLinkSystem() 67 storage := &memstore.Store{} 68 linkSystem.SetReadStorage(storage) 69 linkSystem.SetWriteStorage(storage) 70 linkSystem.NodeReifier = func(_ linking.LinkContext, nd datamodel.Node, _ *linking.LinkSystem) (datamodel.Node, error) { 71 return rot13adl.Reify(nd) 72 } 73 lnk, err := linkSystem.Store(linking.LinkContext{Ctx: context.Background()}, lp, substrateNode) 74 fmt.Printf("storage error: %v\n", err) 75 76 // reload from storage, but this time the NodeReifier function should give us the ADL 77 syntheticView, err := linkSystem.Load(linking.LinkContext{Ctx: context.Background()}, lnk, rot13adl.Prototype.SubstrateRoot) 78 fmt.Printf("load error: %v\n", err) 79 80 // We can inspect the synthetic ADL node like any other node! 81 fmt.Printf("adl node kind: %v\n", syntheticView.Kind()) 82 fmt.Printf("adl view value: %q\n", must.String(syntheticView)) 83 84 // Output: 85 // unmarshal error: <nil> 86 // storage error: <nil> 87 // load error: <nil> 88 // adl node kind: string 89 // adl view value: "a cool string" 90 } 91 func ExampleR13String_creatingViaADL() { 92 // Create a NodeBuilder for the ADL -- the high-level synthesized thing (not the substrate). 93 nb := rot13adl.Prototype.Node.NewBuilder() 94 95 // Create a ADL node via its builder. This is just like creating any other node in IPLD. 96 nb.AssignString("woohoo") 97 n := nb.Build() 98 99 // We can inspect the synthetic ADL node like any other node! 100 fmt.Printf("adl node kind: %v\n", n.Kind()) 101 fmt.Printf("adl view value: %q\n", must.String(n)) 102 103 // We can get the substrate view and examine that as a node too. 104 // (This requires a cast to see that we have an ADL, though. Not all IPLD nodes have a 'Substrate' property.) 105 substrateNode := n.(rot13adl.R13String).Substrate() 106 fmt.Printf("substrate node kind: %v\n", substrateNode.Kind()) 107 fmt.Printf("substrate value: %q\n", must.String(substrateNode)) 108 109 // To marshal the ADL, just use marshal methods on its substrate as normal: 110 var marshalBuffer bytes.Buffer 111 err := dagjson.Encode(substrateNode, &marshalBuffer) 112 fmt.Printf("marshalled: %v\n", marshalBuffer.String()) 113 fmt.Printf("marshal error: %v\n", err) 114 115 // Output: 116 // adl node kind: string 117 // adl view value: "woohoo" 118 // substrate node kind: string 119 // substrate value: "jbbubb" 120 // marshalled: "jbbubb" 121 // marshal error: <nil> 122 } 123 124 // It's worth noting that the builders for an ADL substrate node still return the substrate. 125 // (This is interesting in contrast to Schemas, where codegenerated representation-level builders 126 // yield the type-level node values (and not the representation level node).) 127 // 128 // To convert the substrate node to the high level synthesized view of the ADL, 129 // use Reify as normal -- it's the same whether you've used the substrate type 130 // or if you've used any other node implementation to hold the data. 131 // 132 133 // Future work: unmarshalling which can invoke an ADL mid-structure, 134 // and automatically places the reified ADL in place in the larger structure. 135 // 136 // There will be several ways to do this (it hinges around "the signalling problem", 137 // discussed in https://github.com/ipld/specs/issues/130 ): 138 // 139 // The first way is to use IPLD Schemas, which provide a signalling mechanism 140 // by leaning on the schema, and the matching of shape of surrounding data to the schema, 141 // as a way to determine where an ADL is expected to appear. 142 // 143 // A second mechanism could involve new unmarshal function contracts 144 // which would ake a (fairly complex) argument that says what NodePrototype to use in certain positions. 145 // This could be accomplished by use of Selectors. 146 // (This would also have many other potential purposes -- implementing this in terms of NodePrototype selection is very multi-purpose, 147 // and could be used for efficiency and misc tuning purposes, 148 // for expecting a *schema* thing part way through, and so forth.) 149 //