this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

mst: unexport a bunch of internals, tweak docs, WalkLeavesFrom cb func type (#148)

authored by

Whyrusleeping and committed by
GitHub
0c0e2ec4 d8d3324b

+158 -134
+8 -2
gen/main.go
··· 1 1 package main 2 2 3 3 import ( 4 + "reflect" 5 + 4 6 "github.com/bluesky-social/indigo/api" 5 7 atproto "github.com/bluesky-social/indigo/api/atproto" 6 8 bsky "github.com/bluesky-social/indigo/api/bsky" 7 9 label "github.com/bluesky-social/indigo/api/label" 8 10 "github.com/bluesky-social/indigo/events" 9 11 lexutil "github.com/bluesky-social/indigo/lex/util" 10 - mst "github.com/bluesky-social/indigo/mst" 12 + "github.com/bluesky-social/indigo/mst" 11 13 "github.com/bluesky-social/indigo/repo" 12 14 cbg "github.com/whyrusleeping/cbor-gen" 13 15 ) 14 16 15 17 func main() { 16 - if err := cbg.WriteMapEncodersToFile("mst/cbor_gen.go", "mst", mst.NodeData{}, mst.TreeEntry{}); err != nil { 18 + var typVals []any 19 + for _, typ := range mst.CBORTypes() { 20 + typVals = append(typVals, reflect.New(typ).Elem().Interface()) 21 + } 22 + if err := cbg.WriteMapEncodersToFile("mst/cbor_gen.go", "mst", typVals...); err != nil { 17 23 panic(err) 18 24 } 19 25
+12 -12
mst/cbor_gen.go
··· 18 18 var _ = math.E 19 19 var _ = sort.Sort 20 20 21 - func (t *NodeData) MarshalCBOR(w io.Writer) error { 21 + func (t *nodeData) MarshalCBOR(w io.Writer) error { 22 22 if t == nil { 23 23 _, err := w.Write(cbg.CborNull) 24 24 return err ··· 30 30 return err 31 31 } 32 32 33 - // t.Entries ([]mst.TreeEntry) (slice) 33 + // t.Entries ([]mst.treeEntry) (slice) 34 34 if len("e") > cbg.MaxLength { 35 35 return xerrors.Errorf("Value in field \"e\" was too long") 36 36 } ··· 80 80 return nil 81 81 } 82 82 83 - func (t *NodeData) UnmarshalCBOR(r io.Reader) (err error) { 84 - *t = NodeData{} 83 + func (t *nodeData) UnmarshalCBOR(r io.Reader) (err error) { 84 + *t = nodeData{} 85 85 86 86 cr := cbg.NewCborReader(r) 87 87 ··· 100 100 } 101 101 102 102 if extra > cbg.MaxLength { 103 - return fmt.Errorf("NodeData: map struct too large (%d)", extra) 103 + return fmt.Errorf("nodeData: map struct too large (%d)", extra) 104 104 } 105 105 106 106 var name string ··· 118 118 } 119 119 120 120 switch name { 121 - // t.Entries ([]mst.TreeEntry) (slice) 121 + // t.Entries ([]mst.treeEntry) (slice) 122 122 case "e": 123 123 124 124 maj, extra, err = cr.ReadHeader() ··· 135 135 } 136 136 137 137 if extra > 0 { 138 - t.Entries = make([]TreeEntry, extra) 138 + t.Entries = make([]treeEntry, extra) 139 139 } 140 140 141 141 for i := 0; i < int(extra); i++ { 142 142 143 - var v TreeEntry 143 + var v treeEntry 144 144 if err := v.UnmarshalCBOR(cr); err != nil { 145 145 return err 146 146 } ··· 180 180 181 181 return nil 182 182 } 183 - func (t *TreeEntry) MarshalCBOR(w io.Writer) error { 183 + func (t *treeEntry) MarshalCBOR(w io.Writer) error { 184 184 if t == nil { 185 185 _, err := w.Write(cbg.CborNull) 186 186 return err ··· 279 279 return nil 280 280 } 281 281 282 - func (t *TreeEntry) UnmarshalCBOR(r io.Reader) (err error) { 283 - *t = TreeEntry{} 282 + func (t *treeEntry) UnmarshalCBOR(r io.Reader) (err error) { 283 + *t = treeEntry{} 284 284 285 285 cr := cbg.NewCborReader(r) 286 286 ··· 299 299 } 300 300 301 301 if extra > cbg.MaxLength { 302 - return fmt.Errorf("TreeEntry: map struct too large (%d)", extra) 302 + return fmt.Errorf("treeEntry: map struct too large (%d)", extra) 303 303 } 304 304 305 305 var name string
+10 -10
mst/diff.go
··· 128 128 }) 129 129 130 130 } else if e.isTree() { 131 - if err := e.Tree.WalkLeavesFrom(ctx, "", func(n NodeEntry) error { 131 + if err := e.Tree.WalkLeavesFrom(ctx, "", func(key string, val cid.Cid) error { 132 132 out = append(out, &DiffOp{ 133 133 Op: "del", 134 - Rpath: n.Key, 135 - OldCid: n.Val, 134 + Rpath: key, 135 + OldCid: val, 136 136 }) 137 137 return nil 138 138 }); err != nil { ··· 153 153 }) 154 154 155 155 } else if e.isTree() { 156 - if err := e.Tree.WalkLeavesFrom(ctx, "", func(n NodeEntry) error { 156 + if err := e.Tree.WalkLeavesFrom(ctx, "", func(key string, val cid.Cid) error { 157 157 out = append(out, &DiffOp{ 158 158 Op: "add", 159 - Rpath: n.Key, 160 - NewCid: n.Val, 159 + Rpath: key, 160 + NewCid: val, 161 161 }) 162 162 return nil 163 163 }); err != nil { ··· 169 169 return out, nil 170 170 } 171 171 172 - func nodeEntriesEqual(a, b *NodeEntry) bool { 172 + func nodeEntriesEqual(a, b *nodeEntry) bool { 173 173 if !(a.Key == b.Key && a.Val == b.Val) { 174 174 return false 175 175 } ··· 190 190 tt := LoadMST(cst, root) 191 191 192 192 var ops []*DiffOp 193 - if err := tt.WalkLeavesFrom(ctx, "", func(ne NodeEntry) error { 193 + if err := tt.WalkLeavesFrom(ctx, "", func(key string, val cid.Cid) error { 194 194 ops = append(ops, &DiffOp{ 195 195 Op: "add", 196 - Rpath: ne.Key, 197 - NewCid: ne.Val, 196 + Rpath: key, 197 + NewCid: val, 198 198 }) 199 199 return nil 200 200 }); err != nil {
+102 -82
mst/mst.go
··· 45 45 import ( 46 46 "context" 47 47 "fmt" 48 + "reflect" 48 49 49 50 "github.com/ipfs/go-cid" 50 51 cbor "github.com/ipfs/go-ipld-cbor" 51 52 ) 52 53 53 - // NodeKind is the type of node in the MST. 54 - type NodeKind uint8 54 + // nodeKind is the type of node in the MST. 55 + type nodeKind uint8 55 56 56 57 const ( 57 - EntryUndefined NodeKind = 0 58 - EntryLeaf NodeKind = 1 59 - EntryTree NodeKind = 2 58 + entryUndefined nodeKind = 0 59 + entryLeaf nodeKind = 1 60 + entryTree nodeKind = 2 60 61 ) 61 62 62 - // NodeEntry is a node in the MST. 63 + // nodeEntry is a node in the MST. 63 64 // 64 65 // Following the Typescript implementation, this is basically a flexible 65 66 // "TreeEntry" (aka "leaf") which might also be the "Left" pointer on a 66 67 // NodeData (aka "tree"). This type flexibility is not idiomatic in Go, but 67 68 // we are keeping this a very direct port. 68 - type NodeEntry struct { 69 - Kind NodeKind 69 + type nodeEntry struct { 70 + Kind nodeKind 70 71 Key string 71 72 Val cid.Cid 72 73 Tree *MerkleSearchTree 73 74 } 74 75 75 - func treeEntry(t *MerkleSearchTree) NodeEntry { 76 - return NodeEntry{ 77 - Kind: EntryTree, 76 + func mkTreeEntry(t *MerkleSearchTree) nodeEntry { 77 + return nodeEntry{ 78 + Kind: entryTree, 78 79 Tree: t, 79 80 } 80 81 } 81 82 82 - func (ne NodeEntry) isTree() bool { 83 - return ne.Kind == EntryTree 83 + func (ne nodeEntry) isTree() bool { 84 + return ne.Kind == entryTree 84 85 } 85 86 86 - func (ne NodeEntry) isLeaf() bool { 87 - return ne.Kind == EntryLeaf 87 + func (ne nodeEntry) isLeaf() bool { 88 + return ne.Kind == entryLeaf 88 89 } 89 90 90 - func (ne NodeEntry) isUndefined() bool { 91 - return ne.Kind == EntryUndefined 91 + func (ne nodeEntry) isUndefined() bool { 92 + return ne.Kind == entryUndefined 92 93 } 93 94 94 - // golang-specific helper to sanity check NodeEntry semantics 95 - func checkTreeInvariant(ents []NodeEntry) { 95 + // golang-specific helper to sanity check nodeEntry semantics 96 + func checkTreeInvariant(ents []nodeEntry) { 96 97 for i := 0; i < len(ents)-1; i++ { 97 98 if ents[i].isTree() && ents[i+1].isTree() { 98 99 panic(fmt.Sprintf("two trees next to each other! %d %d", i, i+1)) ··· 100 101 } 101 102 } 102 103 104 + // CBORTypes returns the types in this package that need to be registered with 105 + // the CBOR codec. 106 + func CBORTypes() []reflect.Type { 107 + return []reflect.Type{ 108 + reflect.TypeOf(nodeData{}), 109 + reflect.TypeOf(treeEntry{}), 110 + } 111 + } 112 + 103 113 // MST tree node as gets serialized to CBOR. Note that the CBOR fields are all 104 114 // single-character. 105 - type NodeData struct { 115 + type nodeData struct { 106 116 Left *cid.Cid `cborgen:"l"` // [optional] pointer to lower-level subtree to the "left" of this path/key 107 - Entries []TreeEntry `cborgen:"e"` // ordered list of entries at this node 117 + Entries []treeEntry `cborgen:"e"` // ordered list of entries at this node 108 118 } 109 119 110 - // Elements of NodeData's Entries 111 - type TreeEntry struct { 120 + // treeEntry are elements of nodeData's Entries. 121 + type treeEntry struct { 112 122 PrefixLen int64 `cborgen:"p"` // count of characters shared with previous path/key in tree 113 123 KeySuffix []byte `cborgen:"k"` // remaining part of path/key (appended to "previous key") 114 124 Val cid.Cid `cborgen:"v"` // CID pointer at this path/key 115 125 Tree *cid.Cid `cborgen:"t"` // [optional] pointer to lower-level subtree to the "right" of this path/key entry 116 126 } 117 127 118 - // This abstractly represents an MST tree node (NodeData type). It can be in 128 + // MerkleSearchTree represents an MST tree node (NodeData type). It can be in 119 129 // several levels of hydration: fully hydrated (entries and "pointer" (CID) 120 130 // computed); dirty (entries correct, but pointer (CID) not valid); virtual 121 131 // (pointer is defined, no entries have been pulled from blockstore) 132 + // 133 + // MerkleSearchTree values are immutable. Methods return copies with changes. 122 134 type MerkleSearchTree struct { 123 135 cst cbor.IpldStore 124 - entries []NodeEntry 136 + entries []nodeEntry // non-nil when "hydrated" 125 137 layer int 126 138 pointer cid.Cid 127 139 validPtr bool 128 140 } 129 141 142 + // NewEmptyMST reports a new empty MST using cst as its storage. 143 + func NewEmptyMST(cst cbor.IpldStore) *MerkleSearchTree { 144 + return createMST(cst, cid.Undef, []nodeEntry{}, 0) 145 + } 146 + 130 147 // Typescript: MST.create(storage, entries, layer, fanout) -> MST 131 - func NewMST(cst cbor.IpldStore, ptr cid.Cid, entries []NodeEntry, layer int) *MerkleSearchTree { 148 + func createMST(cst cbor.IpldStore, ptr cid.Cid, entries []nodeEntry, layer int) *MerkleSearchTree { 132 149 mst := &MerkleSearchTree{ 133 150 cst: cst, 134 151 pointer: ptr, ··· 145 162 // This is poorly named in both implementations, because it is lazy 146 163 // Typescript: MST.load(storage, cid, layer=null, fanout) -> MST 147 164 func LoadMST(cst cbor.IpldStore, root cid.Cid) *MerkleSearchTree { 148 - return NewMST(cst, root, nil, -1) 165 + return createMST(cst, root, nil, -1) 149 166 } 150 167 151 - // === "Immuatbility" === 168 + // === "Immutability" === 152 169 153 170 // "We never mutate an MST, we just return a new MST with updated values" 154 171 // Typescript: MST.newTree(entries) -> MST 155 - func (mst *MerkleSearchTree) newTree(entries []NodeEntry) *MerkleSearchTree { 172 + func (mst *MerkleSearchTree) newTree(entries []nodeEntry) *MerkleSearchTree { 156 173 if entries == nil { 157 174 panic("nil entries passed to newTree") 158 175 } 159 - return NewMST(mst.cst, cid.Undef, entries, mst.layer) 176 + return createMST(mst.cst, cid.Undef, entries, mst.layer) 160 177 } 161 178 162 179 // === "Getters (lazy load)" === 163 180 164 181 // "We don't want to load entries of every subtree, just the ones we need" 165 - // Typescript: MST.getEntries() -> NodeEntry[] 166 - func (mst *MerkleSearchTree) getEntries(ctx context.Context) ([]NodeEntry, error) { 182 + // Typescript: MST.getEntries() -> nodeEntry[] 183 + func (mst *MerkleSearchTree) getEntries(ctx context.Context) ([]nodeEntry, error) { 167 184 // if we are "hydrated", entries are available 168 185 if mst.entries != nil { 169 186 return mst.entries, nil ··· 172 189 // otherwise this is a virtual/pointer struct and we need to hydrate from 173 190 // blockstore before returning entries 174 191 if mst.pointer != cid.Undef { 175 - var nd NodeData 192 + var nd nodeData 176 193 if err := mst.cst.Get(ctx, mst.pointer, &nd); err != nil { 177 194 return nil, err 178 195 } ··· 193 210 } 194 211 195 212 // golang-specific helper that calls in to deserializeNodeData 196 - func entriesFromNodeData(ctx context.Context, nd *NodeData, cst cbor.IpldStore) ([]NodeEntry, error) { 213 + func entriesFromNodeData(ctx context.Context, nd *nodeData, cst cbor.IpldStore) ([]nodeEntry, error) { 197 214 layer := -1 198 215 if len(nd.Entries) > 0 { 199 216 // NOTE(bnewbold): can compute the layer on the first KeySuffix, because for the first entry that field is a complete key ··· 326 343 return nil, fmt.Errorf("getting layer failed: %w", err) 327 344 } 328 345 329 - newLeaf := NodeEntry{ 330 - Kind: EntryLeaf, 346 + newLeaf := nodeEntry{ 347 + Kind: entryLeaf, 331 348 Key: key, 332 349 Val: val, 333 350 } ··· 385 402 return nil, err 386 403 } 387 404 388 - return mst.updateEntry(ctx, index-1, treeEntry(newSubtree)) 405 + return mst.updateEntry(ctx, index-1, mkTreeEntry(newSubtree)) 389 406 } else { 390 407 subTree, err := mst.createChild(ctx) 391 408 if err != nil { ··· 397 414 return nil, fmt.Errorf("subtree add: %w", err) 398 415 } 399 416 400 - return mst.spliceIn(ctx, treeEntry(newSubTree), index) 417 + return mst.spliceIn(ctx, mkTreeEntry(newSubTree), index) 401 418 } 402 419 403 420 } else { ··· 435 452 } 436 453 } 437 454 438 - var updated []NodeEntry 455 + var updated []nodeEntry 439 456 if left != nil { 440 - updated = append(updated, treeEntry(left)) 457 + updated = append(updated, mkTreeEntry(left)) 441 458 } 442 459 443 - updated = append(updated, NodeEntry{ 444 - Kind: EntryLeaf, 460 + updated = append(updated, nodeEntry{ 461 + Kind: entryLeaf, 445 462 Key: key, 446 463 Val: val, 447 464 }) 448 465 449 466 if right != nil { 450 - updated = append(updated, treeEntry(right)) 467 + updated = append(updated, mkTreeEntry(right)) 451 468 } 452 469 453 470 checkTreeInvariant(updated) 454 - newRoot := NewMST(mst.cst, cid.Undef, updated, keyZeros) 471 + newRoot := createMST(mst.cst, cid.Undef, updated, keyZeros) 455 472 456 473 // NOTE(bnewbold): We do want to invalid the CID (because this node has 457 474 // changed, and we are "lazy" about recomputing). Setting this flag ··· 521 538 522 539 if !found.isUndefined() && found.isLeaf() && found.Key == k { 523 540 // NOTE(bnewbold): updated here 524 - return mst.updateEntry(ctx, index, NodeEntry{ 525 - Kind: EntryLeaf, 541 + return mst.updateEntry(ctx, index, nodeEntry{ 542 + Kind: entryLeaf, 526 543 Key: string(k), 527 544 Val: val, 528 545 }) ··· 538 555 if err != nil { 539 556 return nil, err 540 557 } 541 - return mst.updateEntry(ctx, index-1, treeEntry(updatedTree)) 558 + 559 + return mst.updateEntry(ctx, index-1, mkTreeEntry(updatedTree)) 542 560 } 543 561 544 562 return nil, ErrNotFound ··· 587 605 if err != nil { 588 606 return nil, err 589 607 } 590 - return mst.newTree(append(append(entries[:ix-1], treeEntry(merged)), entries[ix+2:]...)), nil 608 + return mst.newTree(append(append(entries[:ix-1], mkTreeEntry(merged)), entries[ix+2:]...)), nil 591 609 } else { 592 610 return mst.removeEntry(ctx, ix) 593 611 } ··· 613 631 if len(subtreeEntries) == 0 { 614 632 return mst.removeEntry(ctx, ix-1) 615 633 } else { 616 - return mst.updateEntry(ctx, ix-1, treeEntry(subtree)) 634 + return mst.updateEntry(ctx, ix-1, mkTreeEntry(subtree)) 617 635 } 618 636 } else { 619 637 return nil, fmt.Errorf("could not find record with key: %s", k) ··· 624 642 625 643 // "update entry in place" 626 644 // Typescript: MST.updateEntry(index, entry) -> MST 627 - func (mst *MerkleSearchTree) updateEntry(ctx context.Context, ix int, entry NodeEntry) (*MerkleSearchTree, error) { 645 + func (mst *MerkleSearchTree) updateEntry(ctx context.Context, ix int, entry nodeEntry) (*MerkleSearchTree, error) { 628 646 entries, err := mst.getEntries(ctx) 629 647 if err != nil { 630 648 return nil, err 631 649 } 632 650 633 - nents := make([]NodeEntry, len(entries)) 651 + nents := make([]nodeEntry, len(entries)) 634 652 copy(nents, entries[:ix]) 635 653 nents[ix] = entry 636 654 copy(nents[ix+1:], entries[ix+1:]) ··· 646 664 return nil, err 647 665 } 648 666 649 - nents := make([]NodeEntry, len(entries)-1) 667 + nents := make([]nodeEntry, len(entries)-1) 650 668 copy(nents, entries[:ix]) 651 669 copy(nents[ix:], entries[ix+1:]) 652 670 ··· 655 673 } 656 674 657 675 // "append entry to end of the node" 658 - func (mst *MerkleSearchTree) append(ctx context.Context, ent NodeEntry) (*MerkleSearchTree, error) { 676 + func (mst *MerkleSearchTree) append(ctx context.Context, ent nodeEntry) (*MerkleSearchTree, error) { 659 677 entries, err := mst.getEntries(ctx) 660 678 if err != nil { 661 679 return nil, err 662 680 } 663 681 664 - nents := make([]NodeEntry, len(entries)+1) 682 + nents := make([]nodeEntry, len(entries)+1) 665 683 copy(nents, entries) 666 684 nents[len(nents)-1] = ent 667 685 ··· 670 688 } 671 689 672 690 // "prepend entry to start of the node" 673 - func (mst *MerkleSearchTree) prepend(ctx context.Context, ent NodeEntry) (*MerkleSearchTree, error) { 691 + func (mst *MerkleSearchTree) prepend(ctx context.Context, ent nodeEntry) (*MerkleSearchTree, error) { 674 692 entries, err := mst.getEntries(ctx) 675 693 if err != nil { 676 694 return nil, err 677 695 } 678 696 679 - nents := make([]NodeEntry, len(entries)+1) 697 + nents := make([]nodeEntry, len(entries)+1) 680 698 copy(nents[1:], entries) 681 699 nents[0] = ent 682 700 ··· 686 704 687 705 // "returns entry at index" 688 706 // Apparently returns null if nothing at index, which seems brittle 689 - func (mst *MerkleSearchTree) atIndex(ix int) (NodeEntry, error) { 707 + func (mst *MerkleSearchTree) atIndex(ix int) (nodeEntry, error) { 690 708 entries, err := mst.getEntries(context.TODO()) 691 709 if err != nil { 692 - return NodeEntry{}, err 710 + return nodeEntry{}, err 693 711 } 694 712 695 713 // TODO(bnewbold): same as Typescript, but shouldn't this error instead of returning null? 696 714 if ix < 0 || ix >= len(entries) { 697 - return NodeEntry{}, nil 715 + return nodeEntry{}, nil 698 716 } 699 717 700 718 return entries[ix], nil ··· 703 721 // NOTE(bnewbold): unlike Typescript, golang does not really need the slice(start?, end?) helper 704 722 705 723 // "inserts entry at index" 706 - func (mst *MerkleSearchTree) spliceIn(ctx context.Context, entry NodeEntry, ix int) (*MerkleSearchTree, error) { 724 + func (mst *MerkleSearchTree) spliceIn(ctx context.Context, entry nodeEntry, ix int) (*MerkleSearchTree, error) { 707 725 entries, err := mst.getEntries(ctx) 708 726 if err != nil { 709 727 return nil, err 710 728 } 711 729 712 - nents := make([]NodeEntry, len(entries)+1) 730 + nents := make([]nodeEntry, len(entries)+1) 713 731 copy(nents, entries[:ix]) 714 732 nents[ix] = entry 715 733 copy(nents[ix+1:], entries[ix:]) ··· 719 737 } 720 738 721 739 // "replaces an entry with [ Maybe(tree), Leaf, Maybe(tree) ]" 722 - func (mst *MerkleSearchTree) replaceWithSplit(ctx context.Context, ix int, left *MerkleSearchTree, nl NodeEntry, right *MerkleSearchTree) (*MerkleSearchTree, error) { 740 + func (mst *MerkleSearchTree) replaceWithSplit(ctx context.Context, ix int, left *MerkleSearchTree, nl nodeEntry, right *MerkleSearchTree) (*MerkleSearchTree, error) { 723 741 entries, err := mst.getEntries(ctx) 724 742 if err != nil { 725 743 return nil, err 726 744 } 727 745 checkTreeInvariant(entries) 728 - var update []NodeEntry 746 + var update []nodeEntry 729 747 update = append(update, entries[:ix]...) 730 748 731 749 if left != nil { 732 - update = append(update, NodeEntry{ 733 - Kind: EntryTree, 750 + update = append(update, nodeEntry{ 751 + Kind: entryTree, 734 752 Tree: left, 735 753 }) 736 754 } ··· 738 756 update = append(update, nl) 739 757 740 758 if right != nil { 741 - update = append(update, NodeEntry{ 742 - Kind: EntryTree, 759 + update = append(update, nodeEntry{ 760 + Kind: entryTree, 743 761 Tree: right, 744 762 }) 745 763 } ··· 798 816 } 799 817 800 818 if subl != nil { 801 - left, err = left.append(ctx, treeEntry(subl)) 819 + left, err = left.append(ctx, mkTreeEntry(subl)) 802 820 if err != nil { 803 821 return nil, nil, err 804 822 } 805 823 } 806 824 807 825 if subr != nil { 808 - right, err = right.prepend(ctx, treeEntry(subr)) 826 + right, err = right.prepend(ctx, mkTreeEntry(subr)) 809 827 if err != nil { 810 828 return nil, nil, err 811 829 } ··· 866 884 return nil, err 867 885 } 868 886 869 - return mst.newTree(append(append(entries[:len(entries)-1], treeEntry(merged)), tomergeEnts[1:]...)), nil 887 + return mst.newTree(append(append(entries[:len(entries)-1], mkTreeEntry(merged)), tomergeEnts[1:]...)), nil 870 888 } else { 871 889 return mst.newTree(append(entries, tomergeEnts...)), nil 872 890 } ··· 880 898 return nil, err 881 899 } 882 900 883 - return NewMST(mst.cst, cid.Undef, []NodeEntry{}, layer-1), nil 901 + return createMST(mst.cst, cid.Undef, []nodeEntry{}, layer-1), nil 884 902 } 885 903 886 904 func (mst *MerkleSearchTree) createParent(ctx context.Context) (*MerkleSearchTree, error) { ··· 889 907 return nil, err 890 908 } 891 909 892 - return NewMST(mst.cst, cid.Undef, []NodeEntry{treeEntry(mst)}, layer+1), nil 910 + return createMST(mst.cst, cid.Undef, []nodeEntry{mkTreeEntry(mst)}, layer+1), nil 893 911 } 894 912 895 913 // === "Finding insertion points" === ··· 915 933 916 934 // === "List operations (partial tree traversal)" === 917 935 918 - // "Walk tree starting at key" 919 - func (mst *MerkleSearchTree) WalkLeavesFrom(ctx context.Context, key string, cb func(n NodeEntry) error) error { 920 - index, err := mst.findGtOrEqualLeafIndex(ctx, key) 936 + // WalkLeavesFrom walks the leaves of the tree, calling the cb callback on each 937 + // key that's greater than or equal to the provided from key. 938 + // If cb returns an error, the walk is aborted and the error is returned. 939 + func (mst *MerkleSearchTree) WalkLeavesFrom(ctx context.Context, from string, cb func(key string, val cid.Cid) error) error { 940 + index, err := mst.findGtOrEqualLeafIndex(ctx, from) 921 941 if err != nil { 922 942 return err 923 943 } ··· 930 950 if index > 0 { 931 951 prev := entries[index-1] 932 952 if !prev.isUndefined() && prev.isTree() { 933 - if err := prev.Tree.WalkLeavesFrom(ctx, key, cb); err != nil { 953 + if err := prev.Tree.WalkLeavesFrom(ctx, from, cb); err != nil { 934 954 return err 935 955 } 936 956 } ··· 938 958 939 959 for _, e := range entries[index:] { 940 960 if e.isLeaf() { 941 - if err := cb(e); err != nil { 961 + if err := cb(e.Key, e.Val); err != nil { 942 962 return err 943 963 } 944 964 } else { 945 - if err := e.Tree.WalkLeavesFrom(ctx, key, cb); err != nil { 965 + if err := e.Tree.WalkLeavesFrom(ctx, from, cb); err != nil { 946 966 return err 947 967 } 948 968 } ··· 954 974 // TODO: Typescript: MST.listWithPrefix(prefix, count?) -> Leaf[] 955 975 956 976 // "Walk full tree & emit nodes, consumer can bail at any point by returning false" 957 - // TODO: Typescript: MST.walk() -> NodeEntry (iterator) 958 - // TODO: Typescript: MST.paths() -> NodeEntry[][] 959 - // TODO: Typescript: MST.allNodes() -> NodeEntry[] 977 + // TODO: Typescript: MST.walk() -> nodeEntry (iterator) 978 + // TODO: Typescript: MST.paths() -> nodeEntry[][] 979 + // TODO: Typescript: MST.allNodes() -> nodeEntry[] 960 980 // TODO: Typescript: MST.allCids() -> CidSet 961 981 // TODO: Typescript: MST.leaves() -> Leaf[] 962 982 // TODO: Typescript: MST.leafCount() -> number 963 983 964 - // TODO: Typescript: MST.walkReachable() -> NodeEntry (iterator) 984 + // TODO: Typescript: MST.walkReachable() -> nodeEntry (iterator) 965 985 // TODO: Typescript: MST.reachableLeaves() -> Leaf[] 966 986 967 987 // TODO: Typescript: MST.writeToCarStream(car) -> ()
+3 -3
mst/mst_interop_test.go
··· 166 166 t.Fatal(err) 167 167 } 168 168 169 - simple_nd := NodeData{ 169 + simple_nd := nodeData{ 170 170 Left: nil, 171 - Entries: []TreeEntry{ 172 - TreeEntry{ 171 + Entries: []treeEntry{ 172 + { 173 173 PrefixLen: 0, 174 174 KeySuffix: []byte("com.example.record/3jqfcqzm3fo2j"), 175 175 Val: cid1,
+4 -4
mst/mst_test.go
··· 34 34 35 35 ctx := context.Background() 36 36 cst := util.CborStore(blockstore.NewBlockstore(datastore.NewMapDatastore())) 37 - mst := NewMST(cst, cid.Undef, []NodeEntry{}, -1) 37 + mst := createMST(cst, cid.Undef, []nodeEntry{}, -1) 38 38 39 39 vals := map[string]cid.Cid{ 40 40 "cats/cats": randCid(), ··· 89 89 90 90 func assertValues(t *testing.T, mst *MerkleSearchTree, vals map[string]cid.Cid) { 91 91 out := make(map[string]cid.Cid) 92 - if err := mst.WalkLeavesFrom(context.TODO(), "", func(ne NodeEntry) error { 93 - out[ne.Key] = ne.Val 92 + if err := mst.WalkLeavesFrom(context.TODO(), "", func(key string, val cid.Cid) error { 93 + out[key] = val 94 94 return nil 95 95 }); err != nil { 96 96 t.Fatal(err) ··· 369 369 370 370 func cidMapToMst(t *testing.T, bs blockstore.Blockstore, m map[string]cid.Cid) *MerkleSearchTree { 371 371 cst := util.CborStore(bs) 372 - mt := NewMST(cst, cid.Undef, []NodeEntry{}, -1) 372 + mt := createMST(cst, cid.Undef, []nodeEntry{}, -1) 373 373 374 374 for k, v := range m { 375 375 nmst, err := mt.Add(context.TODO(), k, v, -1)
+17 -17
mst/mst_util.go
··· 39 39 } 40 40 41 41 // Typescript: layerForEntries(entries, fanout) -> (number?) 42 - func layerForEntries(entries []NodeEntry) int { 43 - var firstLeaf NodeEntry 42 + func layerForEntries(entries []nodeEntry) int { 43 + var firstLeaf nodeEntry 44 44 for _, e := range entries { 45 45 if e.isLeaf() { 46 46 firstLeaf = e ··· 48 48 } 49 49 } 50 50 51 - if firstLeaf.Kind == EntryUndefined { 51 + if firstLeaf.Kind == entryUndefined { 52 52 return -1 53 53 } 54 54 ··· 56 56 } 57 57 58 58 // Typescript: deserializeNodeData(storage, data, layer) 59 - func deserializeNodeData(ctx context.Context, cst cbor.IpldStore, nd *NodeData, layer int) ([]NodeEntry, error) { 60 - entries := []NodeEntry{} 59 + func deserializeNodeData(ctx context.Context, cst cbor.IpldStore, nd *nodeData, layer int) ([]nodeEntry, error) { 60 + entries := []nodeEntry{} 61 61 if nd.Left != nil { 62 62 // Note: like Typescript, this is actually a lazy load 63 - entries = append(entries, NodeEntry{ 64 - Kind: EntryTree, 65 - Tree: NewMST(cst, *nd.Left, nil, layer-1), 63 + entries = append(entries, nodeEntry{ 64 + Kind: entryTree, 65 + Tree: createMST(cst, *nd.Left, nil, layer-1), 66 66 }) 67 67 } 68 68 ··· 77 77 return nil, err 78 78 } 79 79 80 - entries = append(entries, NodeEntry{ 81 - Kind: EntryLeaf, 80 + entries = append(entries, nodeEntry{ 81 + Kind: entryLeaf, 82 82 Key: string(key), 83 83 Val: e.Val, 84 84 }) 85 85 86 86 if e.Tree != nil { 87 - entries = append(entries, NodeEntry{ 88 - Kind: EntryTree, 89 - Tree: NewMST(cst, *e.Tree, nil, layer-1), 87 + entries = append(entries, nodeEntry{ 88 + Kind: entryTree, 89 + Tree: createMST(cst, *e.Tree, nil, layer-1), 90 90 Key: string(key), 91 91 }) 92 92 } ··· 97 97 } 98 98 99 99 // Typescript: serializeNodeData(entries) -> NodeData 100 - func serializeNodeData(entries []NodeEntry) (*NodeData, error) { 101 - var data NodeData 100 + func serializeNodeData(entries []nodeEntry) (*nodeData, error) { 101 + var data nodeData 102 102 103 103 i := 0 104 104 if len(entries) > 0 && entries[0].isTree() { ··· 143 143 } 144 144 145 145 prefixLen := countPrefixLen(lastKey, leaf.Key) 146 - data.Entries = append(data.Entries, TreeEntry{ 146 + data.Entries = append(data.Entries, treeEntry{ 147 147 PrefixLen: int64(prefixLen), 148 148 KeySuffix: []byte(leaf.Key)[prefixLen:], 149 149 Val: leaf.Val, ··· 180 180 // both computes *and* persists a tree entry; this is different from typescript 181 181 // implementation 182 182 // Typescript: cidForEntries(entries) -> CID 183 - func cidForEntries(ctx context.Context, entries []NodeEntry, cst cbor.IpldStore) (cid.Cid, error) { 183 + func cidForEntries(ctx context.Context, entries []nodeEntry, cst cbor.IpldStore) (cid.Cid, error) { 184 184 nd, err := serializeNodeData(entries) 185 185 if err != nil { 186 186 return cid.Undef, fmt.Errorf("serializing new entries: %w", err)
+2 -4
repo/repo.go
··· 108 108 func NewRepo(ctx context.Context, did string, bs blockstore.Blockstore) *Repo { 109 109 cst := util.CborStore(bs) 110 110 111 - t := mst.NewMST(cst, cid.Undef, []mst.NodeEntry{}, 0) 111 + t := mst.NewEmptyMST(cst) 112 112 sc := SignedCommit{ 113 113 Did: did, 114 114 Version: 2, ··· 310 310 311 311 t := mst.LoadMST(r.cst, r.sc.Data) 312 312 313 - if err := t.WalkLeavesFrom(ctx, prefix, func(e mst.NodeEntry) error { 314 - return cb(e.Key, e.Val) 315 - }); err != nil { 313 + if err := t.WalkLeavesFrom(ctx, prefix, cb); err != nil { 316 314 if err != ErrDoneIterating { 317 315 return err 318 316 }