github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/longbits/fixed_size.go (about)

     1  // Copyright 2020 Insolar Network Ltd.
     2  // All rights reserved.
     3  // This material is licensed under the Insolar License version 1.0,
     4  // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md.
     5  
     6  package longbits
     7  
     8  import (
     9  	"bytes"
    10  	"errors"
    11  	"io"
    12  
    13  	"github.com/insolar/vanilla/throw"
    14  )
    15  
    16  type Foldable interface {
    17  	FoldToUint64() uint64
    18  }
    19  
    20  //go:generate minimock -i github.com/insolar/vanilla/longbits.FixedReader -o . -s _mock.go -g
    21  type FixedReader interface {
    22  	io.WriterTo
    23  	CopyTo(p []byte) int
    24  	AsByteString() ByteString
    25  
    26  	FixedByteSize() int
    27  }
    28  
    29  //go:generate minimock -i github.com/insolar/vanilla/longbits.FoldableReader -o . -s _mock.go -g
    30  type FoldableReader interface {
    31  	FixedReader
    32  	Foldable
    33  }
    34  
    35  func FoldUint64(v uint64) uint32 {
    36  	return uint32(v) ^ uint32(v>>32)
    37  }
    38  
    39  func Equal(t, o FixedReader) bool {
    40  	switch {
    41  	case t == nil || o == nil:
    42  		return false
    43  	case t.FixedByteSize() == 0:
    44  		return o.FixedByteSize() == 0
    45  	}
    46  	return (&writerToComparer{}).compare(t, o)
    47  }
    48  
    49  func EqualToBytes(t FixedReader, o []byte) bool {
    50  	switch {
    51  	case t == nil:
    52  		return false
    53  	case t.FixedByteSize() == 0:
    54  		return len(o) == 0
    55  	case len(o) == 0:
    56  		return false
    57  	}
    58  	return (&writerToComparer{}).compareBytes(o, t)
    59  }
    60  
    61  type writerToComparer struct {
    62  	thisValue *[]byte
    63  	other     io.WriterTo
    64  	result    bool
    65  }
    66  
    67  func (c *writerToComparer) compareBytes(this []byte, other FixedReader) bool {
    68  	if other == nil || len(this) != other.FixedByteSize() {
    69  		return false
    70  	}
    71  	c.thisValue = &this
    72  	c.other = other
    73  	_, _ = other.WriteTo(c)
    74  	return c.other == nil && c.result
    75  }
    76  
    77  func (c *writerToComparer) compare(this, other FixedReader) bool {
    78  	c.thisValue = nil
    79  	if this == nil || other == nil || this.FixedByteSize() != other.FixedByteSize() {
    80  		return false
    81  	}
    82  	c.other = other
    83  	_, _ = this.WriteTo(c)
    84  	return c.other == nil && c.result
    85  }
    86  
    87  func (c *writerToComparer) Write(otherValue []byte) (int, error) {
    88  	if c.other == nil {
    89  		panic("content of FixedReader must be read/written all at once")
    90  	}
    91  	if c.thisValue == nil {
    92  		c.thisValue = &otherValue
    93  		_, err := c.other.WriteTo(c)
    94  		if err != nil {
    95  			return 0, err
    96  		}
    97  	} else {
    98  		c.other = nil // mark "done"
    99  		c.result = bytes.Equal(*c.thisValue, otherValue)
   100  	}
   101  	return len(otherValue), nil
   102  }
   103  
   104  type fixedSize struct {
   105  	data []byte
   106  }
   107  
   108  func (c fixedSize) AsByteString() ByteString {
   109  	return ByteString(c.data)
   110  }
   111  
   112  func (c fixedSize) String() string {
   113  	return ByteString(c.data).String()
   114  }
   115  
   116  func (c fixedSize) WriteTo(w io.Writer) (n int64, err error) {
   117  	n32, err := w.Write(c.data)
   118  	return int64(n32), err
   119  }
   120  
   121  func (c fixedSize) CopyTo(p []byte) (n int) {
   122  	return copy(p, c.data)
   123  }
   124  
   125  func (c fixedSize) FoldToUint64() uint64 {
   126  	return FoldToUint64(c.data)
   127  }
   128  
   129  func (c fixedSize) CutOutUint64() uint64 {
   130  	return CutOutUint64(c.data)
   131  }
   132  
   133  func (c fixedSize) FixedByteSize() int {
   134  	return len(c.data)
   135  }
   136  
   137  func AsBytes(v FixedReader) []byte {
   138  	if v == nil {
   139  		return nil
   140  	}
   141  	n := v.FixedByteSize()
   142  	if n == 0 {
   143  		return nil
   144  	}
   145  	data := make([]byte, n)
   146  	if v.CopyTo(data) != len(data) {
   147  		panic(throw.Impossible())
   148  	}
   149  	return data
   150  }
   151  
   152  func WrapBytes(data []byte) FoldableReader {
   153  	return fixedSize{data}
   154  }
   155  
   156  func CopyFixed(v FixedReader) FoldableReader {
   157  	if v == nil {
   158  		return EmptyByteString
   159  	}
   160  	if bs, ok := v.(ByteString); ok {
   161  		return bs
   162  	}
   163  	switch n := v.FixedByteSize(); n*8 {
   164  	case 0:
   165  		return EmptyByteString
   166  	case 64:
   167  		dst := Bits64{}
   168  		v.CopyTo(dst[:])
   169  		return dst
   170  	case 128:
   171  		dst := Bits128{}
   172  		v.CopyTo(dst[:])
   173  		return dst
   174  	case 224:
   175  		dst := Bits224{}
   176  		v.CopyTo(dst[:])
   177  		return dst
   178  	case 256:
   179  		dst := Bits256{}
   180  		v.CopyTo(dst[:])
   181  		return dst
   182  	case 512:
   183  		dst := Bits512{}
   184  		v.CopyTo(dst[:])
   185  		return dst
   186  	default:
   187  		data := make([]byte, n)
   188  		if v.CopyTo(data) != n {
   189  			panic(throw.Impossible())
   190  		}
   191  		return WrapBytes(data)
   192  	}
   193  }
   194  
   195  func Copy(to []byte, from FixedReader) error {
   196  	if n := from.FixedByteSize(); n != len(to) {
   197  		if n < len(to) {
   198  			return io.ErrShortBuffer
   199  		}
   200  		return io.ErrShortWrite
   201  	}
   202  	from.CopyTo(to)
   203  	return nil
   204  }
   205  
   206  func VerifyReadAt(b []byte, off int64, max int) (n int, err error) {
   207  	switch {
   208  	case off < 0:
   209  		return 0, errors.New("negative offset")
   210  	case off > int64(max):
   211  		return 0, io.ErrUnexpectedEOF
   212  	case len(b) == 0:
   213  		return 0, nil
   214  	case max == int(off):
   215  		return 0, io.EOF
   216  	}
   217  	return len(b), nil
   218  }