Commit 81c626ef authored by Eric Myhre's avatar Eric Myhre

traversal.SkipMe can now be used to control walks.

parent 23298ebc
...@@ -54,3 +54,16 @@ type Config struct { ...@@ -54,3 +54,16 @@ type Config struct {
// could decide what kind of native type is expected, and return a // could decide what kind of native type is expected, and return a
// `bind.NodeBuilder` for that specific concrete native type. // `bind.NodeBuilder` for that specific concrete native type.
type LinkTargetNodeStyleChooser func(ipld.Link, ipld.LinkContext) (ipld.NodeStyle, error) type LinkTargetNodeStyleChooser func(ipld.Link, ipld.LinkContext) (ipld.NodeStyle, error)
// SkipMe is a signalling "error" which can be used to tell traverse to skip some data.
//
// SkipMe can be returned by the Config.LinkLoader to skip entire blocks without aborting the walk.
// (This can be useful if you know you don't have data on hand,
// but want to continue the walk in other areas anyway;
// or, if you're doing a way where you know that it's valid to memoize seen
// areas based on Link alone.)
type SkipMe struct{}
func (SkipMe) Error() string {
return "skip"
}
...@@ -57,6 +57,8 @@ func WalkTransforming(n ipld.Node, s selector.Selector, fn TransformFn) (ipld.No ...@@ -57,6 +57,8 @@ func WalkTransforming(n ipld.Node, s selector.Selector, fn TransformFn) (ipld.No
// This is important to note because when walking DAGs with Links, // This is important to note because when walking DAGs with Links,
// it means you may visit the same node multiple times // it means you may visit the same node multiple times
// due to having reached it via a different path. // due to having reached it via a different path.
// (You can prevent this by using a LinkLoader function which memoizes a set of
// already-visited Links, and returns a SkipMe when encountering them again.)
// //
// WalkMatching (and the other traversal functions) can be used again again inside the VisitFn! // WalkMatching (and the other traversal functions) can be used again again inside the VisitFn!
// By using the traversal.Progress handed to the VisitFn, // By using the traversal.Progress handed to the VisitFn,
...@@ -122,6 +124,9 @@ func (prog Progress) walkAdv_iterateAll(n ipld.Node, s selector.Selector, fn Adv ...@@ -122,6 +124,9 @@ func (prog Progress) walkAdv_iterateAll(n ipld.Node, s selector.Selector, fn Adv
progNext.LastBlock.Link = lnk progNext.LastBlock.Link = lnk
v, err = progNext.loadLink(v, n) v, err = progNext.loadLink(v, n)
if err != nil { if err != nil {
if _, ok := err.(SkipMe); ok {
return nil
}
return err return err
} }
} }
...@@ -151,6 +156,9 @@ func (prog Progress) walkAdv_iterateSelective(n ipld.Node, attn []ipld.PathSegme ...@@ -151,6 +156,9 @@ func (prog Progress) walkAdv_iterateSelective(n ipld.Node, attn []ipld.PathSegme
progNext.LastBlock.Link = lnk progNext.LastBlock.Link = lnk
v, err = progNext.loadLink(v, n) v, err = progNext.loadLink(v, n)
if err != nil { if err != nil {
if _, ok := err.(SkipMe); ok {
return nil
}
return err return err
} }
} }
...@@ -189,6 +197,9 @@ func (prog Progress) loadLink(v ipld.Node, parent ipld.Node) (ipld.Node, error) ...@@ -189,6 +197,9 @@ func (prog Progress) loadLink(v ipld.Node, parent ipld.Node) (ipld.Node, error)
prog.Cfg.LinkLoader, prog.Cfg.LinkLoader,
) )
if err != nil { if err != nil {
if _, ok := err.(SkipMe); ok {
return nil, err
}
return nil, fmt.Errorf("error traversing node at %q: could not load link %q: %s", prog.Path, lnk, err) return nil, fmt.Errorf("error traversing node at %q: could not load link %q: %s", prog.Path, lnk, err)
} }
return nb.Build(), nil return nb.Build(), nil
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment