package ssob import ( "encoding/binary" "errors" "fmt" "io" "reflect" "sync" ) 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) { return enc.EncodeValue(reflect.ValueOf(e)) } func (enc *Encoder) EncodeValue(value reflect.Value) (err error) { if value.Type() == reflect.TypeOf(errors.New("")) || value.Type() == reflect.TypeOf((*error)(nil)).Elem() { if value.IsNil() { return enc.Encode(string("")) } else { return enc.Encode(value.Interface().(error).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) }