Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use iter.Seq, added in Go 1.23 #49

Merged
merged 1 commit into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: 1.22.x
go-version: 1.23.x
- name: Checkout code
uses: actions/checkout@v4
- name: Test
Expand All @@ -23,7 +23,7 @@ jobs:
test-all:
strategy:
matrix:
go-version: [1.22.x]
go-version: [1.23.x]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
// This package will regularly experience breaking changes.
module github.com/go-json-experiment/json

go 1.22
go 1.23
23 changes: 0 additions & 23 deletions jsontext/pointer.go

This file was deleted.

42 changes: 0 additions & 42 deletions jsontext/pointer_test.go

This file was deleted.

42 changes: 30 additions & 12 deletions jsontext/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package jsontext

import (
"iter"
"math"
"strconv"
"strings"
Expand Down Expand Up @@ -51,20 +52,37 @@ func (s *state) reset() {

// Pointer is a JSON Pointer (RFC 6901) that references a particular JSON value
// relative to the root of the top-level JSON value.
//
// There is exactly one representation of a pointer to a particular value,
// so comparability of Pointer values is equivalent to checking whether
// they both point to the exact same value.
type Pointer string

// nextToken returns the next token in the pointer, reducing the length of p.
func (p *Pointer) nextToken() (token string) {
*p = Pointer(strings.TrimPrefix(string(*p), "/"))
i := min(uint(strings.IndexByte(string(*p), '/')), uint(len(*p)))
token = string(*p)[:i]
*p = (*p)[i:]
if strings.Contains(token, "~") {
// Per RFC 6901, section 3, unescape '~' and '/' characters.
token = strings.ReplaceAll(token, "~1", "/")
token = strings.ReplaceAll(token, "~0", "~")
}
return token
// Tokens returns an iterator over the reference tokens in the JSON pointer,
// starting from the first token until the last token (unless stopped early).
//
// A token is either a JSON object name or an index to a JSON array element
// encoded as a base-10 integer value.
// It is impossible to distinguish between an array index and an object name
// (that happens to be an base-10 encoded integer) without also knowing
// the structure of the top-level JSON value that the pointer refers to.
func (p Pointer) Tokens() iter.Seq[string] {
return func(yield func(string) bool) {
for len(p) > 0 {
p = Pointer(strings.TrimPrefix(string(p), "/"))
i := min(uint(strings.IndexByte(string(p), '/')), uint(len(p)))
token := string(p)[:i]
p = p[i:]
if strings.Contains(token, "~") {
// Per RFC 6901, section 3, unescape '~' and '/' characters.
token = strings.ReplaceAll(token, "~1", "/")
token = strings.ReplaceAll(token, "~0", "~")
}
if !yield(token) {
return
}
}
}
}

// appendStackPointer appends a JSON Pointer (RFC 6901) to the current value.
Expand Down
22 changes: 22 additions & 0 deletions jsontext/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,32 @@ package jsontext
import (
"fmt"
"reflect"
"slices"
"strings"
"testing"
)

func TestPointerTokens(t *testing.T) {
tests := []struct {
in Pointer
want []string
}{
{in: "", want: nil},
{in: "a", want: []string{"a"}},
{in: "~", want: []string{"~"}},
{in: "/a", want: []string{"a"}},
{in: "/foo/bar", want: []string{"foo", "bar"}},
{in: "///", want: []string{"", "", ""}},
{in: "/~0~1", want: []string{"~/"}},
}
for _, tt := range tests {
got := slices.Collect(tt.in.Tokens())
if !slices.Equal(got, tt.want) {
t.Errorf("Pointer(%q).Tokens = %q, want %q", tt.in, got, tt.want)
}
}
}

func TestStateMachine(t *testing.T) {
// To test a state machine, we pass an ordered sequence of operations and
// check whether the current state is as expected.
Expand Down
Loading