Skip to content

Commit

Permalink
Refactor borsh optionality and tags
Browse files Browse the repository at this point in the history
  • Loading branch information
gagliardetto committed Oct 22, 2022
1 parent ccca2dd commit c3e479f
Show file tree
Hide file tree
Showing 12 changed files with 170 additions and 58 deletions.
32 changes: 31 additions & 1 deletion decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,10 @@ func (dec *Decoder) ReadTypeID() (out TypeID, err error) {
return TypeIDFromBytes(discriminator), nil
}

func (dec *Decoder) ReadDiscriminator() (out TypeID, err error) {
return dec.ReadTypeID()
}

func (dec *Decoder) Peek(n int) (out []byte, err error) {
if n < 0 {
err = fmt.Errorf("n not valid: %d", n)
Expand Down Expand Up @@ -373,6 +377,33 @@ func (dec *Decoder) ReadCompactU16() (out int, err error) {
return
}

func (dec *Decoder) ReadOption() (out bool, err error) {
b, err := dec.ReadByte()
if err != nil {
return false, fmt.Errorf("decode: read option, %w", err)
}
out = b != 0
if traceEnabled {
zlog.Debug("decode: read option", zap.Bool("val", out))
}
return
}

func (dec *Decoder) ReadCOption() (out bool, err error) {
b, err := dec.ReadUint32(LE)
if err != nil {
return false, fmt.Errorf("decode: read c-option, %w", err)
}
if b > 1 {
return false, fmt.Errorf("decode: read c-option, invalid value: %d", b)
}
out = b != 0
if traceEnabled {
zlog.Debug("decode: read c-option", zap.Bool("val", out))
}
return
}

func (dec *Decoder) ReadByte() (out byte, err error) {
if dec.Remaining() < TypeSize.Byte {
err = fmt.Errorf("required [1] byte, remaining [%d]", dec.Remaining())
Expand All @@ -394,7 +425,6 @@ func (dec *Decoder) ReadBool() (out bool, err error) {
}

b, err := dec.ReadByte()

if err != nil {
err = fmt.Errorf("readBool, %s", err)
}
Expand Down
8 changes: 4 additions & 4 deletions decoder_bin.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (dec *Decoder) decodeBin(rv reflect.Value, opt *option) (err error) {
}
dec.currentFieldOpt = opt

unmarshaler, rv := indirect(rv, opt.isOptional())
unmarshaler, rv := indirect(rv, opt.is_Optional())

if traceEnabled {
zlog.Debug("decode: type",
Expand All @@ -57,7 +57,7 @@ func (dec *Decoder) decodeBin(rv reflect.Value, opt *option) (err error) {
)
}

if opt.isOptional() {
if opt.is_Optional() {
isPresent, e := dec.ReadUint32(binary.LittleEndian)
if e != nil {
err = fmt.Errorf("decode: %s isPresent, %s", rv.Type().String(), e)
Expand Down Expand Up @@ -316,8 +316,8 @@ func (dec *Decoder) decodeStructBin(rt reflect.Type, rv reflect.Value) (err erro
}

option := &option{
OptionalField: fieldTag.Optional,
Order: fieldTag.Order,
is_OptionalField: fieldTag.Option,
Order: fieldTag.Order,
}

if s, ok := sizeOfMap[structField.Name]; ok {
Expand Down
34 changes: 27 additions & 7 deletions decoder_borsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (dec *Decoder) decodeBorsh(rv reflect.Value, opt *option) (err error) {
}
dec.currentFieldOpt = opt

unmarshaler, rv := indirect(rv, opt.isOptional())
unmarshaler, rv := indirect(rv, opt.is_Optional() || opt.is_COptional())

if traceEnabled {
zlog.Debug("decode: type",
Expand All @@ -57,14 +57,33 @@ func (dec *Decoder) decodeBorsh(rv reflect.Value, opt *option) (err error) {
)
}

if opt.isOptional() {
isPresent, e := dec.ReadByte()
if opt.is_Optional() {
isPresent, e := dec.ReadOption()
if e != nil {
err = fmt.Errorf("decode: %t isPresent, %s", rv.Type(), e)
return
}

if isPresent == 0 {
if !isPresent {
if traceEnabled {
zlog.Debug("decode: skipping optional value", zap.Stringer("type", rv.Kind()))
}

rv.Set(reflect.Zero(rv.Type()))
return
}

// we have ptr here we should not go get the element
unmarshaler, rv = indirect(rv, false)
}
if opt.is_COptional() {
isPresent, e := dec.ReadCOption()
if e != nil {
err = fmt.Errorf("decode: %t isPresent, %s", rv.Type(), e)
return
}

if !isPresent {
if traceEnabled {
zlog.Debug("decode: skipping optional value", zap.Stringer("type", rv.Kind()))
}
Expand All @@ -77,7 +96,7 @@ func (dec *Decoder) decodeBorsh(rv reflect.Value, opt *option) (err error) {
unmarshaler, rv = indirect(rv, false)
}
// Reset optionality so it won't propagate to child types:
opt = opt.clone().setIsOptional(false)
opt = opt.clone().set_Optional(false).set_COptional(false)

if unmarshaler != nil {
if traceEnabled {
Expand Down Expand Up @@ -371,8 +390,9 @@ func (dec *Decoder) decodeStructBorsh(rt reflect.Type, rv reflect.Value) (err er
}

option := &option{
OptionalField: fieldTag.Optional,
Order: fieldTag.Order,
is_OptionalField: fieldTag.Option,
is_COptionalField: fieldTag.COption,
Order: fieldTag.Order,
}

if s, ok := sizeOfMap[structField.Name]; ok {
Expand Down
8 changes: 4 additions & 4 deletions decoder_compact-u16.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (dec *Decoder) decodeCompactU16(rv reflect.Value, opt *option) (err error)
}
dec.currentFieldOpt = opt

unmarshaler, rv := indirect(rv, opt.isOptional())
unmarshaler, rv := indirect(rv, opt.is_Optional())

if traceEnabled {
zlog.Debug("decode: type",
Expand All @@ -56,7 +56,7 @@ func (dec *Decoder) decodeCompactU16(rv reflect.Value, opt *option) (err error)
)
}

if opt.isOptional() {
if opt.is_Optional() {
isPresent, e := dec.ReadByte()
if e != nil {
err = fmt.Errorf("decode: %t isPresent, %s", rv.Type(), e)
Expand Down Expand Up @@ -315,8 +315,8 @@ func (dec *Decoder) decodeStructCompactU16(rt reflect.Type, rv reflect.Value) (e
}

option := &option{
OptionalField: fieldTag.Optional,
Order: fieldTag.Order,
is_OptionalField: fieldTag.Option,
Order: fieldTag.Order,
}

if s, ok := sizeOfMap[structField.Name]; ok {
Expand Down
18 changes: 18 additions & 0 deletions encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,24 @@ func (e *Encoder) WriteByte(b byte) (err error) {
return e.toWriter([]byte{b})
}

func (e *Encoder) WriteOption(b bool) (err error) {
if traceEnabled {
zlog.Debug("encode: write option", zap.Bool("val", b))
}
return e.WriteBool(b)
}

func (e *Encoder) WriteCOption(b bool) (err error) {
if traceEnabled {
zlog.Debug("encode: write c-option", zap.Bool("val", b))
}
var num uint32
if b {
num = 1
}
return e.WriteUint32(num, LE)
}

func (e *Encoder) WriteBool(b bool) (err error) {
if traceEnabled {
zlog.Debug("encode: write bool", zap.Bool("val", b))
Expand Down
8 changes: 4 additions & 4 deletions encoder_bin.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (e *Encoder) encodeBin(rv reflect.Value, opt *option) (err error) {
)
}

if opt.isOptional() {
if opt.is_Optional() {
if rv.IsZero() {
if traceEnabled {
zlog.Debug("encode: skipping optional value with", zap.Stringer("type", rv.Kind()))
Expand All @@ -50,7 +50,7 @@ func (e *Encoder) encodeBin(rv reflect.Value, opt *option) (err error) {
return err
}
// The optionality has been used; stop its propagation:
opt.setIsOptional(false)
opt.set_Optional(false)
}

if isZero(rv) {
Expand Down Expand Up @@ -237,8 +237,8 @@ func (e *Encoder) encodeStructBin(rt reflect.Type, rv reflect.Value) (err error)
}

option := &option{
OptionalField: fieldTag.Optional,
Order: fieldTag.Order,
is_OptionalField: fieldTag.Option,
Order: fieldTag.Order,
}

if s, ok := sizeOfMap[structField.Name]; ok {
Expand Down
29 changes: 22 additions & 7 deletions encoder_borsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,36 @@ func (e *Encoder) encodeBorsh(rv reflect.Value, opt *option) (err error) {
)
}

if opt.isOptional() {
if opt.is_Optional() {
if rv.IsZero() {
if traceEnabled {
zlog.Debug("encode: skipping optional value with", zap.Stringer("type", rv.Kind()))
}
return e.WriteBool(false)
return e.WriteOption(false)
}
err := e.WriteBool(true)
err := e.WriteOption(true)
if err != nil {
return err
}
// The optionality has been used; stop its propagation:
opt.setIsOptional(false)
opt.set_Optional(false)
}
if opt.is_COptional() {
if rv.IsZero() {
if traceEnabled {
zlog.Debug("encode: skipping optional value with", zap.Stringer("type", rv.Kind()))
}
return e.WriteCOption(false)
}
err := e.WriteCOption(true)
if err != nil {
return err
}
// The optionality has been used; stop its propagation:
opt.set_COptional(false)
}
// Reset optionality so it won't propagate to child types:
opt = opt.clone().setIsOptional(false)
opt = opt.clone().set_Optional(false).set_COptional(false)

if isZero(rv) {
return nil
Expand Down Expand Up @@ -327,8 +341,9 @@ func (e *Encoder) encodeStructBorsh(rt reflect.Type, rv reflect.Value) (err erro
}

option := &option{
OptionalField: fieldTag.Optional,
Order: fieldTag.Order,
is_OptionalField: fieldTag.Option,
is_COptionalField: fieldTag.COption,
Order: fieldTag.Order,
}

if s, ok := sizeOfMap[structField.Name]; ok {
Expand Down
8 changes: 4 additions & 4 deletions encoder_compact-u16.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func (e *Encoder) encodeCompactU16(rv reflect.Value, opt *option) (err error) {
)
}

if opt.isOptional() {
if opt.is_Optional() {
if rv.IsZero() {
if traceEnabled {
zlog.Debug("encode: skipping optional value with", zap.Stringer("type", rv.Kind()))
Expand All @@ -49,7 +49,7 @@ func (e *Encoder) encodeCompactU16(rv reflect.Value, opt *option) (err error) {
return err
}
// The optionality has been used; stop its propagation:
opt.setIsOptional(false)
opt.set_Optional(false)
}

if isZero(rv) {
Expand Down Expand Up @@ -235,8 +235,8 @@ func (e *Encoder) encodeStructCompactU16(rt reflect.Type, rv reflect.Value) (err
}

option := &option{
OptionalField: fieldTag.Optional,
Order: fieldTag.Order,
is_OptionalField: fieldTag.Option,
Order: fieldTag.Order,
}

if s, ok := sizeOfMap[structField.Name]; ok {
Expand Down
11 changes: 5 additions & 6 deletions parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,17 @@ func Test_parseFieldTag(t *testing.T) {
name: "with a optional",
tag: `bin:"optional"`,
expectValue: &fieldTag{
Order: binary.LittleEndian,
Optional: true,
Order: binary.LittleEndian,
Option: true,
},
},
{
name: "with a optional and size of",
tag: `bin:"optional sizeof=Nodes"`,
expectValue: &fieldTag{
Order: binary.LittleEndian,
Optional: true,
SizeOf: "Nodes",
Order: binary.LittleEndian,
Option: true,
SizeOf: "Nodes",
},
},
}
Expand All @@ -75,5 +75,4 @@ func Test_parseFieldTag(t *testing.T) {
assert.Equal(t, test.expectValue, parseFieldTag(reflect.StructTag(test.tag)))
})
}

}
Loading

0 comments on commit c3e479f

Please sign in to comment.