diff --git a/src/Falanx.Proto.Codec.Binary/Codec.fs b/src/Falanx.Proto.Codec.Binary/Codec.fs index c5fef6a..b88b41f 100644 --- a/src/Falanx.Proto.Codec.Binary/Codec.fs +++ b/src/Falanx.Proto.Codec.Binary/Codec.fs @@ -24,6 +24,7 @@ namespace Falanx.Proto.Codec.Binary type proto_map<'Key, 'Value> = Collections.Generic.Dictionary<'Key, 'Value> type Writer<'T> = FieldNum -> ZeroCopyBuffer -> 'T -> unit + type PackedWriter<'T> = (ResizeArray<'T> -> uint64, 'T -> ZeroCopyBuffer -> unit) // (obtain len fn, encode val fn) type Reader<'T> = RawField -> 'T // Eventually this interface could be addd to Froto itself @@ -89,6 +90,20 @@ namespace Falanx.Proto.Codec.Binary let writeBool: Writer = write Encode.fromBool let writeString: Writer = write Encode.fromString let writeBytes: Writer = write Encode.fromBytes + + let writeDoublePacked: PackedWriter = (fun a -> a.length * 8, Pack.toDouble) + let writeFloatPacked: PackedWriter = (fun a -> a.length * 4, Pack.toSingle) + let writeInt32Packed: PackedWriter = (Seq.sumBy (uint64 >> Utility.varIntLenNoDefault), uint64 >> Pack.toVarint) + let writeInt64Packed: PackedWriter = (Seq.sumBy (uint64 >> Utility.varIntLenNoDefault), uint64 >> Pack.toVarint) + let writeUInt32Packed: PackedWriter = (Seq.sumBy (uint64 >> Utility.varIntLenNoDefault), uint64 >> Pack.toVarint) + let writeUInt64Packed: PackedWriter = (Seq.sumBy (uint64 >> Utility.varIntLenNoDefault), Pack.toVarint) + let writeSInt32Packed: PackedWriter = (Seq.sumBy (zigZag32 >> uint64 >> Utility.varIntLenNoDefault), zigZag32 >> uint64 >> Pack.toVarint) + let writeSInt64Packed: PackedWriter = (Seq.sumBy (zigZag64 >> uint64 >> Utility.varIntLenNoDefault), zigZag32 >> uint64 >> Pack.toVarint) + let writeFixed32Packed: PackedWriter = (fun a -> a.length * 4, Pack.toFixed32) + let writeFixed64Packed: PackedWriter = (fun a -> a.length * 8, Pack.toFixed64) + let writeSFixed32Packed: PackedWriter = (fun a -> a.length * 4, uint32 >> Pack.toFixed32) + let writeSFixed64Packed: PackedWriter = (fun a -> a.length * 8, uint64 >> Pack.toFixed64) + let writeBoolPacked: PackedWriter = (fun a -> a.length, Pack.toBool) /// Serializes optional field using provided function to handle inner value if present let writeOptional (writeInner: Writer<'T>) (position: FieldNum) buffer value = @@ -119,7 +134,13 @@ namespace Falanx.Proto.Codec.Binary let writeRepeated (writeItem: Writer<'T>) position buffer value = value |> Seq.iter (writeItem position buffer) - + + let writeRepeatedPacked ((getLen, writeItemPacked): PackedWriter<'T>) position buffer (value: ResizeArray<'T>) = + let vlen = getLen value + Pack.toTag position WireType.LengthDelimited buffer |> ignore + Pack.toVarint vlen buffer |> ignore + Seq.iter (fun v -> writeItemPacked v buffer) value + let writeRepeatedEmbedded<'a when 'a :> IMessage > (position, buffer, value ) = for (v: 'a) in (value: ResizeArray<'a>) do buffer diff --git a/src/Falanx.Proto.Core/BinaryCodec/Serialization.fs b/src/Falanx.Proto.Core/BinaryCodec/Serialization.fs index 655d97f..d30cd03 100644 --- a/src/Falanx.Proto.Core/BinaryCodec/Serialization.fs +++ b/src/Falanx.Proto.Core/BinaryCodec/Serialization.fs @@ -27,7 +27,23 @@ module Serialization = | "bool" -> <@@ writeBool @@> | "string" -> <@@ writeString @@> | "bytes" -> <@@ writeBytes @@> - | x -> failwithf "Type %A nor supported" x + | x -> failwithf "Type %A not supported" x + + let primitivePackedWriter = function + | "double" -> <@@ writeDoublePacked @@> + | "float" -> <@@ writeFloatPacked @@> + | "int32" -> <@@ writeInt32Packed @@> + | "int64" -> <@@ writeInt64Packed @@> + | "uint32" -> <@@ writeUInt32Packed @@> + | "uint64" -> <@@ writeUInt64Packed @@> + | "sint32" -> <@@ writeSInt32Packed @@> + | "sint64" -> <@@ writeSInt64Packed @@> + | "fixed32" -> <@@ writeFixed32Packed @@> + | "fixed64" -> <@@ writeFixed64Packed @@> + | "sfixed32" -> <@@ writeSFixed32Packed @@> + | "sfixed64" -> <@@ writeSFixed64Packed @@> + | "bool" -> <@@ writeBoolPacked @@> + | x -> failwithf "Type %A not supported" x let serializeMapExpr buffer this (map: MapDescriptor) = let keyWriter = primitiveWriter map.KeyType.ProtobufType @@ -54,20 +70,25 @@ module Serialization = [keyWriter; positionExpr; buffer; mapExpr] <@@ writeEnumMap x x x x @@> - let callPrimitive writer (prop: PropertyDescriptor) rule position buffer value = + let callPrimitive (prop: PropertyDescriptor) rule position buffer value = let args = [position; buffer; value] match rule with | Required -> - Expr.apply writer args + Expr.apply (primitiveWriter prop.Type.ProtobufType) args | Optional -> Expr.callStaticGeneric [prop.Type.UnderlyingType] - [writer; position; buffer; value] + [primitiveWriter prop.Type.ProtobufType; position; buffer; value] <@@ writeOption x x x x @@> + | Repeated when prop.Type.ProtobufType <> "string" && prop.Type.ProtobufType <> "bytes" -> + Expr.callStaticGeneric + [prop.Type.UnderlyingType] + ((primitivePackedWriter prop.Type.ProtobufType) ::args) + <@@ writeRepeatedPacked x x x x @@> | Repeated -> Expr.callStaticGeneric [prop.Type.UnderlyingType] - (writer::args) + ((primitiveWriter prop.Type.ProtobufType) ::args) <@@ writeRepeated x x x x @@> @@ -114,7 +135,7 @@ module Serialization = [ <@@ writeInt32 @@> ;position; buffer; seqMap] <@@ writeRepeated x x x x @@> | Primitive _type, rule -> - callPrimitive (primitiveWriter prop.Type.ProtobufType) prop rule position buffer value + callPrimitive prop rule position buffer value with | ex -> printfn "Failed to serialize property %s: %O. Error: %O" prop.ProvidedProperty.Name value.Type ex