Skip to content
Draft
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
18 changes: 16 additions & 2 deletions decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,15 @@ func WithDecodeMaxNested(nested uint) decoderOpts {
// WithDecodeMaxElements sets the maximum number of elements allowed in a collection.
// The default value is 1 << 20.
func WithDecodeMaxElements(elements uint32) decoderOpts {
return func(e *Decoder) {
e.maxElements = elements
return func(d *Decoder) {
d.maxElements = elements
}
}

// WithDecodeLocal instructs the decoder to skip decoding of fields with the `nonlocal` tag.
func WithDecodeLocal() decoderOpts {
return func(d *Decoder) {
d.local = true
}
}

Expand All @@ -67,6 +74,7 @@ type Decoder struct {
scratch [9]byte
maxNested uint
maxElements uint32
local bool
}

func (d *Decoder) enterNested() error {
Expand All @@ -85,6 +93,12 @@ func (d *Decoder) read(buf []byte) (int, error) {
return io.ReadFull(d.r, buf)
}

// Local returns true if the decoder is using local mode, that is, skipping fields with
// the `nonlocal` tag.
func (d *Decoder) Local() bool {
return d.local
}

func DecodeByte(d *Decoder) (byte, int, error) {
n, err := d.read(d.scratch[:1])
if err != nil {
Expand Down
14 changes: 14 additions & 0 deletions encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ func WithEncodeMaxElements(elements uint32) encoderOpts {
}
}

// WithEncodeLocal instructs the encoder to skip encoding of fields with the `nonlocal` tag.
func WithEncodeLocal() encoderOpts {
return func(e *Encoder) {
e.local = true
}
}

// NewEncoder returns a new encoder that writes to w.
// If w implements io.StringWriter, the returned encoder will be more efficient in encoding strings.
func NewEncoder(w io.Writer, opts ...encoderOpts) *Encoder {
Expand All @@ -71,6 +78,7 @@ type Encoder struct {
scratch [9]byte
maxNested uint
maxElements uint32
local bool
}

func (e *Encoder) enterNested() error {
Expand All @@ -85,6 +93,12 @@ func (e *Encoder) leaveNested() {
e.maxNested++
}

// Local returns true if the encoder is using local mode, that is, skipping fields with
// the `nonlocal` tag.
func (e *Encoder) Local() bool {
return e.local
}

func EncodeByteSlice(e *Encoder, value []byte) (int, error) {
return EncodeByteSliceWithLimit(e, value, e.maxElements)
}
Expand Down
8 changes: 8 additions & 0 deletions examples/nonlocal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package examples

//go:generate scalegen

type StructWithNonLocalField struct {
Name string `scale:"max=20"`
SomeID string `scale:"nonlocal,max=20"`
}
46 changes: 46 additions & 0 deletions examples/nonlocal_scale.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 43 additions & 0 deletions examples/nonlocal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package examples

import (
"bytes"
"testing"

"github.com/stretchr/testify/require"

"github.com/spacemeshos/go-scale"
)

func TestNonLocal(t *testing.T) {
s := StructWithNonLocalField{
Name: "foo",
SomeID: "bar",
}

buf := bytes.NewBuffer(nil)
encoder := scale.NewEncoder(buf)
n, err := s.EncodeScale(encoder)
require.NoError(t, err)
require.Equal(t, 8, n)

decoder := scale.NewDecoder(bytes.NewReader(buf.Bytes()))
var s1 StructWithNonLocalField
n, err = s1.DecodeScale(decoder)
require.NoError(t, err)
require.Equal(t, 8, n)
require.Equal(t, s, s1)

buf = bytes.NewBuffer(nil)
encoder = scale.NewEncoder(buf, scale.WithEncodeLocal())
n, err = s.EncodeScale(encoder)
require.NoError(t, err)
require.Equal(t, 4, n)

decoder = scale.NewDecoder(bytes.NewReader(buf.Bytes()), scale.WithDecodeLocal())
var s2 StructWithNonLocalField
n, err = s2.DecodeScale(decoder)
require.NoError(t, err)
require.Equal(t, 4, n)
require.Equal(t, StructWithNonLocalField{Name: "foo"}, s2)
}
32 changes: 29 additions & 3 deletions generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ type temp struct {
decode string
}

type action int

const (
encode = iota
encode action = iota
decode
)

Expand Down Expand Up @@ -119,7 +121,7 @@ var (
}
)

func getAction(tm temp, action int) string {
func getAction(tm temp, action action) string {
switch action {
case encode:
return tm.encode
Expand Down Expand Up @@ -266,6 +268,7 @@ type scaleType struct {
Args string
EncodeModifier string
DecodeModifier string
NonLocal bool
}

func getDecodeModifier(parentType reflect.Type, field reflect.StructField) string {
Expand All @@ -277,6 +280,18 @@ func getDecodeModifier(parentType reflect.Type, field reflect.StructField) strin
}

func getScaleType(parentType reflect.Type, field reflect.StructField) (scaleType, error) {
st, err := getScaleTypeInner(parentType, field)
if err != nil {
return scaleType{}, err
}
st.NonLocal, err = nonLocal(field.Tag)
if err != nil {
return scaleType{}, fmt.Errorf("getting tags: %w", err)
}
return st, nil
}

func getScaleTypeInner(parentType reflect.Type, field reflect.StructField) (scaleType, error) {
decodeModifier := getDecodeModifier(parentType, field)
encodableType := reflect.TypeOf((*Encodable)(nil)).Elem()

Expand Down Expand Up @@ -374,7 +389,7 @@ func getTemplate(stype scaleType) temp {
}
}

func executeAction(action int, w io.Writer, tc *typeContext) error {
func executeAction(action action, w io.Writer, tc *typeContext) error {
typ := tc.Type

tpl, err := template.New("").Parse(getAction(start, action))
Expand All @@ -396,6 +411,17 @@ func executeAction(action int, w io.Writer, tc *typeContext) error {
return fmt.Errorf("getting scale type for %s: %w", typ, err)
}

if scaleType.NonLocal {
switch action {
case encode:
w.Write([]byte("if !enc.Local() "))
case decode:
w.Write([]byte("if !dec.Local() "))
default:
panic("BUG: bad action")
}
}

tctx := &typeContext{
Name: field.Name,
Type: field.Type,
Expand Down
Loading