125 lines
3.1 KiB
Go
125 lines
3.1 KiB
Go
package ssob
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"reflect"
|
|
"sync"
|
|
|
|
"gitea.olznet.de/OlzNet/slog"
|
|
)
|
|
|
|
type Encoder struct {
|
|
mutex sync.Mutex
|
|
w io.Writer
|
|
}
|
|
|
|
func NewEncoder(w io.Writer) *Encoder {
|
|
enc := new(Encoder)
|
|
enc.w = w
|
|
return enc
|
|
}
|
|
|
|
func (enc *Encoder) Encode(e interface{}) (err error) {
|
|
t := reflect.TypeOf(e)
|
|
slog.LOG_DEBUGFLN("Enc: %v", t)
|
|
if t == reflect.TypeOf(errors.New("")) || t == reflect.TypeOf((*error)(nil)).Elem() {
|
|
if reflect.ValueOf(e).IsNil() {
|
|
return enc.Encode(string(""))
|
|
} else {
|
|
return enc.Encode(e.(error).Error())
|
|
}
|
|
} else if t == reflect.TypeOf((*error)(nil)) {
|
|
if reflect.Indirect(reflect.ValueOf(e)).IsNil() {
|
|
return enc.Encode(string(""))
|
|
} else {
|
|
return enc.Encode((*e.(*error)).Error())
|
|
}
|
|
}
|
|
|
|
return enc.EncodeValue(reflect.ValueOf(e))
|
|
}
|
|
|
|
func (enc *Encoder) EncodeValue(value reflect.Value) (err error) {
|
|
if value.Kind() == reflect.Invalid {
|
|
return fmt.Errorf("ssob: Cannot encode nil: %w", ErrValueInvalid)
|
|
}
|
|
|
|
if value.Kind() == reflect.Ptr && value.IsNil() {
|
|
return fmt.Errorf("ssob: Cannot encode nil of type %s: %w", value.Type().String(), ErrValueInvalid)
|
|
}
|
|
|
|
bb, err := marshal(value.Interface())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
bl := MarshalInt32(int32(len(bb)))
|
|
|
|
w := make([]byte, 4+len(bb))
|
|
copy(w, bl)
|
|
copy(w[4:], bb)
|
|
|
|
enc.mutex.Lock()
|
|
defer enc.mutex.Unlock()
|
|
|
|
return binary.Write(enc.w, binary.BigEndian, w)
|
|
}
|
|
|
|
func (enc *Encoder) NEncode(e interface{}) (err error) {
|
|
RegisterType(e)
|
|
for _, t := range cacheTypes.ntypes {
|
|
slog.LOG_DEBUGFLN("t: %v", t)
|
|
}
|
|
|
|
var b []byte
|
|
if b, err = marshalVal(e); err != nil {
|
|
return fmt.Errorf("ssob: Cannot encode value: %w", err)
|
|
}
|
|
|
|
enc.mutex.Lock()
|
|
defer enc.mutex.Unlock()
|
|
|
|
if _, err = enc.w.Write(b); err != nil {
|
|
return fmt.Errorf("ssob: Cannot encode value: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (enc *Encoder) encode(e interface{}, indirectLevel int) (err error) {
|
|
t := reflect.TypeOf(e)
|
|
|
|
if t.Kind() == reflect.Invalid {
|
|
return fmt.Errorf("ssob: Cannot encode nil: %w", ErrValueInvalid)
|
|
}
|
|
|
|
v := reflect.ValueOf(e)
|
|
//slog.LOG_DEBUGFLN("ssob: encode t.name: %s", t.Name())
|
|
//slog.LOG_DEBUGFLN("ssob: encode t.kind: %s", t.Kind())
|
|
slog.LOG_DEBUGFLN("ssob: encode v.type: %s", v.Type())
|
|
switch t.Kind() {
|
|
case reflect.Ptr:
|
|
if v.IsNil() {
|
|
return fmt.Errorf("ssob: Cannot encode nil pointer: %w", ErrValueInvalid)
|
|
}
|
|
p := reflect.Indirect(v)
|
|
return enc.encode(p.Interface(), indirectLevel+1)
|
|
case reflect.Struct:
|
|
return fmt.Errorf("ssob: Type '%s' named '%s' unknown: %w", t.Kind().String(), t.Name(), ErrTypeUnknown)
|
|
case reflect.Slice:
|
|
return fmt.Errorf("ssob: Type '%s' with types '%s' unknown: %w", t.Kind().String(), t.Elem().Kind().String(), ErrTypeUnknown)
|
|
case reflect.Array:
|
|
return fmt.Errorf("ssob: Type '%s' with types '%s' unknown: %w", t.Kind().String(), t.Name(), ErrTypeUnknown)
|
|
default:
|
|
if v, ok := cacheTypes.names[t.Kind().String()]; !ok {
|
|
return fmt.Errorf("ssob: Type '%s' unknown: %w", t.Kind().String(), ErrTypeUnknown)
|
|
} else {
|
|
enc.mutex.Lock()
|
|
defer enc.mutex.Unlock()
|
|
return cacheTypes.types[v].marshal(e, enc.w)
|
|
}
|
|
}
|
|
}
|