1
0
Fork 0
mirror of https://github.com/Luzifer/sii.git synced 2024-10-18 05:14:19 +00:00
sii/genericMarshaller.go

180 lines
4.4 KiB
Go
Raw Normal View History

package sii
import (
"bytes"
"fmt"
"reflect"
"strconv"
"github.com/pkg/errors"
)
func genericMarshal(in interface{}) ([]byte, error) {
if reflect.TypeOf(in).Kind() == reflect.Ptr {
in = reflect.ValueOf(in).Elem().Interface()
}
if reflect.TypeOf(in).Kind() != reflect.Struct {
return nil, errors.New("Calling marshaller with non-struct")
}
var buf = new(bytes.Buffer)
st := reflect.ValueOf(in)
for i := 0; i < st.NumField(); i++ {
valField := st.Field(i)
typeField := st.Type().Field(i)
attributeName := typeField.Tag.Get("sii")
if attributeName == "" {
// Names must be explicitly defined, library does not support name guessing
continue
}
switch typeField.Type {
case reflect.TypeOf(Ptr{}):
v := valField.Interface().(Ptr).MarshalSII()
buf.WriteString(fmt.Sprintf(" %s: %s\n", attributeName, v))
continue
case reflect.TypeOf(Placement{}):
v, err := valField.Interface().(Placement).MarshalSII()
if err != nil {
return nil, errors.Wrap(err, "Unable to encode Placement")
}
buf.WriteString(fmt.Sprintf(" %s: %s\n", attributeName, v))
continue
}
switch typeField.Type.Kind() {
case reflect.Bool:
v := valField.Bool()
buf.WriteString(fmt.Sprintf(" %s: %s\n", attributeName, strconv.FormatBool(v)))
case reflect.Float32:
v, err := float2sii(float32(valField.Float()))
if err != nil {
return nil, errors.Wrap(err, "Unable to encode float32")
}
buf.WriteString(fmt.Sprintf(" %s: %s\n", attributeName, v))
case reflect.Int, reflect.Int64:
buf.WriteString(fmt.Sprintf(" %s: %d\n", attributeName, valField.Int()))
case reflect.String:
buf.WriteString(fmt.Sprintf(" %s: %q\n", attributeName, valField.String()))
case reflect.Uint64:
v := strconv.FormatUint(valField.Uint(), 10)
buf.WriteString(fmt.Sprintf(" %s: %s\n", attributeName, v))
case reflect.Ptr:
switch typeField.Type.Elem().Kind() {
case reflect.Int64:
var v string
if valField.IsNil() {
v = "nil"
} else {
v = strconv.FormatInt(valField.Elem().Int(), 10)
}
buf.WriteString(fmt.Sprintf(" %s: %s\n", attributeName, v))
default:
return nil, errors.Errorf("Unsupported type: *%s", typeField.Type.Elem().Kind())
}
case reflect.Slice:
var values []string
switch typeField.Type.Elem() {
case reflect.TypeOf(Ptr{}):
for _, val := range valField.Interface().([]Ptr) {
values = append(values, string(val.MarshalSII()))
}
buf.Write(encodeSliceValue(attributeName, values))
continue
case reflect.TypeOf(Placement{}):
for _, val := range valField.Interface().([]Placement) {
ev, err := val.MarshalSII()
if err != nil {
return nil, errors.Wrap(err, "Unable to encode Placement")
}
values = append(values, string(ev))
}
buf.Write(encodeSliceValue(attributeName, values))
continue
case reflect.TypeOf(RawValue{}):
for _, val := range valField.Interface().([]RawValue) {
ev, err := val.MarshalSII()
if err != nil {
return nil, errors.Wrap(err, "Unable to encode RawValue")
}
values = append(values, string(ev))
}
buf.Write(encodeSliceValue(attributeName, values))
continue
}
switch typeField.Type.Elem().Kind() {
case reflect.Bool:
for _, val := range valField.Interface().([]bool) {
values = append(values, strconv.FormatBool(val))
}
buf.Write(encodeSliceValue(attributeName, values))
case reflect.Int:
for _, val := range valField.Interface().([]int) {
values = append(values, strconv.FormatInt(int64(val), 10))
}
buf.Write(encodeSliceValue(attributeName, values))
case reflect.Int64:
for _, val := range valField.Interface().([]int64) {
values = append(values, strconv.FormatInt(val, 10))
}
buf.Write(encodeSliceValue(attributeName, values))
case reflect.String:
for _, val := range valField.Interface().([]string) {
values = append(values, val)
}
buf.Write(encodeSliceValue(attributeName, values))
default:
return nil, errors.Errorf("Unsupported type: []%s", typeField.Type.Elem().Kind())
}
default:
return nil, errors.Errorf("Unsupported type: %s", typeField.Type.Kind())
}
}
return buf.Bytes(), nil
}
func encodeSliceValue(attributeName string, values []string) []byte {
var buf = new(bytes.Buffer)
fmt.Fprintf(buf, " %s: %d\n", attributeName, len(values))
for i, v := range values {
fmt.Fprintf(buf, " %s[%d]: %s\n", attributeName, i, v)
}
return buf.Bytes()
}