You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gophp/serialize/serialize.go

109 lines
2.4 KiB

package serialize
import (
"bytes"
"fmt"
"go.dtapp.net/gostring"
"reflect"
"sort"
)
func Marshal(value interface{}) ([]byte, error) {
if value == nil {
return MarshalNil(), nil
}
t := reflect.TypeOf(value)
switch t.Kind() {
case reflect.Bool:
return MarshalBool(value.(bool)), nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64:
return MarshalNumber(value), nil
case reflect.String:
return MarshalString(value.(string)), nil
case reflect.Map:
return MarshalMap(value)
case reflect.Slice:
return MarshalSlice(value)
default:
return nil, fmt.Errorf("marshal: Unknown type %T with value %#v", t, value)
}
}
func MarshalNil() []byte {
return []byte("N;")
}
func MarshalBool(value bool) []byte {
if value {
return []byte("b:1;")
}
return []byte("b:0;")
}
func MarshalNumber(value interface{}) []byte {
var val string
isFloat := false
switch value.(type) {
default:
val = "0"
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
val, _ = gostring.NumericalToString(value)
case float32, float64:
val, _ = gostring.NumericalToString(value)
isFloat = true
}
if isFloat {
return []byte("d:" + val + ";")
} else {
return []byte("i:" + val + ";")
}
}
func MarshalString(value string) []byte {
return []byte(fmt.Sprintf("s:%d:\"%s\";", len(value), value))
}
func MarshalMap(value interface{}) ([]byte, error) {
s := reflect.ValueOf(value)
mapKeys := s.MapKeys()
sort.Slice(mapKeys, func(i, j int) bool {
return lessValue(mapKeys[i], mapKeys[j])
})
var buffer bytes.Buffer
for _, mapKey := range mapKeys {
m, err := Marshal(mapKey.Interface())
if err != nil {
return nil, err
}
buffer.Write(m)
m, err = Marshal(s.MapIndex(mapKey).Interface())
if err != nil {
return nil, err
}
buffer.Write(m)
}
return []byte(fmt.Sprintf("a:%d:{%s}", s.Len(), buffer.String())), nil
}
func MarshalSlice(value interface{}) ([]byte, error) {
s := reflect.ValueOf(value)
var buffer bytes.Buffer
for i := 0; i < s.Len(); i++ {
m, err := Marshal(i)
if err != nil {
return nil, err
}
buffer.Write(m)
m, err = Marshal(s.Index(i).Interface())
if err != nil {
return nil, err
}
buffer.Write(m)
}
return []byte(fmt.Sprintf("a:%d:{%s}", s.Len(), buffer.String())), nil
}