1
0
Fork 0
mirror of https://github.com/Luzifer/sii.git synced 2024-12-21 00:21:15 +00:00
sii/genericMarshaller.go
Knut Ahlers 9c22ab945c
Fix: Looks like SOME positions are arrays of int 😭
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2019-12-23 21:32:10 +01:00

290 lines
7.5 KiB
Go

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
case reflect.TypeOf(RawValue{}):
v, err := valField.Interface().(RawValue).MarshalSII()
if err != nil {
return nil, errors.Wrap(err, "Unable to encode RawValue")
}
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.Array:
switch typeField.Type.Elem().Kind() {
case reflect.Float32:
var vals [][]byte
switch typeField.Type.Len() {
case 3:
for _, v := range valField.Interface().([3]float32) {
bv, err := float2sii(v)
if err != nil {
return nil, errors.Wrap(err, "Unable to encode float32")
}
vals = append(vals, bv)
}
default:
return nil, errors.Errorf("Unsupported type: [%d]%s", typeField.Type.Len(), typeField.Type.Elem().Kind())
}
buf.WriteString(fmt.Sprintf(" %s: (%s)\n", attributeName, bytes.Join(vals, []byte(", "))))
case reflect.Int64:
var vals [][]byte
switch typeField.Type.Len() {
case 3:
for _, v := range valField.Interface().([3]int64) {
bv := []byte(strconv.FormatInt(v, 10))
vals = append(vals, bv)
}
default:
return nil, errors.Errorf("Unsupported type: [%d]%s", typeField.Type.Len(), typeField.Type.Elem().Kind())
}
buf.WriteString(fmt.Sprintf(" %s: (%s)\n", attributeName, bytes.Join(vals, []byte(", "))))
default:
return nil, errors.Errorf("Unsupported type: [%d]%s", typeField.Type.Len(), typeField.Type.Elem().Kind())
}
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.Float32:
for _, val := range valField.Interface().([]float32) {
v, err := float2sii(val)
if err != nil {
return nil, errors.Wrap(err, "Unable to encode float32")
}
values = append(values, string(v))
}
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, fmt.Sprintf("%q", val))
}
buf.Write(encodeSliceValue(attributeName, values))
case reflect.Array:
switch typeField.Type.Elem().Elem().Kind() {
case reflect.Float32:
switch typeField.Type.Elem().Len() {
case 3:
for _, val := range valField.Interface().([][3]float32) {
var vals [][]byte
for _, v := range val {
bv, err := float2sii(v)
if err != nil {
return nil, errors.Wrap(err, "Unable to encode float32")
}
vals = append(vals, bv)
}
values = append(values, fmt.Sprintf("(%s)", bytes.Join(vals, []byte(", "))))
}
case 4:
for _, val := range valField.Interface().([][4]float32) {
var vals [][]byte
for _, v := range val {
bv, err := float2sii(v)
if err != nil {
return nil, errors.Wrap(err, "Unable to encode float32")
}
vals = append(vals, bv)
}
values = append(values, fmt.Sprintf("(%s; %s)", vals[0], bytes.Join(vals[1:], []byte(", "))))
}
default:
return nil, errors.Errorf("Unsupported len of type: [][%d]%s", typeField.Type.Elem().Len(), typeField.Type.Elem().Elem().Kind())
}
default:
return nil, errors.Errorf("Unsupported type: [][%d]%s", typeField.Type.Elem().Len(), typeField.Type.Elem().Elem().Kind())
}
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()
}