github.com/trim21/go-phpserialize@v0.0.22-0.20240301204449-2fca0319b3f0/internal/encoder/map.go (about) 1 package encoder 2 3 import ( 4 "reflect" 5 6 "github.com/trim21/go-phpserialize/internal/runtime" 7 ) 8 9 // !!! not safe to use in reflect case !!! 10 func compileMap(rt *runtime.Type, seen seenMap) (encoder, error) { 11 // for map[int]string, keyType is int, valueType is string 12 keyType := rt.Key() 13 valueType := rt.Elem() 14 15 switch keyType.Kind() { 16 case reflect.String, 17 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 18 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 19 default: 20 return nil, &UnsupportedTypeAsMapKeyError{Type: runtime.RType2Type(keyType)} 21 } 22 23 keyEncoder, err := compileMapKey(keyType) 24 if err != nil { 25 return nil, err 26 } 27 28 var valueEncoder encoder 29 30 // need special take care 31 // fmt.Println(runtime.IfaceIndir(rt), runtime.IfaceIndir(valueType), rt.String()) 32 if valueType.Kind() == reflect.Map { 33 enc, err := compileMap(valueType, seen) 34 if err != nil { 35 return nil, err 36 } 37 valueEncoder = deRefNilEncoder(enc) 38 } else { 39 valueEncoder, err = compile(valueType, seen) 40 if err != nil { 41 return nil, err 42 } 43 } 44 45 return func(ctx *Ctx, b []byte, p uintptr) ([]byte, error) { 46 if p == 0 { 47 // nil 48 return appendNull(b), nil 49 } 50 51 ptr := ptrToUnsafePtr(p) 52 53 mapLen := runtime.MapLen(ptr) 54 if mapLen == 0 { 55 return appendEmptyArray(b), nil 56 } 57 58 b = appendArrayBegin(b, int64(mapLen)) 59 60 var mapCtx = newMapCtx() 61 defer freeMapCtx(mapCtx) 62 63 runtime.MapIterInit(rt, ptr, &mapCtx.Iter) 64 var err error // create a new error value, so shadow compiler's error 65 for i := 0; i < mapLen; i++ { 66 b, err = keyEncoder(ctx, b, runtime.MapIterKey(&mapCtx.Iter)) 67 if err != nil { 68 return b, err 69 } 70 71 b, err = valueEncoder(ctx, b, runtime.MapIterValue(&mapCtx.Iter)) 72 if err != nil { 73 return b, err 74 } 75 76 runtime.MapIterNext(&mapCtx.Iter) 77 } 78 return append(b, '}'), nil 79 }, nil 80 }