mirror of
https://github.com/Luzifer/sii.git
synced 2024-12-21 00:21:15 +00:00
290 lines
7.5 KiB
Go
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()
|
|
}
|