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/LICENSE9
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/README.md41
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/helpers.go250
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/load.go267
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/mangle.go154
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/manglers.go190
6 files changed, 911 insertions, 0 deletions
diff --git a/vendor/codeberg.org/gruf/go-mangler/LICENSE b/vendor/codeberg.org/gruf/go-mangler/LICENSE
new file mode 100644
index 000000000..dffbdf0c9
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/LICENSE
@@ -0,0 +1,9 @@
+MIT License
+
+Copyright (c) 2023 gruf
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/codeberg.org/gruf/go-mangler/README.md b/vendor/codeberg.org/gruf/go-mangler/README.md
new file mode 100644
index 000000000..ef08a0d7b
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/README.md
@@ -0,0 +1,41 @@
+# go-mangler
+
+[Documentation](https://pkg.go.dev/codeberg.org/gruf/go-mangler).
+
+To put it simply is a bit of an odd library. It aims to provide incredibly fast, unique string outputs for all default supported input data types during a given runtime instance.
+
+It is useful, for example, for use as part of larger abstractions involving hashmaps. That was my particular usecase anyways...
+
+This package does make liberal use of the "unsafe" package.
+
+Benchmarks are below. Those with missing values panicked during our set of benchmarks, usually a case of not handling nil values elegantly. Please note the more important thing to notice here is the relative difference in benchmark scores, the actual `ns/op`,`B/op`,`allocs/op` accounts for running through over 80 possible test cases, including some not-ideal situations.
+
+The choice of libraries in the benchmark are just a selection of libraries that could be used in a similar manner to this one, i.e. serializing in some manner.
+
+```
+go test -run=none -benchmem -gcflags=all='-l=4' -bench=.*
+goos: linux
+goarch: amd64
+pkg: codeberg.org/gruf/go-mangler
+cpu: 11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz
+BenchmarkMangle
+BenchmarkMangle-8 877761 1323 ns/op 0 B/op 0 allocs/op
+BenchmarkMangleKnown
+BenchmarkMangleKnown-8 1462954 814.5 ns/op 0 B/op 0 allocs/op
+BenchmarkJSON
+BenchmarkJSON-8 199930 5910 ns/op 2698 B/op 119 allocs/op
+BenchmarkLoosy
+BenchmarkLoosy-8 307575 3718 ns/op 664 B/op 53 allocs/op
+BenchmarkBinary
+BenchmarkBinary-8 413216 2640 ns/op 3824 B/op 116 allocs/op
+BenchmarkFmt
+BenchmarkFmt-8 133429 8568 ns/op 3010 B/op 207 allocs/op
+BenchmarkFxmackerCbor
+BenchmarkFxmackerCbor-8 258562 4268 ns/op 2118 B/op 134 allocs/op
+BenchmarkMitchellhHashStructure
+BenchmarkMitchellhHashStructure-8 88941 13049 ns/op 10269 B/op 1096 allocs/op
+BenchmarkCnfStructhash
+BenchmarkCnfStructhash-8 5586 179537 ns/op 290373 B/op 5863 allocs/op
+PASS
+ok codeberg.org/gruf/go-mangler 12.469s
+```
diff --git a/vendor/codeberg.org/gruf/go-mangler/helpers.go b/vendor/codeberg.org/gruf/go-mangler/helpers.go
new file mode 100644
index 000000000..c7e91376e
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/helpers.go
@@ -0,0 +1,250 @@
+package mangler
+
+import (
+ "reflect"
+ "unsafe"
+
+ "github.com/modern-go/reflect2"
+)
+
+type (
+ byteser interface{ Bytes() []byte }
+ stringer interface{ String() string }
+ binarymarshaler interface{ MarshalBinary() ([]byte, error) }
+ textmarshaler interface{ MarshalText() ([]byte, error) }
+ jsonmarshaler interface{ MarshalJSON() ([]byte, error) }
+)
+
+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 deref_ptr_mangler(rtype reflect.Type, mangle Mangler, count int) Mangler {
+ if rtype == nil || mangle == nil || count == 0 {
+ panic("bad input")
+ }
+
+ // Get reflect2's type for later
+ // unsafe interface data repacking,
+ type2 := reflect2.Type2(rtype)
+
+ return func(buf []byte, value any) []byte {
+ // Get raw value data.
+ ptr := eface_data(value)
+
+ // Deref n - 1 number times.
+ for i := 0; i < count-1; 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 value check.
+ buf = append(buf, '0')
+ return buf
+ }
+
+ // Repack and mangle fully deref'd
+ value = type2.UnsafeIndirect(ptr)
+ buf = append(buf, '1')
+ return mangle(buf, value)
+ }
+}
+
+func iter_slice_mangler(rtype reflect.Type, mangle Mangler) Mangler {
+ if rtype == nil || mangle == nil {
+ panic("bad input")
+ }
+
+ // Get reflect2's type for later
+ // unsafe slice data manipulation.
+ slice2 := reflect2.Type2(rtype).(*reflect2.UnsafeSliceType)
+
+ return func(buf []byte, value any) []byte {
+ // Get raw value data.
+ ptr := eface_data(value)
+
+ // Get length of slice value.
+ n := slice2.UnsafeLengthOf(ptr)
+
+ for i := 0; i < n; i++ {
+ // Mangle data at each slice index.
+ e := slice2.UnsafeGetIndex(ptr, i)
+ buf = mangle(buf, e)
+ buf = append(buf, ',')
+ }
+
+ if n > 0 {
+ // Drop final comma.
+ buf = buf[:len(buf)-1]
+ }
+
+ return buf
+ }
+}
+
+func iter_array_mangler(rtype reflect.Type, mangle Mangler) Mangler {
+ if rtype == nil || mangle == nil {
+ panic("bad input")
+ }
+
+ // Get reflect2's type for later
+ // unsafe slice data manipulation.
+ array2 := reflect2.Type2(rtype).(*reflect2.UnsafeArrayType)
+ n := array2.Len()
+
+ return func(buf []byte, value any) []byte {
+ // Get raw value data.
+ ptr := eface_data(value)
+
+ for i := 0; i < n; i++ {
+ // Mangle data at each slice index.
+ e := array2.UnsafeGetIndex(ptr, i)
+ buf = mangle(buf, e)
+ buf = append(buf, ',')
+ }
+
+ if n > 0 {
+ // Drop final comma.
+ buf = buf[:len(buf)-1]
+ }
+
+ return buf
+ }
+}
+
+func iter_map_mangler(rtype reflect.Type, kmangle, emangle Mangler) Mangler {
+ if rtype == nil || kmangle == nil || emangle == nil {
+ panic("bad input")
+ }
+
+ // Get reflect2's type for later
+ // unsafe map data manipulation.
+ map2 := reflect2.Type2(rtype).(*reflect2.UnsafeMapType)
+ key2, elem2 := map2.Key(), map2.Elem()
+
+ return func(buf []byte, value any) []byte {
+ // Get raw value data.
+ ptr := eface_data(value)
+ ptr = indirect_ptr(ptr)
+
+ // Create iterator for map value.
+ iter := map2.UnsafeIterate(ptr)
+
+ // Check if empty map.
+ empty := !iter.HasNext()
+
+ for iter.HasNext() {
+ // Get key + elem data as ifaces.
+ kptr, eptr := iter.UnsafeNext()
+ key := key2.UnsafeIndirect(kptr)
+ elem := elem2.UnsafeIndirect(eptr)
+
+ // Mangle data for key + elem.
+ buf = kmangle(buf, key)
+ buf = append(buf, ':')
+ buf = emangle(buf, elem)
+ buf = append(buf, ',')
+ }
+
+ if !empty {
+ // Drop final comma.
+ buf = buf[:len(buf)-1]
+ }
+
+ return buf
+ }
+}
+
+func iter_struct_mangler(rtype reflect.Type, manglers []Mangler) Mangler {
+ if rtype == nil || len(manglers) != rtype.NumField() {
+ panic("bad input")
+ }
+
+ type field struct {
+ type2 reflect2.Type
+ field *reflect2.UnsafeStructField
+ mangle Mangler
+ }
+
+ // Get reflect2's type for later
+ // unsafe struct field data access.
+ struct2 := reflect2.Type2(rtype).(*reflect2.UnsafeStructType)
+
+ // Bundle together the fields and manglers.
+ fields := make([]field, rtype.NumField())
+ for i := range fields {
+ fields[i].field = struct2.Field(i).(*reflect2.UnsafeStructField)
+ fields[i].type2 = fields[i].field.Type()
+ fields[i].mangle = manglers[i]
+ if fields[i].type2 == nil ||
+ fields[i].field == nil ||
+ fields[i].mangle == nil {
+ panic("bad input")
+ }
+ }
+
+ return func(buf []byte, value any) []byte {
+ // Get raw value data.
+ ptr := eface_data(value)
+
+ for i := range fields {
+ // Get struct field as iface via offset.
+ fptr := fields[i].field.UnsafeGet(ptr)
+ field := fields[i].type2.UnsafeIndirect(fptr)
+
+ // Mangle the struct field data.
+ buf = fields[i].mangle(buf, field)
+ buf = append(buf, ',')
+ }
+
+ if len(fields) > 0 {
+ // Drop final comma.
+ buf = buf[:len(buf)-1]
+ }
+
+ return buf
+ }
+}
+
+func indirect_ptr(p unsafe.Pointer) unsafe.Pointer {
+ return unsafe.Pointer(&p)
+}
+
+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
new file mode 100644
index 000000000..c4d94cd7e
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/load.go
@@ -0,0 +1,267 @@
+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(a any, t reflect.Type) Mangler {
+ // Load mangler fn
+ mng := load(a, t)
+ 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(a any, t reflect.Type) Mangler {
+ if t == nil {
+ // There is no reflect type to search by
+ panic("cannot mangle nil interface{} type")
+ }
+
+ if a == nil {
+ // Alloc new iface instance
+ v := reflect.New(t).Elem()
+ a = v.Interface()
+ }
+
+ // Check for Mangled implementation.
+ if _, ok := a.(Mangled); ok {
+ return mangle_mangled
+ }
+
+ // Search mangler by reflection.
+ mng := loadReflect(t)
+ if mng != nil {
+ return mng
+ }
+
+ // Prefer iface mangler.
+ mng = loadIface(a)
+ if mng != nil {
+ return mng
+ }
+
+ return nil
+}
+
+// loadIface is used as a near-last-resort interface{} type switch
+// loader for types implementating other known (slower) functions.
+func loadIface(a any) Mangler {
+ switch a.(type) {
+ case binarymarshaler:
+ return mangle_binary
+ case byteser:
+ return mangle_byteser
+ case stringer:
+ return mangle_stringer
+ case textmarshaler:
+ return mangle_text
+ case jsonmarshaler:
+ return mangle_json
+ default:
+ 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(t reflect.Type) Mangler {
+ switch t.Kind() {
+ case reflect.Pointer:
+ return loadReflectPtr(t)
+
+ case reflect.String:
+ return mangle_string
+
+ case reflect.Struct:
+ return loadReflectStruct(t)
+
+ case reflect.Array:
+ return loadReflectArray(t)
+
+ case reflect.Slice:
+ return loadReflectSlice(t)
+
+ case reflect.Map:
+ return loadReflectMap(t)
+
+ case reflect.Bool:
+ return mangle_bool
+
+ case reflect.Int,
+ reflect.Uint,
+ reflect.Uintptr:
+ return mangle_platform_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(t reflect.Type) Mangler {
+ var count int
+
+ // Elem
+ et := t
+
+ // Iteratively dereference ptrs
+ for et.Kind() == reflect.Pointer {
+ et = et.Elem()
+ count++
+ }
+
+ // Search for ptr elemn type mangler.
+ if mng := load(nil, et); mng != nil {
+ return deref_ptr_mangler(et, mng, count)
+ }
+
+ return nil
+}
+
+// loadReflectKnownSlice loads a Mangler function for a
+// known slice-of-element type (in this case, primtives).
+func loadReflectKnownSlice(et reflect.Type) Mangler {
+ switch et.Kind() {
+ case reflect.String:
+ return mangle_string_slice
+
+ case reflect.Bool:
+ return mangle_bool_slice
+
+ case reflect.Int,
+ reflect.Uint,
+ reflect.Uintptr:
+ return mangle_platform_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(t reflect.Type) Mangler {
+ // Element type
+ et := t.Elem()
+
+ // Preferably look for known slice mangler func
+ if mng := loadReflectKnownSlice(et); mng != nil {
+ return mng
+ }
+
+ // Fallback to nested mangler iteration.
+ if mng := load(nil, et); mng != nil {
+ return iter_slice_mangler(t, mng)
+ }
+
+ return nil
+}
+
+// loadReflectArray ...
+func loadReflectArray(t reflect.Type) Mangler {
+ // Element type.
+ et := t.Elem()
+
+ // Use manglers for nested iteration.
+ if mng := load(nil, et); mng != nil {
+ return iter_array_mangler(t, mng)
+ }
+
+ return nil
+}
+
+// loadReflectMap ...
+func loadReflectMap(t reflect.Type) Mangler {
+ // Map types.
+ kt := t.Key()
+ et := t.Elem()
+
+ // Load manglers.
+ kmng := load(nil, kt)
+ emng := load(nil, et)
+
+ // Use manglers for nested iteration.
+ if kmng != nil && emng != nil {
+ return iter_map_mangler(t, kmng, emng)
+ }
+
+ return nil
+}
+
+// loadReflectStruct ...
+func loadReflectStruct(t reflect.Type) Mangler {
+ var mngs []Mangler
+
+ // Gather manglers for all fields.
+ for i := 0; i < t.NumField(); i++ {
+ field := t.Field(i)
+
+ // Load mangler for field type.
+ mng := load(nil, field.Type)
+ if mng == nil {
+ return nil
+ }
+
+ // Append next to map.
+ mngs = append(mngs, mng)
+ }
+
+ // Use manglers for nested iteration.
+ return iter_struct_mangler(t, mngs)
+}
diff --git a/vendor/codeberg.org/gruf/go-mangler/mangle.go b/vendor/codeberg.org/gruf/go-mangler/mangle.go
new file mode 100644
index 000000000..b44d26dc5
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/mangle.go
@@ -0,0 +1,154 @@
+package mangler
+
+import (
+ "reflect"
+ "sync"
+ "unsafe"
+)
+
+// manglers is a map of runtime
+// type ptrs => Mangler functions.
+var manglers sync.Map
+
+// Mangled is an interface that allows any type to implement a custom
+// Mangler function to improve performance when mangling this type.
+type Mangled interface{ Mangle(buf []byte) []byte }
+
+// 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, value any) []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(nil, t)
+ } else {
+ // cast cached value
+ mng = v.(Mangler)
+ }
+
+ // Get platform int mangler func.
+ mangle_int := mangle_platform_int()
+
+ return func(buf []byte, value any) []byte {
+ // Type check passed against original type.
+ if vt := reflect.TypeOf(value); vt != t {
+ return buf
+ }
+
+ // First write the type ptr (this adds
+ // a unique prefix for each runtime type).
+ buf = mangle_int(buf, uptr)
+
+ // Finally, mangle value
+ return mng(buf, value)
+ }
+}
+
+// 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 mangler into cache
+ mng = loadMangler(nil, t)
+ manglers.Store(uptr, mng)
+ } else {
+ // cast cached value
+ mng = v.(Mangler)
+ }
+
+ // Get platform int mangler func.
+ mangle_int := mangle_platform_int()
+
+ // First write the type ptr (this adds
+ // a unique prefix for each runtime type).
+ b = mangle_int(b, uptr)
+
+ // Finally, mangle value
+ return mng(b, a)
+}
+
+// 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
+// - time.Time{}
+// - url.URL{}
+// - net.IPAddr{}
+// - netip.Addr{}, netip.AddrPort{}
+// - mangler.Mangled{}
+// - fmt.Stringer{}
+// - json.Marshaler{}
+// - encoding.BinaryMarshaler{}
+// - encoding.TextMarshaler{}
+// - all pointers to the above
+// - all slices / arrays of the above
+// - all map keys / values 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/manglers.go b/vendor/codeberg.org/gruf/go-mangler/manglers.go
new file mode 100644
index 000000000..63cd82bbe
--- /dev/null
+++ b/vendor/codeberg.org/gruf/go-mangler/manglers.go
@@ -0,0 +1,190 @@
+package mangler
+
+import (
+ "math/bits"
+ _ "unsafe"
+)
+
+// Notes:
+// the use of unsafe conversion from the direct interface values to
+// the chosen types in each of the below functions allows us to convert
+// not only those types directly, but anything type-aliased to those
+// types. e.g. `time.Duration` directly as int64.
+
+func mangle_string(buf []byte, a any) []byte {
+ return append(buf, *(*string)(eface_data(a))...)
+}
+
+func mangle_string_slice(buf []byte, a any) []byte {
+ s := *(*[]string)(eface_data(a))
+ for _, s := range s {
+ buf = append(buf, s...)
+ buf = append(buf, ',')
+ }
+ if len(s) > 0 {
+ buf = buf[:len(buf)-1]
+ }
+ return buf
+}
+
+func mangle_bool(buf []byte, a any) []byte {
+ if *(*bool)(eface_data(a)) {
+ return append(buf, '1')
+ }
+ return append(buf, '0')
+}
+
+func mangle_bool_slice(buf []byte, a any) []byte {
+ for _, b := range *(*[]bool)(eface_data(a)) {
+ if b {
+ buf = append(buf, '1')
+ } else {
+ buf = append(buf, '0')
+ }
+ }
+ return buf
+}
+
+func mangle_8bit(buf []byte, a any) []byte {
+ return append(buf, *(*uint8)(eface_data(a)))
+}
+
+func mangle_8bit_slice(buf []byte, a any) []byte {
+ return append(buf, *(*[]uint8)(eface_data(a))...)
+}
+
+func mangle_16bit(buf []byte, a any) []byte {
+ return append_uint16(buf, *(*uint16)(eface_data(a)))
+}
+
+func mangle_16bit_slice(buf []byte, a any) []byte {
+ for _, u := range *(*[]uint16)(eface_data(a)) {
+ buf = append_uint16(buf, u)
+ }
+ return buf
+}
+
+func mangle_32bit(buf []byte, a any) []byte {
+ return append_uint32(buf, *(*uint32)(eface_data(a)))
+}
+
+func mangle_32bit_slice(buf []byte, a any) []byte {
+ for _, u := range *(*[]uint32)(eface_data(a)) {
+ buf = append_uint32(buf, u)
+ }
+ return buf
+}
+
+func mangle_64bit(buf []byte, a any) []byte {
+ return append_uint64(buf, *(*uint64)(eface_data(a)))
+}
+
+func mangle_64bit_slice(buf []byte, a any) []byte {
+ for _, u := range *(*[]uint64)(eface_data(a)) {
+ buf = append_uint64(buf, u)
+ }
+ return buf
+}
+
+func mangle_platform_int() Mangler {
+ switch bits.UintSize {
+ case 32:
+ return mangle_32bit
+ case 64:
+ return mangle_64bit
+ default:
+ panic("unexpected platform int size")
+ }
+}
+
+func mangle_platform_int_slice() Mangler {
+ switch bits.UintSize {
+ case 32:
+ return mangle_32bit_slice
+ case 64:
+ return mangle_64bit_slice
+ default:
+ panic("unexpected platform int size")
+ }
+}
+
+func mangle_128bit(buf []byte, a any) []byte {
+ u2 := *(*[2]uint64)(eface_data(a))
+ buf = append_uint64(buf, u2[0])
+ buf = append_uint64(buf, u2[1])
+ return buf
+}
+
+func mangle_128bit_slice(buf []byte, a any) []byte {
+ for _, u2 := range *(*[][2]uint64)(eface_data(a)) {
+ buf = append_uint64(buf, u2[0])
+ buf = append_uint64(buf, u2[1])
+ }
+ return buf
+}
+
+func mangle_mangled(buf []byte, a any) []byte {
+ if v := a.(Mangled); v != nil {
+ buf = append(buf, '1')
+ return v.Mangle(buf)
+ }
+ buf = append(buf, '0')
+ return buf
+}
+
+func mangle_binary(buf []byte, a any) []byte {
+ if v := a.(binarymarshaler); v != nil {
+ b, err := v.MarshalBinary()
+ if err != nil {
+ panic("mangle_binary: " + err.Error())
+ }
+ buf = append(buf, '1')
+ return append(buf, b...)
+ }
+ buf = append(buf, '0')
+ return buf
+}
+
+func mangle_byteser(buf []byte, a any) []byte {
+ if v := a.(byteser); v != nil {
+ buf = append(buf, '1')
+ return append(buf, v.Bytes()...)
+ }
+ buf = append(buf, '0')
+ return buf
+}
+
+func mangle_stringer(buf []byte, a any) []byte {
+ if v := a.(stringer); v != nil {
+ buf = append(buf, '1')
+ return append(buf, v.String()...)
+ }
+ buf = append(buf, '0')
+ return buf
+}
+
+func mangle_text(buf []byte, a any) []byte {
+ if v := a.(textmarshaler); v != nil {
+ b, err := v.MarshalText()
+ if err != nil {
+ panic("mangle_text: " + err.Error())
+ }
+ buf = append(buf, '1')
+ return append(buf, b...)
+ }
+ buf = append(buf, '0')
+ return buf
+}
+
+func mangle_json(buf []byte, a any) []byte {
+ if v := a.(jsonmarshaler); v != nil {
+ b, err := v.MarshalJSON()
+ if err != nil {
+ panic("mangle_json: " + err.Error())
+ }
+ buf = append(buf, '1')
+ return append(buf, b...)
+ }
+ buf = append(buf, '0')
+ return buf
+}