summaryrefslogtreecommitdiff
path: root/vendor/codeberg.org/gruf/go-mangler/load.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/codeberg.org/gruf/go-mangler/load.go')
-rw-r--r--vendor/codeberg.org/gruf/go-mangler/load.go267
1 files changed, 267 insertions, 0 deletions
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)
+}