github.com/trim21/go-phpserialize@v0.0.22-0.20240301204449-2fca0319b3f0/internal/encoder/slice.go (about) 1 package encoder 2 3 import ( 4 "reflect" 5 "unsafe" 6 7 "github.com/trim21/go-phpserialize/internal/runtime" 8 ) 9 10 const lenOffset = unsafe.Offsetof(reflect.SliceHeader{}.Len) 11 12 func compileSlice(rt *runtime.Type, seen seenMap) (encoder, error) { 13 offset := rt.Elem().Size() 14 var enc encoder 15 var err error 16 17 if rt.Elem().Kind() == reflect.Map { 18 enc, err = compile(runtime.PtrTo(rt.Elem()), seen) 19 if err != nil { 20 return nil, err 21 } 22 } else { 23 enc, err = compile(rt.Elem(), seen) 24 if err != nil { 25 return nil, err 26 } 27 } 28 return func(ctx *Ctx, b []byte, p uintptr) ([]byte, error) { 29 if p == 0 { 30 return appendNull(b), nil 31 } 32 dataPtr := **(**uintptr)(unsafe.Pointer(&p)) 33 // no data ptr, nil slice 34 if dataPtr == 0 { 35 return appendNull(b), nil 36 } 37 38 length := *(*int)(unsafe.Add(ptrToUnsafePtr(p), lenOffset)) 39 40 b = appendArrayBegin(b, int64(length)) 41 var err error // create a new error value, so shadow compiler's error 42 for i := 0; i < length; i++ { 43 b = appendIntBytes(b, int64(i)) 44 b, err = enc(ctx, b, dataPtr+offset*uintptr(i)) 45 if err != nil { 46 return b, err 47 } 48 } 49 return append(b, '}'), nil 50 }, nil 51 }