Files
eventstore/ratel/keys/serial/serial.go
2024-09-08 20:16:34 +01:00

82 lines
1.8 KiB
Go

package serial
import (
"bytes"
"encoding/binary"
"fmt"
. "nostr.mleku.dev"
"store.mleku.dev/ratel/keys"
)
const Len = 8
// T is a badger DB serial number used for conflict free event record keys.
type T struct {
Val []byte
}
var _ keys.Element = &T{}
// New returns a new serial record key.Element - if nil or short slice is given,
// initialize a fresh one with Len (for reading), otherwise if equal or longer,
// trim if long and store into struct (for writing).
func New(ser []byte) (p *T) {
switch {
case len(ser) < Len:
// Log.I.Ln("empty serial")
// allows use of nil to init
ser = make([]byte, Len)
default:
ser = ser[:Len]
}
return &T{Val: ser}
}
// FromKey expects the last Len bytes of the given slice to be the serial.
func FromKey(k []byte) (p *T) {
if len(k) < Len {
panic(fmt.Sprintf("cannot get a serial without at least 8 bytes %x", k))
}
key := make([]byte, Len)
copy(key, k[len(k)-Len:])
return &T{Val: key}
}
func Make(s uint64) (ser []byte) {
ser = make([]byte, 8)
binary.BigEndian.PutUint64(ser, s)
return
}
func (p *T) Write(buf *bytes.Buffer) {
if len(p.Val) != Len {
panic(fmt.Sprintln("must use New or initialize Val with len", Len))
}
buf.Write(p.Val)
}
func (p *T) Read(buf *bytes.Buffer) (el keys.Element) {
// allow uninitialized struct
if len(p.Val) != Len {
p.Val = make([]byte, Len)
}
if n, err := buf.Read(p.Val); Chk.E(err) || n != Len {
return nil
}
return p
}
func (p *T) Len() int { return Len }
func (p *T) Uint64() (u uint64) { return binary.BigEndian.Uint64(p.Val) }
// Match compares a key bytes to a serial, all indexes have the serial at
// the end indicating the event record they refer to, and if they match returns
// true.
func Match(index, ser []byte) bool {
l := len(index)
if l < Len {
return false
}
return bytes.Compare(index[l-Len:], ser) == 0
}