diff --git a/pointer.go b/pointer.go index 025bc87..13f3ccd 100644 --- a/pointer.go +++ b/pointer.go @@ -16,6 +16,8 @@ import ( "strings" ) +const defaultPointerAllocationSize = 32 + // Parse parses str into a Pointer structure. // str may be a pointer or a url string. // If a url string, Parse will use the URL's fragment component @@ -35,6 +37,25 @@ func Parse(str string) (Pointer, error) { return parse(u.Fragment) } +// IsEmpty is a utility function to check if the Pointer +// is empty / nil equivalent +func (p Pointer) IsEmpty() bool { + return len(p) == 0 +} + +// Head returns the root of the Pointer +func (p Pointer) Head() *string { + if len(p) == 0 { + return nil + } + return &p[0] +} + +// Tail returns everything after the Pointer head +func (p Pointer) Tail() Pointer { + return Pointer(p[1:]) +} + // The ABNF syntax of a JSON Pointer is: // json-pointer = *( "/" reference-token ) // reference-token = *( unescaped / escaped ) @@ -62,6 +83,12 @@ func parse(str string) (Pointer, error) { // Pointer represents a parsed JSON pointer type Pointer []string +// NewPointer creates a Pointer with a pre-allocated block of memory +// to avoid repeated slice expansions +func NewPointer() Pointer { + return make([]string, 0, defaultPointerAllocationSize) +} + // String implements the stringer interface for Pointer, // giving the escaped string func (p Pointer) String() (str string) { @@ -104,6 +131,14 @@ func (p Pointer) Descendant(path string) (Pointer, error) { return append(p, dpath...), nil } +// RawDescendant extends the pointer with 1 or more path tokens +// The function itself is unsafe as it doesnt fully parse the input +// and assumes the user is directly managing the pointer +// This allows for much faster pointer management +func (p Pointer) RawDescendant(path ...string) Pointer { + return append(p, path...) +} + // Evaluation of each reference token begins by decoding any escaped // character sequence. This is performed by first transforming any // occurrence of the sequence '~1' to '/', and then transforming any diff --git a/pointer_test.go b/pointer_test.go index d04064e..e02c315 100644 --- a/pointer_test.go +++ b/pointer_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "reflect" + "strings" "testing" ) @@ -60,7 +61,7 @@ func TestParse(t *testing.T) { {"#/foo", "/foo", ""}, {"#/foo/", "/foo/", ""}, - {"://", "", "parse ://: missing protocol scheme"}, + {"://", "", "missing protocol scheme"}, {"#7", "", "non-empty references must begin with a '/' character"}, {"", "", ""}, {"https://example.com#", "", ""}, @@ -68,7 +69,7 @@ func TestParse(t *testing.T) { for i, c := range cases { got, err := Parse(c.raw) - if !(err == nil && c.err == "" || err != nil && err.Error() == c.err) { + if !(err == nil && c.err == "" || err != nil && strings.Contains(err.Error(), c.err)) { t.Errorf("case %d error mismatch. expected: '%s', got: '%s'", i, c.err, err) continue }