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