github.com/gagliardetto/binary@v0.7.9/encoder.go (about)

     1  // Copyright 2021 github.com/gagliardetto
     2  // This file has been modified by github.com/gagliardetto
     3  //
     4  // Copyright 2020 dfuse Platform Inc.
     5  //
     6  // Licensed under the Apache License, Version 2.0 (the "License");
     7  // you may not use this file except in compliance with the License.
     8  // You may obtain a copy of the License at
     9  //
    10  //      http://www.apache.org/licenses/LICENSE-2.0
    11  //
    12  // Unless required by applicable law or agreed to in writing, software
    13  // distributed under the License is distributed on an "AS IS" BASIS,
    14  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15  // See the License for the specific language governing permissions and
    16  // limitations under the License.
    17  
    18  package bin
    19  
    20  import (
    21  	"encoding/binary"
    22  	"errors"
    23  	"fmt"
    24  	"io"
    25  	"math"
    26  	"reflect"
    27  
    28  	"go.uber.org/zap"
    29  )
    30  
    31  type Encoder struct {
    32  	count int
    33  
    34  	currentFieldOpt *option
    35  	encoding        Encoding
    36  
    37  	output io.Writer
    38  }
    39  
    40  func (enc *Encoder) IsBorsh() bool {
    41  	return enc.encoding.IsBorsh()
    42  }
    43  
    44  func (enc *Encoder) IsBin() bool {
    45  	return enc.encoding.IsBin()
    46  }
    47  
    48  func (enc *Encoder) IsCompactU16() bool {
    49  	return enc.encoding.IsCompactU16()
    50  }
    51  
    52  func NewEncoderWithEncoding(writer io.Writer, enc Encoding) *Encoder {
    53  	if !isValidEncoding(enc) {
    54  		panic(fmt.Sprintf("provided encoding is not valid: %s", enc))
    55  	}
    56  	return &Encoder{
    57  		output:   writer,
    58  		count:    0,
    59  		encoding: enc,
    60  	}
    61  }
    62  
    63  func NewBinEncoder(writer io.Writer) *Encoder {
    64  	return NewEncoderWithEncoding(writer, EncodingBin)
    65  }
    66  
    67  func NewBorshEncoder(writer io.Writer) *Encoder {
    68  	return NewEncoderWithEncoding(writer, EncodingBorsh)
    69  }
    70  
    71  func NewCompactU16Encoder(writer io.Writer) *Encoder {
    72  	return NewEncoderWithEncoding(writer, EncodingCompactU16)
    73  }
    74  
    75  func (e *Encoder) Encode(v interface{}) (err error) {
    76  	switch e.encoding {
    77  	case EncodingBin:
    78  		return e.encodeBin(reflect.ValueOf(v), nil)
    79  	case EncodingBorsh:
    80  		return e.encodeBorsh(reflect.ValueOf(v), nil)
    81  	case EncodingCompactU16:
    82  		return e.encodeCompactU16(reflect.ValueOf(v), nil)
    83  	default:
    84  		panic(fmt.Errorf("encoding not implemented: %s", e.encoding))
    85  	}
    86  }
    87  
    88  func (e *Encoder) toWriter(bytes []byte) (err error) {
    89  	e.count += len(bytes)
    90  	if traceEnabled {
    91  		zlog.Debug("	> encode: appending", zap.Stringer("hex", HexBytes(bytes)), zap.Int("pos", e.count))
    92  	}
    93  	_, err = e.output.Write(bytes)
    94  	return
    95  }
    96  
    97  // Written returns the count of bytes written.
    98  func (e *Encoder) Written() int {
    99  	return e.count
   100  }
   101  
   102  func (e *Encoder) WriteBytes(b []byte, writeLength bool) error {
   103  	if traceEnabled {
   104  		zlog.Debug("encode: write byte array", zap.Int("len", len(b)))
   105  	}
   106  	if writeLength {
   107  		if err := e.WriteLength(len(b)); err != nil {
   108  			return err
   109  		}
   110  	}
   111  	if len(b) == 0 {
   112  		return nil
   113  	}
   114  	return e.toWriter(b)
   115  }
   116  
   117  func (e *Encoder) Write(b []byte) (n int, err error) {
   118  	e.count += len(b)
   119  	if traceEnabled {
   120  		zlog.Debug("	> encode: appending", zap.Stringer("hex", HexBytes(b)), zap.Int("pos", e.count))
   121  	}
   122  	return e.output.Write(b)
   123  }
   124  
   125  func (e *Encoder) WriteLength(length int) error {
   126  	if traceEnabled {
   127  		zlog.Debug("encode: write length", zap.Int("len", length))
   128  	}
   129  	switch e.encoding {
   130  	case EncodingBin:
   131  		if err := e.WriteUVarInt(length); err != nil {
   132  			return err
   133  		}
   134  	case EncodingBorsh:
   135  		if err := e.WriteUint32(uint32(length), LE); err != nil {
   136  			return err
   137  		}
   138  	case EncodingCompactU16:
   139  		var buf []byte
   140  		EncodeCompactU16Length(&buf, length)
   141  		if err := e.WriteBytes(buf, false); err != nil {
   142  			return err
   143  		}
   144  	default:
   145  		panic(fmt.Errorf("encoding not implemented: %s", e.encoding))
   146  	}
   147  	return nil
   148  }
   149  
   150  func (e *Encoder) WriteUVarInt(v int) (err error) {
   151  	if traceEnabled {
   152  		zlog.Debug("encode: write uvarint", zap.Int("val", v))
   153  	}
   154  
   155  	buf := make([]byte, 8)
   156  	l := binary.PutUvarint(buf, uint64(v))
   157  	return e.toWriter(buf[:l])
   158  }
   159  
   160  func (e *Encoder) WriteVarInt(v int) (err error) {
   161  	if traceEnabled {
   162  		zlog.Debug("encode: write varint", zap.Int("val", v))
   163  	}
   164  
   165  	buf := make([]byte, 8)
   166  	l := binary.PutVarint(buf, int64(v))
   167  	return e.toWriter(buf[:l])
   168  }
   169  
   170  func (e *Encoder) WriteByte(b byte) (err error) {
   171  	if traceEnabled {
   172  		zlog.Debug("encode: write byte", zap.Uint8("val", b))
   173  	}
   174  	return e.toWriter([]byte{b})
   175  }
   176  
   177  func (e *Encoder) WriteOption(b bool) (err error) {
   178  	if traceEnabled {
   179  		zlog.Debug("encode: write option", zap.Bool("val", b))
   180  	}
   181  	return e.WriteBool(b)
   182  }
   183  
   184  func (e *Encoder) WriteCOption(b bool) (err error) {
   185  	if traceEnabled {
   186  		zlog.Debug("encode: write c-option", zap.Bool("val", b))
   187  	}
   188  	var num uint32
   189  	if b {
   190  		num = 1
   191  	}
   192  	return e.WriteUint32(num, LE)
   193  }
   194  
   195  func (e *Encoder) WriteBool(b bool) (err error) {
   196  	if traceEnabled {
   197  		zlog.Debug("encode: write bool", zap.Bool("val", b))
   198  	}
   199  	var out byte
   200  	if b {
   201  		out = 1
   202  	}
   203  	return e.WriteByte(out)
   204  }
   205  
   206  func (e *Encoder) WriteUint8(i uint8) (err error) {
   207  	return e.WriteByte(i)
   208  }
   209  
   210  func (e *Encoder) WriteInt8(i int8) (err error) {
   211  	return e.WriteByte(uint8(i))
   212  }
   213  
   214  func (e *Encoder) WriteUint16(i uint16, order binary.ByteOrder) (err error) {
   215  	if traceEnabled {
   216  		zlog.Debug("encode: write uint16", zap.Uint16("val", i))
   217  	}
   218  	buf := make([]byte, TypeSize.Uint16)
   219  	order.PutUint16(buf, i)
   220  	return e.toWriter(buf)
   221  }
   222  
   223  func (e *Encoder) WriteInt16(i int16, order binary.ByteOrder) (err error) {
   224  	if traceEnabled {
   225  		zlog.Debug("encode: write int16", zap.Int16("val", i))
   226  	}
   227  	return e.WriteUint16(uint16(i), order)
   228  }
   229  
   230  func (e *Encoder) WriteUint32(i uint32, order binary.ByteOrder) (err error) {
   231  	if traceEnabled {
   232  		zlog.Debug("encode: write uint32", zap.Uint32("val", i))
   233  	}
   234  	buf := make([]byte, TypeSize.Uint32)
   235  	order.PutUint32(buf, i)
   236  	return e.toWriter(buf)
   237  }
   238  
   239  func (e *Encoder) WriteInt32(i int32, order binary.ByteOrder) (err error) {
   240  	if traceEnabled {
   241  		zlog.Debug("encode: write int32", zap.Int32("val", i))
   242  	}
   243  	return e.WriteUint32(uint32(i), order)
   244  }
   245  
   246  func (e *Encoder) WriteUint64(i uint64, order binary.ByteOrder) (err error) {
   247  	if traceEnabled {
   248  		zlog.Debug("encode: write uint64", zap.Uint64("val", i))
   249  	}
   250  	buf := make([]byte, TypeSize.Uint64)
   251  	order.PutUint64(buf, i)
   252  	return e.toWriter(buf)
   253  }
   254  
   255  func (e *Encoder) WriteInt64(i int64, order binary.ByteOrder) (err error) {
   256  	if traceEnabled {
   257  		zlog.Debug("encode: write int64", zap.Int64("val", i))
   258  	}
   259  	return e.WriteUint64(uint64(i), order)
   260  }
   261  
   262  func (e *Encoder) WriteUint128(i Uint128, order binary.ByteOrder) (err error) {
   263  	if traceEnabled {
   264  		zlog.Debug("encode: write uint128", zap.Stringer("hex", i), zap.Uint64("lo", i.Lo), zap.Uint64("hi", i.Hi))
   265  	}
   266  	buf := make([]byte, TypeSize.Uint128)
   267  	switch order {
   268  	case binary.LittleEndian:
   269  		order.PutUint64(buf[:8], i.Lo)
   270  		order.PutUint64(buf[8:], i.Hi)
   271  	case binary.BigEndian:
   272  		order.PutUint64(buf[:8], i.Hi)
   273  		order.PutUint64(buf[8:], i.Lo)
   274  	default:
   275  		return fmt.Errorf("invalid byte order: %v", order)
   276  	}
   277  	return e.toWriter(buf)
   278  }
   279  
   280  func (e *Encoder) WriteInt128(i Int128, order binary.ByteOrder) (err error) {
   281  	if traceEnabled {
   282  		zlog.Debug("encode: write int128", zap.Stringer("hex", i), zap.Uint64("lo", i.Lo), zap.Uint64("hi", i.Hi))
   283  	}
   284  	buf := make([]byte, TypeSize.Uint128)
   285  	switch order {
   286  	case binary.LittleEndian:
   287  		order.PutUint64(buf[:8], i.Lo)
   288  		order.PutUint64(buf[8:], i.Hi)
   289  	case binary.BigEndian:
   290  		order.PutUint64(buf[:8], i.Hi)
   291  		order.PutUint64(buf[8:], i.Lo)
   292  	default:
   293  		return fmt.Errorf("invalid byte order: %v", order)
   294  	}
   295  	return e.toWriter(buf)
   296  }
   297  
   298  func (e *Encoder) WriteFloat32(f float32, order binary.ByteOrder) (err error) {
   299  	if traceEnabled {
   300  		zlog.Debug("encode: write float32", zap.Float32("val", f))
   301  	}
   302  
   303  	if e.IsBorsh() {
   304  		if math.IsNaN(float64(f)) {
   305  			return errors.New("NaN float value")
   306  		}
   307  	}
   308  
   309  	i := math.Float32bits(f)
   310  	buf := make([]byte, TypeSize.Uint32)
   311  	order.PutUint32(buf, i)
   312  
   313  	return e.toWriter(buf)
   314  }
   315  
   316  func (e *Encoder) WriteFloat64(f float64, order binary.ByteOrder) (err error) {
   317  	if traceEnabled {
   318  		zlog.Debug("encode: write float64", zap.Float64("val", f))
   319  	}
   320  
   321  	if e.IsBorsh() {
   322  		if math.IsNaN(float64(f)) {
   323  			return errors.New("NaN float value")
   324  		}
   325  	}
   326  	i := math.Float64bits(f)
   327  	buf := make([]byte, TypeSize.Uint64)
   328  	order.PutUint64(buf, i)
   329  
   330  	return e.toWriter(buf)
   331  }
   332  
   333  func (e *Encoder) WriteString(s string) (err error) {
   334  	if traceEnabled {
   335  		zlog.Debug("encode: write string", zap.String("val", s))
   336  	}
   337  	return e.WriteBytes([]byte(s), true)
   338  }
   339  
   340  func (e *Encoder) WriteRustString(s string) (err error) {
   341  	err = e.WriteUint64(uint64(len(s)), binary.LittleEndian)
   342  	if err != nil {
   343  		return err
   344  	}
   345  	if traceEnabled {
   346  		zlog.Debug("encode: write Rust string", zap.String("val", s))
   347  	}
   348  	return e.WriteBytes([]byte(s), false)
   349  }
   350  
   351  func (e *Encoder) WriteCompactU16(ln int) (err error) {
   352  	if traceEnabled {
   353  		zlog.Debug("encode: write compact-u16", zap.Int("val", ln))
   354  	}
   355  	buf := make([]byte, 0)
   356  	EncodeCompactU16Length(&buf, ln)
   357  	return e.toWriter(buf)
   358  }
   359  
   360  func (e *Encoder) WriteCompactU16Length(ln int) (err error) {
   361  	return e.WriteCompactU16(ln)
   362  }
   363  
   364  func reflect_writeArrayOfBytes(e *Encoder, l int, rv reflect.Value) error {
   365  	arr := make([]byte, l)
   366  	for i := 0; i < l; i++ {
   367  		arr[i] = byte(rv.Index(i).Uint())
   368  	}
   369  	return e.WriteBytes(arr, false)
   370  }
   371  
   372  func reflect_writeArrayOfUint16(e *Encoder, l int, rv reflect.Value, order binary.ByteOrder) error {
   373  	arr := make([]byte, l*2)
   374  	for i := 0; i < l; i++ {
   375  		order.PutUint16(arr[i*2:], uint16(rv.Index(i).Uint()))
   376  	}
   377  	return e.WriteBytes(arr, false)
   378  }
   379  
   380  func reflect_writeArrayOfUint32(e *Encoder, l int, rv reflect.Value, order binary.ByteOrder) error {
   381  	arr := make([]byte, l*4)
   382  	for i := 0; i < l; i++ {
   383  		order.PutUint32(arr[i*4:], uint32(rv.Index(i).Uint()))
   384  	}
   385  	return e.WriteBytes(arr, false)
   386  }
   387  
   388  func reflect_writeArrayOfUint64(e *Encoder, l int, rv reflect.Value, order binary.ByteOrder) error {
   389  	arr := make([]byte, l*8)
   390  	for i := 0; i < l; i++ {
   391  		order.PutUint64(arr[i*8:], uint64(rv.Index(i).Uint()))
   392  	}
   393  	return e.WriteBytes(arr, false)
   394  }
   395  
   396  // reflect_writeArrayOfUint_ is used for writing arrays/slices of uints of any size.
   397  func reflect_writeArrayOfUint_(e *Encoder, l int, k reflect.Kind, rv reflect.Value, order binary.ByteOrder) error {
   398  	switch k {
   399  	// case reflect.Uint:
   400  	// 	// switch on system architecture (32 or 64 bit)
   401  	// 	if unsafe.Sizeof(uintptr(0)) == 4 {
   402  	// 		return reflect_writeArrayOfUint32(e, l, rv, order)
   403  	// 	}
   404  	// 	return reflect_writeArrayOfUint64(e, l, rv, order)
   405  	case reflect.Uint8:
   406  		return reflect_writeArrayOfBytes(e, l, rv)
   407  	case reflect.Uint16:
   408  		return reflect_writeArrayOfUint16(e, l, rv, order)
   409  	case reflect.Uint32:
   410  		return reflect_writeArrayOfUint32(e, l, rv, order)
   411  	case reflect.Uint64:
   412  		return reflect_writeArrayOfUint64(e, l, rv, order)
   413  	default:
   414  		return fmt.Errorf("unsupported kind: %v", k)
   415  	}
   416  }