github.com/protolambda/zssz@v0.1.5/types/ssz_vector.go (about)

     1  package types
     2  
     3  import (
     4  	"fmt"
     5  	. "github.com/protolambda/zssz/dec"
     6  	. "github.com/protolambda/zssz/enc"
     7  	. "github.com/protolambda/zssz/htr"
     8  	"github.com/protolambda/zssz/merkle"
     9  	. "github.com/protolambda/zssz/pretty"
    10  	"reflect"
    11  	"unsafe"
    12  )
    13  
    14  type SSZVector struct {
    15  	length      uint64
    16  	elemMemSize uintptr
    17  	elemSSZ     SSZ
    18  	isFixedLen  bool
    19  	fixedLen    uint64
    20  	minLen      uint64
    21  	maxLen      uint64
    22  	fuzzMinLen  uint64
    23  	fuzzMaxLen  uint64
    24  }
    25  
    26  func NewSSZVector(factory SSZFactoryFn, typ reflect.Type) (*SSZVector, error) {
    27  	if typ.Kind() != reflect.Array {
    28  		return nil, fmt.Errorf("typ is not a fixed-length array")
    29  	}
    30  	length := uint64(typ.Len())
    31  	elemTyp := typ.Elem()
    32  
    33  	elemSSZ, err := factory(elemTyp)
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	var fixedElemLen, minElemLen, maxElemLen uint64
    38  	if elemSSZ.IsFixed() {
    39  		fixedElemLen = elemSSZ.FixedLen()
    40  		minElemLen = elemSSZ.MinLen()
    41  		maxElemLen = elemSSZ.MaxLen()
    42  		if fixedElemLen != minElemLen || fixedElemLen != maxElemLen {
    43  			return nil, fmt.Errorf("fixed-size element vector has invalid element min/max length:"+
    44  				" fixed: %d min: %d max: %d ", fixedElemLen, minElemLen, maxElemLen)
    45  		}
    46  	} else {
    47  		fixedElemLen = BYTES_PER_LENGTH_OFFSET
    48  		minElemLen = BYTES_PER_LENGTH_OFFSET + elemSSZ.MinLen()
    49  		maxElemLen = BYTES_PER_LENGTH_OFFSET + elemSSZ.MaxLen()
    50  	}
    51  	res := &SSZVector{
    52  		length:      length,
    53  		elemMemSize: elemTyp.Size(),
    54  		elemSSZ:     elemSSZ,
    55  		isFixedLen:  elemSSZ.IsFixed(),
    56  		fixedLen:    fixedElemLen * length,
    57  		minLen:      minElemLen * length,
    58  		maxLen:      maxElemLen * length,
    59  		fuzzMinLen:  elemSSZ.FuzzMinLen() * length,
    60  		fuzzMaxLen:  elemSSZ.FuzzMaxLen() * length,
    61  	}
    62  	return res, nil
    63  }
    64  
    65  func (v *SSZVector) FuzzMinLen() uint64 {
    66  	return v.fuzzMinLen
    67  }
    68  
    69  func (v *SSZVector) FuzzMaxLen() uint64 {
    70  	return v.fuzzMaxLen
    71  }
    72  
    73  func (v *SSZVector) MinLen() uint64 {
    74  	return v.minLen
    75  }
    76  
    77  func (v *SSZVector) MaxLen() uint64 {
    78  	return v.maxLen
    79  }
    80  
    81  func (v *SSZVector) FixedLen() uint64 {
    82  	return v.fixedLen
    83  }
    84  
    85  func (v *SSZVector) IsFixed() bool {
    86  	return v.isFixedLen
    87  }
    88  
    89  func (v *SSZVector) SizeOf(p unsafe.Pointer) uint64 {
    90  	if v.IsFixed() {
    91  		return v.fixedLen
    92  	} else {
    93  		out := v.fixedLen
    94  		memOffset := uintptr(0)
    95  		for i := uint64(0); i < v.length; i++ {
    96  			elemPtr := unsafe.Pointer(uintptr(p) + memOffset)
    97  			memOffset += v.elemMemSize
    98  			out += v.elemSSZ.SizeOf(elemPtr)
    99  		}
   100  		return out
   101  	}
   102  }
   103  
   104  func (v *SSZVector) Encode(eb *EncodingWriter, p unsafe.Pointer) error {
   105  	if v.IsFixed() {
   106  		return EncodeFixedSeries(v.elemSSZ.Encode, v.length, v.elemMemSize, eb, p)
   107  	} else {
   108  		return EncodeVarSeries(v.elemSSZ.Encode, v.elemSSZ.SizeOf, v.length, v.elemMemSize, eb, p)
   109  	}
   110  }
   111  
   112  func (v *SSZVector) Decode(dr *DecodingReader, p unsafe.Pointer) error {
   113  	if v.IsFixed() {
   114  		return DecodeFixedSeries(v.elemSSZ.Decode, v.length, v.elemMemSize, dr, p)
   115  	} else {
   116  		if dr.IsFuzzMode() {
   117  			return DecodeVarSeriesFuzzMode(v.elemSSZ, v.length, v.elemMemSize, dr, p)
   118  		} else {
   119  			return DecodeVarSeries(v.elemSSZ.Decode, v.length, v.elemMemSize, dr, p)
   120  		}
   121  	}
   122  }
   123  
   124  func (v *SSZVector) DryCheck(dr *DecodingReader) error {
   125  	if v.IsFixed() {
   126  		return DryCheckFixedSeries(v.elemSSZ.DryCheck, v.length, dr)
   127  	} else {
   128  		return DryCheckVarSeries(v.elemSSZ.DryCheck, v.length, dr)
   129  	}
   130  }
   131  
   132  func (v *SSZVector) HashTreeRoot(h MerkleFn, p unsafe.Pointer) [32]byte {
   133  	elemHtr := v.elemSSZ.HashTreeRoot
   134  	elemSize := v.elemMemSize
   135  	leaf := func(i uint64) []byte {
   136  		v := elemHtr(h, unsafe.Pointer(uintptr(p)+(elemSize*uintptr(i))))
   137  		return v[:]
   138  	}
   139  	return merkle.Merkleize(h, v.length, v.length, leaf)
   140  }
   141  
   142  func (v *SSZVector) Pretty(indent uint32, w *PrettyWriter, p unsafe.Pointer) {
   143  	w.WriteIndent(indent)
   144  	w.Write("[\n")
   145  	CallSeries(func(i uint64, p unsafe.Pointer) {
   146  		v.elemSSZ.Pretty(indent+1, w, p)
   147  		if i == v.length-1 {
   148  			w.Write("\n")
   149  		} else {
   150  			w.Write(",\n")
   151  		}
   152  	}, v.length, v.elemMemSize, p)
   153  	w.WriteIndent(indent)
   154  	w.Write("]")
   155  }