summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-mangler
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/codeberg.org/gruf/go-mangler')
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/helpers.go230
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/load.go230
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/mangle.go130
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/LICENSE (renamed from vendor/codeberg.org/gruf/go-mangler/LICENSE)0
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/README.md (renamed from vendor/codeberg.org/gruf/go-mangler/README.md)0
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/array.go55
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/cache.go62
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/helpers.go43
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/load.go150
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/mangle.go93
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/manglers.go (renamed from vendor/codeberg.org/gruf/go-mangler/manglers.go)0
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/map.go80
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/method.go105
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/pointer.go81
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/slice.go95
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/struct.go75
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/v2/type.go20
17 files changed, 859 insertions, 590 deletions
diff --git a/vendor/codeberg.org/gruf/go-mangler/helpers.go b/vendor/codeberg.org/gruf/go-mangler/helpers.go
deleted file mode 100644
index 71d45e201..000000000
--- a/vendor/codeberg.org/gruf/go-mangler/helpers.go
+++ /dev/null
@@ -1,230 +0,0 @@
-//go:build go1.19 && !go1.25
-
-package mangler
-
-import (
- "reflect"
- "unsafe"
-)
-
-func append_uint16(b []byte, u uint16) []byte {
- return append(b, // LE
- byte(u),
- byte(u>>8),
- )
-}
-
-func append_uint32(b []byte, u uint32) []byte {
- return append(b, // LE
- byte(u),
- byte(u>>8),
- byte(u>>16),
- byte(u>>24),
- )
-}
-
-func append_uint64(b []byte, u uint64) []byte {
- return append(b, // LE
- byte(u),
- byte(u>>8),
- byte(u>>16),
- byte(u>>24),
- byte(u>>32),
- byte(u>>40),
- byte(u>>48),
- byte(u>>56),
- )
-}
-
-type typecontext struct {
- isptr bool
- direct bool
- ntype reflect.Type
- rtype reflect.Type
-}
-
-func (ctx *typecontext) set_nested(direct bool) {
- ctx.direct = ctx.direct && direct && !ctx.isptr
- ctx.ntype = ctx.rtype
- ctx.rtype = nil
- ctx.isptr = false
-}
-
-func deref_ptr_mangler(ctx typecontext, mangle Mangler, n uint) Mangler {
- if mangle == nil || n == 0 {
- panic("bad input")
- }
-
- // If this is a direct value type, i.e. non-nested primitive,
- // or part of a single-field struct / single element array
- // then it can be treated as a direct ptr with 1 less deref.
- if ctx.direct {
- n--
- }
-
- return func(buf []byte, ptr unsafe.Pointer) []byte {
- // Deref n number times.
- for i := n; i > 0; i-- {
-
- if ptr == nil {
- // Check for nil values
- buf = append(buf, '0')
- return buf
- }
-
- // Further deref ptr
- buf = append(buf, '1')
- ptr = *(*unsafe.Pointer)(ptr)
- }
-
- if ptr == nil {
- // Final nil val check
- buf = append(buf, '0')
- return buf
- }
-
- // Mangle fully deref'd
- buf = append(buf, '1')
- buf = mangle(buf, ptr)
- return buf
- }
-}
-
-func iter_slice_mangler(ctx typecontext, mangle Mangler) Mangler {
- if ctx.rtype == nil || mangle == nil {
- panic("bad input")
- }
-
- // memory size of elem.
- esz := ctx.rtype.Size()
-
- return func(buf []byte, ptr unsafe.Pointer) []byte {
- // Get data as slice hdr.
- hdr := (*slice_header)(ptr)
-
- for i := 0; i < hdr.len; i++ {
- // Mangle data at slice index.
- eptr := array_at(hdr.data, esz, i)
- buf = mangle(buf, eptr)
- buf = append(buf, ',')
- }
-
- if hdr.len > 0 {
- // Drop final comma.
- buf = buf[:len(buf)-1]
- }
-
- return buf
- }
-}
-
-func iter_array_mangler(ctx typecontext, mangle Mangler) Mangler {
- if ctx.rtype == nil || mangle == nil {
- panic("bad input")
- }
-
- // no. array elements.
- n := ctx.ntype.Len()
-
- // Optimize
- // easy cases.
- switch n {
- case 0:
- return empty_mangler
- case 1:
- return mangle
- }
-
- // memory size of elem.
- esz := ctx.rtype.Size()
-
- return func(buf []byte, ptr unsafe.Pointer) []byte {
- for i := 0; i < n; i++ {
- // Mangle data at array index.
- offset := esz * uintptr(i)
- eptr := add(ptr, offset)
- buf = mangle(buf, eptr)
- buf = append(buf, ',')
- }
-
- if n > 0 {
- // Drop final comma.
- buf = buf[:len(buf)-1]
- }
-
- return buf
- }
-}
-
-func iter_struct_mangler(ctx typecontext, manglers []Mangler) Mangler {
- if ctx.rtype == nil || len(manglers) != ctx.ntype.NumField() {
- panic("bad input")
- }
-
- // Optimized easy cases.
- switch len(manglers) {
- case 0:
- return empty_mangler
- case 1:
- return manglers[0]
- }
-
- type field struct {
- mangle Mangler
- offset uintptr
- }
-
- // Bundle together the fields and manglers.
- fields := make([]field, ctx.ntype.NumField())
- for i := range fields {
- rfield := ctx.ntype.Field(i)
- fields[i].offset = rfield.Offset
- fields[i].mangle = manglers[i]
- if fields[i].mangle == nil {
- panic("bad input")
- }
- }
-
- return func(buf []byte, ptr unsafe.Pointer) []byte {
- for i := range fields {
- // Get struct field ptr via offset.
- fptr := add(ptr, fields[i].offset)
-
- // Mangle the struct field data.
- buf = fields[i].mangle(buf, fptr)
- buf = append(buf, ',')
- }
-
- if len(fields) > 0 {
- // Drop final comma.
- buf = buf[:len(buf)-1]
- }
-
- return buf
- }
-}
-
-func empty_mangler(buf []byte, _ unsafe.Pointer) []byte {
- return buf
-}
-
-// array_at returns ptr to index in array at ptr, given element size.
-func array_at(ptr unsafe.Pointer, esz uintptr, i int) unsafe.Pointer {
- return unsafe.Pointer(uintptr(ptr) + esz*uintptr(i))
-}
-
-// add returns the ptr addition of starting ptr and a delta.
-func add(ptr unsafe.Pointer, delta uintptr) unsafe.Pointer {
- return unsafe.Pointer(uintptr(ptr) + delta)
-}
-
-type slice_header struct {
- data unsafe.Pointer
- len int
- cap int
-}
-
-func eface_data(a any) unsafe.Pointer {
- type eface struct{ _, data unsafe.Pointer }
- return (*eface)(unsafe.Pointer(&a)).data
-}
diff --git a/vendor/codeberg.org/gruf/go-mangler/load.go b/vendor/codeberg.org/gruf/go-mangler/load.go
deleted file mode 100644
index ba2b9351b..000000000
--- a/vendor/codeberg.org/gruf/go-mangler/load.go
+++ /dev/null
@@ -1,230 +0,0 @@
-package mangler
-
-import (
- "reflect"
-)
-
-// loadMangler is the top-most Mangler load function. It guarantees that a Mangler
-// function will be returned for given value interface{} and reflected type. Else panics.
-func loadMangler(t reflect.Type) Mangler {
- ctx := typecontext{rtype: t}
- ctx.direct = true
-
- // Load mangler fn
- mng := load(ctx)
- if mng != nil {
- return mng
- }
-
- // No mangler function could be determined
- panic("cannot mangle type: " + t.String())
-}
-
-// load will load a Mangler or reflect Mangler for given type and iface 'a'.
-// Note: allocates new interface value if nil provided, i.e. if coming via reflection.
-func load(ctx typecontext) Mangler {
- if ctx.rtype == nil {
- // There is no reflect type to search by
- panic("cannot mangle nil interface{} type")
- }
-
- // Search by reflection.
- mng := loadReflect(ctx)
- if mng != nil {
- return mng
- }
-
- return nil
-}
-
-// loadReflect will load a Mangler (or rMangler) function for the given reflected type info.
-// NOTE: this is used as the top level load function for nested reflective searches.
-func loadReflect(ctx typecontext) Mangler {
- switch ctx.rtype.Kind() {
- case reflect.Pointer:
- return loadReflectPtr(ctx)
-
- case reflect.String:
- return mangle_string
-
- case reflect.Struct:
- return loadReflectStruct(ctx)
-
- case reflect.Array:
- return loadReflectArray(ctx)
-
- case reflect.Slice:
- return loadReflectSlice(ctx)
-
- case reflect.Bool:
- return mangle_bool
-
- case reflect.Int,
- reflect.Uint,
- reflect.Uintptr:
- return mangle_int
-
- case reflect.Int8, reflect.Uint8:
- return mangle_8bit
-
- case reflect.Int16, reflect.Uint16:
- return mangle_16bit
-
- case reflect.Int32, reflect.Uint32:
- return mangle_32bit
-
- case reflect.Int64, reflect.Uint64:
- return mangle_64bit
-
- case reflect.Float32:
- return mangle_32bit
-
- case reflect.Float64:
- return mangle_64bit
-
- case reflect.Complex64:
- return mangle_64bit
-
- case reflect.Complex128:
- return mangle_128bit
-
- default:
- return nil
- }
-}
-
-// loadReflectPtr loads a Mangler (or rMangler) function for a ptr's element type.
-// This also handles further dereferencing of any further ptr indrections (e.g. ***int).
-func loadReflectPtr(ctx typecontext) Mangler {
- var n uint
-
- // Iteratively dereference ptrs
- for ctx.rtype.Kind() == reflect.Pointer {
- ctx.rtype = ctx.rtype.Elem()
- n++
- }
-
- // Set ptr type.
- ctx.isptr = true
-
- // Search for elemn type mangler.
- if mng := load(ctx); mng != nil {
- return deref_ptr_mangler(ctx, mng, n)
- }
-
- return nil
-}
-
-// loadReflectKnownSlice loads a Mangler function for a
-// known slice-of-element type (in this case, primtives).
-func loadReflectKnownSlice(ctx typecontext) Mangler {
- switch ctx.rtype.Kind() {
- case reflect.String:
- return mangle_string_slice
-
- case reflect.Bool:
- return mangle_bool_slice
-
- case reflect.Int,
- reflect.Uint,
- reflect.Uintptr:
- return mangle_int_slice
-
- case reflect.Int8, reflect.Uint8:
- return mangle_8bit_slice
-
- case reflect.Int16, reflect.Uint16:
- return mangle_16bit_slice
-
- case reflect.Int32, reflect.Uint32:
- return mangle_32bit_slice
-
- case reflect.Int64, reflect.Uint64:
- return mangle_64bit_slice
-
- case reflect.Float32:
- return mangle_32bit_slice
-
- case reflect.Float64:
- return mangle_64bit_slice
-
- case reflect.Complex64:
- return mangle_64bit_slice
-
- case reflect.Complex128:
- return mangle_128bit_slice
-
- default:
- return nil
- }
-}
-
-// loadReflectSlice ...
-func loadReflectSlice(ctx typecontext) Mangler {
-
- // Get nested element type.
- elem := ctx.rtype.Elem()
-
- // Set this as nested type.
- ctx.set_nested(false)
- ctx.rtype = elem
-
- // Preferably look for known slice mangler func
- if mng := loadReflectKnownSlice(ctx); mng != nil {
- return mng
- }
-
- // Use nested mangler iteration.
- if mng := load(ctx); mng != nil {
- return iter_slice_mangler(ctx, mng)
- }
-
- return nil
-}
-
-// loadReflectArray ...
-func loadReflectArray(ctx typecontext) Mangler {
-
- // Get nested element type.
- elem := ctx.rtype.Elem()
-
- // Set this as a nested value type.
- direct := ctx.rtype.Len() <= 1
- ctx.set_nested(direct)
- ctx.rtype = elem
-
- // Use manglers for nested iteration.
- if mng := load(ctx); mng != nil {
- return iter_array_mangler(ctx, mng)
- }
-
- return nil
-}
-
-// loadReflectStruct ...
-func loadReflectStruct(ctx typecontext) Mangler {
- var mngs []Mangler
-
- // Set this as a nested value type.
- direct := ctx.rtype.NumField() <= 1
- ctx.set_nested(direct)
-
- // Gather manglers for all fields.
- for i := 0; i < ctx.ntype.NumField(); i++ {
-
- // Update context with field at index.
- ctx.rtype = ctx.ntype.Field(i).Type
-
- // Load mangler.
- mng := load(ctx)
- if mng == nil {
- return nil
- }
-
- // Append next to map.
- mngs = append(mngs, mng)
- }
-
- // Use manglers for nested iteration.
- return iter_struct_mangler(ctx, mngs)
-}
diff --git a/vendor/codeberg.org/gruf/go-mangler/mangle.go b/vendor/codeberg.org/gruf/go-mangler/mangle.go
deleted file mode 100644
index 576286682..000000000
--- a/vendor/codeberg.org/gruf/go-mangler/mangle.go
+++ /dev/null
@@ -1,130 +0,0 @@
-package mangler
-
-import (
- "reflect"
- "sync"
- "unsafe"
-)
-
-// manglers is a map of runtime
-// type ptrs => Mangler functions.
-var manglers sync.Map
-
-// Mangler is a function that will take an input interface value of known
-// type, and append it in mangled serialized form to the given byte buffer.
-// While the value type is an interface, the Mangler functions are accessed
-// by the value's runtime type pointer, allowing the input value type to be known.
-type Mangler func(buf []byte, ptr unsafe.Pointer) []byte
-
-// Get will fetch the Mangler function for given runtime type.
-// Note that the returned mangler will be a no-op in the case
-// that an incorrect type is passed as the value argument.
-func Get(t reflect.Type) Mangler {
- var mng Mangler
-
- // Get raw runtime type ptr
- uptr := uintptr(eface_data(t))
-
- // Look for a cached mangler
- v, ok := manglers.Load(uptr)
-
- if !ok {
- // Load mangler function
- mng = loadMangler(t)
- } else {
- // cast cached value
- mng = v.(Mangler)
- }
-
- return func(buf []byte, ptr unsafe.Pointer) []byte {
- // First write the type ptr (this adds
- // a unique prefix for each runtime type).
- buf = append_uint64(buf, uint64(uptr))
-
- // Finally, mangle value
- return mng(buf, ptr)
- }
-}
-
-// Register will register the given Mangler function for use with vars of given runtime type. This allows
-// registering performant manglers for existing types not implementing Mangled (e.g. std library types).
-// NOTE: panics if there already exists a Mangler function for given type. Register on init().
-func Register(t reflect.Type, m Mangler) {
- if t == nil {
- // Nil interface{} types cannot be searched by, do not accept
- panic("cannot register mangler for nil interface{} type")
- }
-
- // Get raw runtime type ptr
- uptr := uintptr(eface_data(t))
-
- // Ensure this is a unique encoder
- if _, ok := manglers.Load(uptr); ok {
- panic("already registered mangler for type: " + t.String())
- }
-
- // Cache this encoder func
- manglers.Store(uptr, m)
-}
-
-// Append will append the mangled form of input value 'a' to buffer 'b'.
-// See mangler.String() for more information on mangled output.
-func Append(b []byte, a any) []byte {
- var mng Mangler
-
- // Get reflect type of 'a'
- t := reflect.TypeOf(a)
-
- // Get raw runtime type ptr
- uptr := uintptr(eface_data(t))
-
- // Look for a cached mangler
- v, ok := manglers.Load(uptr)
-
- if !ok {
- // Load into cache
- mng = loadMangler(t)
- manglers.Store(uptr, mng)
- } else {
- // cast cached value
- mng = v.(Mangler)
- }
-
- // First write the type ptr (this adds
- // a unique prefix for each runtime type).
- b = append_uint64(b, uint64(uptr))
-
- // Finally, mangle value
- ptr := eface_data(a)
- return mng(b, ptr)
-}
-
-// String will return the mangled format of input value 'a'. This
-// mangled output will be unique for all default supported input types
-// during a single runtime instance. Uniqueness cannot be guaranteed
-// between separate runtime instances (whether running concurrently, or
-// the same application running at different times).
-//
-// The exact formatting of the output data should not be relied upon,
-// only that it is unique given the above constraints. Generally though,
-// the mangled output is the binary formatted text of given input data.
-//
-// Uniqueness is guaranteed for similar input data of differing types
-// (e.g. string("hello world") vs. []byte("hello world")) by prefixing
-// mangled output with the input data's runtime type pointer.
-//
-// Default supported types include:
-// - string
-// - bool
-// - int,int8,int16,int32,int64
-// - uint,uint8,uint16,uint32,uint64,uintptr
-// - float32,float64
-// - complex64,complex128
-// - arbitrary structs
-// - all type aliases of above
-// - all pointers to the above
-// - all slices / arrays of the above
-func String(a any) string {
- b := Append(make([]byte, 0, 32), a)
- return *(*string)(unsafe.Pointer(&b))
-}
diff --git a/vendor/codeberg.org/gruf/go-mangler/LICENSE b/vendor/codeberg.org/gruf/go-mangler/v2/LICENSE
index dffbdf0c9..dffbdf0c9 100644
--- a/vendor/codeberg.org/gruf/go-mangler/LICENSE
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/LICENSE
diff --git a/vendor/codeberg.org/gruf/go-mangler/README.md b/vendor/codeberg.org/gruf/go-mangler/v2/README.md
index 636c2494c..636c2494c 100644
--- a/vendor/codeberg.org/gruf/go-mangler/README.md
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/README.md
diff --git a/vendor/codeberg.org/gruf/go-mangler/v2/array.go b/vendor/codeberg.org/gruf/go-mangler/v2/array.go
new file mode 100644
index 000000000..6638a6e2d
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/array.go
@@ -0,0 +1,55 @@
+package mangler
+
+import (
+ "unsafe"
+
+ "codeberg.org/gruf/go-xunsafe"
+)
+
+// iterArrayType returns a Mangler capable of iterating
+// and mangling the given array type currently in TypeIter{}.
+// note this will fetch sub-Mangler for array element type.
+func iterArrayType(t xunsafe.TypeIter) Mangler {
+
+ // Array element type.
+ elem := t.Type.Elem()
+
+ // Get nested elem TypeIter with appropriate flags.
+ flags := xunsafe.ReflectArrayElemFlags(t.Flag, elem)
+ et := t.Child(elem, flags)
+
+ // Get elem mangler.
+ fn := loadOrGet(et)
+ if fn == nil {
+ return nil
+ }
+
+ // Array element in-memory size.
+ esz := t.Type.Elem().Size()
+
+ // No of elements.
+ n := t.Type.Len()
+ switch n {
+ case 0:
+ return empty_mangler
+ case 1:
+ return fn
+ default:
+ return func(buf []byte, ptr unsafe.Pointer) []byte {
+ for i := 0; i < n; i++ {
+ // Mangle data at array index.
+ offset := esz * uintptr(i)
+ eptr := add(ptr, offset)
+ buf = fn(buf, eptr)
+ buf = append(buf, ',')
+ }
+
+ if n > 0 {
+ // Drop final comma.
+ buf = buf[:len(buf)-1]
+ }
+
+ return buf
+ }
+ }
+}
diff --git a/vendor/codeberg.org/gruf/go-mangler/v2/cache.go b/vendor/codeberg.org/gruf/go-mangler/v2/cache.go
new file mode 100644
index 000000000..0f6f71cd0
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/cache.go
@@ -0,0 +1,62 @@
+package mangler
+
+import (
+ "sync/atomic"
+ "unsafe"
+
+ "codeberg.org/gruf/go-xunsafe"
+)
+
+var manglers cache
+
+// cache is a concurrency-safe map[xunsafe.TypeInfo]Mangler
+// cache, designed for heavy reads but with unfortunately expensive
+// writes. it is designed such that after some initial load period
+// in which functions are cached by types, all future ops are reads.
+type cache struct{ p unsafe.Pointer }
+
+// Get will check cache for mangler func under key.
+func (c *cache) Get(t xunsafe.TypeInfo) Mangler {
+ if p := c.load(); p != nil {
+ return (*p)[t]
+ }
+ return nil
+}
+
+// Put will place given mangler func in cache under key, if not already exists.
+func (c *cache) Put(t xunsafe.TypeInfo, fn Mangler) {
+ for {
+ p := c.load()
+
+ var cache map[xunsafe.TypeInfo]Mangler
+
+ if p != nil {
+ if _, ok := (*p)[t]; ok {
+ return
+ }
+
+ cache = make(map[xunsafe.TypeInfo]Mangler, len(*p)+1)
+ for key, value := range *p {
+ cache[key] = value
+ }
+ } else {
+ cache = make(map[xunsafe.TypeInfo]Mangler, 1)
+ }
+
+ cache[t] = fn
+
+ if c.cas(p, &cache) {
+ return
+ }
+ }
+}
+
+// load is a typed wrapper around atomic.LoadPointer().
+func (c *cache) load() *map[xunsafe.TypeInfo]Mangler {
+ return (*map[xunsafe.TypeInfo]Mangler)(atomic.LoadPointer(&c.p))
+}
+
+// cas is a typed wrapper around atomic.CompareAndSwapPointer().
+func (c *cache) cas(old, new *map[xunsafe.TypeInfo]Mangler) bool {
+ return atomic.CompareAndSwapPointer(&c.p, unsafe.Pointer(old), unsafe.Pointer(new))
+}
diff --git a/vendor/codeberg.org/gruf/go-mangler/v2/helpers.go b/vendor/codeberg.org/gruf/go-mangler/v2/helpers.go
new file mode 100644
index 000000000..0b07bba13
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/helpers.go
@@ -0,0 +1,43 @@
+package mangler
+
+import (
+ "unsafe"
+)
+
+func append_uint16(b []byte, u uint16) []byte {
+ return append(b, // LE
+ byte(u),
+ byte(u>>8),
+ )
+}
+
+func append_uint32(b []byte, u uint32) []byte {
+ return append(b, // LE
+ byte(u),
+ byte(u>>8),
+ byte(u>>16),
+ byte(u>>24),
+ )
+}
+
+func append_uint64(b []byte, u uint64) []byte {
+ return append(b, // LE
+ byte(u),
+ byte(u>>8),
+ byte(u>>16),
+ byte(u>>24),
+ byte(u>>32),
+ byte(u>>40),
+ byte(u>>48),
+ byte(u>>56),
+ )
+}
+
+func empty_mangler(buf []byte, _ unsafe.Pointer) []byte {
+ return buf
+}
+
+// add returns the ptr addition of starting ptr and a delta.
+func add(ptr unsafe.Pointer, delta uintptr) unsafe.Pointer {
+ return unsafe.Pointer(uintptr(ptr) + delta)
+}
diff --git a/vendor/codeberg.org/gruf/go-mangler/v2/load.go b/vendor/codeberg.org/gruf/go-mangler/v2/load.go
new file mode 100644
index 000000000..8355c5f3c
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/load.go
@@ -0,0 +1,150 @@
+package mangler
+
+import (
+ "reflect"
+ "unsafe"
+
+ "codeberg.org/gruf/go-xunsafe"
+)
+
+// loadOrStore first checks the cache for a Mangler
+// function, else generates one by calling get().
+// note: this does store generated funcs in cache.
+func loadOrStore(t xunsafe.TypeIter) Mangler {
+
+ // Get cache key.
+ key := t.TypeInfo
+
+ // Check cache for func.
+ fn := manglers.Get(key)
+
+ if fn == nil {
+ // Generate new mangler
+ // func for this type.
+ fn = get(t)
+ if fn == nil {
+ return nil
+ }
+
+ // Store func in cache.
+ manglers.Put(key, fn)
+ }
+
+ return fn
+}
+
+// loadOrGet first checks the cache for a Mangler
+// function, else generates one by calling get().
+// note: it does not store the function in cache.
+func loadOrGet(t xunsafe.TypeIter) Mangler {
+
+ // Check cache for mangler func.
+ fn := manglers.Get(t.TypeInfo)
+
+ if fn == nil {
+ // Generate new mangler
+ // func for this type.
+ fn = get(t)
+ }
+
+ return fn
+}
+
+var (
+ // reflectTypeType is the reflected type of the reflect type,
+ // used in fmt.get() to prevent iter of internal ABI structs.
+ reflectTypeType = reflect.TypeOf(reflect.TypeOf(0))
+)
+
+// get attempts to generate a new Mangler function
+// capable of mangling a ptr of given type information.
+func get(t xunsafe.TypeIter) (fn Mangler) {
+ defer func() {
+ if fn == nil {
+ // nothing more
+ // we can do.
+ return
+ }
+
+ if t.Parent != nil {
+ // We're only interested
+ // in wrapping top-level.
+ return
+ }
+
+ // Get reflected type ptr for prefix.
+ ptr := xunsafe.ReflectTypeData(t.Type)
+ uptr := uintptr(ptr)
+
+ // Outer fn.
+ mng := fn
+
+ // Wrap the mangler func to prepend type pointer.
+ fn = func(buf []byte, ptr unsafe.Pointer) []byte {
+ buf = append_uint64(buf, uint64(uptr))
+ return mng(buf, ptr)
+ }
+ }()
+
+ if t.Type == nil {
+ // nil type.
+ return nil
+ }
+
+ if t.Type == reflectTypeType {
+ // DO NOT iterate down internal ABI
+ // types, some are in non-GC memory.
+ return nil
+ }
+
+ // Check supports known method receiver.
+ if fn := getMethodType(t); fn != nil {
+ return fn
+ }
+
+ if !visit(t) {
+ // On type recursion simply
+ // mangle as raw pointer.
+ return mangle_int
+ }
+
+ // Get func for type kind.
+ switch t.Type.Kind() {
+ case reflect.Pointer:
+ return derefPointerType(t)
+ case reflect.Struct:
+ return iterStructType(t)
+ case reflect.Array:
+ return iterArrayType(t)
+ case reflect.Slice:
+ return iterSliceType(t)
+ case reflect.Map:
+ return iterMapType(t)
+ case reflect.String:
+ return mangle_string
+ case reflect.Bool:
+ return mangle_bool
+ case reflect.Int,
+ reflect.Uint,
+ reflect.Uintptr:
+ return mangle_int
+ case reflect.Int8, reflect.Uint8:
+ return mangle_8bit
+ case reflect.Int16, reflect.Uint16:
+ return mangle_16bit
+ case reflect.Int32, reflect.Uint32:
+ return mangle_32bit
+ case reflect.Int64, reflect.Uint64:
+ return mangle_64bit
+ case reflect.Float32:
+ return mangle_32bit
+ case reflect.Float64:
+ return mangle_64bit
+ case reflect.Complex64:
+ return mangle_64bit
+ case reflect.Complex128:
+ return mangle_128bit
+ default:
+ return nil
+ }
+}
diff --git a/vendor/codeberg.org/gruf/go-mangler/v2/mangle.go b/vendor/codeberg.org/gruf/go-mangler/v2/mangle.go
new file mode 100644
index 000000000..0c746fc95
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/mangle.go
@@ -0,0 +1,93 @@
+package mangler
+
+import (
+ "fmt"
+ "unsafe"
+
+ "codeberg.org/gruf/go-xunsafe"
+)
+
+// Mangler is a function that will take an input value of known type,
+// and append it in mangled serialized form to the given byte buffer.
+type Mangler func(buf []byte, ptr unsafe.Pointer) []byte
+
+// Get will fetch the Mangler function for given runtime type information.
+// The required argument is of type xunsafe.TypeIter{} as unsafe pointer
+// access requires further contextual information like type nesting.
+func Get(t xunsafe.TypeIter) Mangler {
+ t.Parent = nil // enforce type prefix
+ fn := loadOrStore(t)
+ if fn == nil {
+ panic(fmt.Sprintf("cannot mangle type: %s", t.Type))
+ }
+ return fn
+}
+
+// GetNoLoad is functionally similar to Get(),
+// without caching the resulting Mangler.
+func GetNoLoad(t xunsafe.TypeIter) Mangler {
+ t.Parent = nil // enforce type prefix
+ fn := loadOrGet(t)
+ if fn == nil {
+ panic(fmt.Sprintf("cannot mangle type: %s", t.Type))
+ }
+ return fn
+}
+
+// Append will append the mangled form of input value 'a' to buffer 'b'.
+//
+// See mangler.String() for more information on mangled output.
+func Append(b []byte, a any) []byte {
+ t := xunsafe.TypeIterFrom(a)
+ p := xunsafe.UnpackEface(a)
+ return Get(t)(b, p)
+}
+
+// AppendMulti appends all mangled forms of input value(s) 'a' to buffer 'b'
+// separated by colon characters. When all type manglers are currently cached
+// for all types in 'a', this will be faster than multiple calls to Append().
+//
+// See mangler.String() for more information on mangled output.
+func AppendMulti(b []byte, a ...any) []byte {
+ if p := manglers.load(); p != nil {
+ b4 := len(b)
+ for _, a := range a {
+ t := xunsafe.TypeIterFrom(a)
+ m := (*p)[t.TypeInfo]
+ if m == nil {
+ b = b[:b4]
+ goto slow
+ }
+ b = m(b, xunsafe.UnpackEface(a))
+ b = append(b, '.')
+ }
+ return b
+ }
+slow:
+ for _, a := range a {
+ b = Append(b, a)
+ b = append(b, '.')
+ }
+ return b
+}
+
+// String will return the mangled format of input value 'a'. This
+// mangled output will be unique for all default supported input types
+// during a single runtime instance. Uniqueness cannot be guaranteed
+// between separate runtime instances (whether running concurrently, or
+// the same application running at different times).
+//
+// The exact formatting of the output data should not be relied upon,
+// only that it is unique given the above constraints. Generally though,
+// the mangled output is the binary formatted text of given input data.
+//
+// Uniqueness is guaranteed for similar input data of differing types
+// (e.g. string("hello world") vs. []byte("hello world")) by prefixing
+// mangled output with the input data's runtime type pointer.
+//
+// Default supported types include all concrete (i.e. non-interface{})
+// data types, and interfaces implementing Mangleable{}.
+func String(a any) string {
+ b := Append(make([]byte, 0, 32), a)
+ return *(*string)(unsafe.Pointer(&b))
+}
diff --git a/vendor/codeberg.org/gruf/go-mangler/manglers.go b/vendor/codeberg.org/gruf/go-mangler/v2/manglers.go
index 79bfe3c00..79bfe3c00 100644
--- a/vendor/codeberg.org/gruf/go-mangler/manglers.go
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/manglers.go
diff --git a/vendor/codeberg.org/gruf/go-mangler/v2/map.go b/vendor/codeberg.org/gruf/go-mangler/v2/map.go
new file mode 100644
index 000000000..986aca4b0
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/map.go
@@ -0,0 +1,80 @@
+package mangler
+
+import (
+ "unsafe"
+
+ "codeberg.org/gruf/go-xunsafe"
+)
+
+// iterMapType returns a Mangler capable of iterating
+// and mangling the given map type currently in TypeIter{}.
+// note this will fetch sub-Manglers for key / value types.
+func iterMapType(t xunsafe.TypeIter) Mangler {
+
+ // Key / value types.
+ key := t.Type.Key()
+ elem := t.Type.Elem()
+
+ // Get nested k / v TypeIters with appropriate flags.
+ flagsKey := xunsafe.ReflectMapKeyFlags(key)
+ flagsVal := xunsafe.ReflectMapElemFlags(elem)
+ kt := t.Child(key, flagsKey)
+ vt := t.Child(elem, flagsVal)
+
+ // Get key mangler.
+ kfn := loadOrGet(kt)
+ if kfn == nil {
+ return nil
+ }
+
+ // Get value mangler.
+ vfn := loadOrGet(vt)
+ if vfn == nil {
+ return nil
+ }
+
+ // Final map type.
+ rtype := t.Type
+ flags := t.Flag
+
+ return func(buf []byte, ptr unsafe.Pointer) []byte {
+ if ptr == nil || *(*unsafe.Pointer)(ptr) == nil {
+ // Append nil indicator.
+ buf = append(buf, '0')
+ return buf
+ }
+
+ // Build reflect value, and then a map iterator.
+ v := xunsafe.BuildReflectValue(rtype, ptr, flags)
+ i := xunsafe.GetMapIter(v)
+
+ // Before len.
+ l := len(buf)
+
+ // Append not-nil flag.
+ buf = append(buf, '1')
+
+ for i.Next() {
+ // Pass to map key func.
+ ptr = xunsafe.Map_Key(i)
+ buf = kfn(buf, ptr)
+
+ // Add key seperator.
+ buf = append(buf, ':')
+
+ // Pass to map elem func.
+ ptr = xunsafe.Map_Elem(i)
+ buf = vfn(buf, ptr)
+
+ // Add comma seperator.
+ buf = append(buf, ',')
+ }
+
+ if len(buf) != l {
+ // Drop final comma.
+ buf = buf[:len(buf)-1]
+ }
+
+ return buf
+ }
+}
diff --git a/vendor/codeberg.org/gruf/go-mangler/v2/method.go b/vendor/codeberg.org/gruf/go-mangler/v2/method.go
new file mode 100644
index 000000000..7a938d6ae
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/method.go
@@ -0,0 +1,105 @@
+package mangler
+
+import (
+ "reflect"
+ "unsafe"
+
+ "codeberg.org/gruf/go-xunsafe"
+)
+
+var (
+ // mangleable type for implement checks.
+ mangleableType = reflect.TypeFor[Mangleable]()
+)
+
+type Mangleable interface {
+ Mangle(dst []byte) []byte
+}
+
+// getMethodType returns a *possible* Mangler to handle case
+// of a type that implements any known interface{} types, else nil.
+func getMethodType(t xunsafe.TypeIter) Mangler {
+ switch {
+ case t.Type.Implements(mangleableType):
+ switch t.Type.Kind() {
+ case reflect.Interface:
+ return getInterfaceMangleableType(t)
+ default:
+ return getConcreteMangleableType(t)
+ }
+ default:
+ return nil
+ }
+}
+
+// getInterfaceMangleableType returns a Mangler to handle case of an interface{}
+// type that implements Mangleable{}, i.e. Mangleable{} itself and any superset of.
+func getInterfaceMangleableType(t xunsafe.TypeIter) Mangler {
+ switch t.Indirect() && !t.IfaceIndir() {
+ case true:
+ return func(buf []byte, ptr unsafe.Pointer) []byte {
+ ptr = *(*unsafe.Pointer)(ptr)
+ if ptr == nil || (*xunsafe.Abi_NonEmptyInterface)(ptr).Data == nil {
+ buf = append(buf, '0')
+ return buf
+ }
+ v := *(*Mangleable)(ptr)
+ buf = append(buf, '1')
+ buf = v.Mangle(buf)
+ return buf
+ }
+ case false:
+ return func(buf []byte, ptr unsafe.Pointer) []byte {
+ if ptr == nil || (*xunsafe.Abi_NonEmptyInterface)(ptr).Data == nil {
+ buf = append(buf, '0')
+ return buf
+ }
+ v := *(*Mangleable)(ptr)
+ buf = append(buf, '1')
+ buf = v.Mangle(buf)
+ return buf
+ }
+ default:
+ panic("unreachable")
+ }
+}
+
+// getConcreteMangleableType returns a Manlger to handle case of concrete
+// (i.e. non-interface{}) type that has a Mangleable{} method receiver.
+func getConcreteMangleableType(t xunsafe.TypeIter) Mangler {
+ itab := xunsafe.GetIfaceITab[Mangleable](t.Type)
+ switch {
+ case t.Indirect() && !t.IfaceIndir():
+ return func(buf []byte, ptr unsafe.Pointer) []byte {
+ ptr = *(*unsafe.Pointer)(ptr)
+ if ptr == nil {
+ buf = append(buf, '0')
+ return buf
+ }
+ v := *(*Mangleable)(xunsafe.PackIface(itab, ptr))
+ buf = append(buf, '1')
+ buf = v.Mangle(buf)
+ return buf
+ }
+ case t.Type.Kind() == reflect.Pointer && t.Type.Implements(mangleableType):
+ // if the interface implementation is received by
+ // value type, the pointer type will also support
+ // it but it requires an extra dereference check.
+ return func(buf []byte, ptr unsafe.Pointer) []byte {
+ if ptr == nil {
+ buf = append(buf, '0')
+ return buf
+ }
+ v := *(*Mangleable)(xunsafe.PackIface(itab, ptr))
+ buf = append(buf, '1')
+ buf = v.Mangle(buf)
+ return buf
+ }
+ default:
+ return func(buf []byte, ptr unsafe.Pointer) []byte {
+ v := *(*Mangleable)(xunsafe.PackIface(itab, ptr))
+ buf = v.Mangle(buf)
+ return buf
+ }
+ }
+}
diff --git a/vendor/codeberg.org/gruf/go-mangler/v2/pointer.go b/vendor/codeberg.org/gruf/go-mangler/v2/pointer.go
new file mode 100644
index 000000000..d732b2f67
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/pointer.go
@@ -0,0 +1,81 @@
+package mangler
+
+import (
+ "reflect"
+ "unsafe"
+
+ "codeberg.org/gruf/go-xunsafe"
+)
+
+// derefPointerType returns a Mangler capable of dereferencing
+// and formatting the given pointer type currently in TypeIter{}.
+// note this will fetch a sub-Mangler for resulting value type.
+func derefPointerType(t xunsafe.TypeIter) Mangler {
+ var derefs int
+ var indirects int64
+ rtype := t.Type
+ flags := t.Flag
+
+ // Iteratively dereference pointer types.
+ for rtype.Kind() == reflect.Pointer {
+
+ // Only if this is actual indirect memory do we
+ // perform a derefence, otherwise we just skip over
+ // and increase the dereference indicator, i.e. '1'.
+ if flags&xunsafe.Reflect_flagIndir != 0 {
+ indirects |= 1 << derefs
+ }
+ derefs++
+
+ // Get next elem type.
+ rtype = rtype.Elem()
+
+ // Get next set of dereferenced element type flags.
+ flags = xunsafe.ReflectPointerElemFlags(flags, rtype)
+ }
+
+ // Ensure this is a reasonable number of derefs.
+ if derefs > 4*int(unsafe.Sizeof(indirects)) {
+ return nil
+ }
+
+ // Wrap value as TypeIter.
+ vt := t.Child(rtype, flags)
+
+ // Get value mangler.
+ fn := loadOrGet(vt)
+ if fn == nil {
+ return nil
+ }
+
+ return func(buf []byte, ptr unsafe.Pointer) []byte {
+ for i := 0; i < derefs; i++ {
+ switch {
+ case indirects&1<<i == 0:
+ // No dereference needed.
+ buf = append(buf, '1')
+
+ case ptr == nil:
+ // Nil value, return here.
+ buf = append(buf, '0')
+ return buf
+
+ default:
+ // Further deref ptr.
+ buf = append(buf, '1')
+ ptr = *(*unsafe.Pointer)(ptr)
+ }
+ }
+
+ if ptr == nil {
+ // Final nil val check.
+ buf = append(buf, '0')
+ return buf
+ }
+
+ // Mangle fully deref'd.
+ buf = append(buf, '1')
+ buf = fn(buf, ptr)
+ return buf
+ }
+}
diff --git a/vendor/codeberg.org/gruf/go-mangler/v2/slice.go b/vendor/codeberg.org/gruf/go-mangler/v2/slice.go
new file mode 100644
index 000000000..0a68c0575
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/slice.go
@@ -0,0 +1,95 @@
+package mangler
+
+import (
+ "reflect"
+ "unsafe"
+
+ "codeberg.org/gruf/go-xunsafe"
+)
+
+// iterSliceType returns a Mangler capable of iterating
+// and mangling the given slice type currently in TypeIter{}.
+// note this will fetch sub-Mangler for slice element type.
+func iterSliceType(t xunsafe.TypeIter) Mangler {
+
+ // Get nested element type.
+ elem := t.Type.Elem()
+ esz := elem.Size()
+
+ // Get nested elem TypeIter{} with flags.
+ flags := xunsafe.ReflectSliceElemFlags(elem)
+ et := t.Child(elem, flags)
+
+ // Prefer to use a known slice mangler func.
+ if fn := mangleKnownSlice(et); fn != nil {
+ return fn
+ }
+
+ // Get elem mangler.
+ fn := loadOrGet(et)
+ if fn == nil {
+ return nil
+ }
+
+ return func(buf []byte, ptr unsafe.Pointer) []byte {
+ // Get data as unsafe slice header.
+ hdr := (*xunsafe.Unsafeheader_Slice)(ptr)
+ if hdr == nil || hdr.Data == nil {
+
+ // Append nil indicator.
+ buf = append(buf, '0')
+ return buf
+ }
+
+ // Append not-nil flag.
+ buf = append(buf, '1')
+
+ for i := 0; i < hdr.Len; i++ {
+ // Mangle at array index.
+ offset := esz * uintptr(i)
+ ptr = add(hdr.Data, offset)
+ buf = fn(buf, ptr)
+ buf = append(buf, ',')
+ }
+
+ if hdr.Len > 0 {
+ // Drop final comma.
+ buf = buf[:len(buf)-1]
+ }
+
+ return buf
+ }
+}
+
+// mangleKnownSlice loads a Mangler function for a
+// known slice-of-element type (in this case, primtives).
+func mangleKnownSlice(t xunsafe.TypeIter) Mangler {
+ switch t.Type.Kind() {
+ case reflect.String:
+ return mangle_string_slice
+ case reflect.Bool:
+ return mangle_bool_slice
+ case reflect.Int,
+ reflect.Uint,
+ reflect.Uintptr:
+ return mangle_int_slice
+ case reflect.Int8, reflect.Uint8:
+ return mangle_8bit_slice
+ case reflect.Int16, reflect.Uint16:
+ return mangle_16bit_slice
+ case reflect.Int32, reflect.Uint32:
+ return mangle_32bit_slice
+ case reflect.Int64, reflect.Uint64:
+ return mangle_64bit_slice
+ case reflect.Float32:
+ return mangle_32bit_slice
+ case reflect.Float64:
+ return mangle_64bit_slice
+ case reflect.Complex64:
+ return mangle_64bit_slice
+ case reflect.Complex128:
+ return mangle_128bit_slice
+ default:
+ return nil
+ }
+}
diff --git a/vendor/codeberg.org/gruf/go-mangler/v2/struct.go b/vendor/codeberg.org/gruf/go-mangler/v2/struct.go
new file mode 100644
index 000000000..e9672bf2b
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/struct.go
@@ -0,0 +1,75 @@
+package mangler
+
+import (
+ "unsafe"
+
+ "codeberg.org/gruf/go-xunsafe"
+)
+
+// field stores the minimum necessary
+// data for iterating and mangling
+// each field in a given struct.
+type field struct {
+ mangle Mangler
+ offset uintptr
+}
+
+// iterStructType returns a Mangler capable of iterating
+// and mangling the given struct type currently in TypeIter{}.
+// note this will fetch sub-Manglers for each struct field.
+func iterStructType(t xunsafe.TypeIter) Mangler {
+
+ // Number of struct fields.
+ n := t.Type.NumField()
+
+ // Gather mangler functions.
+ fields := make([]field, n)
+ for i := 0; i < n; i++ {
+
+ // Get struct field at index.
+ sfield := t.Type.Field(i)
+ rtype := sfield.Type
+
+ // Get nested field TypeIter with appropriate flags.
+ flags := xunsafe.ReflectStructFieldFlags(t.Flag, rtype)
+ ft := t.Child(sfield.Type, flags)
+
+ // Get field mangler.
+ fn := loadOrGet(ft)
+ if fn == nil {
+ return nil
+ }
+
+ // Set field info.
+ fields[i] = field{
+ mangle: fn,
+ offset: sfield.Offset,
+ }
+ }
+
+ // Handle no. fields.
+ switch len(fields) {
+ case 0:
+ return empty_mangler
+ case 1:
+ return fields[0].mangle
+ default:
+ return func(buf []byte, ptr unsafe.Pointer) []byte {
+ for i := range fields {
+ // Get struct field ptr via offset.
+ fptr := add(ptr, fields[i].offset)
+
+ // Mangle the struct field data.
+ buf = fields[i].mangle(buf, fptr)
+ buf = append(buf, ',')
+ }
+
+ if len(fields) > 0 {
+ // Drop final comma.
+ buf = buf[:len(buf)-1]
+ }
+
+ return buf
+ }
+ }
+}
diff --git a/vendor/codeberg.org/gruf/go-mangler/v2/type.go b/vendor/codeberg.org/gruf/go-mangler/v2/type.go
new file mode 100644
index 000000000..71be7f0b4
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/v2/type.go
@@ -0,0 +1,20 @@
+package mangler
+
+import (
+ "codeberg.org/gruf/go-xunsafe"
+)
+
+// visit checks if current type has already
+// appeared in the TypeIter{}'s parent heirarchy.
+func visit(iter xunsafe.TypeIter) bool {
+ t := iter.Type
+
+ // Check if type is already encountered further up tree.
+ for node := iter.Parent; node != nil; node = node.Parent {
+ if node.Type == t {
+ return false
+ }
+ }
+
+ return true
+}