Created
May 24, 2021 19:13
-
-
Save object/dbfc9069725504ced1069eebe5be405c to your computer and use it in GitHub Desktop.
Protobuf serialization in F#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module ProtobufSerializationTests | |
open System | |
open System.IO | |
open ProtoBuf | |
open Xunit | |
module ProtoBufUtils = | |
[<ProtoContract>] | |
type DateTimeOffsetSurrogate() = | |
[<ProtoMember(1)>] | |
member val DateTimeString = "" with get, set | |
static member public op_Implicit(value : DateTimeOffset) : DateTimeOffsetSurrogate = | |
DateTimeOffsetSurrogate(DateTimeString = value.ToString("o")) | |
static member public op_Implicit(value : DateTimeOffsetSurrogate) : DateTimeOffset = | |
DateTimeOffset.Parse(value.DateTimeString) | |
let initProtoBuf () = | |
ProtoBuf.Meta.RuntimeTypeModel.Default.Add(typedefof<DateTimeOffset>, false).SetSurrogate(typedefof<DateTimeOffsetSurrogate>) | |
[<AllowNullLiteral>] | |
type IProtoBufSerializable = interface end | |
[<AllowNullLiteral>] | |
type IProtoBufSerializableEvent = | |
inherit IProtoBufSerializable | |
abstract member Timestamp : DateTimeOffset | |
[<ProtoContract;CLIMutable;NoComparison>] | |
type ReceivedTranscodingVersion = | |
{ [<ProtoMember(1)>] Version : int | |
[<ProtoMember(2)>] Timestamp : DateTimeOffset } | |
interface IProtoBufSerializableEvent with | |
member this.Timestamp = this.Timestamp | |
static member FromDomainWithTimestamp (version, timestamp) = | |
{ Version = version | |
Timestamp = timestamp } | |
static member FromDomain version = | |
ReceivedTranscodingVersion.FromDomainWithTimestamp (version, DateTimeOffset.Now) | |
member this.ToDomain() = | |
this.Version | |
[<ProtoContract;CLIMutable;NoComparison>] | |
type AssignedProgramId = | |
{ [<ProtoMember(1)>] ProgramId : string | |
[<ProtoMember(2)>] Timestamp : DateTimeOffset } | |
interface IProtoBufSerializableEvent with | |
member this.Timestamp = this.Timestamp | |
static member FromDomainWithTimestamp (progId, timestamp) = | |
{ ProgramId = progId | |
Timestamp = timestamp } | |
static member FromDomain piProgId = | |
AssignedProgramId.FromDomainWithTimestamp (piProgId, DateTimeOffset.Now) | |
member this.ToDomain() = | |
this.ProgramId | |
let [<Literal>] AssignedProgramIdManifest = "AssignedProgramId" | |
let [<Literal>] ReceivedTranscodingVersionManifest = "ReceivedTranscodingVersion" | |
type ProtobufSerializer () = | |
member this.ToBinary(o:obj) = | |
use stream = new MemoryStream() | |
Serializer.Serialize(stream, o) | |
stream.ToArray() | |
member this.FromBinary(bytes:byte[], manifest:string) = | |
use stream = new MemoryStream(bytes) | |
let typ = | |
match manifest with | |
| AssignedProgramIdManifest -> typedefof<AssignedProgramId> | |
| ReceivedTranscodingVersionManifest -> typedefof<ReceivedTranscodingVersion> | |
| _ -> failwith $"Unknown manifest: %s{manifest}" | |
Serializer.Deserialize(typ, stream) | |
member this.Manifest(o:obj) = | |
match o with | |
| :? AssignedProgramId -> AssignedProgramIdManifest | |
| :? ReceivedTranscodingVersion -> ReceivedTranscodingVersionManifest | |
| _ -> failwith $"Unknown type : %s{o.GetType().FullName}" | |
let testSerialization<'DomainType,'PersistentType> (serializer : ProtobufSerializer) (domainMsg : 'DomainType) fromDomain toDomain (manifest : string) = | |
let input = fromDomain domainMsg | |
let bytes = serializer.ToBinary(input) | |
let deserialized = serializer.FromBinary(bytes, manifest) :?> 'PersistentType | |
Assert.Equal(input, deserialized) | |
Assert.Equal(domainMsg, toDomain deserialized) | |
[<Fact>] | |
let ``Test round trip serialization`` () = | |
ProtoBufUtils.initProtoBuf () | |
let serializer = ProtobufSerializer() | |
let versionMessage = 0 | |
testSerialization serializer versionMessage ReceivedTranscodingVersion.FromDomain (fun x -> x.ToDomain()) ReceivedTranscodingVersionManifest | |
let msg = "abcd" | |
testSerialization serializer msg AssignedProgramId.FromDomain (fun x -> x.ToDomain()) AssignedProgramIdManifest |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment