1. 22 Jan, 2020 1 commit
    • Eric Myhre's avatar
      Library updates. · 4e6a8c0b
      Eric Myhre authored
      Be aware I'm using the go mod files blindly, and actually testing and
      developing using the git submodules.
      
      I actually only wanted one update here -- the go-wish library bump,
      for a specific new feature I wanted for some work on another branch --
      but as long as I'm here, apparently all these bumps break nothing.
      4e6a8c0b
  2. 07 Dec, 2019 1 commit
  3. 03 Dec, 2019 1 commit
    • Eric Myhre's avatar
      Readme and key Node interface docs improvements. · 76bd5090
      Eric Myhre authored
      The readme hadn't seen an update for quite a long time, so it was just
      overdue for it.  I think the comments about where to expect changes
      at this point are practically accurate and now are also stated.
      
      The Node interface, despite being so central to the entire system,
      was missing a doc block on the type as a whole!  It now has one.
      (I'd like to continue to iterate on this and have it do more linking
      out to ipld docs for some of the more conceptual parts, but we've
      got a lot of work to do on that content as well, so, for now just
      doing it here is better than not having it.)
      Signed-off-by: default avatarEric Myhre <hash@exultant.us>
      76bd5090
  4. 13 Nov, 2019 1 commit
  5. 08 Nov, 2019 1 commit
  6. 07 Nov, 2019 1 commit
  7. 25 Oct, 2019 8 commits
  8. 24 Oct, 2019 7 commits
  9. 22 Oct, 2019 3 commits
  10. 17 Oct, 2019 2 commits
    • Eric Myhre's avatar
      gen: rearrange files. · 68b3383d
      Eric Myhre authored
      The previous names started to seem more questionable as we start
      generating additional code which is natively typed rather than
      interface constrained.  Now the latter stuff is in a file that
      includes 'Node' as part of the filename.  This seems better.
      68b3383d
    • Eric Myhre's avatar
      Beginning natively-typed access and builders. · 41d79374
      Eric Myhre authored
      This introduces several new methods to the type generator.
      The new comment at the top of 'gen.go' explains the direction.
      
      There are several (sizable impact) TODOs in the methods for structs;
      this is because some other research I've been doing on performance
      is going to result in a re-think of how we regard pointers,
      and a *lot* of the struct code is going to get a shakeup shortly.
      Should be coming up in about two commits or so.
      (The 'Maybe' structs getting their first mention here will have
      something to do with it!)
      
      Some more file split-ups to keep node interface generation separate
      from native-typed API generation will be coming up next commit.
      
      You can also see here some TODOs regarding the future possibility of
      "validate" methods.  This is something I want to pursue, but the
      implementation work will be nontrivial -- those TODOs will probably
      stay there a good while.
      Signed-off-by: default avatarEric Myhre <hash@exultant.us>
      41d79374
  11. 15 Oct, 2019 1 commit
  12. 14 Oct, 2019 3 commits
    • Eric Myhre's avatar
      Merge pull request #32 from ipld/childbuilder-recursion-and-typed-unmarshal · 4141100d
      Eric Myhre authored
      Child-builder recursion; and typed unmarshal over codegen native structs.
      4141100d
    • Eric Myhre's avatar
      Add child-builder methods to NodeBuilder interface; and typed unmarshal! · a2b49bed
      Eric Myhre authored
      (At long last!  These child-builder methods are a step that was known
      to be needed for some time now, but I've intentionally been pushing off
      the implementation of it until we finally reached some *other* piece of
      functionality that would depend on it and force the issue.  Finally,
      that's happened: that issue is unmarshalling into natively-typed
      codegenerated nodes, and that's now.  Woo!)
      
      (Though the current focus of this is for natively-typed codegen'd nodes,
      if we put further effort into reflective-bind node implementations,
      they'll also lean heavily on these child-builder-getters for internally
      tracking the correct `reflect.Type` to create new values of -- very
      similar to what our schema-typed things are doing, just with the Golang
      type system instead of our schema types.)
      
      The child-builder getter methods more or less explain themselves.
      They yield a new NodeBuilder that's correctly specialized for child
      nodes in recursive structures.  This is necessary for both keys and
      values in maps, and for values in lists.  For values in lists and maps,
      getting the child-builder requires takes a parameter -- this is so
      typed nodes (namely, structs; but some unions will also lean on this)
      may have discriminated contents that differ per key or index.
      
      The BuilderForValue functions are able to take primitive strings and
      ints as parameters rather than Node, because all uses that have
      discriminated results are places where complex keys are not acceptable.
      Therefore primitives are fine, and preferred since it avoids boxing.
      
      The 'free' node implementation is updated to include this feature,
      as are codegenerated nodes.
      (The runtime wrapper typed node implementations have partial support,
      but stubbed methods where the path forward is clear but the
      implementation effort nontrivial and not currently on-priority-path.)
      
      Unmarshalling now uses these child-builder-getters to correctly handle
      the passing down of constraints and typeinfo.  This addresses several
      TODO's that have been in the unmarshalling code for aeons -- hooray!
      (Somewhat remarkably, our solution here is much better than the one
      proposed in those ancient TODO's -- we actually got this done *without*
      direct abstraction-breaking examination for typed nodes.  Nice!)
      
      Unmarshalling tests are also in this same diff.
      There's even a wee little benchmark using a snippet of JSON as fixture.
      This is the first time we see unmarshalling and marshalling end-to-end
      connected with codegen'd nodes.  This is very exciting!
      
      There's still some questions to be answered about the most correct
      (and most performance-friendly) place to put error handling against
      asks for a child NodeBuilder with an invalid key or index, which is
      a very real invalid state that's reachable for typed nodes that are
      structs.  Comments about that are inline in the diff.  We'll probably
      have to come back to that soon, but I'm gonna let it stew on the
      back burner for a bit.  Currently, panics are used, but this may not
      be acceptable ergonomics.
      
      ---
      
      It's somewhat effortful to even detail how many thoughts about
      performance and the future optimization potentials go into this diff.
      Some comments I had in the area of the child-builder specialization
      functions included concerns on:
      
      - where common-subexpression-elimination will and won't apply
      - where inlining is possible vs facing function call stack shuffle overhead
      - ... as well as how that affects common-subexpression-elimination
      - ... as well as how that affects escape analysis and shifts to heap
      - whether an isDiscriminated property will make any of these things better
      - can BuilderForValue hang onto a builder, boxed into interface already, when appropriate?
      - ... for the maps case, should amortize in a way comparable to isDiscriminated, yes?  verify.
      - ... can we do that without the builder keeping another two words of memory just... around?  i don't think so.  question is if it pays for itself.
      - question: do zero value no-fields structs get a bonus?  reading runtime/iface.go -- doesn't look like it.  but needs confirmation.
      - ... revised statement: they do, it's just nonobvious.  iface.go doesn't have a specialization, but the mallocgc call hits a special path internally for zero, and then the typedmemmove call 'coincidentally' hits its "src == dst" short-circuit, thus also being fast.
      
      ... all in all, as many of these as possible of these concerns have
      been considered and this design should be optimization-friendly;
      some of them are bucketed into "we'll see", because we need to build
      nontrivial programs to see how significant the needs are, as well as
      to see how clever the compiler can get with what we've already done.
      
      There are some possible alternative ways we might re-engineer the
      builders in the future to make them more performance-friendly.
      In particular, the fact that many builders carry a previous value
      with them in anticipation of one of the 'Amend' calls -- which is
      not necessarily going to be used! -- is a potential obstruction to
      optimization, since it makes many structures go from zero to
      more-than-zero size, and that hits significantly different paths
      in the runtime with very different performance characteristics.
      However, that is a bit much to change today; so the thought lives
      here as a note for potential future work.
      
      Adding a `BuilderForValueIsDiscriminated() bool` method later seems
      still seems on the table, but since it wouldn't require substantial
      restructurings or headaches, can be deferred until benchmarks show
      us exactly how much it matters.
      (A single `type ChildBuilders interface { Style() Complexity; ... }`
      with some enum for `Compleixty` resembling
      `SimpleList | SimpleMap | DiscriminatedMap | DiscriminatedList` might
      also be a tempting way to go about this.)
      
      ---
      
      An alternative design considered that deserves a quick note: we
      could've added a `ChildBuilders()` method to the MapBuilder and
      ListBuilder, and attached the further getter methods there.
      This might still be viable, if we found that there are more methods
      involved in the future and we want to group them: it *should* always
      land on the zero-fields struct path, which means it can be done
      without hitting an expensive malloc.  However, at present this doesn't
      seem warranted: we don't have enough methods to make it feel important
      (especially after the recognition that Node variants of methods aren't
      needed in addition to the primitive args variants, described above).
      
      ---
      
      Whew.
      
      Lines of code in diff does not correlate to hours of thought required.
      
      Glad to have this landing.  Even performance minutae aside,
      there was a significant period of time where I was terrified that all
      these abstractions were going to shatter magnificently when it came
      time to do the final end-to-end unification of all this massive arc
      of work.  But now it's done.  And it works.  Whew.
      
      Next: more fleshing out of more types; perhaps more benchmarks; and
      also it's time to do some more drafts of the native accessors and
      builders.  Some of that already has been done in parallel in gists
      while this diff was incubating, but it's time to commit it too.
      a2b49bed
    • Eric Myhre's avatar
      b0e36859
  13. 02 Oct, 2019 3 commits
  14. 03 Sep, 2019 1 commit
  15. 01 Sep, 2019 4 commits
    • Eric Myhre's avatar
      Add exported accessors for builders + reprbuilders · dc19057d
      Eric Myhre authored
      I'm not sure if I like these symbol names.  Or rather, I don't,
      but haven't decided on what would be preferable yet.
      
      There's a couple of options that have come to mind:
      
      - option 1
        - `func {{ .Type.Name }}__NodeBuilder() ipld.NodeBuilder`
        - `func {{ .Type.Name }}__ReprBuilder() ipld.NodeBuilder`
      
      - option 2
        - `func NewBuilderFor{{ .Type.Name }}() ipld.NodeBuilder`
        - `func NewReprBuilderFor{{ .Type.Name }}() ipld.NodeBuilder`
      
      - option 3
        - `func (Builders) {{ .Type.Name }}() ipld.NodeBuilder`
        - `func (ReprBuilders) {{ .Type.Name }}() ipld.NodeBuilder`
      
      Option 3 would make 'Builders' and 'ReprBuilders' effectively reserved
      as type names if you're using codegen.  Schemas using them could use
      adjunct config specific to golang to rename things out of conflict in
      the generated code, but it's still a potential friction.
      
      Option 2 would also have some naming collision hijinx to worry about,
      on further though.  Only Option 1 is immune, by virtue of using "__"
      in combination with the schema rule that type names can't contain "__".
      
      This diff is implementing Option 1.  I think I'm partial to Option 3,
      but not quite confident enough in it to lunge for it yet.
      
      Putting more methods on the *concrete* types would also be another
      interesting fourth option!  These methods would ignore the actual
      value, and typically be used on the zero value: e.g., usage would
      resemble `Foo{}.ReprBuilder()`.
      The upside of this would be we'd then have no package scoped exported
      symbols except exactly the set matching type names in the schema.
      However, the opportunities for confusion with this would be numerous:
      we couldn't use the 'NodeBuilder' method name (because that's the
      potentially-stateful/COW one), but would still be returning a
      NodeBuilder type?  Etc.  Might not be good.
      
      More to think about here in the future.
      Signed-off-by: default avatarEric Myhre <hash@exultant.us>
      dc19057d
    • Eric Myhre's avatar
      Finish migrating to ident munge helper funcs. · ec1434e7
      Eric Myhre authored
      Fixed at least one bug along the way (in iterators, which don't have
      test coverage yet, so no test fix.  Still planning to cover those
      via serialization, when we get that feature, "soon").
      
      'go doc .' on the generated code now only lists one type per type in
      the schema which seems like a good sanity heuristic; and
      'go doc -u .' on the package now looks much more consistent.
      (There's *8* types for every struct in the schema!  Uffdah.
      But if that's what it takes to make a focused,
      correctness-emphasizing library surface area, so be it.)
      Signed-off-by: default avatarEric Myhre <hash@exultant.us>
      ec1434e7
    • Eric Myhre's avatar
      DRYing some type ident munges. · a84c7ec1
      Eric Myhre authored
      I'm still aiming to keep this as simple and un-clever as possible,
      because putting lipstick on a pig -- this is all about to become
      strings which get shoveled back to a compiler parser anyway -- is
      not useful, and becomes antiuseful if it obstructs readability...
      
      But I'm starting to find these elements are repeated enough that
      it will help rather than hurt readability to extract some things.
      
      Also, since the munges have recently started to appear in both go code
      source as well as in the templates, that starts to put more weight in
      favor of extracting a function for it, which keeps the two syntactic
      universes from drifting on this subject.
      
      At the same time, moved all NodeBuilders to being unexported (by using
      idents prefixed with a "_").  I looked at the godoc for the generated
      code and felt this is looking like a wiser choice than exporting.
      
      We'll need to export more methods for getting initial instances of the
      now-unexported stuff... but we should be adding those anyway, so this
      is not an argument against unexporting.
      
      Some additional type idents around iterators and map builders have not
      yet been hoisted to DRYed munge methods.  I'm debating if that's useful
      (as you can see in the comments in that file), but leaning towards
      it being more parsimoneous to just go for it.  So that'll probably be
      the next commit.
      Signed-off-by: default avatarEric Myhre <hash@exultant.us>
      a84c7ec1
    • Eric Myhre's avatar
      Gen'd map reprs of struct dtrt for absent fields. · 116a4db7
      Eric Myhre authored
      And fixed tests for same.
      
      The value returned is still ipld.Undef, and I'm not sure I'm going to
      particularly defend that choice vs returning null, but it seems
      six of one and half a dozen of the other.  Might be worth review later,
      once we have some field reports on whether that vs nils would be
      recieved as the more surprising/annoying choice in non-toy usage.
      116a4db7
  16. 30 Aug, 2019 2 commits