github.com/ipld/go-ipld-prime@v0.21.0/adl/rot13adl/rot13reification.go (about) 1 package rot13adl 2 3 import ( 4 "fmt" 5 6 "github.com/ipld/go-ipld-prime/datamodel" 7 ) 8 9 // Reify examines data in a Node to see if it matches the shape for valid substrate data for this ADL, 10 // and if so, synthesizes and returns the high-level view of the ADL. 11 // If it succeeds in recognizing the raw data as this ADL, 12 // Reify returns a new Node which exhibits the logical behaviors of the ADL; 13 // otherwise, it returns an error. 14 // 15 // The input data can be any implementation of ipld.Node; 16 // it will be considered purely through that interface. 17 // 18 // If your application is expecting ADL data, this pipeline can be optimized 19 // by using the SubstratePrototype right from the start when unmarshalling; 20 // then, Reify can detect if the rawRoot parameter is of that implementation, 21 // and it can save some processing work internally that can be known to already be done. 22 // 23 // Reification will generally operate on the data in a single block 24 // (e.g. this function will not do any additional block loads and unmarshalling). 25 // This is important because some ADLs handle data so large that loading it all 26 // eagerly would be impractical (and in some cases outright impossible). 27 // However, it also necessarily implies that invalid data may lie beyond 28 // one of those lazy loads, and it won't be discovered at the time of Reify. 29 // 30 // In this demo ADL, we don't have multi-block content at all, 31 // so of course we don't have any additional block loads! 32 // However, ADL implementations may vary in their approaches to lazy vs eager loading. 33 // All ADLs should document their exact semantics regarding this -- 34 // especially if it has any implications for boundaries of data validity checking. 35 // 36 // REVIEW: this function is currently not conforming to any particular interface; 37 // if we evolve the contract for ADLs to include an interface for reficiation functions, 38 // might we need to add context and link loader systems as parameters to it? 39 // Not all implementations might need it, as per previous paragraph; but some might. 40 // Reification for multiblock ADLs might also need link loader systems as a parameter here 41 // so they can capture them as config and hold them for use in future operations that do lazy loading. 42 func Reify(maybeSubstrateRoot datamodel.Node) (datamodel.Node, error) { 43 // Reify is often very easy to implement, 44 // especially if you have an IPLD Schema that specifies the shape of the substrate data: 45 // We can just check if the data in maybeSubstrateRoot happens to already be exactly the right type, 46 // and if so, take very direct shortcuts because we already know its been validated in shape; 47 // otherwise, we create a new piece of memory for our native substrate memory layout, 48 // and assign into it from the raw node, validating in the process, 49 // which again just leans directly on the shape validation logic already given to us by the schema logic on that type. 50 // (Checking the concrete type of maybeSubstrateRoot in search of a shortcut is seemingly a tad redundant, 51 // because the AssignNode path later also has such a check! 52 // However, doing it earlier allows us to avoid an allocation; 53 // the AssignNode path doesn't become available until after NewBuilder is invoked, and NewBuilder is where allocations happen.) 54 55 // Check if we can recognize the maybeSubstrateRoot as being our own substrate types; 56 // if it is, we can shortcut pretty drastically. 57 if x, ok := maybeSubstrateRoot.(*_Substrate); ok { 58 // In this ADL implementation, the high level node has the exact same memory layout as the substrate root, 59 // and so our only remaining processing here is just to cast them, so that 60 // the node we return has the correct methodset exposed. 61 return (*_R13String)(x), nil 62 } 63 64 // Shortcut didn't work. Process via the data model. 65 // The AssignNode method on the substrate type already contains all the logic necessary for this, so we use that. 66 nb := Prototype.SubstrateRoot.NewBuilder() 67 if err := nb.AssignNode(maybeSubstrateRoot); err != nil { 68 return nil, fmt.Errorf("rot13adl.Reify failed: data does not match expected shape for substrate: %w", err) 69 } 70 return (*_R13String)(nb.Build().(*_Substrate)), nil 71 }