src.dualinventive.com/go/dinet/rpc/deferred_decoder.go

121 lines
3.0 KiB
Go

package rpc
import (
"encoding/json"
"fmt"
"gopkg.in/vmihailenco/msgpack.v4"
)
type decoderDataType string
const (
decoderDataTypeJSON decoderDataType = "json"
decoderDataTypeMsgpack decoderDataType = "msgpack"
)
type genericUnmarshaller func([]byte, interface{}) error
// deferredDecoder defers unmarshalling for specific types, it also supports
// re-marshalling the same thing and marshalling generig types
type deferredDecoder struct {
data []byte
dataType decoderDataType
out interface{}
unmarshaller genericUnmarshaller
}
// IsEmpty returns when this struct is empty. It is empty when there is no data and no out value
func (p *deferredDecoder) IsEmpty() bool {
return len(p.data) == 0 && p.out == nil
}
func (p *deferredDecoder) String() string {
data, err := p.MarshalJSON()
if err != nil {
return fmt.Sprintf("ERROR:%v", err)
}
return string(data)
}
// UnmarshalJSON unmashals json code
func (p *deferredDecoder) UnmarshalJSON(data []byte) error {
p.data = data
p.unmarshaller = json.Unmarshal
p.dataType = decoderDataTypeJSON
return nil
}
// MarshalJSON marshals json code
func (p *deferredDecoder) MarshalJSON() ([]byte, error) {
if p.out == nil {
if len(p.data) == 0 {
return []byte("null"), nil
}
switch p.dataType {
case decoderDataTypeJSON:
return p.data, nil
case decoderDataTypeMsgpack:
// we want to marshal JSON and have msgpack we
// unmarshall this into p.out and leave the
// marshaller at the end to marshal it
p.out = map[interface{}]interface{}{}
if err := p.Unmarshal(p.out); err != nil {
return nil, err
}
}
}
return json.Marshal(p.out)
}
// MarshalMsgpack msgpack marshaler
func (p *deferredDecoder) MarshalMsgpack() ([]byte, error) {
if p.out == nil {
switch p.dataType {
case decoderDataTypeMsgpack:
return p.data, nil
case decoderDataTypeJSON:
// we want to marshal msgpack and have JSON we
// unmarshall this into p.out and leave the
// marshaller at the end to marshal it
p.out = map[interface{}]interface{}{}
if err := p.Unmarshal(p.out); err != nil {
return nil, err
}
}
}
return msgpack.Marshal(p.out)
}
// UnmarshalMsgpack msgpack unmarshaler
func (p *deferredDecoder) UnmarshalMsgpack(data []byte) error {
p.data = data
p.unmarshaller = msgpack.Unmarshal
p.dataType = decoderDataTypeMsgpack
return nil
}
// Unmarshal unpacks parameters into the provided destination
func (p *deferredDecoder) Unmarshal(dst interface{}) error {
if p.unmarshaller == nil {
return ErrMsgNoData
}
return p.unmarshaller(p.data, dst)
}
// RetrieveResultData retrieves the data from the result object when it is an deferred decoder
func RetrieveResultData(msg *Msg) interface{} {
if dec, ok := msg.Result.(*deferredDecoder); ok {
return dec.out
}
return nil
}
// RetrieveParamsData retrieves the data from the result object when it is an deferred decoder
func RetrieveParamsData(msg *Msg) interface{} {
if dec, ok := msg.Params.(*deferredDecoder); ok {
return dec.out
}
return nil
}