gotosocial/vendor/codeberg.org/gruf/go-mangler/v2/mangle.go

94 lines
2.8 KiB
Go
Raw Normal View History

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))
}