rot13reification.go 4.04 KB
Newer Older
1 2 3 4
package rot13adl

import (
	"fmt"
tavit ohanian's avatar
tavit ohanian committed
5 6

	"gitlab.dms3.io/ld/go-ld-prime"
7 8
)

9 10
// Reify examines data in a Node to see if it matches the shape for valid substrate data for this ADL,
// and if so, synthesizes and returns the high-level view of the ADL.
11 12 13 14
// If it succeeds in recognizing the raw data as this ADL,
// Reify returns a new Node which exhibits the logical behaviors of the ADL;
// otherwise, it returns an error.
//
tavit ohanian's avatar
tavit ohanian committed
15
// The input data can be any implementation of ld.Node;
16 17 18 19 20 21 22
// it will be considered purely through that interface.
//
// If your application is expecting ADL data, this pipeline can be optimized
// by using the SubstratePrototype right from the start when unmarshalling;
// then, Reify can detect if the rawRoot parameter is of that implementation,
// and it can save some processing work internally that can be known to already be done.
//
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
// Reification will generally operate on the data in a single block
// (e.g. this function will not do any additional block loads and unmarshalling).
// This is important because some ADLs handle data so large that loading it all
// eagerly would be impractical (and in some cases outright impossible).
// However, it also necessarily implies that invalid data may lie beyond
// one of those lazy loads, and it won't be discovered at the time of Reify.
//
// In this demo ADL, we don't have multi-block content at all,
// so of course we don't have any additional block loads!
// However, ADL implementations may vary in their approaches to lazy vs eager loading.
// All ADLs should document their exact semantics regarding this --
// especially if it has any implications for boundaries of data validity checking.
//
// REVIEW: this function is currently not conforming to any particular interface;
// if we evolve the contract for ADLs to include an interface for reficiation functions,
// might we need to add context and link loader systems as parameters to it?
// Not all implementations might need it, as per previous paragraph; but some might.
// Reification for multiblock ADLs might also need link loader systems as a parameter here
// so they can capture them as config and hold them for use in future operations that do lazy loading.
//
tavit ohanian's avatar
tavit ohanian committed
43
func Reify(maybeSubstrateRoot ld.Node) (ld.Node, error) {
44
	// Reify is often very easy to implement,
45
	//  especially if you have an LD Schema that specifies the shape of the substrate data:
46 47 48 49 50 51
	// We can just check if the data in maybeSubstrateRoot happens to already be exactly the right type,
	//  and if so, take very direct shortcuts because we already know its been validated in shape;
	// otherwise, we create a new piece of memory for our native substrate memory layout,
	//  and assign into it from the raw node, validating in the process,
	//   which again just leans directly on the shape validation logic already given to us by the schema logic on that type.
	// (Checking the concrete type of maybeSubstrateRoot in search of a shortcut is seemingly a tad redundant,
52
	//  because the AssignNode path later also has such a check!
53
	//  However, doing it earlier allows us to avoid an allocation;
54
	//   the AssignNode path doesn't become available until after NewBuilder is invoked, and NewBuilder is where allocations happen.)
55

56 57 58 59 60 61
	// Check if we can recognize the maybeSubstrateRoot as being our own substrate types;
	//  if it is, we can shortcut pretty drastically.
	if x, ok := maybeSubstrateRoot.(*_Substrate); ok {
		// In this ADL implementation, the high level node has the exact same memory layout as the substrate root,
		//  and so our only remaining processing here is just to cast them, so that
		//   the node we return has the correct methodset exposed.
62 63
		return (*_R13String)(x), nil
	}
64

65
	// Shortcut didn't work.  Process via the data model.
66
	//  The AssignNode method on the substrate type already contains all the logic necessary for this, so we use that.
67
	nb := Prototype.SubstrateRoot.NewBuilder()
68
	if err := nb.AssignNode(maybeSubstrateRoot); err != nil {
69 70 71
		fmt.Errorf("rot13adl.Reify failed: data does not match expected shape for substrate: %w", err)
	}
	return (*_R13String)(nb.Build().(*_Substrate)), nil
72
}