// PathSegment can describe either a key in a map, or an index in a list.
//
// Create a PathSegment via either ParsePathSegment, PathSegmentOfString,
// or PathSegmentOfInt; or, via one of the constructors of Path,
// which will implicitly create PathSegment internally.
// Using PathSegment's natural zero value directly is discouraged
// (it will act like ParsePathSegment("0"), which likely not what you'd expect).
//
// Path segments are "stringly typed" -- they may be interpreted as either strings or ints depending on context.
// A path segment of "123" will be used as a string when traversing a node of map kind;
// and it will be converted to an integer when traversing a node of list kind.
...
...
@@ -15,10 +21,21 @@ import (
// Internally, PathSegment will store either a string or an integer,
// depending on how it was constructed,
// and will automatically convert to the other on request.
// (This means if two pieces of code communicate using PathSegment, one producing ints and the other expecting ints, they will work together efficiently.)
// (This means if two pieces of code communicate using PathSegment,
// one producing ints and the other expecting ints,
// then they will work together efficiently.)
// PathSegment in a Path produced by ParsePath generally have all strings internally,
// because there is distinction possible when parsing a Path string
// (and attempting to pre-parse all strings into ints "in case" would waste time in almost all cases).
// because there is no distinction possible when parsing a Path string
// (and attempting to pre-parse all strings into ints "just in case" would waste time in almost all cases).
//
// Be cautious of attempting to use PathSegment as a map key!
// Due to the implementation detail of internal storage, it's possible for
// PathSegment values which are "equal" per PathSegment.Equal's definition
// to still be unequal in the eyes of golang's native maps.
// You should probably use the string values of the PathSegment as map keys.
// (This has the additional bonus of hitting a special fastpath that the golang
// built-in maps have specifically for plain string keys.)
//
typePathSegmentstruct{
/*
A quick implementation note about the Go compiler and "union" semantics:
...
...
@@ -43,9 +60,10 @@ type PathSegment struct {
we're using the first tactic.
(We also currently get away with having no extra discriminator bit
because empty string is not considered a valid segment,
because we use a signed int for indexes, and negative values aren't valid there,
and thus we can use it as a sentinel value.
This may change if the IPLD Path spec comes to other conclusions about this.)
(Fun note: Empty strings were originally used for this sentinel,
but it turns out empty strings are valid PathSegment themselves, so!))
*/
sstring
...
...
@@ -57,16 +75,16 @@ type PathSegment struct {
// (Note: there is currently no escaping specified for PathSegments,
// so this is currently functionally equivalent to PathSegmentOfString.)
funcParsePathSegment(sstring)PathSegment{
returnPathSegment{s:s}
returnPathSegment{s:s,i:-1}
}
// PathSegmentOfString boxes a string into a PathSegement.
// PathSegmentOfString boxes a string into a PathSegment.
// It does not attempt to parse any escaping; use ParsePathSegment for that.
funcPathSegmentOfString(sstring)PathSegment{
returnPathSegment{s:s}
returnPathSegment{s:s,i:-1}
}
// PathSegmentOfString boxes an int into a PathSegement.
// PathSegmentOfString boxes an int into a PathSegment.