github.com/spi-ca/misc@v1.0.1/types/bytes16.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "crypto/subtle" 6 "database/sql/driver" 7 "encoding/hex" 8 "errors" 9 "fmt" 10 ) 11 12 // Bytes16 is an alias for [16]byte, 13 // Bytes16 implements Marshal and Unmarshal. 14 type Bytes16 [16]byte 15 16 // Marshal obj into your JSON variable. 17 func (b Bytes16) Marshal() ([]byte, error) { 18 return b[:], nil 19 } 20 21 func (b Bytes16) MarshalTo(buf []byte) (n int, err error) { 22 copy(buf, b[:]) 23 return len(b), nil 24 } 25 26 // Unmarshal your JSON variable into dest. 27 func (b *Bytes16) Unmarshal(buf []byte) error { 28 if len(buf) != 16 { 29 return fmt.Errorf("invalid bytes16 (got %d bytes)", len(buf)) 30 } 31 copy(b[:], buf) 32 return nil 33 } 34 35 func (b Bytes16) Compare(other Bytes16) int { 36 return bytes.Compare(b[:], other[:]) 37 } 38 39 func (b Bytes16) Equal(other Bytes16) bool { 40 return subtle.ConstantTimeCompare(b[:], other[:]) == 1 41 } 42 43 // ParseBytes is like Parse, except it parses a byte slice instead of a string. 44 func ParseBytes16(buf []byte) (b Bytes16, err error) { 45 if len(buf) != hex.EncodedLen(len(b)) { 46 err = fmt.Errorf("invalid bytes16 length: %d", len(buf)) 47 } 48 _, err = hex.Decode(b[:], buf) 49 return 50 } 51 52 func (b *Bytes16) UnmarshalJSON(from []byte) error { 53 quote := []byte("\"") 54 quoteSize := len(quote) 55 56 if len(from) < quoteSize*2 { 57 return errors.New("invalid quote notation") 58 } 59 60 if !bytes.HasPrefix(from, quote) || !bytes.HasSuffix(from, quote) { 61 return errors.New("invalid quote notation") 62 } else if parsed, err := ParseBytes16(from[quoteSize : len(from)-quoteSize]); err == nil { 63 *b = parsed 64 } 65 return nil 66 } 67 68 func (b Bytes16) MarshalJSON() ([]byte, error) { 69 var buffer bytes.Buffer 70 buffer.WriteRune('"') 71 buffer.WriteString(hex.EncodeToString(b[:])) 72 buffer.WriteRune('"') 73 return buffer.Bytes(), nil 74 } 75 76 func (b *Bytes16) Size() int { 77 if b == nil { 78 return 0 79 } 80 return 16 81 } 82 83 func (b *Bytes16) FromHexString(buf []byte) error { 84 hexBuf := make([]byte, hex.DecodedLen(len(buf))) 85 if n, err := hex.Decode(hexBuf, buf); err != nil { 86 return err 87 } else { 88 hexBuf = hexBuf[:n] 89 } 90 if err := b.Unmarshal(hexBuf); err != nil { 91 return err 92 } 93 return nil 94 } 95 96 func (b Bytes16) ToHexString() string { 97 return hex.EncodeToString(b[:]) 98 } 99 100 // Scan implements the Scanner interface. 101 func (b *Bytes16) Scan(src any) error { 102 switch src.(type) { 103 case string: 104 b.FromHexString([]byte(src.(string))) 105 default: 106 return errors.New("Incompatible type") 107 } 108 return nil 109 } 110 111 // Value implements the driver Valuer interface. 112 func (b Bytes16) Value() (driver.Value, error) { 113 return b.ToHexString(), nil 114 }