diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 6c73ed2..146c7c1 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -10,7 +10,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: "1.22.x" + go-version: "1.21.x" - name: Install dependencies run: go get . - name: Vet diff --git a/go.mod b/go.mod index e331b1d..6372916 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/restatedev/sdk-go -go 1.22.0 +go 1.21.0 require ( github.com/golang-jwt/jwt/v5 v5.2.1 diff --git a/internal/rand/rand.go b/internal/rand/rand.go index 946d548..215376b 100644 --- a/internal/rand/rand.go +++ b/internal/rand/rand.go @@ -3,17 +3,16 @@ package rand import ( "crypto/sha256" "encoding/binary" - "math/rand/v2" "github.com/google/uuid" ) type Rand struct { - *rand.Rand + source *Source } func New(invocationID []byte) *Rand { - return &Rand{rand.New(newSource(invocationID))} + return &Rand{newSource(invocationID)} } func (r *Rand) UUID() uuid.UUID { @@ -25,6 +24,23 @@ func (r *Rand) UUID() uuid.UUID { return uuid } +func (r *Rand) Float64() float64 { + // use the math/rand/v2 implementation of Float64() which is more correct + // and also matches our TS implementation + return float64(r.Uint64()<<11>>11) / (1 << 53) +} + +func (r *Rand) Uint64() uint64 { + return r.source.Uint64() +} + +// Source returns a deterministic random source that can be provided to math/rand.New() +// and math/rand/v2.New(). The v2 version of rand is strongly recommended where Go 1.22 +// is used, and once this library begins to depend on 1.22, it will be embedded in Rand. +func (r *Rand) Source() *Source { + return r.source +} + type Source struct { state [4]uint64 } @@ -43,6 +59,15 @@ func newSource(invocationID []byte) *Source { }} } +func (s *Source) Int63() int64 { + return int64(s.Uint64() & ((1 << 63) - 1)) +} + +// only the v1 rand package has this method +func (s *Source) Seed(int64) { + panic("The Restate random source is already deterministic based on invocation ID and must not be seeded") +} + func (s *Source) Uint64() uint64 { result := rotl((s.state[0]+s.state[3]), 23) + s.state[0] @@ -63,5 +88,3 @@ func (s *Source) Uint64() uint64 { func rotl(x uint64, k uint64) uint64 { return (x << k) | (x >> (64 - k)) } - -var _ rand.Source = (*Source)(nil) diff --git a/internal/rand/rand_test.go b/internal/rand/rand_test.go index 6a91faa..4257fbf 100644 --- a/internal/rand/rand_test.go +++ b/internal/rand/rand_test.go @@ -2,7 +2,6 @@ package rand import ( "encoding/hex" - "math/rand/v2" "testing" ) @@ -35,7 +34,7 @@ func TestUint64(t *testing.T) { func TestFloat64(t *testing.T) { source := &Source{state: [4]uint64{1, 2, 3, 4}} - rand := &Rand{rand.New(source)} + rand := &Rand{source} expected := []float64{ 4.656612984099695e-9, 6.519269457605503e-9, 0.39843750651926946, @@ -53,7 +52,7 @@ func TestFloat64(t *testing.T) { func TestUUID(t *testing.T) { source := &Source{state: [4]uint64{1, 2, 3, 4}} - rand := &Rand{rand.New(source)} + rand := &Rand{source} expected := []string{ "01008002-0000-4000-a700-800300000000", diff --git a/reflect.go b/reflect.go index 08a77eb..6469f0a 100644 --- a/reflect.go +++ b/reflect.go @@ -14,10 +14,10 @@ type serviceNamer interface { } var ( - typeOfContext = reflect.TypeFor[Context]() - typeOfObjectContext = reflect.TypeFor[ObjectContext]() - typeOfVoid = reflect.TypeFor[Void]() - typeOfError = reflect.TypeFor[error]() + typeOfContext = reflect.TypeOf((*Context)(nil)).Elem() + typeOfObjectContext = reflect.TypeOf((*ObjectContext)(nil)).Elem() + typeOfVoid = reflect.TypeOf((*Void)(nil)) + typeOfError = reflect.TypeOf((*error)(nil)) ) // Object converts a struct with methods into a Virtual Object where each correctly-typed