Commit 23298ebc authored by Eric Myhre's avatar Eric Myhre

Improvements to traversal docs.

Walk functions weren't sufficiently fleshed out.

A few notes about expansion effects due to paths are now made.

General consistency pass across all the methods.
parent fc80c2b0
...@@ -6,30 +6,44 @@ import ( ...@@ -6,30 +6,44 @@ import (
ipld "github.com/ipld/go-ipld-prime" ipld "github.com/ipld/go-ipld-prime"
) )
// Focus is a shortcut for kicking off // Focus traverses a Node graph according to a path, reaches a single Node,
// traversal.Progress.Focus with an empty initial state // and calls the given VisitFn on that reached node.
// (e.g. the Node given here is the "root" node of your operation). //
// This function is a helper function which starts a new traversal with default configuration.
// It cannot cross links automatically (since this requires configuration).
// Use the equivalent Focus function on the Progress structure
// for more advanced and configurable walks.
func Focus(n ipld.Node, p ipld.Path, fn VisitFn) error { func Focus(n ipld.Node, p ipld.Path, fn VisitFn) error {
return Progress{}.Focus(n, p, fn) return Progress{}.Focus(n, p, fn)
} }
// FocusedTransform is a shortcut for kicking off // FocusedTransform traverses an ipld.Node graph, reaches a single Node,
// traversal.Progress.FocusedTransform with an empty initial state // and calls the given TransformFn to decide what new node to replace the visited node with.
// (e.g. the Node given here is the "root" node of your operation). // A new Node tree will be returned (the original is unchanged).
//
// This function is a helper function which starts a new traversal with default configuration.
// It cannot cross links automatically (since this requires configuration).
// Use the equivalent FocusedTransform function on the Progress structure
// for more advanced and configurable walks.
func FocusedTransform(n ipld.Node, p ipld.Path, fn TransformFn) (ipld.Node, error) { func FocusedTransform(n ipld.Node, p ipld.Path, fn TransformFn) (ipld.Node, error) {
return Progress{}.FocusedTransform(n, p, fn) return Progress{}.FocusedTransform(n, p, fn)
} }
// Focus traverses an ipld.Node graph, reaches a single Node, // Focus traverses a Node graph according to a path, reaches a single Node,
// and applies a function to the reached node. // and calls the given VisitFn on that reached node.
// //
// Focus is a read-only traversal. // Focus is a read-only traversal.
// See FocusedTransform if looking for a way to do an "update" to a Node. // See FocusedTransform if looking for a way to do an "update" to a Node.
// //
// Focus can be used again again inside the applied VisitFn! // Provide configuration to this process using the Config field in the Progress object.
// By using the traversal.Progress handed to the VisitFn, the Path recorded //
// of the traversal so far will continue to be extended, and thus continued // This walk will automatically cross links, but requires some configuration
// nested uses of Focus will see a fully contextualized Path. // with link loading functions to do so.
//
// Focus (and the other traversal functions) can be used again again inside the VisitFn!
// By using the traversal.Progress handed to the VisitFn,
// the Path recorded of the traversal so far will continue to be extended,
// and thus continued nested uses of Walk and Focus will see the fully contextualized Path.
func (prog Progress) Focus(n ipld.Node, p ipld.Path, fn VisitFn) error { func (prog Progress) Focus(n ipld.Node, p ipld.Path, fn VisitFn) error {
prog.init() prog.init()
segments := p.Segments() segments := p.Segments()
...@@ -93,10 +107,11 @@ func (prog Progress) Focus(n ipld.Node, p ipld.Path, fn VisitFn) error { ...@@ -93,10 +107,11 @@ func (prog Progress) Focus(n ipld.Node, p ipld.Path, fn VisitFn) error {
} }
// FocusedTransform traverses an ipld.Node graph, reaches a single Node, // FocusedTransform traverses an ipld.Node graph, reaches a single Node,
// and applies a function to the reached node which make return a new Node. // and calls the given TransformFn to decide what new node to replace the visited node with.
// A new Node tree will be returned (the original is unchanged).
// //
// If the TransformFn returns a Node which is the same as the original // If the TransformFn returns the same Node which it was called with,
// reached node, the transform is a no-op, and the Node returned from the // then the transform is a no-op, and the Node returned from the
// FocusedTransform call as a whole will also be the same as its starting Node. // FocusedTransform call as a whole will also be the same as its starting Node.
// //
// Otherwise, the reached node will be "replaced" with the new Node -- meaning // Otherwise, the reached node will be "replaced" with the new Node -- meaning
...@@ -120,6 +135,8 @@ func (prog Progress) Focus(n ipld.Node, p ipld.Path, fn VisitFn) error { ...@@ -120,6 +135,8 @@ func (prog Progress) Focus(n ipld.Node, p ipld.Path, fn VisitFn) error {
// do with regular Node and NodeBuilder usage directly. Transform just // do with regular Node and NodeBuilder usage directly. Transform just
// does a large amount of the intermediate bookkeeping that's useful when // does a large amount of the intermediate bookkeeping that's useful when
// creating new values which are partial updates to existing values. // creating new values which are partial updates to existing values.
//
// This feature is not yet implemented.
func (prog Progress) FocusedTransform(n ipld.Node, p ipld.Path, fn TransformFn) (ipld.Node, error) { func (prog Progress) FocusedTransform(n ipld.Node, p ipld.Path, fn TransformFn) (ipld.Node, error) {
panic("TODO") // TODO surprisingly different from Focus -- need to store nodes we traversed, and able do building. panic("TODO") // TODO surprisingly different from Focus -- need to store nodes we traversed, and able do building.
} }
...@@ -7,18 +7,62 @@ import ( ...@@ -7,18 +7,62 @@ import (
"github.com/ipld/go-ipld-prime/traversal/selector" "github.com/ipld/go-ipld-prime/traversal/selector"
) )
// WalkMatching walks a graph of Nodes, deciding which to visit by applying a Selector,
// and calling the given VisitFn on those that the Selector deems a match.
//
// This function is a helper function which starts a new walk with default configuration.
// It cannot cross links automatically (since this requires configuration).
// Use the equivalent WalkMatching function on the Progress structure
// for more advanced and configurable walks.
func WalkMatching(n ipld.Node, s selector.Selector, fn VisitFn) error { func WalkMatching(n ipld.Node, s selector.Selector, fn VisitFn) error {
return Progress{}.WalkMatching(n, s, fn) return Progress{}.WalkMatching(n, s, fn)
} }
// WalkAdv is identical to WalkMatching, except it is called for *all* nodes
// visited (not just matching nodes), together with the reason for the visit.
// An AdvVisitFn is used instead of a VisitFn, so that the reason can be provided.
//
// This function is a helper function which starts a new walk with default configuration.
// It cannot cross links automatically (since this requires configuration).
// Use the equivalent WalkAdv function on the Progress structure
// for more advanced and configurable walks.
func WalkAdv(n ipld.Node, s selector.Selector, fn AdvVisitFn) error { func WalkAdv(n ipld.Node, s selector.Selector, fn AdvVisitFn) error {
return Progress{}.WalkAdv(n, s, fn) return Progress{}.WalkAdv(n, s, fn)
} }
// WalkTransforming walks a graph of Nodes, deciding which to alter by applying a Selector,
// and calls the given TransformFn to decide what new node to replace the visited node with.
// A new Node tree will be returned (the original is unchanged).
//
// This function is a helper function which starts a new walk with default configuration.
// It cannot cross links automatically (since this requires configuration).
// Use the equivalent WalkTransforming function on the Progress structure
// for more advanced and configurable walks.
func WalkTransforming(n ipld.Node, s selector.Selector, fn TransformFn) (ipld.Node, error) { func WalkTransforming(n ipld.Node, s selector.Selector, fn TransformFn) (ipld.Node, error) {
return Progress{}.WalkTransforming(n, s, fn) return Progress{}.WalkTransforming(n, s, fn)
} }
// WalkMatching walks a graph of Nodes, deciding which to visit by applying a Selector,
// and calling the given VisitFn on those that the Selector deems a match.
//
// WalkMatching is a read-only traversal.
// See WalkTransforming if looking for a way to do "updates" to a tree of nodes.
//
// Provide configuration to this process using the Config field in the Progress object.
//
// This walk will automatically cross links, but requires some configuration
// with link loading functions to do so.
//
// Traversals are defined as visiting a (node,path) tuple.
// This is important to note because when walking DAGs with Links,
// it means you may visit the same node multiple times
// due to having reached it via a different path.
//
// WalkMatching (and the other traversal functions) can be used again again inside the VisitFn!
// By using the traversal.Progress handed to the VisitFn,
// the Path recorded of the traversal so far will continue to be extended,
// and thus continued nested uses of Walk and Focus will see the fully contextualized Path.
//
func (prog Progress) WalkMatching(n ipld.Node, s selector.Selector, fn VisitFn) error { func (prog Progress) WalkMatching(n ipld.Node, s selector.Selector, fn VisitFn) error {
prog.init() prog.init()
return prog.walkAdv(n, s, func(prog Progress, n ipld.Node, tr VisitReason) error { return prog.walkAdv(n, s, func(prog Progress, n ipld.Node, tr VisitReason) error {
...@@ -29,6 +73,10 @@ func (prog Progress) WalkMatching(n ipld.Node, s selector.Selector, fn VisitFn) ...@@ -29,6 +73,10 @@ func (prog Progress) WalkMatching(n ipld.Node, s selector.Selector, fn VisitFn)
}) })
} }
// WalkAdv is identical to WalkMatching, except it is called for *all* nodes
// visited (not just matching nodes), together with the reason for the visit.
// An AdvVisitFn is used instead of a VisitFn, so that the reason can be provided.
//
func (prog Progress) WalkAdv(n ipld.Node, s selector.Selector, fn AdvVisitFn) error { func (prog Progress) WalkAdv(n ipld.Node, s selector.Selector, fn AdvVisitFn) error {
prog.init() prog.init()
return prog.walkAdv(n, s, fn) return prog.walkAdv(n, s, fn)
...@@ -146,6 +194,25 @@ func (prog Progress) loadLink(v ipld.Node, parent ipld.Node) (ipld.Node, error) ...@@ -146,6 +194,25 @@ func (prog Progress) loadLink(v ipld.Node, parent ipld.Node) (ipld.Node, error)
return nb.Build(), nil return nb.Build(), nil
} }
// WalkTransforming walks a graph of Nodes, deciding which to alter by applying a Selector,
// and calls the given TransformFn to decide what new node to replace the visited node with.
// A new Node tree will be returned (the original is unchanged).
//
// If the TransformFn returns the same Node which it was called with,
// then the transform is a no-op; if every visited node is a no-op,
// then the root node returned from the walk as a whole will also be
// the same as its starting Node (no new memory will be used).
//
// When a Node is replaced, no further recursion of this walk will occur on its contents.
// (You can certainly do a additional traversals, including transforms,
// from inside the TransformFn while building the replacement node.)
//
// The style (that is, implementation) of Node returned will be the same as the
// styles of the Nodes at the same positions in the existing tree
// (literally, builders used to construct any new needed intermediate nodes
// are chosen by asking the existing nodes about their style).
//
// This feature is not yet implemented.
func (prog Progress) WalkTransforming(n ipld.Node, s selector.Selector, fn TransformFn) (ipld.Node, error) { func (prog Progress) WalkTransforming(n ipld.Node, s selector.Selector, fn TransformFn) (ipld.Node, error) {
panic("TODO") panic("TODO")
} }
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