From 102908c6801e80223246e7ac4d57e8839fd2fc9f Mon Sep 17 00:00:00 2001 From: Mildred Ki'Lya Date: Thu, 31 Dec 2015 17:59:07 +0100 Subject: [PATCH] Add NodeReaderAt type (read a node from a subpath) --- reader.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/reader.go b/reader.go index 071b36c..560fc16 100644 --- a/reader.go +++ b/reader.go @@ -1,5 +1,12 @@ package ipld +import( + "fmt" + "errors" + "strings" + "reflect" +) + type nodeReadErrors struct { error } var NodeReadAbort error = &nodeReadErrors{errors.New("abort")} var NodeReadSkip error = &nodeReadErrors{errors.New("skip")} @@ -73,3 +80,53 @@ type NodeReader interface { Read(f ReadFun) error; } +// Convert a []interface{} path to a []string path +// This should only convert array indices to strings, and such are not ambiguous +// because array indices and object keys cannot be mixed for the same prefix. +func ToStringPath(anyPath []interface{}) []string { + var res []string + for _, e := range anyPath { + if str, ok := e.(string); ok { + res = append(res, str) + } else if i, ok := e.(int); ok { + res = append(res, fmt.Sprintf("%d", i)) + } else { + res = append(res, fmt.Sprintf("%v", e)) + } + } + return res +} + +// A NodeReader that only read elements from a path prefix +type NodeReaderAt struct { + parent NodeReader + prefix []string +} + +func (n *NodeReaderAt) Read(f ReadFun) error { + found := false + return n.parent.Read(func(path []interface{}, tokenType ReaderToken, value interface{}) error { + if isPathPrefix(n.prefix, ToStringPath(path)) { + found = true + return f(path[len(n.prefix):], tokenType, value) + } else if found { + // Finished, stop early + return NodeReadAbort + } else { + // Not yet here, continue + return nil + } + }) +} + +// Return true if path has prefix +func isPathPrefix(prefix, path []string) bool { + return len(prefix) <= len(path) && reflect.DeepEqual(prefix, path[0:len(prefix)]) +} + +// Return an instance of NodeReaderAt that read root only starting at the given +// prefix. +func GetReaderAt(root NodeReader, path string) *NodeReaderAt { + return &NodeReaderAt{root, strings.Split(path, "/")} +} +