github.com/ipld/go-ipld-prime@v0.21.0/HACKME.md (about)

     1  hackme
     2  ======
     3  
     4  Design rational are documented here.
     5  
     6  This doc is not necessary reading for users of this package,
     7  but if you're considering submitting patches -- or just trying to understand
     8  why it was written this way, and check for reasoning that might be dated --
     9  then it might be useful reading.
    10  
    11  It may also be an incomplete doc.  It's been written opportunistically.
    12  If you don't understand the rationale for some things, try checking git history
    13  (many of the commit messages are downright bookish), or get in touch via
    14  a github issue, irc, matrix, etc and ask!
    15  
    16  
    17  about NodeAssembler and NodeBuilder
    18  -----------------------------------
    19  
    20  See the godoc on these types.
    21  
    22  In short, a `NodeBuilder` is for creating a new piece of memory;
    23  a `NodeAssembler` is for instantiating some memory which you already have.
    24  
    25  Generally, you'll start any function using a `NodeBuilder`, but then continue
    26  and recurse by passing on the `NodeAssembler`.
    27  
    28  See the `./HACKME_builderBehaviors.md` doc for more details on
    29  high level rules and implementation patterns to look out for.
    30  
    31  
    32  
    33  about NodePrototype
    34  ---------------
    35  
    36  ### NodePrototype promises information without allocations
    37  
    38  You'll notice nearly every `ipld.NodePrototype` implementation is
    39  a golang struct type with _zero fields_.
    40  
    41  This is important.
    42  Getting a NodePrototype is generally expected to be "free" (i.e., zero allocations),
    43  while `NewBuilder` is allowed to be costly (usually causes at least one allocation).
    44  Zero-member structs can be referred to by an interface without requiring an allocation,
    45  which is how it's possible ensure `NodePrototype` are always "free" to refer to.
    46  
    47  (Note that a `NodePrototype` that bundles some information like ADL configuration
    48  will subvert this pattern -- but these are an exception, not the rule.)
    49  
    50  ### NodePrototype reported by a Node
    51  
    52  `ipld.NodePrototype` is a type that opaquely represents some information about how
    53  a node was constructed and is implemented.  The general contract for what
    54  should happen when asking a node about its prototype
    55  (via the `ipld.Node.Prototype() NodePrototype` interface) is that prototype should contain
    56  effective instructions for how one could build a copy of that node, using
    57  the same implementation details.
    58  
    59  By example, if some node `n` was made as a `basicnode.plainString`,
    60  then `n.Prototype()` will be `basicnode.Prototype.String`,
    61  and `n.Prototype().NewBuilder().AssignString("xyz")` can be presumed to work.
    62  
    63  Note there are also limits to this: if a node was built in a flexible way,
    64  the prototype it reports later may only report what it is now, and not return
    65  that same flexibility again.
    66  By example, if something was made as an "any" -- i.e.,
    67  via `basicnode.Prototype.Any.NewBuilder()`, and then *happened* to be assigned a string value --
    68  the resulting node will still carry a `Prototype()` property that returns
    69  `basicnode.Prototype.String` -- **not** `basicnode.Prototype.Any`.
    70  
    71  #### NodePrototype meets generic transformation
    72  
    73  One of the core purposes of the `NodePrototype` interface (and all the different
    74  ways you can get it from existing data) is to enable the `traversal` package
    75  (or other user-written packages like it) to do transformations on data.
    76  
    77  // work-in-progress warning: generic transformations are not fully implemented.
    78  
    79  When implementating a transformation that works over unknown data,
    80  the signiture of function a user provides is roughly:
    81  `func(oldValue Node, acceptableValues NodePrototype) (Node, error)`.
    82  (This signiture may vary by the strategy taken by the transformation -- this
    83  signiture is useful because it's capable of no-op'ing; an alternative signiture
    84  might give the user a `NodeAssembler` instead of the `NodePrototype`.)
    85  
    86  In this situation, the transformation system determines the `NodePrototype`
    87  (or `NodeAssembler`) to use by asking the parent value of the one we're visiting.
    88  This is because we want to give the update function the ability to create
    89  any kind of value that would be accepted in this position -- not just create a
    90  value of the same prototype as the one currently there!  It is for this reason
    91  the `oldValue.Prototype()` property can't be used directly.
    92  
    93  At the root of such a transformation, we use the `node.Prototype()` property to
    94  determine how to get started building a new value.
    95  
    96  #### NodePrototype meets recursive assemblers
    97  
    98  Asking for a NodePrototype in a recursive assembly process tells you about what
    99  kind of node would be accepted in an `AssignNode(Node)` call.
   100  It does *not* make any remark on the fact it's a key assembler or value assembler
   101  and might be wrapped with additional rules (such as map key uniqueness, field
   102  name expectations, etc).
   103  
   104  (Note that it's also not an exclusive statement about what `AssignNode(Node)` will
   105  accept; e.g. in many situations, while a `Prototype.MyStringType` might be the prototype
   106  returned, any string kinded node can be used in `AssignNode(Node)` and will be
   107  appropriately converted.)
   108  
   109  Any of these paths counts as "recursive assembly process":
   110  
   111  - `MapAssembler.KeyPrototype()`
   112  - `MapAssembler.ValuePrototype(string)`
   113  - `MapAssembler.AssembleKey().Prototype()`
   114  - `MapAssembler.AssembleValue().Prototype()`
   115  - `ListAssembler.ValuePrototype()`
   116  - `ListAssembler.AssembleValue().Prototype()`
   117  
   118  ### NodePrototype for carrying ADL configuration
   119  
   120  // work-in-progress warning: this is an intention of the design, but not implemented.