diff --git a/internal/serde/reflect.go b/internal/serde/reflect.go index 9433184..63ee8de 100644 --- a/internal/serde/reflect.go +++ b/internal/serde/reflect.go @@ -215,6 +215,13 @@ func serializePointedAt(s *Serializer, t reflect.Type, p unsafe.Pointer) { return } + if static(p) { + serializeVarint(s, -1) + off := staticOffset(p) + serializeVarint(s, off) + return + } + id, new := s.assignPointerID(p) serializeVarint(s, int(id)) if !new { diff --git a/internal/serde/serde.go b/internal/serde/serde.go index d01c41a..b5c09c5 100644 --- a/internal/serde/serde.go +++ b/internal/serde/serde.go @@ -71,6 +71,15 @@ func newDeserializer(b []byte) *Deserializer { func (d *Deserializer) readPtr() (unsafe.Pointer, sID) { x, n := binary.Varint(d.b) d.b = d.b[n:] + + // pointer into static uint64 table + if x == -1 { + x, n = binary.Varint(d.b) + d.b = d.b[n:] + p := staticPointer(int(x)) + return p, 0 + } + i := sID(x) p := d.ptrs[i] return p, i diff --git a/internal/serde/unsafe.go b/internal/serde/unsafe.go index ecdc18a..c52fb21 100644 --- a/internal/serde/unsafe.go +++ b/internal/serde/unsafe.go @@ -36,3 +36,23 @@ func inlined(t reflect.Type) bool { return false } } + +var staticuint64s unsafe.Pointer + +func init() { + zero := 0 + var x interface{} = zero + staticuint64s = (*iface)(unsafe.Pointer(&x)).ptr +} + +func static(p unsafe.Pointer) bool { + return uintptr(p) >= uintptr(staticuint64s) && uintptr(p) < uintptr(staticuint64s)+256 +} + +func staticOffset(p unsafe.Pointer) int { + return int(uintptr(p) - uintptr(staticuint64s)) +} + +func staticPointer(offset int) unsafe.Pointer { + return unsafe.Add(staticuint64s, offset) +} diff --git a/serde/serde_test.go b/serde/serde_test.go index 90057d0..b4176fa 100644 --- a/serde/serde_test.go +++ b/serde/serde_test.go @@ -93,6 +93,16 @@ func TestReflect(t *testing.T) { }) } +func TestInt257(t *testing.T) { + one := 1 + x := []any{ + true, + one, + } + serde.RegisterType[[]any]() + assertRoundTrip(t, x) +} + func TestReflectCustom(t *testing.T) { ser := func(s *serde.Serializer, x *int) error { str := strconv.Itoa(*x)