From b0c96b25dc3264c295227dcfa28b9bf68026c4ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Mur=C3=A9?= Date: Sat, 31 Aug 2024 15:48:24 +0200 Subject: [PATCH] selector: simplify the public interface of the package Those extra interfaces are not necessary. --- capability/policy/selector/selector.go | 76 +++++++-------------- capability/policy/selector/selector_test.go | 4 +- 2 files changed, 26 insertions(+), 54 deletions(-) diff --git a/capability/policy/selector/selector.go b/capability/policy/selector/selector.go index 40a432a..c6da69a 100644 --- a/capability/policy/selector/selector.go +++ b/capability/policy/selector/selector.go @@ -13,7 +13,7 @@ import ( // Selector describes a UCAN policy selector, as specified here: // https://github.com/ucan-wg/delegation/blob/4094d5878b58f5d35055a3b93fccda0b8329ebae/README.md#selectors -type Selector []Segment +type Selector []segment func (s Selector) String() string { var str string @@ -23,23 +23,6 @@ func (s Selector) String() string { return str } -type Segment interface { - // Identity flags that this selector is the identity selector. - Identity() bool - // Optional flags that this selector is optional. - Optional() bool - // Iterator flags that this selector is an iterator segment. - Iterator() bool - // Slice flags that this segemnt targets a range of a slice. - Slice() []int - // Field is the name of a field in a struct/map. - Field() string - // Index is an index of a slice. - Index() int - // String returns the segment's string representation. - String() string -} - var Identity = segment{".", true, false, false, nil, "", 0} var ( @@ -58,37 +41,44 @@ type segment struct { index int } +// String returns the segment's string representation. func (s segment) String() string { return s.str } +// Identity flags that this selector is the identity selector. func (s segment) Identity() bool { return s.identity } +// Optional flags that this selector is optional. func (s segment) Optional() bool { return s.optional } +// Iterator flags that this selector is an iterator segment. func (s segment) Iterator() bool { return s.iterator } +// Slice flags that this segment targets a range of a slice. func (s segment) Slice() []int { return s.slice } +// Field is the name of a field in a struct/map. func (s segment) Field() string { return s.field } +// Index is an index of a slice. func (s segment) Index() int { return s.index } func Parse(str string) (Selector, error) { if string(str[0]) != "." { - return nil, NewParseError("selector must start with identity segment '.'", str, 0, string(str[0])) + return nil, newParseError("selector must start with identity segment '.'", str, 0, string(str[0])) } col := 0 @@ -102,7 +92,7 @@ func Parse(str string) (Selector, error) { switch seg { case ".": if len(sel) > 0 && sel[len(sel)-1].Identity() { - return nil, NewParseError("selector contains unsupported recursive descent segment: '..'", str, col, tok) + return nil, newParseError("selector contains unsupported recursive descent segment: '..'", str, col, tok) } sel = append(sel, Identity) case "[]": @@ -114,7 +104,7 @@ func Parse(str string) (Selector, error) { if indexRegex.MatchString(lookup) { // index idx, err := strconv.Atoi(lookup) if err != nil { - return nil, NewParseError("invalid index", str, col, tok) + return nil, newParseError("invalid index", str, col, tok) } sel = append(sel, segment{str: tok, optional: opt, index: idx}) } else if strings.HasPrefix(lookup, "\"") && strings.HasSuffix(lookup, "\"") { // explicit field @@ -127,25 +117,25 @@ func Parse(str string) (Selector, error) { } else { i, err := strconv.Atoi(splt[0]) if err != nil { - return nil, NewParseError("invalid slice index", str, col, tok) + return nil, newParseError("invalid slice index", str, col, tok) } rng = append(rng, i) } if splt[1] != "" { i, err := strconv.Atoi(splt[1]) if err != nil { - return nil, NewParseError("invalid slice index", str, col, tok) + return nil, newParseError("invalid slice index", str, col, tok) } rng = append(rng, i) } sel = append(sel, segment{str: tok, optional: opt, slice: rng}) } else { - return nil, NewParseError(fmt.Sprintf("invalid segment: %s", seg), str, col, tok) + return nil, newParseError(fmt.Sprintf("invalid segment: %s", seg), str, col, tok) } } else if fieldRegex.MatchString(seg) { sel = append(sel, segment{str: tok, optional: opt, field: seg[1:]}) } else { - return nil, NewParseError(fmt.Sprintf("invalid segment: %s", seg), str, col, tok) + return nil, newParseError(fmt.Sprintf("invalid segment: %s", seg), str, col, tok) } } col += len(tok) @@ -193,15 +183,6 @@ func tokenize(str string) []string { return toks } -type ParseError interface { - error - Name() string - Message() string - Source() string - Column() int - Token() string -} - type parseerr struct { msg string src string @@ -233,7 +214,7 @@ func (p parseerr) Token() string { return p.tok } -func NewParseError(message string, source string, column int, token string) error { +func newParseError(message string, source string, column int, token string) error { return parseerr{message, source, column, token} } @@ -312,7 +293,7 @@ func resolve(sel Selector, subject ipld.Node, at []string) (ipld.Node, []ipld.No } else if seg.Optional() { cur = nil } else { - return nil, nil, NewResolutionError(fmt.Sprintf("can not iterate over kind: %s", kindString(cur)), at) + return nil, nil, newResolutionError(fmt.Sprintf("can not iterate over kind: %s", kindString(cur)), at) } } else if seg.Field() != "" { @@ -324,7 +305,7 @@ func resolve(sel Selector, subject ipld.Node, at []string) (ipld.Node, []ipld.No if seg.Optional() { cur = nil } else { - return nil, nil, NewResolutionError(fmt.Sprintf("object has no field named: %s", seg.Field()), at) + return nil, nil, newResolutionError(fmt.Sprintf("object has no field named: %s", seg.Field()), at) } } else { return nil, nil, err @@ -334,17 +315,17 @@ func resolve(sel Selector, subject ipld.Node, at []string) (ipld.Node, []ipld.No } else if seg.Optional() { cur = nil } else { - return nil, nil, NewResolutionError(fmt.Sprintf("can not access field: %s on kind: %s", seg.Field(), kindString(cur)), at) + return nil, nil, newResolutionError(fmt.Sprintf("can not access field: %s on kind: %s", seg.Field(), kindString(cur)), at) } } else if seg.Slice() != nil { if cur != nil && cur.Kind() == datamodel.Kind_List { - return nil, nil, NewResolutionError("list slice selection not yet implemented", at) + return nil, nil, newResolutionError("list slice selection not yet implemented", at) } else if cur != nil && cur.Kind() == datamodel.Kind_Bytes { - return nil, nil, NewResolutionError("bytes slice selection not yet implemented", at) + return nil, nil, newResolutionError("bytes slice selection not yet implemented", at) } else if seg.Optional() { cur = nil } else { - return nil, nil, NewResolutionError(fmt.Sprintf("can not index: %s on kind: %s", seg.Field(), kindString(cur)), at) + return nil, nil, newResolutionError(fmt.Sprintf("can not index: %s on kind: %s", seg.Field(), kindString(cur)), at) } } else { at = append(at, fmt.Sprintf("%d", seg.Index())) @@ -355,7 +336,7 @@ func resolve(sel Selector, subject ipld.Node, at []string) (ipld.Node, []ipld.No if seg.Optional() { cur = nil } else { - return nil, nil, NewResolutionError(fmt.Sprintf("index out of bounds: %d", seg.Index()), at) + return nil, nil, newResolutionError(fmt.Sprintf("index out of bounds: %d", seg.Index()), at) } } else { return nil, nil, err @@ -365,7 +346,7 @@ func resolve(sel Selector, subject ipld.Node, at []string) (ipld.Node, []ipld.No } else if seg.Optional() { cur = nil } else { - return nil, nil, NewResolutionError(fmt.Sprintf("can not access field: %s on kind: %s", seg.Field(), kindString(cur)), at) + return nil, nil, newResolutionError(fmt.Sprintf("can not access field: %s on kind: %s", seg.Field(), kindString(cur)), at) } } } @@ -393,13 +374,6 @@ func isMissing(err error) bool { return false } -type ResolutionError interface { - error - Name() string - Message() string - At() []string -} - type resolutionerr struct { msg string at []string @@ -421,6 +395,6 @@ func (r resolutionerr) Error() string { return r.Message() } -func NewResolutionError(message string, at []string) error { +func newResolutionError(message string, at []string) error { return resolutionerr{message, at} } diff --git a/capability/policy/selector/selector_test.go b/capability/policy/selector/selector_test.go index b19282f..1c43f0f 100644 --- a/capability/policy/selector/selector_test.go +++ b/capability/policy/selector/selector_test.go @@ -377,9 +377,7 @@ func TestSelect(t *testing.T) { fmt.Println(err) - if _, ok := err.(ResolutionError); !ok { - t.Fatalf("error was not a resolution error") - } + require.ErrorAs(t, err, &resolutionerr{}, "error was not a resolution error") }) t.Run("optional not exists", func(t *testing.T) {