mirror of
https://github.com/luxfi/utils.git
synced 2026-07-26 22:49:03 +00:00
feat: add wrappers and bimap packages
Add wrappers package with Packer, Errs, and Closer types for binary serialization and error handling. These are needed by other Lux packages that were previously importing from vm. Add bimap package for bidirectional maps. Update atomic.go to re-export from standalone atomic module.
This commit is contained in:
@@ -4,60 +4,15 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
"github.com/luxfi/atomic"
|
||||
)
|
||||
|
||||
var (
|
||||
_ json.Marshaler = (*Atomic[struct{}])(nil)
|
||||
_ json.Unmarshaler = (*Atomic[struct{}])(nil)
|
||||
)
|
||||
|
||||
type Atomic[T any] struct {
|
||||
lock sync.RWMutex
|
||||
value T
|
||||
}
|
||||
// Atomic is a re-export from the standalone atomic module for backward compatibility.
|
||||
// Use github.com/luxfi/atomic directly for new code.
|
||||
type Atomic[T any] = atomic.Atomic[T]
|
||||
|
||||
// NewAtomic creates a new Atomic with the given initial value.
|
||||
// Use github.com/luxfi/atomic.NewAtomic directly for new code.
|
||||
func NewAtomic[T any](value T) *Atomic[T] {
|
||||
return &Atomic[T]{
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Atomic[T]) Get() T {
|
||||
a.lock.RLock()
|
||||
defer a.lock.RUnlock()
|
||||
|
||||
return a.value
|
||||
}
|
||||
|
||||
func (a *Atomic[T]) Set(value T) {
|
||||
a.lock.Lock()
|
||||
defer a.lock.Unlock()
|
||||
|
||||
a.value = value
|
||||
}
|
||||
|
||||
func (a *Atomic[T]) Swap(value T) T {
|
||||
a.lock.Lock()
|
||||
defer a.lock.Unlock()
|
||||
|
||||
old := a.value
|
||||
a.value = value
|
||||
|
||||
return old
|
||||
}
|
||||
|
||||
func (a *Atomic[T]) MarshalJSON() ([]byte, error) {
|
||||
a.lock.RLock()
|
||||
defer a.lock.RUnlock()
|
||||
|
||||
return json.Marshal(a.value)
|
||||
}
|
||||
|
||||
func (a *Atomic[T]) UnmarshalJSON(b []byte) error {
|
||||
a.lock.Lock()
|
||||
defer a.lock.Unlock()
|
||||
|
||||
return json.Unmarshal(b, &a.value)
|
||||
return atomic.NewAtomic(value)
|
||||
}
|
||||
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
// Package bimap provides a bidirectional map implementation.
|
||||
package bimap
|
||||
|
||||
// BiMap is a bidirectional map that allows lookups in both directions.
|
||||
type BiMap[K comparable, V comparable] struct {
|
||||
forward map[K]V
|
||||
backward map[V]K
|
||||
}
|
||||
|
||||
// New creates a new empty BiMap.
|
||||
func New[K comparable, V comparable]() *BiMap[K, V] {
|
||||
return &BiMap[K, V]{
|
||||
forward: make(map[K]V),
|
||||
backward: make(map[V]K),
|
||||
}
|
||||
}
|
||||
|
||||
// Put inserts a key-value pair into the BiMap.
|
||||
// Returns true if the pair was inserted, false if either key or value already exists.
|
||||
func (b *BiMap[K, V]) Put(key K, value V) bool {
|
||||
if _, exists := b.forward[key]; exists {
|
||||
return false
|
||||
}
|
||||
if _, exists := b.backward[value]; exists {
|
||||
return false
|
||||
}
|
||||
b.forward[key] = value
|
||||
b.backward[value] = key
|
||||
return true
|
||||
}
|
||||
|
||||
// Get returns the value associated with the key.
|
||||
func (b *BiMap[K, V]) Get(key K) (V, bool) {
|
||||
value, ok := b.forward[key]
|
||||
return value, ok
|
||||
}
|
||||
|
||||
// GetValue is an alias for Get.
|
||||
func (b *BiMap[K, V]) GetValue(key K) (V, bool) {
|
||||
return b.Get(key)
|
||||
}
|
||||
|
||||
// GetKey returns the key associated with the value.
|
||||
func (b *BiMap[K, V]) GetKey(value V) (K, bool) {
|
||||
key, ok := b.backward[value]
|
||||
return key, ok
|
||||
}
|
||||
|
||||
// Delete removes the key-value pair by key.
|
||||
func (b *BiMap[K, V]) Delete(key K) bool {
|
||||
if value, ok := b.forward[key]; ok {
|
||||
delete(b.forward, key)
|
||||
delete(b.backward, value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// DeleteValue removes the key-value pair by value.
|
||||
func (b *BiMap[K, V]) DeleteValue(value V) bool {
|
||||
if key, ok := b.backward[value]; ok {
|
||||
delete(b.forward, key)
|
||||
delete(b.backward, value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Len returns the number of entries in the BiMap.
|
||||
func (b *BiMap[K, V]) Len() int {
|
||||
return len(b.forward)
|
||||
}
|
||||
|
||||
// HasKey returns true if the key exists.
|
||||
func (b *BiMap[K, V]) HasKey(key K) bool {
|
||||
_, ok := b.forward[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
// HasValue returns true if the value exists.
|
||||
func (b *BiMap[K, V]) HasValue(value V) bool {
|
||||
_, ok := b.backward[value]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Keys returns all keys in the BiMap.
|
||||
func (b *BiMap[K, V]) Keys() []K {
|
||||
keys := make([]K, 0, len(b.forward))
|
||||
for k := range b.forward {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// Values returns all values in the BiMap.
|
||||
func (b *BiMap[K, V]) Values() []V {
|
||||
values := make([]V, 0, len(b.backward))
|
||||
for v := range b.backward {
|
||||
values = append(values, v)
|
||||
}
|
||||
return values
|
||||
}
|
||||
@@ -3,41 +3,15 @@ module github.com/luxfi/utils
|
||||
go 1.25.5
|
||||
|
||||
require (
|
||||
github.com/luxfi/constants v1.4.3
|
||||
github.com/luxfi/crypto v1.17.39
|
||||
github.com/luxfi/atomic v1.0.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251230134950-44c893854e3f // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
||||
github.com/gorilla/rpc v1.2.1 // indirect
|
||||
github.com/holiman/uint256 v1.3.2 // indirect
|
||||
github.com/luxfi/cache v1.2.0 // indirect
|
||||
github.com/luxfi/container v0.0.4 // indirect
|
||||
github.com/luxfi/geth v1.16.69 // indirect
|
||||
github.com/luxfi/ids v1.2.9 // indirect
|
||||
github.com/luxfi/math v1.2.3 // indirect
|
||||
github.com/luxfi/math/big v0.1.0 // indirect
|
||||
github.com/luxfi/metric v1.4.10 // indirect
|
||||
github.com/luxfi/mock v0.1.1 // indirect
|
||||
github.com/luxfi/sampler v1.0.0 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.23.2 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.67.5 // indirect
|
||||
github.com/prometheus/procfs v0.19.2 // indirect
|
||||
go.uber.org/mock v0.6.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
gonum.org/v1/gonum v0.16.0 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
@@ -1,85 +1,23 @@
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251230134950-44c893854e3f h1:a5PUgHGinaD6XrLmIDLQmGHocjIjBsBAcR5gALjZvMU=
|
||||
github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251230134950-44c893854e3f/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/gorilla/rpc v1.2.1 h1:yC+LMV5esttgpVvNORL/xX4jvTTEUE30UZhZ5JF7K9k=
|
||||
github.com/gorilla/rpc v1.2.1/go.mod h1:uNpOihAlF5xRFLuTYhfR0yfCTm0WTQSQttkMSptRfGk=
|
||||
github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA=
|
||||
github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||
github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk=
|
||||
github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/luxfi/cache v1.2.0 h1:VEk/ue13oi8w3sKBB/Dsv9fnjmfdXgb0NMibcPLVbss=
|
||||
github.com/luxfi/cache v1.2.0/go.mod h1:Esn48WMB3JL/+UOdCEV2Chyjr1MG3SSckXWLhB/P080=
|
||||
github.com/luxfi/constants v1.4.3 h1:bcqUO8twMOhHWCgN/RbjfWulVPbvUQcxDkssaRrCx4g=
|
||||
github.com/luxfi/constants v1.4.3/go.mod h1:ENkJ121cmDEkwQPDiKK4QhnTnW9u37PGpepbrdVcAmc=
|
||||
github.com/luxfi/container v0.0.4 h1:BXhF82WyfqVP5mjlNcr7tP0Fcnvl0Ap1rkiu+rq5XuM=
|
||||
github.com/luxfi/container v0.0.4/go.mod h1:Z3SpmMF5d4t77MM0nHYXURpn+EMVaeu1fhbd/3BGaek=
|
||||
github.com/luxfi/crypto v1.17.39 h1:dDmktYOD/sU6WjIpitIfuHp7mRbc3izOsyJrQ1c5eOQ=
|
||||
github.com/luxfi/crypto v1.17.39/go.mod h1:mChLWmW4CLR1wAN6CeJTveCzUv0DTzGQnYgq01x3W0U=
|
||||
github.com/luxfi/geth v1.16.69 h1:CHO6xTZ+A+3itk94ts4uyVRJajNVP3RxWTjJp5qGOlk=
|
||||
github.com/luxfi/geth v1.16.69/go.mod h1:8eEO1hW5sa6OH2VeCMaCPnRz28JBxFvCPBCWPLsU2ck=
|
||||
github.com/luxfi/ids v1.2.9 h1:+yjdhXW99drnd2Zlp1u/p8k3G23W3/1btJQ4ogHawUI=
|
||||
github.com/luxfi/ids v1.2.9/go.mod h1:khJOEdOPxd22yn0jcVrnbX1ADa0GHn5Y74gvCzN5BYc=
|
||||
github.com/luxfi/math v1.2.3 h1:BgvIFw/srPXFLbcqtoDhLJOfmBsn86GPA1iWgsoyUb4=
|
||||
github.com/luxfi/math v1.2.3/go.mod h1:C8STnF2H+D6rqBPt248CiWY2TGuJgdtv/+4UqrT15iM=
|
||||
github.com/luxfi/math/big v0.1.0 h1:Vz4c0RsZVPdIKPsHPgAJChH/R3p15WHRUz7LkLf+NIQ=
|
||||
github.com/luxfi/math/big v0.1.0/go.mod h1:BuxSu22RbO93xBLk5Eam5nldFponoJ73xDFz4uJ3Huk=
|
||||
github.com/luxfi/metric v1.4.10 h1:uWeLupMLxK7YK1c99gY23cT+hornWg7OmZgHNK4HNbw=
|
||||
github.com/luxfi/metric v1.4.10/go.mod h1:3OIQ+e6mciesm3cik3Q4CSOAvTlBy4JA0ZoKzCB9APo=
|
||||
github.com/luxfi/mock v0.1.1 h1:0HEtIjg1J6CWz+IUyP6rsGqNWTcmxjFnSQIhaDuARwY=
|
||||
github.com/luxfi/mock v0.1.1/go.mod h1:jo35akl3Vtd8LbzDts8VJ0jmSVycrd1/eBi6g6t5hKU=
|
||||
github.com/luxfi/sampler v1.0.0 h1:k8Sf6otW83w4pQp0jXLA+g3J/joB7w7SqXQsWmNTOV0=
|
||||
github.com/luxfi/sampler v1.0.0/go.mod h1:f96/ozlj9vFfZj+akLtrHn4VpulQahwB+MQQhpeIekk=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/luxfi/atomic v1.0.0 h1:xUV60MuzRvXngaQ1sM0yVC2v4TRoLlUGkkH7M9PS4yw=
|
||||
github.com/luxfi/atomic v1.0.0/go.mod h1:0G2mTlQ6TXWHICUHrUUPu1/qAiIyR4gSZ2tva9ci/bI=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
|
||||
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
|
||||
github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws=
|
||||
github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
|
||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
|
||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package wrappers
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Closer is a nice utility for closing a group of objects while reporting an
|
||||
// error if one occurs.
|
||||
type Closer struct {
|
||||
lock sync.Mutex
|
||||
closers []io.Closer
|
||||
}
|
||||
|
||||
// Add a new object to be closed.
|
||||
func (c *Closer) Add(closer io.Closer) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
c.closers = append(c.closers, closer)
|
||||
}
|
||||
|
||||
// Close closes each of the closers add to [c] and returns the first error
|
||||
// that occurs or nil if no error occurs.
|
||||
func (c *Closer) Close() error {
|
||||
c.lock.Lock()
|
||||
closers := c.closers
|
||||
c.closers = nil
|
||||
c.lock.Unlock()
|
||||
|
||||
errs := Errs{}
|
||||
for _, closer := range closers {
|
||||
errs.Add(closer.Close())
|
||||
}
|
||||
return errs.Err
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package wrappers
|
||||
|
||||
type Errs struct{ Err error }
|
||||
|
||||
func (errs *Errs) Errored() bool {
|
||||
return errs.Err != nil
|
||||
}
|
||||
|
||||
func (errs *Errs) Add(errors ...error) {
|
||||
if errs.Err == nil {
|
||||
for _, err := range errors {
|
||||
if err != nil {
|
||||
errs.Err = err
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package wrappers
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math"
|
||||
)
|
||||
|
||||
const (
|
||||
MaxStringLen = math.MaxUint16
|
||||
|
||||
// ByteLen is the number of bytes per byte...
|
||||
ByteLen = 1
|
||||
// ShortLen is the number of bytes per short
|
||||
ShortLen = 2
|
||||
// IntLen is the number of bytes per int
|
||||
IntLen = 4
|
||||
// LongLen is the number of bytes per long
|
||||
LongLen = 8
|
||||
// BoolLen is the number of bytes per bool
|
||||
BoolLen = 1
|
||||
)
|
||||
|
||||
func StringLen(str string) int {
|
||||
// note: there is a max length for string ([MaxStringLen])
|
||||
// we defer to PackString checking whether str is within limits
|
||||
return ShortLen + len(str)
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInsufficientLength = errors.New("packer has insufficient length for input")
|
||||
errNegativeOffset = errors.New("negative offset")
|
||||
errInvalidInput = errors.New("input does not match expected format")
|
||||
errBadBool = errors.New("unexpected value when unpacking bool")
|
||||
errOversized = errors.New("size is larger than limit")
|
||||
)
|
||||
|
||||
// Packer packs and unpacks a byte array from/to standard values
|
||||
type Packer struct {
|
||||
Errs
|
||||
|
||||
// The largest allowed size of expanding the byte array
|
||||
MaxSize int
|
||||
// The current byte array
|
||||
Bytes []byte
|
||||
// The offset that is being written to in the byte array
|
||||
Offset int
|
||||
}
|
||||
|
||||
// PackByte append a byte to the byte array
|
||||
func (p *Packer) PackByte(val byte) {
|
||||
p.expand(ByteLen)
|
||||
if p.Errored() {
|
||||
return
|
||||
}
|
||||
|
||||
p.Bytes[p.Offset] = val
|
||||
p.Offset++
|
||||
}
|
||||
|
||||
// UnpackByte unpack a byte from the byte array
|
||||
func (p *Packer) UnpackByte() byte {
|
||||
p.checkSpace(ByteLen)
|
||||
if p.Errored() {
|
||||
return 0
|
||||
}
|
||||
|
||||
val := p.Bytes[p.Offset]
|
||||
p.Offset += ByteLen
|
||||
return val
|
||||
}
|
||||
|
||||
// PackShort append a short to the byte array
|
||||
func (p *Packer) PackShort(val uint16) {
|
||||
p.expand(ShortLen)
|
||||
if p.Errored() {
|
||||
return
|
||||
}
|
||||
|
||||
binary.BigEndian.PutUint16(p.Bytes[p.Offset:], val)
|
||||
p.Offset += ShortLen
|
||||
}
|
||||
|
||||
// UnpackShort unpack a short from the byte array
|
||||
func (p *Packer) UnpackShort() uint16 {
|
||||
p.checkSpace(ShortLen)
|
||||
if p.Errored() {
|
||||
return 0
|
||||
}
|
||||
|
||||
val := binary.BigEndian.Uint16(p.Bytes[p.Offset:])
|
||||
p.Offset += ShortLen
|
||||
return val
|
||||
}
|
||||
|
||||
// PackInt append an int to the byte array
|
||||
func (p *Packer) PackInt(val uint32) {
|
||||
p.expand(IntLen)
|
||||
if p.Errored() {
|
||||
return
|
||||
}
|
||||
|
||||
binary.BigEndian.PutUint32(p.Bytes[p.Offset:], val)
|
||||
p.Offset += IntLen
|
||||
}
|
||||
|
||||
// UnpackInt unpack an int from the byte array
|
||||
func (p *Packer) UnpackInt() uint32 {
|
||||
p.checkSpace(IntLen)
|
||||
if p.Errored() {
|
||||
return 0
|
||||
}
|
||||
|
||||
val := binary.BigEndian.Uint32(p.Bytes[p.Offset:])
|
||||
p.Offset += IntLen
|
||||
return val
|
||||
}
|
||||
|
||||
// PackLong append a long to the byte array
|
||||
func (p *Packer) PackLong(val uint64) {
|
||||
p.expand(LongLen)
|
||||
if p.Errored() {
|
||||
return
|
||||
}
|
||||
|
||||
binary.BigEndian.PutUint64(p.Bytes[p.Offset:], val)
|
||||
p.Offset += LongLen
|
||||
}
|
||||
|
||||
// UnpackLong unpack a long from the byte array
|
||||
func (p *Packer) UnpackLong() uint64 {
|
||||
p.checkSpace(LongLen)
|
||||
if p.Errored() {
|
||||
return 0
|
||||
}
|
||||
|
||||
val := binary.BigEndian.Uint64(p.Bytes[p.Offset:])
|
||||
p.Offset += LongLen
|
||||
return val
|
||||
}
|
||||
|
||||
// PackBool packs a bool into the byte array
|
||||
func (p *Packer) PackBool(b bool) {
|
||||
if b {
|
||||
p.PackByte(1)
|
||||
} else {
|
||||
p.PackByte(0)
|
||||
}
|
||||
}
|
||||
|
||||
// UnpackBool unpacks a bool from the byte array
|
||||
func (p *Packer) UnpackBool() bool {
|
||||
b := p.UnpackByte()
|
||||
switch b {
|
||||
case 0:
|
||||
return false
|
||||
case 1:
|
||||
return true
|
||||
default:
|
||||
p.Add(errBadBool)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// PackFixedBytes append a byte slice, with no length descriptor to the byte
|
||||
// array
|
||||
func (p *Packer) PackFixedBytes(bytes []byte) {
|
||||
p.expand(len(bytes))
|
||||
if p.Errored() {
|
||||
return
|
||||
}
|
||||
|
||||
copy(p.Bytes[p.Offset:], bytes)
|
||||
p.Offset += len(bytes)
|
||||
}
|
||||
|
||||
// UnpackFixedBytes unpack a byte slice, with no length descriptor from the byte
|
||||
// array
|
||||
func (p *Packer) UnpackFixedBytes(size int) []byte {
|
||||
p.checkSpace(size)
|
||||
if p.Errored() {
|
||||
return nil
|
||||
}
|
||||
|
||||
bytes := p.Bytes[p.Offset : p.Offset+size]
|
||||
p.Offset += size
|
||||
return bytes
|
||||
}
|
||||
|
||||
// PackBytes append a byte slice to the byte array
|
||||
func (p *Packer) PackBytes(bytes []byte) {
|
||||
p.PackInt(uint32(len(bytes)))
|
||||
p.PackFixedBytes(bytes)
|
||||
}
|
||||
|
||||
// UnpackBytes unpack a byte slice from the byte array
|
||||
func (p *Packer) UnpackBytes() []byte {
|
||||
size := p.UnpackInt()
|
||||
return p.UnpackFixedBytes(int(size))
|
||||
}
|
||||
|
||||
// UnpackLimitedBytes unpacks a byte slice. If the size of the slice is greater
|
||||
// than [limit], adds [errOversized] to the packer and returns nil.
|
||||
func (p *Packer) UnpackLimitedBytes(limit uint32) []byte {
|
||||
size := p.UnpackInt()
|
||||
if size > limit {
|
||||
p.Add(errOversized)
|
||||
return nil
|
||||
}
|
||||
return p.UnpackFixedBytes(int(size))
|
||||
}
|
||||
|
||||
// PackStr append a string to the byte array
|
||||
func (p *Packer) PackStr(str string) {
|
||||
strSize := len(str)
|
||||
if strSize > MaxStringLen {
|
||||
p.Add(errInvalidInput)
|
||||
return
|
||||
}
|
||||
p.PackShort(uint16(strSize))
|
||||
p.PackFixedBytes([]byte(str))
|
||||
}
|
||||
|
||||
// UnpackStr unpacks a string from the byte array
|
||||
func (p *Packer) UnpackStr() string {
|
||||
strSize := p.UnpackShort()
|
||||
return string(p.UnpackFixedBytes(int(strSize)))
|
||||
}
|
||||
|
||||
// UnpackLimitedStr unpacks a string. If the size of the string is greater than
|
||||
// [limit], adds [errOversized] to the packer and returns the empty string.
|
||||
func (p *Packer) UnpackLimitedStr(limit uint16) string {
|
||||
strSize := p.UnpackShort()
|
||||
if strSize > limit {
|
||||
p.Add(errOversized)
|
||||
return ""
|
||||
}
|
||||
return string(p.UnpackFixedBytes(int(strSize)))
|
||||
}
|
||||
|
||||
// checkSpace requires that there is at least [bytes] of write space left in the
|
||||
// byte array. If this is not true, an error is added to the packer
|
||||
func (p *Packer) checkSpace(bytes int) {
|
||||
switch {
|
||||
case p.Offset < 0:
|
||||
p.Add(errNegativeOffset)
|
||||
case bytes < 0:
|
||||
p.Add(errInvalidInput)
|
||||
case len(p.Bytes)-p.Offset < bytes:
|
||||
p.Add(ErrInsufficientLength)
|
||||
}
|
||||
}
|
||||
|
||||
// expand ensures that there is [bytes] bytes left of space in the byte slice.
|
||||
// If this is not allowed due to the maximum size, an error is added to the packer
|
||||
// In order to understand this code, its important to understand the difference
|
||||
// between a slice's length and its capacity.
|
||||
func (p *Packer) expand(bytes int) {
|
||||
neededSize := bytes + p.Offset // Need byte slice's length to be at least [neededSize]
|
||||
switch {
|
||||
case neededSize <= len(p.Bytes): // Byte slice has sufficient length already
|
||||
return
|
||||
case neededSize > p.MaxSize: // Lengthening the byte slice would cause it to grow too large
|
||||
p.Err = ErrInsufficientLength
|
||||
return
|
||||
case neededSize <= cap(p.Bytes): // Byte slice has sufficient capacity to lengthen it without mem alloc
|
||||
p.Bytes = p.Bytes[:neededSize]
|
||||
return
|
||||
default: // Add capacity/length to byte slice
|
||||
p.Bytes = append(p.Bytes[:cap(p.Bytes)], make([]byte, neededSize-cap(p.Bytes))...)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package wrappers
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
ByteSentinel = 0
|
||||
ShortSentinel = 0
|
||||
IntSentinel = 0
|
||||
LongSentinel = 0
|
||||
BoolSentinel = false
|
||||
)
|
||||
|
||||
func TestPackerCheckSpace(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{Offset: -1}
|
||||
p.checkSpace(1)
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, errNegativeOffset)
|
||||
|
||||
p = Packer{}
|
||||
p.checkSpace(-1)
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, errInvalidInput)
|
||||
|
||||
p = Packer{Bytes: []byte{0x01}, Offset: 1}
|
||||
p.checkSpace(1)
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
|
||||
p = Packer{Bytes: []byte{0x01}, Offset: 2}
|
||||
p.checkSpace(0)
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerExpand(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{Bytes: []byte{0x01}, Offset: 2}
|
||||
p.expand(1)
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
|
||||
p = Packer{Bytes: []byte{0x01, 0x02, 0x03}, Offset: 0}
|
||||
p.expand(1)
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal([]byte{0x01, 0x02, 0x03}, p.Bytes)
|
||||
}
|
||||
|
||||
func TestPackerPackByte(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{MaxSize: 1}
|
||||
p.PackByte(0x01)
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal([]byte{0x01}, p.Bytes)
|
||||
|
||||
p.PackByte(0x02)
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerUnpackByte(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{Bytes: []byte{0x01}, Offset: 0}
|
||||
require.Equal(uint8(1), p.UnpackByte())
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal(ByteLen, p.Offset)
|
||||
|
||||
require.Equal(uint8(ByteSentinel), p.UnpackByte())
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerPackShort(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{MaxSize: 2}
|
||||
p.PackShort(0x0102)
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal([]byte{0x01, 0x02}, p.Bytes)
|
||||
}
|
||||
|
||||
func TestPackerUnpackShort(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{Bytes: []byte{0x01, 0x02}, Offset: 0}
|
||||
require.Equal(uint16(0x0102), p.UnpackShort())
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal(ShortLen, p.Offset)
|
||||
|
||||
require.Equal(uint16(ShortSentinel), p.UnpackShort())
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerPackInt(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{MaxSize: 4}
|
||||
p.PackInt(0x01020304)
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal([]byte{0x01, 0x02, 0x03, 0x04}, p.Bytes)
|
||||
|
||||
p.PackInt(0x05060708)
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerUnpackInt(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{Bytes: []byte{0x01, 0x02, 0x03, 0x04}, Offset: 0}
|
||||
require.Equal(uint32(0x01020304), p.UnpackInt())
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal(IntLen, p.Offset)
|
||||
|
||||
require.Equal(uint32(IntSentinel), p.UnpackInt())
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerPackLong(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{MaxSize: 8}
|
||||
p.PackLong(0x0102030405060708)
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal([]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, p.Bytes)
|
||||
|
||||
p.PackLong(0x090a0b0c0d0e0f00)
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerUnpackLong(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{Bytes: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, Offset: 0}
|
||||
require.Equal(uint64(0x0102030405060708), p.UnpackLong())
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal(LongLen, p.Offset)
|
||||
|
||||
require.Equal(uint64(LongSentinel), p.UnpackLong())
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerPackFixedBytes(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{MaxSize: 4}
|
||||
p.PackFixedBytes([]byte("Lux"))
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal([]byte("Lux"), p.Bytes)
|
||||
|
||||
p.PackFixedBytes([]byte("Lux"))
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerUnpackFixedBytes(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{Bytes: []byte("Lux")}
|
||||
require.Equal([]byte("Lux"), p.UnpackFixedBytes(3))
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal(3, p.Offset)
|
||||
|
||||
require.Nil(p.UnpackFixedBytes(4))
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerPackBytes(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{MaxSize: 8}
|
||||
p.PackBytes([]byte("Lux"))
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal([]byte("\x00\x00\x00\x03Lux"), p.Bytes)
|
||||
|
||||
p.PackBytes([]byte("Lux"))
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerUnpackBytes(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{Bytes: []byte("\x00\x00\x00\x03Lux")}
|
||||
require.Equal([]byte("Lux"), p.UnpackBytes())
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal(7, p.Offset)
|
||||
|
||||
require.Nil(p.UnpackBytes())
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerUnpackLimitedBytes(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{Bytes: []byte("\x00\x00\x00\x03Lux")}
|
||||
require.Equal([]byte("Lux"), p.UnpackLimitedBytes(10))
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal(7, p.Offset)
|
||||
|
||||
require.Nil(p.UnpackLimitedBytes(10))
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
|
||||
// Reset and don't allow enough bytes
|
||||
p = Packer{Bytes: p.Bytes}
|
||||
require.Nil(p.UnpackLimitedBytes(2))
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, errOversized)
|
||||
}
|
||||
|
||||
func TestPackerString(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{MaxSize: 6}
|
||||
|
||||
p.PackStr("Lux")
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal([]byte{0x00, 0x03, 0x4c, 0x75, 0x78}, p.Bytes)
|
||||
}
|
||||
|
||||
func TestPackerUnpackString(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{Bytes: []byte("\x00\x03Lux")}
|
||||
|
||||
require.Equal("Lux", p.UnpackStr())
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal(5, p.Offset)
|
||||
|
||||
require.Empty(p.UnpackStr())
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerUnpackLimitedString(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{Bytes: []byte("\x00\x03Lux")}
|
||||
require.Equal("Lux", p.UnpackLimitedStr(10))
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal(5, p.Offset)
|
||||
|
||||
require.Empty(p.UnpackLimitedStr(10))
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
|
||||
// Reset and don't allow enough bytes
|
||||
p = Packer{Bytes: p.Bytes}
|
||||
require.Empty(p.UnpackLimitedStr(2))
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, errOversized)
|
||||
}
|
||||
|
||||
func TestPacker(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{MaxSize: 3}
|
||||
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
|
||||
p.PackShort(17)
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal([]byte{0x0, 0x11}, p.Bytes)
|
||||
|
||||
p.PackShort(1)
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
|
||||
p = Packer{Bytes: p.Bytes}
|
||||
require.Equal(uint16(17), p.UnpackShort())
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
}
|
||||
|
||||
func TestPackBool(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{MaxSize: 3}
|
||||
p.PackBool(false)
|
||||
p.PackBool(true)
|
||||
p.PackBool(false)
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
|
||||
p = Packer{Bytes: p.Bytes}
|
||||
bool1, bool2, bool3 := p.UnpackBool(), p.UnpackBool(), p.UnpackBool()
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.False(bool1)
|
||||
require.True(bool2)
|
||||
require.False(bool3)
|
||||
}
|
||||
|
||||
func TestPackerPackBool(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{MaxSize: 1}
|
||||
|
||||
p.PackBool(true)
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal([]byte{0x01}, p.Bytes)
|
||||
|
||||
p.PackBool(false)
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
}
|
||||
|
||||
func TestPackerUnpackBool(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
p := Packer{Bytes: []byte{0x01}, Offset: 0}
|
||||
|
||||
require.True(p.UnpackBool())
|
||||
require.False(p.Errored())
|
||||
require.NoError(p.Err)
|
||||
require.Equal(BoolLen, p.Offset)
|
||||
|
||||
require.Equal(BoolSentinel, p.UnpackBool())
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, ErrInsufficientLength)
|
||||
|
||||
p = Packer{Bytes: []byte{0x42}, Offset: 0}
|
||||
require.False(p.UnpackBool())
|
||||
require.True(p.Errored())
|
||||
require.ErrorIs(p.Err, errBadBool)
|
||||
}
|
||||
Reference in New Issue
Block a user