[chore] update dependencies (#4361)

- codeberg.org/gruf/go-kv/v2 v2.0.5 => v2.0.6
- github.com/coreos/go-oidc/v3 v3.14.1 => v3.15.0
- github.com/miekg/dns v1.1.67 => v1.1.68
- github.com/tdewolff/minify/v2 v2.23.9 => v2.23.11
- github.com/yuin/goldmark v1.7.12 => v1.7.13
- golang.org/x/crypto v0.40.0 => v0.41.0
- golang.org/x/image v0.29.0 => v0.30.0
- golang.org/x/net v0.42.0 => v0.43.0
- golang.org/x/sys v0.34.0 => v0.35.0
- golang.org/x/text v0.27.0 => v0.28.0
- modernc.org/sqlite v1.38.0 => v1.38.2

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4361
Co-authored-by: kim <grufwub@gmail.com>
Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
kim 2025-08-10 15:05:54 +02:00 committed by kim
commit 67100809b3
111 changed files with 49874 additions and 40191 deletions

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 gruf
Copyright (c) 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:

View file

@ -5,88 +5,10 @@ package format
import (
"reflect"
"unsafe"
"codeberg.org/gruf/go-xunsafe"
)
const (
// see: go/src/internal/abi/type.go
abi_KindDirectIface uint8 = 1 << 5
abi_KindMask uint8 = (1 << 5) - 1
)
// abi_Type is a copy of the memory layout of abi.Type{}.
//
// see: go/src/internal/abi/type.go
type abi_Type struct {
_ uintptr
PtrBytes uintptr
_ uint32
_ uint8
_ uint8
_ uint8
Kind_ uint8
_ func(unsafe.Pointer, unsafe.Pointer) bool
_ *byte
_ int32
_ int32
}
// abi_EmptyInterface is a copy of the memory layout of abi.EmptyInterface{},
// which is to say also the memory layout of any method-less interface.
//
// see: go/src/internal/abi/iface.go
type abi_EmptyInterface struct {
Type *abi_Type
Data unsafe.Pointer
}
// abi_NonEmptyInterface is a copy of the memory layout of abi.NonEmptyInterface{},
// which is to say also the memory layout of any interface containing method(s).
//
// see: go/src/internal/abi/iface.go on 1.25+
// see: go/src/reflect/value.go on 1.24
type abi_NonEmptyInterface struct {
ITab uintptr
Data unsafe.Pointer
}
// see: go/src/internal/abi/type.go Type.Kind()
func abi_Type_Kind(t reflect.Type) uint8 {
iface := (*abi_NonEmptyInterface)(unsafe.Pointer(&t))
atype := (*abi_Type)(unsafe.Pointer(iface.Data))
return atype.Kind_ & abi_KindMask
}
// see: go/src/internal/abi/type.go Type.IfaceIndir()
func abi_Type_IfaceIndir(t reflect.Type) bool {
iface := (*abi_NonEmptyInterface)(unsafe.Pointer(&t))
atype := (*abi_Type)(unsafe.Pointer(iface.Data))
return atype.Kind_&abi_KindDirectIface == 0
}
// pack_iface packs a new reflect.nonEmptyInterface{} using shielded
// itab and data pointer, returning a pointer for caller casting.
func pack_iface(itab uintptr, word unsafe.Pointer) unsafe.Pointer {
return unsafe.Pointer(&abi_NonEmptyInterface{
ITab: itab,
Data: word,
})
}
// get_iface_ITab generates a new value of given type,
// casts it to the generic param interface type, and
// returns the .itab portion of the reflect.nonEmptyInterface{}.
// this is useful for later calls to pack_iface for known type.
func get_iface_ITab[I any](t reflect.Type) uintptr {
s := reflect.New(t).Elem().Interface().(I)
i := (*abi_NonEmptyInterface)(unsafe.Pointer(&s))
return i.ITab
}
// unpack_eface returns the .Data portion of an abi.EmptyInterface{}.
func unpack_eface(a any) unsafe.Pointer {
return (*abi_EmptyInterface)(unsafe.Pointer((&a))).Data
}
// 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)
@ -97,167 +19,7 @@ func typeof[T any]() reflect.Type {
return reflect.TypeFor[T]()
}
// see: go/src/reflect/value.go
type reflect_flag uintptr
const (
// see: go/src/reflect/value.go
reflect_flagKindWidth = 5 // there are 27 kinds
reflect_flagKindMask reflect_flag = 1<<reflect_flagKindWidth - 1
reflect_flagStickyRO reflect_flag = 1 << 5
reflect_flagEmbedRO reflect_flag = 1 << 6
reflect_flagIndir reflect_flag = 1 << 7
reflect_flagAddr reflect_flag = 1 << 8
reflect_flagMethod reflect_flag = 1 << 9
reflect_flagMethodShift = 10
reflect_flagRO reflect_flag = reflect_flagStickyRO | reflect_flagEmbedRO
// custom flag to indicate key types.
flagKeyType = 1 << 10
// custom xunsafe.Reflect_flag to indicate key types.
flagKeyType xunsafe.Reflect_flag = 1 << 10
)
// reflect_iface_elem_flags returns the reflect_flag expected of an unboxed interface element of type.
//
// see: go/src/reflect/value.go unpackElem()
func reflect_iface_elem_flags(elemType reflect.Type) reflect_flag {
if elemType == nil {
return 0
}
flags := reflect_flag(abi_Type_Kind(elemType))
if abi_Type_IfaceIndir(elemType) {
flags |= reflect_flagIndir
}
return flags
}
// reflect_pointer_elem_flags returns the reflect_flag expected of a dereferenced pointer element of type.
//
// see: go/src/reflect/value.go Value.Elem()
func reflect_pointer_elem_flags(ptrFlags reflect_flag, elemType reflect.Type) reflect_flag {
return ptrFlags | reflect_flagIndir | reflect_flagAddr | reflect_flag(abi_Type_Kind(elemType))
}
// reflect_array_elem_flags returns the reflect_flag expected of an element of type in an array.
//
// see: go/src/reflect/value.go Value.Index()
func reflect_array_elem_flags(arrayFlags reflect_flag, elemType reflect.Type) reflect_flag {
return arrayFlags&(reflect_flagIndir|reflect_flagAddr) | reflect_flag(abi_Type_Kind(elemType))
}
// reflect_slice_elem_flags returns the reflect_flag expected of a slice element of type.
//
// see: go/src/reflect/value.go Value.Index()
func reflect_slice_elem_flags(elemType reflect.Type) reflect_flag {
return reflect_flagAddr | reflect_flagIndir | reflect_flag(abi_Type_Kind(elemType))
}
// reflect_struct_field_flags returns the reflect_flag expected of a struct field of type.
//
// see: go/src/reflect/value.go Value.Field()
func reflect_struct_field_flags(structFlags reflect_flag, fieldType reflect.Type) reflect_flag {
return structFlags&(reflect_flagIndir|reflect_flagAddr) | reflect_flag(abi_Type_Kind(fieldType))
}
// reflect_map_key_flags returns the reflect_flag expected of a map key of type (with our own key type mask set).
//
// see: go/src/reflect/map_swiss.go MapIter.Key()
func reflect_map_key_flags(keyType reflect.Type) reflect_flag {
return flagKeyType | reflect_flag(abi_Type_Kind(keyType))
}
// reflect_map_elem_flags returns the reflect_flag expected of a map element of type.
//
// see: go/src/reflect/map_swiss.go MapIter.Value()
func reflect_map_elem_flags(elemType reflect.Type) reflect_flag {
return reflect_flag(abi_Type_Kind(elemType))
}
// reflect_Value is a copy of the memory layout of reflect.Value{}.
//
// see: go/src/reflect/value.go
type reflect_Value struct {
typ_ unsafe.Pointer
ptr unsafe.Pointer
reflect_flag
}
func init() {
if unsafe.Sizeof(reflect_Value{}) != unsafe.Sizeof(reflect.Value{}) {
panic("reflect_Value{} not in sync with reflect.Value{}")
}
}
// reflect_type_data returns the .word from the reflect.Type{} cast
// as the reflect.nonEmptyInterface{}, which itself will be a pointer
// to the actual abi.Type{} that this reflect.Type{} is wrapping.
func reflect_type_data(t reflect.Type) unsafe.Pointer {
return (*abi_NonEmptyInterface)(unsafe.Pointer(&t)).Data
}
// build_reflect_value manually builds a reflect.Value{} by setting the internal field members.
func build_reflect_value(rtype reflect.Type, data unsafe.Pointer, flags reflect_flag) reflect.Value {
return *(*reflect.Value)(unsafe.Pointer(&reflect_Value{reflect_type_data(rtype), data, flags}))
}
// maps_Iter is a copy of the memory layout of maps.Iter{}.
//
// see: go/src/internal/runtime/maps/table.go
type maps_Iter struct {
key unsafe.Pointer
elem unsafe.Pointer
_ uintptr
_ uintptr
_ uint64
_ uint64
_ uint64
_ uint8
_ int
_ uintptr
_ struct{ _ unsafe.Pointer }
_ uint64
}
// reflect_MapIter is a copy of the memory layout of reflect.MapIter{}.
//
// see: go/src/reflect/map_swiss.go
type reflect_MapIter struct {
m reflect.Value
hiter maps_Iter
}
func init() {
if unsafe.Sizeof(reflect_MapIter{}) != unsafe.Sizeof(reflect.MapIter{}) {
panic("reflect_MapIter{} not in sync with reflect.MapIter{}")
}
}
// map_iter creates a new map iterator from value,
// skipping the initial v.MapRange() type checking.
func map_iter(v reflect.Value) *reflect.MapIter {
var i reflect_MapIter
i.m = v
return (*reflect.MapIter)(unsafe.Pointer(&i))
}
// map_key returns ptr to current map key in iter.
func map_key(i *reflect.MapIter) unsafe.Pointer {
return (*reflect_MapIter)(unsafe.Pointer(i)).hiter.key
}
// map_elem returns ptr to current map element in iter.
func map_elem(i *reflect.MapIter) unsafe.Pointer {
return (*reflect_MapIter)(unsafe.Pointer(i)).hiter.elem
}
// see: go/src/internal/unsafeheader/unsafeheader.go
type unsafeheader_Slice struct {
Data unsafe.Pointer
Len int
Cap int
}
// see: go/src/internal/unsafeheader/unsafeheader.go
type unsafeheader_String struct {
Data unsafe.Pointer
Len int
}

View file

@ -1,19 +1,23 @@
package format
import "unsafe"
import (
"unsafe"
"codeberg.org/gruf/go-xunsafe"
)
// iterArrayType returns a FormatFunc capable of iterating
// and formatting the given array type currently in typenode{}.
// and formatting the given array type currently in TypeIter{}.
// note this will fetch a sub-FormatFunc for the array element
// type, and also handle special cases of [n]byte, [n]rune arrays.
func (fmt *Formatter) iterArrayType(t typenode) FormatFunc {
func (fmt *Formatter) iterArrayType(t xunsafe.TypeIter) FormatFunc {
// Array element type.
elem := t.rtype.Elem()
elem := t.Type.Elem()
// Get nested elem typenode with appropriate flags.
flags := reflect_array_elem_flags(t.flags, elem)
et := t.next(elem, flags)
// Get nested elem TypeIter with appropriate flags.
flags := xunsafe.ReflectArrayElemFlags(t.Flag, elem)
et := t.Child(elem, flags)
// Get elem format func.
fn := fmt.loadOrGet(et)
@ -22,7 +26,7 @@ func (fmt *Formatter) iterArrayType(t typenode) FormatFunc {
}
// Handle possible sizes.
switch t.rtype.Len() {
switch t.Type.Len() {
case 0:
return emptyArrayType(t)
case 1:
@ -32,8 +36,8 @@ func (fmt *Formatter) iterArrayType(t typenode) FormatFunc {
}
}
func emptyArrayType(t typenode) FormatFunc {
if !t.needs_typestr() {
func emptyArrayType(t xunsafe.TypeIter) FormatFunc {
if !needs_typestr(t) {
// Simply append empty.
return func(s *State) {
s.B = append(s.B, "[]"...)
@ -41,7 +45,7 @@ func emptyArrayType(t typenode) FormatFunc {
}
// Array type string with refs.
typestr := t.typestr_with_refs()
typestr := typestr_with_refs(t)
// Append empty with type.
return func(s *State) {
@ -54,8 +58,8 @@ func emptyArrayType(t typenode) FormatFunc {
}
}
func iterSingleArrayType(t typenode, fn FormatFunc) FormatFunc {
if !t.needs_typestr() {
func iterSingleArrayType(t xunsafe.TypeIter, fn FormatFunc) FormatFunc {
if !needs_typestr(t) {
return func(s *State) {
// Wrap 'fn' in braces.
s.B = append(s.B, '[')
@ -65,7 +69,7 @@ func iterSingleArrayType(t typenode, fn FormatFunc) FormatFunc {
}
// Array type string with refs.
typestr := t.typestr_with_refs()
typestr := typestr_with_refs(t)
// Wrap in type+braces.
return func(s *State) {
@ -87,14 +91,14 @@ func iterSingleArrayType(t typenode, fn FormatFunc) FormatFunc {
}
}
func iterMultiArrayType(t typenode, fn FormatFunc) FormatFunc {
func iterMultiArrayType(t xunsafe.TypeIter, fn FormatFunc) FormatFunc {
// Array element in-memory size.
esz := t.rtype.Elem().Size()
esz := t.Type.Elem().Size()
// Number of elements.
n := t.rtype.Len()
n := t.Type.Len()
if !t.needs_typestr() {
if !needs_typestr(t) {
// Wrap elems in braces.
return func(s *State) {
ptr := s.P
@ -121,7 +125,7 @@ func iterMultiArrayType(t typenode, fn FormatFunc) FormatFunc {
}
// Array type string with refs.
typestr := t.typestr_with_refs()
typestr := typestr_with_refs(t)
// Wrap in type+braces.
return func(s *State) {
@ -158,13 +162,13 @@ func iterMultiArrayType(t typenode, fn FormatFunc) FormatFunc {
}
}
func wrapByteArray(t typenode, fn FormatFunc) FormatFunc {
n := t.rtype.Len()
if !t.needs_typestr() {
func wrapByteArray(t xunsafe.TypeIter, fn FormatFunc) FormatFunc {
n := t.Type.Len()
if !needs_typestr(t) {
return func(s *State) {
if s.A.AsText() || s.A.AsQuotedText() || s.A.AsQuotedASCII() {
var v string
p := (*unsafeheader_String)(unsafe.Pointer(&v))
p := (*xunsafe.Unsafeheader_String)(unsafe.Pointer(&v))
p.Len = n
p.Data = s.P
appendString(s, v)
@ -173,11 +177,11 @@ func wrapByteArray(t typenode, fn FormatFunc) FormatFunc {
}
}
}
typestr := t.typestr_with_ptrs()
typestr := typestr_with_ptrs(t)
return func(s *State) {
if s.A.AsText() || s.A.AsQuotedText() || s.A.AsQuotedASCII() {
var v string
p := (*unsafeheader_String)(unsafe.Pointer(&v))
p := (*xunsafe.Unsafeheader_String)(unsafe.Pointer(&v))
p.Len = n
p.Data = s.P
if s.A.WithType() {
@ -193,13 +197,13 @@ func wrapByteArray(t typenode, fn FormatFunc) FormatFunc {
}
}
func wrapRuneArray(t typenode, fn FormatFunc) FormatFunc {
n := t.rtype.Len()
if !t.needs_typestr() {
func wrapRuneArray(t xunsafe.TypeIter, fn FormatFunc) FormatFunc {
n := t.Type.Len()
if !needs_typestr(t) {
return func(s *State) {
if s.A.AsText() || s.A.AsQuotedText() || s.A.AsQuotedASCII() {
var v []rune
p := (*unsafeheader_Slice)(unsafe.Pointer(&v))
p := (*xunsafe.Unsafeheader_Slice)(unsafe.Pointer(&v))
p.Cap = n
p.Len = n
p.Data = s.P
@ -209,11 +213,11 @@ func wrapRuneArray(t typenode, fn FormatFunc) FormatFunc {
}
}
}
typestr := t.typestr_with_ptrs()
typestr := typestr_with_ptrs(t)
return func(s *State) {
if s.A.AsText() || s.A.AsQuotedText() || s.A.AsQuotedASCII() {
var v []rune
p := (*unsafeheader_Slice)(unsafe.Pointer(&v))
p := (*xunsafe.Unsafeheader_Slice)(unsafe.Pointer(&v))
p.Cap = n
p.Len = n
p.Data = s.P

60
vendor/codeberg.org/gruf/go-kv/v2/format/cache.go generated vendored Normal file
View file

@ -0,0 +1,60 @@
package format
import (
"sync/atomic"
"unsafe"
"codeberg.org/gruf/go-xunsafe"
)
// cache is a concurrency-safe map[xunsafe.TypeInfo]FormatFunc
// 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 format func under key.
func (c *cache) Get(t xunsafe.TypeInfo) FormatFunc {
if p := c.load(); p != nil {
return (*p)[t]
}
return nil
}
// Put will place given format func in cache under key, if not already exists.
func (c *cache) Put(t xunsafe.TypeInfo, fn FormatFunc) {
for {
p := c.load()
var cache map[xunsafe.TypeInfo]FormatFunc
if p != nil {
if _, ok := (*p)[t]; ok {
return
}
cache = make(map[xunsafe.TypeInfo]FormatFunc, len(*p)+1)
for key, value := range *p {
cache[key] = value
}
} else {
cache = make(map[xunsafe.TypeInfo]FormatFunc, 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]FormatFunc {
return (*map[xunsafe.TypeInfo]FormatFunc)(atomic.LoadPointer(&c.p))
}
// cas is a typed wrapper around atomic.CompareAndSwapPointer().
func (c *cache) cas(old, new *map[xunsafe.TypeInfo]FormatFunc) bool {
return atomic.CompareAndSwapPointer(&c.p, unsafe.Pointer(old), unsafe.Pointer(new))
}

View file

@ -4,8 +4,9 @@ import (
"reflect"
"runtime/debug"
"strconv"
"sync"
"unsafe"
"codeberg.org/gruf/go-xunsafe"
)
// Global formatter instance.
@ -93,15 +94,7 @@ type Formatter struct {
// internal
// format func
// cache map.
fns sync.Map
}
// LoadFor returns a FormatFunc for the given value type.
func (fmt *Formatter) LoadFor(value any) FormatFunc {
rtype := reflect.TypeOf(value)
flags := reflect_iface_elem_flags(rtype)
t := new_typenode(rtype, flags)
return fmt.loadOrStore(t)
fns cache
}
// Append calls AppendState() with a newly allocated State{}, returning byte buffer.
@ -126,17 +119,17 @@ func (fmt *Formatter) AppendState(s *State, value any) {
// global defaults.
s.A = defaultArgs
}
s.P = unpack_eface(value)
t := xunsafe.TypeIterFrom(value)
s.P = xunsafe.UnpackEface(value)
s.ifaces.clear()
s.ifaces.set(s.P)
fmt.LoadFor(value)(s)
fmt.loadOrStore(t)(s)
}
func (fmt *Formatter) loadOrGet(t typenode) FormatFunc {
func (fmt *Formatter) loadOrGet(t xunsafe.TypeIter) FormatFunc {
// Look for existing stored
// func under this type key.
v, _ := fmt.fns.Load(t.key())
fn, _ := v.(FormatFunc)
fn := fmt.fns.Get(t.TypeInfo)
if fn == nil {
// Load format func
@ -150,14 +143,13 @@ func (fmt *Formatter) loadOrGet(t typenode) FormatFunc {
return fn
}
func (fmt *Formatter) loadOrStore(t typenode) FormatFunc {
func (fmt *Formatter) loadOrStore(t xunsafe.TypeIter) FormatFunc {
// Get cache key.
key := t.key()
key := t.TypeInfo
// Look for existing stored
// func under this type key.
v, _ := fmt.fns.Load(key)
fn, _ := v.(FormatFunc)
fn := fmt.fns.Get(key)
if fn == nil {
// Load format func
@ -167,8 +159,8 @@ func (fmt *Formatter) loadOrStore(t typenode) FormatFunc {
panic("unreachable")
}
// Store in map under type.
fmt.fns.Store(key, fn)
// Store under type.
fmt.fns.Put(key, fn)
}
return fn
@ -188,8 +180,8 @@ var (
runesType = typeof[[]rune]()
)
func (fmt *Formatter) get(t typenode) (fn FormatFunc) {
if t.rtype == nil {
func (fmt *Formatter) get(t xunsafe.TypeIter) (fn FormatFunc) {
if t.Type == nil {
// catch nil type.
return appendNil
}
@ -205,7 +197,7 @@ func (fmt *Formatter) get(t typenode) (fn FormatFunc) {
// Don't allow method functions for map keys,
// to prevent situation of the method receiver
// attempting to modify stored map key itself.
if t.flags&flagKeyType != 0 {
if t.Flag&flagKeyType != 0 {
return
}
@ -228,20 +220,20 @@ func (fmt *Formatter) get(t typenode) (fn FormatFunc) {
}
}()
if t.rtype == reflectTypeType {
if t.Type == reflectTypeType {
// DO NOT iterate down internal ABI
// types, some are in non-GC memory.
return getPointerType(t)
}
if !t.visit() {
if !visit(t) {
// On type recursion simply
// format as raw pointer.
return getPointerType(t)
}
// Get func for type kind.
switch t.rtype.Kind() {
switch t.Type.Kind() {
case reflect.Interface:
return fmt.getInterfaceType(t)
case reflect.String:
@ -269,7 +261,7 @@ func (fmt *Formatter) get(t typenode) (fn FormatFunc) {
case reflect.Pointer:
return fmt.derefPointerType(t)
case reflect.Array:
elem := t.rtype.Elem()
elem := t.Type.Elem()
switch fn := fmt.iterArrayType(t); {
case elem.AssignableTo(byteType):
return wrapByteArray(t, fn)
@ -280,9 +272,9 @@ func (fmt *Formatter) get(t typenode) (fn FormatFunc) {
}
case reflect.Slice:
switch fn := fmt.iterSliceType(t); {
case t.rtype.AssignableTo(bytesType):
case t.Type.AssignableTo(bytesType):
return wrapByteSlice(t, fn)
case t.rtype.AssignableTo(runesType):
case t.Type.AssignableTo(runesType):
return wrapRuneSlice(t, fn)
default:
return fn
@ -296,12 +288,12 @@ func (fmt *Formatter) get(t typenode) (fn FormatFunc) {
}
}
func (fmt *Formatter) getInterfaceType(t typenode) FormatFunc {
if t.rtype.NumMethod() == 0 {
func (fmt *Formatter) getInterfaceType(t xunsafe.TypeIter) FormatFunc {
if t.Type.NumMethod() == 0 {
return func(s *State) {
// Unpack empty interface.
eface := *(*any)(s.P)
s.P = unpack_eface(eface)
s.P = xunsafe.UnpackEface(eface)
// Get reflected type information.
rtype := reflect.TypeOf(eface)
@ -319,9 +311,10 @@ func (fmt *Formatter) getInterfaceType(t typenode) FormatFunc {
// Store value ptr.
s.ifaces.set(s.P)
// Wrap in our typenode for before load.
flags := reflect_iface_elem_flags(rtype)
t := new_typenode(rtype, flags)
// Wrap before load.
var t xunsafe.TypeIter
t.Flag = xunsafe.ReflectIfaceElemFlags(rtype)
t.Type = rtype
// Load + pass to func.
fmt.loadOrStore(t)(s)
@ -330,7 +323,7 @@ func (fmt *Formatter) getInterfaceType(t typenode) FormatFunc {
return func(s *State) {
// Unpack interface-with-method ptr.
iface := *(*interface{ M() })(s.P)
s.P = unpack_eface(iface)
s.P = xunsafe.UnpackEface(iface)
// Get reflected type information.
rtype := reflect.TypeOf(iface)
@ -348,9 +341,10 @@ func (fmt *Formatter) getInterfaceType(t typenode) FormatFunc {
// Store value ptr.
s.ifaces.set(s.P)
// Wrap in our typenode for before load.
flags := reflect_iface_elem_flags(rtype)
t := new_typenode(rtype, flags)
// Wrap before load.
var t xunsafe.TypeIter
t.Flag = xunsafe.ReflectIfaceElemFlags(rtype)
t.Type = rtype
// Load + pass to func.
fmt.loadOrStore(t)(s)
@ -358,20 +352,20 @@ func (fmt *Formatter) getInterfaceType(t typenode) FormatFunc {
}
}
func getStringType(t typenode) FormatFunc {
func getStringType(t xunsafe.TypeIter) FormatFunc {
return with_typestr_ptrs(t, func(s *State) {
appendString(s, *(*string)(s.P))
})
}
func getBoolType(t typenode) FormatFunc {
func getBoolType(t xunsafe.TypeIter) FormatFunc {
return with_typestr_ptrs(t, func(s *State) {
s.B = strconv.AppendBool(s.B, *(*bool)(s.P))
})
}
func getIntType(t typenode) FormatFunc {
switch t.rtype.Bits() {
func getIntType(t xunsafe.TypeIter) FormatFunc {
switch t.Type.Bits() {
case 8:
return with_typestr_ptrs(t, func(s *State) {
appendInt(s, int64(*(*int8)(s.P)))
@ -403,8 +397,8 @@ func getIntType(t typenode) FormatFunc {
}
}
func getUintType(t typenode) FormatFunc {
switch t.rtype.Bits() {
func getUintType(t xunsafe.TypeIter) FormatFunc {
switch t.Type.Bits() {
case 8:
return with_typestr_ptrs(t, func(s *State) {
switch {
@ -433,8 +427,8 @@ func getUintType(t typenode) FormatFunc {
}
}
func getFloatType(t typenode) FormatFunc {
switch t.rtype.Bits() {
func getFloatType(t xunsafe.TypeIter) FormatFunc {
switch t.Type.Bits() {
case 32:
return with_typestr_ptrs(t, func(s *State) {
appendFloat(s, float64(*(*float32)(s.P)), 32)
@ -448,8 +442,8 @@ func getFloatType(t typenode) FormatFunc {
}
}
func getComplexType(t typenode) FormatFunc {
switch t.rtype.Bits() {
func getComplexType(t xunsafe.TypeIter) FormatFunc {
switch t.Type.Bits() {
case 64:
return with_typestr_ptrs(t, func(s *State) {
v := *(*complex64)(s.P)
@ -467,8 +461,8 @@ func getComplexType(t typenode) FormatFunc {
}
}
func getPointerType(t typenode) FormatFunc {
switch t.indirect() {
func getPointerType(t xunsafe.TypeIter) FormatFunc {
switch t.Indirect() {
case true:
return with_typestr_ptrs(t, func(s *State) {
s.P = *(*unsafe.Pointer)(s.P)
@ -483,18 +477,18 @@ func getPointerType(t typenode) FormatFunc {
}
}
func with_typestr_ptrs(t typenode, fn FormatFunc) FormatFunc {
func with_typestr_ptrs(t xunsafe.TypeIter, fn FormatFunc) FormatFunc {
if fn == nil {
panic("nil func")
}
// Check for type wrapping.
if !t.needs_typestr() {
if !needs_typestr(t) {
return fn
}
// Get type string with pointers.
typestr := t.typestr_with_ptrs()
typestr := typestr_with_ptrs(t)
// Wrap format func to include
// type information when needed.

View file

@ -1,21 +1,25 @@
package format
import "unsafe"
import (
"unsafe"
"codeberg.org/gruf/go-xunsafe"
)
// iterMapType returns a FormatFunc capable of iterating
// and formatting the given map type currently in typenode{}.
// and formatting the given map type currently in TypeIter{}.
// note this will fetch sub-FormatFuncs for key / value types.
func (fmt *Formatter) iterMapType(t typenode) FormatFunc {
func (fmt *Formatter) iterMapType(t xunsafe.TypeIter) FormatFunc {
// Key / value types.
key := t.rtype.Key()
elem := t.rtype.Elem()
key := t.Type.Key()
elem := t.Type.Elem()
// Get nested k / v typenodes with appropriate flags.
flagsKey := reflect_map_key_flags(key)
flagsVal := reflect_map_elem_flags(elem)
kt := t.next(t.rtype.Key(), flagsKey)
vt := t.next(t.rtype.Elem(), flagsVal)
// Get nested k / v TypeIters with appropriate flags.
flagsKey := xunsafe.ReflectMapKeyFlags(key) | flagKeyType
flagsVal := xunsafe.ReflectMapElemFlags(elem)
kt := t.Child(key, flagsKey)
vt := t.Child(elem, flagsVal)
// Get key format func.
kfn := fmt.loadOrGet(kt)
@ -30,14 +34,14 @@ func (fmt *Formatter) iterMapType(t typenode) FormatFunc {
}
// Final map type.
rtype := t.rtype
flags := t.flags
rtype := t.Type
flags := t.Flag
// Map type string with ptrs / refs.
typestrPtrs := t.typestr_with_ptrs()
typestrRefs := t.typestr_with_refs()
typestrPtrs := typestr_with_ptrs(t)
typestrRefs := typestr_with_refs(t)
if !t.needs_typestr() {
if !needs_typestr(t) {
return func(s *State) {
if s.P == nil || *(*unsafe.Pointer)(s.P) == nil {
// Append nil.
@ -45,9 +49,9 @@ func (fmt *Formatter) iterMapType(t typenode) FormatFunc {
return
}
// Build reflect value, and then a map iter.
v := build_reflect_value(rtype, s.P, flags)
i := map_iter(v)
// Build reflect value, and then a map iterator.
v := xunsafe.BuildReflectValue(rtype, s.P, flags)
i := xunsafe.GetMapIter(v)
// Prepend object brace.
s.B = append(s.B, '{')
@ -56,15 +60,15 @@ func (fmt *Formatter) iterMapType(t typenode) FormatFunc {
l := len(s.B)
for i.Next() {
// Pass to key fn.
s.P = map_key(i)
// Pass to map key func.
s.P = xunsafe.Map_Key(i)
kfn(s)
// Add key seperator.
s.B = append(s.B, '=')
// Pass to elem fn.
s.P = map_elem(i)
// Pass to map elem func.
s.P = xunsafe.Map_Elem(i)
vfn(s)
// Add comma pair seperator.
@ -89,8 +93,8 @@ func (fmt *Formatter) iterMapType(t typenode) FormatFunc {
}
// Build reflect value, and then a map iter.
v := build_reflect_value(rtype, s.P, flags)
i := map_iter(v)
v := xunsafe.BuildReflectValue(rtype, s.P, flags)
i := xunsafe.GetMapIter(v)
// Include type info.
if s.A.WithType() {
@ -104,15 +108,15 @@ func (fmt *Formatter) iterMapType(t typenode) FormatFunc {
l := len(s.B)
for i.Next() {
// Pass to key fn.
s.P = map_key(i)
// Pass to map key func.
s.P = xunsafe.Map_Key(i)
kfn(s)
// Add key seperator.
s.B = append(s.B, '=')
// Pass to elem fn.
s.P = map_elem(i)
// Pass to map elem func.
s.P = xunsafe.Map_Elem(i)
vfn(s)
// Add comma pair seperator.

View file

@ -3,31 +3,45 @@ package format
import (
"reflect"
"unsafe"
"codeberg.org/gruf/go-xunsafe"
)
type Stringer interface{ String() string }
type Formattable interface{ Format(*State) }
var (
// stringer type for implement checks.
stringerType = typeof[Stringer]()
// formattableType type for implement checks.
formattableType = typeof[Formattable]()
// error type for implement checks.
errorType = typeof[error]()
)
// getMethodType returns a *possible* FormatFunc to handle case
// of a type that implements any known interface{} types, else nil.
func getMethodType(t typenode) FormatFunc {
func getMethodType(t xunsafe.TypeIter) FormatFunc {
switch {
case t.rtype.Implements(stringerType):
switch t.rtype.Kind() {
case t.Type.Implements(stringerType):
switch t.Type.Kind() {
case reflect.Interface:
return getInterfaceStringerType(t)
default:
return getConcreteStringerType(t)
}
case t.rtype.Implements(errorType):
switch t.rtype.Kind() {
case t.Type.Implements(formattableType):
switch t.Type.Kind() {
case reflect.Interface:
return getInterfaceFormattableType(t)
default:
return getConcreteFormattableType(t)
}
case t.Type.Implements(errorType):
switch t.Type.Kind() {
case reflect.Interface:
return getInterfaceErrorType(t)
default:
@ -40,12 +54,12 @@ func getMethodType(t typenode) FormatFunc {
// getInterfaceStringerType returns a FormatFunc to handle case of an interface{}
// type that implements Stringer{}, i.e. Stringer{} itself and any superset of.
func getInterfaceStringerType(t typenode) FormatFunc {
switch t.indirect() && !t.iface_indir() {
func getInterfaceStringerType(t xunsafe.TypeIter) FormatFunc {
switch t.Indirect() && !t.IfaceIndir() {
case true:
return with_typestr_ptrs(t, func(s *State) {
s.P = *(*unsafe.Pointer)(s.P)
if s.P == nil || (*abi_NonEmptyInterface)(s.P).Data == nil {
if s.P == nil || (*xunsafe.Abi_NonEmptyInterface)(s.P).Data == nil {
appendNil(s)
return
}
@ -54,7 +68,7 @@ func getInterfaceStringerType(t typenode) FormatFunc {
})
case false:
return with_typestr_ptrs(t, func(s *State) {
if s.P == nil || (*abi_NonEmptyInterface)(s.P).Data == nil {
if s.P == nil || (*xunsafe.Abi_NonEmptyInterface)(s.P).Data == nil {
appendNil(s)
return
}
@ -68,9 +82,9 @@ func getInterfaceStringerType(t typenode) FormatFunc {
// getConcreteStringerType returns a FormatFunc to handle case of concrete
// (i.e. non-interface{}) type that has a Stringer{} method receiver.
func getConcreteStringerType(t typenode) FormatFunc {
itab := get_iface_ITab[Stringer](t.rtype)
switch t.indirect() && !t.iface_indir() {
func getConcreteStringerType(t xunsafe.TypeIter) FormatFunc {
itab := xunsafe.GetIfaceITab[Stringer](t.Type)
switch t.Indirect() && !t.IfaceIndir() {
case true:
return with_typestr_ptrs(t, func(s *State) {
s.P = *(*unsafe.Pointer)(s.P)
@ -78,17 +92,66 @@ func getConcreteStringerType(t typenode) FormatFunc {
appendNil(s)
return
}
v := *(*Stringer)(pack_iface(itab, s.P))
v := *(*Stringer)(xunsafe.PackIface(itab, s.P))
appendString(s, v.String())
})
case false:
return with_typestr_ptrs(t, func(s *State) {
v := *(*Stringer)(xunsafe.PackIface(itab, s.P))
appendString(s, v.String())
})
default:
panic("unreachable")
}
}
// getInterfaceFormattableType returns a FormatFunc to handle case of an interface{}
// type that implements Formattable{}, i.e. Formattable{} itself and any superset of.
func getInterfaceFormattableType(t xunsafe.TypeIter) FormatFunc {
switch t.Indirect() && !t.IfaceIndir() {
case true:
return with_typestr_ptrs(t, func(s *State) {
s.P = *(*unsafe.Pointer)(s.P)
if s.P == nil || (*xunsafe.Abi_NonEmptyInterface)(s.P).Data == nil {
appendNil(s)
return
}
v := *(*Formattable)(s.P)
v.Format(s)
})
case false:
return with_typestr_ptrs(t, func(s *State) {
if s.P == nil || (*xunsafe.Abi_NonEmptyInterface)(s.P).Data == nil {
appendNil(s)
return
}
v := *(*Formattable)(s.P)
v.Format(s)
})
default:
panic("unreachable")
}
}
// getConcreteFormattableType returns a FormatFunc to handle case of concrete
// (i.e. non-interface{}) type that has a Formattable{} method receiver.
func getConcreteFormattableType(t xunsafe.TypeIter) FormatFunc {
itab := xunsafe.GetIfaceITab[Formattable](t.Type)
switch t.Indirect() && !t.IfaceIndir() {
case true:
return with_typestr_ptrs(t, func(s *State) {
s.P = *(*unsafe.Pointer)(s.P)
if s.P == nil {
appendNil(s)
return
}
v := *(*Stringer)(pack_iface(itab, s.P))
appendString(s, v.String())
v := *(*Formattable)(xunsafe.PackIface(itab, s.P))
v.Format(s)
})
case false:
return with_typestr_ptrs(t, func(s *State) {
v := *(*Formattable)(xunsafe.PackIface(itab, s.P))
v.Format(s)
})
default:
panic("unreachable")
@ -97,12 +160,12 @@ func getConcreteStringerType(t typenode) FormatFunc {
// getInterfaceErrorType returns a FormatFunc to handle case of an interface{}
// type that implements error{}, i.e. error{} itself and any superset of.
func getInterfaceErrorType(t typenode) FormatFunc {
switch t.indirect() && !t.iface_indir() {
func getInterfaceErrorType(t xunsafe.TypeIter) FormatFunc {
switch t.Indirect() && !t.IfaceIndir() {
case true:
return with_typestr_ptrs(t, func(s *State) {
s.P = *(*unsafe.Pointer)(s.P)
if s.P == nil || (*abi_NonEmptyInterface)(s.P).Data == nil {
if s.P == nil || (*xunsafe.Abi_NonEmptyInterface)(s.P).Data == nil {
appendNil(s)
return
}
@ -111,7 +174,7 @@ func getInterfaceErrorType(t typenode) FormatFunc {
})
case false:
return with_typestr_ptrs(t, func(s *State) {
if s.P == nil || (*abi_NonEmptyInterface)(s.P).Data == nil {
if s.P == nil || (*xunsafe.Abi_NonEmptyInterface)(s.P).Data == nil {
appendNil(s)
return
}
@ -125,9 +188,9 @@ func getInterfaceErrorType(t typenode) FormatFunc {
// getConcreteErrorType returns a FormatFunc to handle case of concrete
// (i.e. non-interface{}) type that has an error{} method receiver.
func getConcreteErrorType(t typenode) FormatFunc {
itab := get_iface_ITab[error](t.rtype)
switch t.indirect() && !t.iface_indir() {
func getConcreteErrorType(t xunsafe.TypeIter) FormatFunc {
itab := xunsafe.GetIfaceITab[error](t.Type)
switch t.Indirect() && !t.IfaceIndir() {
case true:
return with_typestr_ptrs(t, func(s *State) {
s.P = *(*unsafe.Pointer)(s.P)
@ -135,16 +198,12 @@ func getConcreteErrorType(t typenode) FormatFunc {
appendNil(s)
return
}
v := *(*error)(pack_iface(itab, s.P))
v := *(*error)(xunsafe.PackIface(itab, s.P))
appendString(s, v.Error())
})
case false:
return with_typestr_ptrs(t, func(s *State) {
if s.P == nil {
appendNil(s)
return
}
v := *(*error)(pack_iface(itab, s.P))
v := *(*error)(xunsafe.PackIface(itab, s.P))
appendString(s, v.Error())
})
default:

View file

@ -3,34 +3,36 @@ package format
import (
"reflect"
"unsafe"
"codeberg.org/gruf/go-xunsafe"
)
// derefPointerType returns a FormatFunc capable of dereferencing
// and formatting the given pointer type currently in typenode{}.
// and formatting the given pointer type currently in TypeIter{}.
// note this will fetch a sub-FormatFunc for resulting value type.
func (fmt *Formatter) derefPointerType(t typenode) FormatFunc {
func (fmt *Formatter) derefPointerType(t xunsafe.TypeIter) FormatFunc {
var n int
rtype := t.rtype
flags := t.flags
rtype := t.Type
flags := t.Flag
// Iteratively dereference pointer types.
for rtype.Kind() == reflect.Pointer {
// If this is actual indirect
// memory, increase dereferences.
if flags&reflect_flagIndir != 0 {
// If this actual indirect memory,
// increase dereferences counter.
if flags&xunsafe.Reflect_flagIndir != 0 {
n++
}
// Get next elem type.
rtype = rtype.Elem()
// Get next set of dereferenced elem type flags.
flags = reflect_pointer_elem_flags(flags, rtype)
// Get next set of dereferenced element type flags.
flags = xunsafe.ReflectPointerElemFlags(flags, rtype)
}
// Wrap value as typenode.
vt := t.next(rtype, flags)
// Wrap value as TypeIter.
vt := t.Child(rtype, flags)
// Get value format func.
fn := fmt.loadOrGet(vt)
@ -38,7 +40,7 @@ func (fmt *Formatter) derefPointerType(t typenode) FormatFunc {
panic("unreachable")
}
if !t.needs_typestr() {
if !needs_typestr(t) {
if n <= 0 {
// No derefs are needed.
return func(s *State) {
@ -83,7 +85,7 @@ func (fmt *Formatter) derefPointerType(t typenode) FormatFunc {
}
// Final type string with ptrs.
typestr := t.typestr_with_ptrs()
typestr := typestr_with_ptrs(t)
if n <= 0 {
// No derefs are needed.

View file

@ -1,18 +1,20 @@
package format
import "codeberg.org/gruf/go-xunsafe"
// iterSliceType returns a FormatFunc capable of iterating
// and formatting the given slice type currently in typenode{}.
// and formatting the given slice type currently in TypeIter{}.
// note this will fetch a sub-FormatFunc for the slice element
// type, and also handle special cases of []byte, []rune slices.
func (fmt *Formatter) iterSliceType(t typenode) FormatFunc {
func (fmt *Formatter) iterSliceType(t xunsafe.TypeIter) FormatFunc {
// Get nested element type.
elem := t.rtype.Elem()
elem := t.Type.Elem()
esz := elem.Size()
// Get nested elem typenode with flags.
flags := reflect_slice_elem_flags(elem)
et := t.next(elem, flags)
// Get nested elem TypeIter{} with flags.
flags := xunsafe.ReflectSliceElemFlags(elem)
et := t.Child(elem, flags)
// Get elem format func.
fn := fmt.loadOrGet(et)
@ -20,12 +22,12 @@ func (fmt *Formatter) iterSliceType(t typenode) FormatFunc {
panic("unreachable")
}
if !t.needs_typestr() {
if !needs_typestr(t) {
return func(s *State) {
ptr := s.P
// Get data as unsafe slice header.
hdr := (*unsafeheader_Slice)(ptr)
hdr := (*xunsafe.Unsafeheader_Slice)(ptr)
if hdr == nil || hdr.Data == nil {
// Append nil.
@ -57,14 +59,14 @@ func (fmt *Formatter) iterSliceType(t typenode) FormatFunc {
}
// Slice type string with ptrs / refs.
typestrPtrs := t.typestr_with_ptrs()
typestrRefs := t.typestr_with_refs()
typestrPtrs := typestr_with_ptrs(t)
typestrRefs := typestr_with_refs(t)
return func(s *State) {
ptr := s.P
// Get data as unsafe slice header.
hdr := (*unsafeheader_Slice)(ptr)
hdr := (*xunsafe.Unsafeheader_Slice)(ptr)
if hdr == nil || hdr.Data == nil {
// Append nil value with type.
@ -105,8 +107,8 @@ func (fmt *Formatter) iterSliceType(t typenode) FormatFunc {
}
}
func wrapByteSlice(t typenode, fn FormatFunc) FormatFunc {
if !t.needs_typestr() {
func wrapByteSlice(t xunsafe.TypeIter, fn FormatFunc) FormatFunc {
if !needs_typestr(t) {
return func(s *State) {
if s.A.AsText() || s.A.AsQuotedText() || s.A.AsQuotedASCII() {
appendString(s, *(*string)(s.P))
@ -115,7 +117,7 @@ func wrapByteSlice(t typenode, fn FormatFunc) FormatFunc {
}
}
}
typestr := t.typestr_with_ptrs()
typestr := typestr_with_ptrs(t)
return func(s *State) {
if s.A.AsText() || s.A.AsQuotedText() || s.A.AsQuotedASCII() {
if s.A.WithType() {
@ -131,8 +133,8 @@ func wrapByteSlice(t typenode, fn FormatFunc) FormatFunc {
}
}
func wrapRuneSlice(t typenode, fn FormatFunc) FormatFunc {
if !t.needs_typestr() {
func wrapRuneSlice(t xunsafe.TypeIter, fn FormatFunc) FormatFunc {
if !needs_typestr(t) {
return func(s *State) {
if s.A.AsText() || s.A.AsQuotedText() || s.A.AsQuotedASCII() {
appendString(s, string(*(*[]rune)(s.P)))
@ -141,7 +143,7 @@ func wrapRuneSlice(t typenode, fn FormatFunc) FormatFunc {
}
}
}
typestr := t.typestr_with_ptrs()
typestr := typestr_with_ptrs(t)
return func(s *State) {
if s.A.AsText() || s.A.AsQuotedText() || s.A.AsQuotedASCII() {
if s.A.WithType() {

View file

@ -1,5 +1,7 @@
package format
import "codeberg.org/gruf/go-xunsafe"
// field stores the minimum necessary
// data for iterating and formatting
// each field in a given struct.
@ -10,23 +12,23 @@ type field struct {
}
// iterStructType returns a FormatFunc capable of iterating
// and formatting the given struct type currently in typenode{}.
// and formatting the given struct type currently in TypeIter{}.
// note this will fetch sub-FormatFuncs for each struct field.
func (fmt *Formatter) iterStructType(t typenode) FormatFunc {
func (fmt *Formatter) iterStructType(t xunsafe.TypeIter) FormatFunc {
// Number of struct fields.
n := t.rtype.NumField()
n := t.Type.NumField()
// Gather format functions.
fields := make([]field, n)
for i := 0; i < n; i++ {
// Get struct field at index.
sfield := t.rtype.Field(i)
sfield := t.Type.Field(i)
rtype := sfield.Type
// Get nested field typenode with appropriate flags.
flags := reflect_struct_field_flags(t.flags, rtype)
ft := t.next(sfield.Type, flags)
// Get nested field TypeIter with appropriate flags.
flags := xunsafe.ReflectStructFieldFlags(t.Flag, rtype)
ft := t.Child(sfield.Type, flags)
// Get field format func.
fn := fmt.loadOrGet(ft)
@ -53,8 +55,8 @@ func (fmt *Formatter) iterStructType(t typenode) FormatFunc {
}
}
func emptyStructType(t typenode) FormatFunc {
if !t.needs_typestr() {
func emptyStructType(t xunsafe.TypeIter) FormatFunc {
if !needs_typestr(t) {
return func(s *State) {
// Append empty object.
s.B = append(s.B, "{}"...)
@ -62,7 +64,7 @@ func emptyStructType(t typenode) FormatFunc {
}
// Struct type string with refs.
typestr := t.typestr_with_refs()
typestr := typestr_with_refs(t)
// Append empty object
// with type information.
@ -74,12 +76,12 @@ func emptyStructType(t typenode) FormatFunc {
}
}
func iterSingleFieldStructType(t typenode, field field) FormatFunc {
func iterSingleFieldStructType(t xunsafe.TypeIter, field field) FormatFunc {
if field.format == nil {
panic("nil func")
}
if !t.needs_typestr() {
if !needs_typestr(t) {
return func(s *State) {
// Wrap 'fn' with braces + field name.
s.B = append(s.B, "{"+field.name+"="...)
@ -89,7 +91,7 @@ func iterSingleFieldStructType(t typenode, field field) FormatFunc {
}
// Struct type string with refs.
typestr := t.typestr_with_refs()
typestr := typestr_with_refs(t)
return func(s *State) {
// Include type info.
@ -104,14 +106,14 @@ func iterSingleFieldStructType(t typenode, field field) FormatFunc {
}
}
func iterMultiFieldStructType(t typenode, fields []field) FormatFunc {
func iterMultiFieldStructType(t xunsafe.TypeIter, fields []field) FormatFunc {
for _, field := range fields {
if field.format == nil {
panic("nil func")
}
}
if !t.needs_typestr() {
if !needs_typestr(t) {
return func(s *State) {
ptr := s.P
@ -139,7 +141,7 @@ func iterMultiFieldStructType(t typenode, fields []field) FormatFunc {
}
// Struct type string with refs.
typestr := t.typestr_with_refs()
typestr := typestr_with_refs(t)
return func(s *State) {
ptr := s.P

View file

@ -3,58 +3,17 @@ package format
import (
"reflect"
"strings"
"codeberg.org/gruf/go-xunsafe"
)
// typenode ...
type typenode struct {
typeinfo
parent *typenode
}
// typeinfo ...
type typeinfo struct {
rtype reflect.Type
flags reflect_flag
}
// new_typenode returns a new typenode{} with reflect.Type and flags.
func new_typenode(t reflect.Type, flags reflect_flag) typenode {
return typenode{typeinfo: typeinfo{
rtype: t,
flags: flags,
}}
}
// key returns data (i.e. type value info)
// to store a FormatFunc under in a cache.
func (n typenode) key() typeinfo {
return n.typeinfo
}
// indirect returns whether reflect_flagIndir is set for given type flags.
func (n typenode) indirect() bool {
return n.flags&reflect_flagIndir != 0
}
// iface_indir returns the result of abi.Type{}.IfaceIndir() for underlying type.
func (n typenode) iface_indir() bool {
return abi_Type_IfaceIndir(n.rtype)
}
// next ...
func (n typenode) next(t reflect.Type, flags reflect_flag) typenode {
child := new_typenode(t, flags)
child.parent = &n
return child
}
// visit ...
func (n typenode) visit() bool {
t := n.rtype
func visit(iter xunsafe.TypeIter) bool {
t := iter.Type
// Check if type is already encountered further up tree.
for node := n.parent; node != nil; node = node.parent {
if node.rtype == t {
for node := iter.Parent; node != nil; node = node.Parent {
if node.Type == t {
return false
}
}
@ -63,16 +22,16 @@ func (n typenode) visit() bool {
}
// needs_typestr returns whether the type contained in the
// receiving typenode{} needs type string information prefixed
// receiving TypeIter{} needs type string information prefixed
// when the TypeMask argument flag bit is set. Certain types
// don't need this as the parent type already indicates this.
func (n typenode) needs_typestr() bool {
if n.parent == nil {
func needs_typestr(iter xunsafe.TypeIter) bool {
if iter.Parent == nil {
return true
}
switch p := n.parent.rtype; p.Kind() {
switch p := iter.Parent.Type; p.Kind() {
case reflect.Pointer:
return n.parent.needs_typestr()
return needs_typestr(*iter.Parent)
case reflect.Slice,
reflect.Array,
reflect.Map:
@ -83,17 +42,17 @@ func (n typenode) needs_typestr() bool {
}
// typestr_with_ptrs returns the type string for
// current typenode{} with asterisks for pointers.
func (n typenode) typestr_with_ptrs() string {
t := n.rtype
// current xunsafe.TypeIter{} with asterisks for pointers.
func typestr_with_ptrs(iter xunsafe.TypeIter) string {
t := iter.Type
// Check for parent.
if n.parent == nil {
if iter.Parent == nil {
return t.String()
}
// Get parent type.
p := n.parent.rtype
p := iter.Parent.Type
// If parent is not ptr, then
// this was not a deref'd ptr.
@ -107,17 +66,17 @@ func (n typenode) typestr_with_ptrs() string {
}
// typestr_with_refs returns the type string for
// current typenode{} with ampersands for pointers.
func (n typenode) typestr_with_refs() string {
t := n.rtype
// current xunsafe.TypeIter{} with ampersands for pointers.
func typestr_with_refs(iter xunsafe.TypeIter) string {
t := iter.Type
// Check for parent.
if n.parent == nil {
if iter.Parent == nil {
return t.String()
}
// Get parent type.
p := n.parent.rtype
p := iter.Parent.Type
var d int

9
vendor/codeberg.org/gruf/go-xunsafe/LICENSE generated vendored Normal file
View file

@ -0,0 +1,9 @@
MIT License
Copyright (c) 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.

3
vendor/codeberg.org/gruf/go-xunsafe/README.md generated vendored Normal file
View file

@ -0,0 +1,3 @@
# go-xunsafe
xunafe as in EXTRA UNSAFE. this exposes reflect and internal ABI package data structures in a manner that is kept up-to-date and version gated by the compile-time Go version. This package performs no validity checks on the data you provide to it, it is expected that you know what you are doing. Not to mention that some of the internal ABI data must only be exposed VERY carefully given that it is in non garbage-collected memory.

109
vendor/codeberg.org/gruf/go-xunsafe/abi.go generated vendored Normal file
View file

@ -0,0 +1,109 @@
//go:build go1.24 && !go1.26
package xunsafe
import (
"reflect"
"unsafe"
)
func init() {
// TypeOf(reflect.Type{}) == *struct{ abi.Type{} }
t := reflect.TypeOf(reflect.TypeOf(0)).Elem()
if t.Size() != unsafe.Sizeof(Abi_Type{}) {
panic("Abi_Type{} not in sync with abi.Type{}")
}
}
const (
// see: go/src/internal/abi/type.go
Abi_KindDirectIface uint8 = 1 << 5
Abi_KindMask uint8 = (1 << 5) - 1
)
// Abi_Type is a copy of the memory layout of abi.Type{}.
//
// see: go/src/internal/abi/type.go
type Abi_Type struct {
_ uintptr
PtrBytes uintptr
_ uint32
_ uint8
_ uint8
_ uint8
Kind_ uint8
_ func(unsafe.Pointer, unsafe.Pointer) bool
_ *byte
_ int32
_ int32
}
// Abi_EmptyInterface is a copy of the memory layout of abi.EmptyInterface{},
// which is to say also the memory layout of any method-less interface.
//
// see: go/src/internal/abi/iface.go
type Abi_EmptyInterface struct {
Type *Abi_Type
Data unsafe.Pointer
}
// Abi_NonEmptyInterface is a copy of the memory layout of abi.NonEmptyInterface{},
// which is to say also the memory layout of any interface containing method(s).
//
// see: go/src/internal/abi/iface.go on 1.25+
// see: go/src/reflect/value.go on 1.24
type Abi_NonEmptyInterface struct {
ITab uintptr
Data unsafe.Pointer
}
// see: go/src/internal/abi/type.go Type.Kind()
func Abi_Type_Kind(t reflect.Type) uint8 {
iface := (*Abi_NonEmptyInterface)(unsafe.Pointer(&t))
atype := (*Abi_Type)(unsafe.Pointer(iface.Data))
return atype.Kind_ & Abi_KindMask
}
// see: go/src/internal/abi/type.go Type.IfaceIndir()
func Abi_Type_IfaceIndir(t reflect.Type) bool {
iface := (*Abi_NonEmptyInterface)(unsafe.Pointer(&t))
atype := (*Abi_Type)(unsafe.Pointer(iface.Data))
return atype.Kind_&Abi_KindDirectIface == 0
}
// PackIface packs a new reflect.nonEmptyInterface{} using shielded
// itab and data pointer, returning a pointer for caller casting.
func PackIface(itab uintptr, word unsafe.Pointer) unsafe.Pointer {
return unsafe.Pointer(&Abi_NonEmptyInterface{
ITab: itab,
Data: word,
})
}
// GetIfaceITab generates a new value of given type,
// casts it to the generic param interface type, and
// returns the .itab portion of the abi.NonEmptyInterface{}.
// this is useful for later calls to PackIface for known type.
func GetIfaceITab[I any](t reflect.Type) uintptr {
s := reflect.New(t).Elem().Interface().(I)
i := (*Abi_NonEmptyInterface)(unsafe.Pointer(&s))
return i.ITab
}
// UnpackEface returns the .Data portion of an abi.EmptyInterface{}.
func UnpackEface(a any) unsafe.Pointer {
return (*Abi_EmptyInterface)(unsafe.Pointer((&a))).Data
}
// see: go/src/internal/unsafeheader/unsafeheader.go
type Unsafeheader_Slice struct {
Data unsafe.Pointer
Len int
Cap int
}
// see: go/src/internal/unsafeheader/unsafeheader.go
type Unsafeheader_String struct {
Data unsafe.Pointer
Len int
}

157
vendor/codeberg.org/gruf/go-xunsafe/reflect.go generated vendored Normal file
View file

@ -0,0 +1,157 @@
//go:build go1.24 && !go1.26
package xunsafe
import (
"reflect"
"unsafe"
)
// see: go/src/reflect/value.go
type Reflect_flag uintptr
const (
// see: go/src/reflect/value.go
Reflect_flagKindWidth = 5 // there are 27 kinds
Reflect_flagKindMask Reflect_flag = 1<<Reflect_flagKindWidth - 1
Reflect_flagStickyRO Reflect_flag = 1 << 5
Reflect_flagEmbedRO Reflect_flag = 1 << 6
Reflect_flagIndir Reflect_flag = 1 << 7
Reflect_flagAddr Reflect_flag = 1 << 8
Reflect_flagMethod Reflect_flag = 1 << 9
Reflect_flagMethodShift = 10
Reflect_flagRO Reflect_flag = Reflect_flagStickyRO | Reflect_flagEmbedRO
)
// ReflectIfaceElemFlags returns the reflect_flag expected of an unboxed interface element of type.
//
// see: go/src/reflect/value.go unpackElem()
func ReflectIfaceElemFlags(elemType reflect.Type) Reflect_flag {
if elemType == nil {
return 0
}
flags := Reflect_flag(Abi_Type_Kind(elemType))
if Abi_Type_IfaceIndir(elemType) {
flags |= Reflect_flagIndir
}
return flags
}
// ReflectPointerElemFlags returns the reflect_flag expected of a dereferenced pointer element of type.
//
// see: go/src/reflect/value.go Value.Elem()
func ReflectPointerElemFlags(ptrFlags Reflect_flag, elemType reflect.Type) Reflect_flag {
return ptrFlags | Reflect_flagIndir | Reflect_flagAddr | Reflect_flag(Abi_Type_Kind(elemType))
}
// ReflectArrayElemFlags returns the reflect_flag expected of an element of type in an array.
//
// see: go/src/reflect/value.go Value.Index()
func ReflectArrayElemFlags(arrayFlags Reflect_flag, elemType reflect.Type) Reflect_flag {
return arrayFlags&(Reflect_flagIndir|Reflect_flagAddr) | Reflect_flag(Abi_Type_Kind(elemType))
}
// reflect_slice_elem_flags returns the reflect_flag expected of a slice element of type.
//
// see: go/src/reflect/value.go Value.Index()
func ReflectSliceElemFlags(elemType reflect.Type) Reflect_flag {
return Reflect_flagAddr | Reflect_flagIndir | Reflect_flag(Abi_Type_Kind(elemType))
}
// ReflectStructFieldFlags returns the reflect_flag expected of a struct field of type.
//
// see: go/src/reflect/value.go Value.Field()
func ReflectStructFieldFlags(structFlags Reflect_flag, fieldType reflect.Type) Reflect_flag {
return structFlags&(Reflect_flagIndir|Reflect_flagAddr) | Reflect_flag(Abi_Type_Kind(fieldType))
}
// ReflectMapKeyFlags returns the reflect_flag expected of a map key of type.
//
// see: go/src/reflect/map_swiss.go MapIter.Key()
func ReflectMapKeyFlags(keyType reflect.Type) Reflect_flag {
return Reflect_flag(Abi_Type_Kind(keyType))
}
// ReflectMapElemFlags returns the reflect_flag expected of a map element of type.
//
// see: go/src/reflect/map_swiss.go MapIter.Value()
func ReflectMapElemFlags(elemType reflect.Type) Reflect_flag {
return Reflect_flag(Abi_Type_Kind(elemType))
}
// reflect_Value is a copy of the memory layout of reflect.Value{}.
//
// see: go/src/reflect/value.go
type reflect_Value struct {
typ_ unsafe.Pointer
ptr unsafe.Pointer
Reflect_flag
}
func init() {
if unsafe.Sizeof(reflect_Value{}) != unsafe.Sizeof(reflect.Value{}) {
panic("reflect_Value{} not in sync with reflect.Value{}")
}
}
// reflect_type_data returns the .word from the reflect.Type{} cast
// as the reflect.nonEmptyInterface{}, which itself will be a pointer
// to the actual abi.Type{} that this reflect.Type{} is wrapping.
func ReflectTypeData(t reflect.Type) unsafe.Pointer {
return (*Abi_NonEmptyInterface)(unsafe.Pointer(&t)).Data
}
// BuildReflectValue manually builds a reflect.Value{} by setting the internal field members.
func BuildReflectValue(rtype reflect.Type, data unsafe.Pointer, flags Reflect_flag) reflect.Value {
return *(*reflect.Value)(unsafe.Pointer(&reflect_Value{ReflectTypeData(rtype), data, flags}))
}
// Reflect_MapIter is a copy of the memory layout of reflect.MapIter{}.
//
// see: go/src/reflect/map_swiss.go
type Reflect_MapIter struct {
m reflect.Value
hiter maps_Iter
}
// maps_Iter is a copy of the memory layout of maps.Iter{}.
//
// see: go/src/internal/runtime/maps/table.go
type maps_Iter struct {
key unsafe.Pointer
elem unsafe.Pointer
_ uintptr
_ uintptr
_ uint64
_ uint64
_ uint64
_ uint8
_ int
_ uintptr
_ struct{ _ unsafe.Pointer }
_ uint64
}
func init() {
if unsafe.Sizeof(Reflect_MapIter{}) != unsafe.Sizeof(reflect.MapIter{}) {
panic("Reflect_MapIter{} not in sync with reflect.MapIter{}")
}
}
// GetMapIter creates a new map iterator from value,
// skipping the initial v.MapRange() type checking.
func GetMapIter(v reflect.Value) *reflect.MapIter {
var i Reflect_MapIter
i.m = v
return (*reflect.MapIter)(unsafe.Pointer(&i))
}
// Map_Key returns ptr to current map key in iter.
func Map_Key(i *reflect.MapIter) unsafe.Pointer {
return (*Reflect_MapIter)(unsafe.Pointer(i)).hiter.key
}
// Map_Elem returns ptr to current map element in iter.
func Map_Elem(i *reflect.MapIter) unsafe.Pointer {
return (*Reflect_MapIter)(unsafe.Pointer(i)).hiter.elem
}

49
vendor/codeberg.org/gruf/go-xunsafe/types.go generated vendored Normal file
View file

@ -0,0 +1,49 @@
package xunsafe
import "reflect"
// TypeIter provides a simple wrapper for
// a means of following reflected types.
type TypeIter struct {
TypeInfo
Parent *TypeIter
}
// TypeInfo wraps reflect type information
// along with flags specifying further details
// necessary due to type nesting.
type TypeInfo struct {
Type reflect.Type
Flag Reflect_flag
}
// ToTypeIter creates a new TypeIter{} from reflect type and flags.
func ToTypeIter(rtype reflect.Type, flags Reflect_flag) TypeIter {
return TypeIter{TypeInfo: TypeInfo{rtype, flags}}
}
// TypeIterFrom creates new TypeIter from interface value type.
// Note this will always assume the initial value passed to you
// will be coming from an interface.
func TypeIterFrom(a any) TypeIter {
rtype := reflect.TypeOf(a)
flags := ReflectIfaceElemFlags(rtype)
return ToTypeIter(rtype, flags)
}
// Indirect returns whether Reflect_flagIndir is set on receiving TypeInfo{}.Flag.
func (t TypeInfo) Indirect() bool {
return t.Flag&Reflect_flagIndir != 0
}
// IfaceIndir calls Abi_Type_IfaceIndir() on receiving TypeInfo{}.Type.
func (t TypeInfo) IfaceIndir() bool {
return Abi_Type_IfaceIndir(t.Type)
}
// Child returns a new TypeIter{} for given type and flags, with parent pointing to receiver.
func (i TypeIter) Child(rtype reflect.Type, flags Reflect_flag) TypeIter {
child := ToTypeIter(rtype, flags)
child.Parent = &i
return child
}