github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/ident/ident.go (about)

     1  package ident
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"encoding/binary"
     6  	"encoding/hex"
     7  	"hash"
     8  	"sort"
     9  )
    10  
    11  type Identifiable interface {
    12  	Identity() []byte
    13  }
    14  
    15  type AddressProvider interface {
    16  	ContentAddress(entity Identifiable) string
    17  }
    18  
    19  type HexAddressProvider struct{}
    20  
    21  func NewHexAddressProvider() *HexAddressProvider {
    22  	return &HexAddressProvider{}
    23  }
    24  
    25  func (*HexAddressProvider) ContentAddress(entity Identifiable) string {
    26  	return hex.EncodeToString(entity.Identity())
    27  }
    28  
    29  type AddressType uint8
    30  
    31  const (
    32  	AddressTypeBytes AddressType = iota
    33  	AddressTypeString
    34  	AddressTypeInt64
    35  	AddressTypeStringSlice
    36  	AddressTypeStringMap
    37  	AddressTypeEmbeddedIdentifiable
    38  )
    39  
    40  // linter is angry because h can be an io.Writer, but we explicitly want a Hash here.
    41  //
    42  //nolint:interfacer
    43  func marshalType(h hash.Hash, addressType AddressType) {
    44  	_, _ = h.Write([]byte{byte(addressType)})
    45  }
    46  
    47  func MarshalBytes(h hash.Hash, v []byte) {
    48  	marshalType(h, AddressTypeBytes)
    49  	MarshalInt64(h, int64(len(v)))
    50  	_, _ = h.Write(v)
    51  }
    52  
    53  func MarshalString(h hash.Hash, v string) {
    54  	marshalType(h, AddressTypeString)
    55  	MarshalInt64(h, int64(len(v)))
    56  	_, _ = h.Write([]byte(v))
    57  }
    58  
    59  func MarshalInt64(h hash.Hash, v int64) {
    60  	const int64Bytes = 8
    61  	marshalType(h, AddressTypeInt64)
    62  	_, _ = h.Write([]byte{int64Bytes})
    63  	bytes := make([]byte, int64Bytes)
    64  	binary.BigEndian.PutUint64(bytes, uint64(v))
    65  	_, _ = h.Write(bytes)
    66  }
    67  
    68  func MarshalStringSlice(h hash.Hash, v []string) {
    69  	marshalType(h, AddressTypeStringSlice)
    70  	MarshalInt64(h, int64(len(v)))
    71  	for _, item := range v {
    72  		MarshalString(h, item)
    73  	}
    74  }
    75  
    76  func MarshalStringMap(h hash.Hash, v map[string]string) {
    77  	marshalType(h, AddressTypeStringMap)
    78  	MarshalInt64(h, int64(len(v)))
    79  	keys := make([]string, len(v))
    80  	i := 0
    81  	for k := range v {
    82  		keys[i] = k
    83  		i++
    84  	}
    85  	sort.Strings(keys)
    86  	for _, k := range keys {
    87  		MarshalString(h, k)
    88  		MarshalString(h, v[k])
    89  	}
    90  }
    91  
    92  func MarshalIdentifiable(h hash.Hash, v Identifiable) {
    93  	marshalType(h, AddressTypeEmbeddedIdentifiable)
    94  	MarshalBytes(h, v.Identity())
    95  }
    96  
    97  type AddressWriter struct {
    98  	hash.Hash
    99  }
   100  
   101  func NewAddressWriter() *AddressWriter {
   102  	return &AddressWriter{Hash: sha256.New()}
   103  }
   104  
   105  func (b *AddressWriter) MarshalBytes(v []byte) *AddressWriter {
   106  	MarshalBytes(b, v)
   107  	return b
   108  }
   109  
   110  func (b *AddressWriter) MarshalString(v string) *AddressWriter {
   111  	MarshalString(b, v)
   112  	return b
   113  }
   114  
   115  func (b *AddressWriter) MarshalStringOpt(v string) *AddressWriter {
   116  	if len(v) > 0 {
   117  		MarshalString(b, v)
   118  	}
   119  	return b
   120  }
   121  
   122  func (b *AddressWriter) MarshalInt64(v int64) *AddressWriter {
   123  	MarshalInt64(b, v)
   124  	return b
   125  }
   126  
   127  func (b *AddressWriter) MarshalStringSlice(v []string) *AddressWriter {
   128  	MarshalStringSlice(b, v)
   129  	return b
   130  }
   131  
   132  func (b *AddressWriter) MarshalStringMap(v map[string]string) *AddressWriter {
   133  	MarshalStringMap(b, v)
   134  	return b
   135  }
   136  
   137  func (b *AddressWriter) MarshalIdentifiable(v Identifiable) *AddressWriter {
   138  	MarshalIdentifiable(b, v)
   139  	return b
   140  }
   141  
   142  func (b *AddressWriter) Identity() []byte {
   143  	return b.Sum(nil)
   144  }