diff options
Diffstat (limited to 'vendor/codeberg.org/gruf/go-mangler/load.go')
-rw-r--r-- | vendor/codeberg.org/gruf/go-mangler/load.go | 267 |
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) +} |