mus-dts-go provides DTM support for the mus-go serializer. It allows to create DTS (DTM Support) for a type.
DTSs are useful when there is a need to deserialize data, but we don't know in
advance what type it is. For example, it could be Foo
or Bar
(or it could be
just different versions of the same data, like FooV1
or FooV2
), we just
don't know, but want to handle both of these cases.
DTS encode/decode DTM (which is just a number) + data itself. Thanks to DTM, we can distinguish one type of data from another, let's see how:
package main
import (
"math/rand"
com "github.com/mus-format/common-go"
dts "github.com/mus-format/mus-dts-go"
"github.com/mus-format/mus-go"
)
// First of all, we have to define DTMs, unique DTM for each type.
const (
FooDTM = iota + 1
BarDTM
)
type Foo struct{...}
type Bar struct{..}
// Then define Marshal/Unmarshal/Size/Skip functions.
func MarshalFooMUS(f Foo, bs []byte) (n int) {...}
func UnmarshalFooMUS(bs []byte) (f Foo, n int, err error) {...}
func SizeFooMUS(v Foo) (size int) {...}
func SkipFooMUS(bs []byte) (n int, err error) {...}
func MarshalBarMUS(b Bar, bs []byte) (n int) {...}
func UnmarshalBarMUS(bs []byte) (b Bar, n int, err error) {...}
func SizeBarMUS(b Bar) (size int) {...}
func SkipBarMUS(bs []byte) (n int, err error) {...}
// And only now we can define DTSs.
var FooDTS = dts.New[Foo](FooDTM,
mus.MarshallerFn[Foo](MarshalFooMUS),
mus.UnmarshallerFn[Foo](UnmarshalFooMUS),
mus.SizerFn[Foo](SizeFooMUS),
mus.Skipper(SkipFooMUS),
)
var BarDTS = dts.New[Bar](BarDTM,
mus.MarshallerFn[Bar](MarshalBarMUS),
mus.UnmarshallerFn[Bar](UnmarshalBarMUS),
mus.SizerFn[Bar](SizeBarMUS),
mus.Skipper(SkipBarMUS),
)
func main() {
// Let's make a random data
bs, err := randomData()
if err != nil {
panic(err)
}
// and Unmarshal DTM.
dtm, n, err := dts.UnmarshalDTM(bs)
if err != nil {
panic(err)
}
// Now we can deserialize and process data depending on the DTM.
switch dtm {
case FooDTM:
foo, _, err := FooDTS.UnmarshalData(bs[n:])
// process foo ...
case BarDTM:
bar, _, err := BarDTS.UnmarshalData(bs[n:])
// process bar ...
default:
panic(fmt.Sprintf("unexpected %v DTM", dtm))
}
}
func randomData() (bs []byte) {
// Generate random DTM
dtm := com.DTM(rand.Intn(2) + 1)
switch dtm {
// Marshal Foo
case FooDTM:
foo := Foo{...}
bs = make([]byte, FooDTS.Size(foo))
FooDTS.Marshal(foo, bs)
// Marshal Bar
case BarDTM:
bar := Bar{...}
bs = make([]byte, BarDTS.Size(bar))
BarDTS.Marshal(bar, bs)
default:
panic(fmt.Sprintf("unexpected %v DTM", dtm))
}
return
}
A full example can be found at mus-examples-go
Test coverage is 100%.