├── .github └── renovate.json ├── .gitignore ├── BinaryBenchmark.AvroConvert.cs ├── BinaryBenchmark.BSON.cs ├── BinaryBenchmark.Bebop.cs ├── BinaryBenchmark.CBOR.cs ├── BinaryBenchmark.GroBuf.cs ├── BinaryBenchmark.Hyperion.cs ├── BinaryBenchmark.MemoryPack.cs ├── BinaryBenchmark.MessagePack.cs ├── BinaryBenchmark.MsgPack.cs ├── BinaryBenchmark.ProtobufNet.cs ├── BinaryBenchmark.cs ├── Converters └── Cbor │ └── GuidConverter.cs ├── Data_Large.json ├── Data_Medium.json ├── Data_Small.json ├── JsonBenchmark.cs ├── JsonBenchmarks.Jil.cs ├── JsonBenchmarks.NewtonsoftJson.cs ├── JsonBenchmarks.ServiceStack.cs ├── JsonBenchmarks.SpanJson.cs ├── JsonBenchmarks.System.Text.Json-SrcGen.cs ├── JsonBenchmarks.System.Text.Json.cs ├── JsonBenchmarks.UTF8Json.cs ├── LICENSE ├── Models ├── Bebop.Models.g.cs ├── Gender.cs ├── Models.bop ├── Order.cs └── User.cs ├── Program.cs ├── README.md ├── SerializationBenchmarks.csproj ├── SerializationBenchmarks.sln └── SerializerBenchmark.cs /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | ":disableDependencyDashboard", 5 | ":rebaseStalePrs" 6 | ], 7 | "addLabels": [ 8 | "type: dependencies" 9 | ], 10 | "groupName": "all dependencies", 11 | "groupSlug": "all", 12 | "packageRules": [ 13 | { 14 | "automerge": true, 15 | "groupName": "all dependencies", 16 | "groupSlug": "all", 17 | "matchPackagePatterns": [ 18 | "*" 19 | ], 20 | "matchUpdateTypes": [ 21 | "minor", 22 | "patch", 23 | "pin", 24 | "digest" 25 | ] 26 | } 27 | ], 28 | "semanticCommits": "enabled", 29 | "separateMajorMinor": false 30 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | .idea/ 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # .NET Core 57 | project.lock.json 58 | project.fragment.lock.json 59 | artifacts/ 60 | 61 | # StyleCop 62 | StyleCopReport.xml 63 | 64 | # Files built by Visual Studio 65 | *_i.c 66 | *_p.c 67 | *_h.h 68 | *.ilk 69 | *.meta 70 | *.obj 71 | *.iobj 72 | *.pch 73 | *.pdb 74 | *.ipdb 75 | *.pgc 76 | *.pgd 77 | *.rsp 78 | *.sbr 79 | *.tlb 80 | *.tli 81 | *.tlh 82 | *.tmp 83 | *.tmp_proj 84 | *_wpftmp.csproj 85 | *.vspscc 86 | *.vssscc 87 | .builds 88 | *.pidb 89 | *.svclog 90 | *.scc 91 | 92 | # Chutzpah Test files 93 | _Chutzpah* 94 | 95 | # Visual C++ cache files 96 | ipch/ 97 | *.aps 98 | *.ncb 99 | *.opendb 100 | *.opensdf 101 | *.sdf 102 | *.cachefile 103 | *.VC.db 104 | *.VC.VC.opendb 105 | 106 | # Visual Studio profiler 107 | *.psess 108 | *.vsp 109 | *.vspx 110 | *.sap 111 | 112 | # Visual Studio Trace Files 113 | *.e2e 114 | 115 | # TFS 2012 Local Workspace 116 | $tf/ 117 | 118 | # Guidance Automation Toolkit 119 | *.gpState 120 | 121 | # ReSharper is a .NET coding add-in 122 | _ReSharper*/ 123 | *.[Rr]e[Ss]harper 124 | *.DotSettings.user 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # NuGet Symbol Packages 184 | *.snupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | *.appxbundle 210 | *.appxupload 211 | 212 | # Visual Studio cache files 213 | # files ending in .cache can be ignored 214 | *.[Cc]ache 215 | # but keep track of directories ending in .cache 216 | !?*.[Cc]ache/ 217 | 218 | # Others 219 | ClientBin/ 220 | ~$* 221 | *~ 222 | *.dbmdl 223 | *.dbproj.schemaview 224 | *.jfm 225 | *.pfx 226 | *.publishsettings 227 | orleans.codegen.cs 228 | 229 | # Including strong name files can present a security risk 230 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 231 | #*.snk 232 | 233 | # Since there are multiple workflows, uncomment next line to ignore bower_components 234 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 235 | #bower_components/ 236 | 237 | # RIA/Silverlight projects 238 | Generated_Code/ 239 | 240 | # Backup & report files from converting an old project file 241 | # to a newer Visual Studio version. Backup files are not needed, 242 | # because we have git ;-) 243 | _UpgradeReport_Files/ 244 | Backup*/ 245 | UpgradeLog*.XML 246 | UpgradeLog*.htm 247 | ServiceFabricBackup/ 248 | *.rptproj.bak 249 | 250 | # SQL Server files 251 | *.mdf 252 | *.ldf 253 | *.ndf 254 | 255 | # Business Intelligence projects 256 | *.rdl.data 257 | *.bim.layout 258 | *.bim_*.settings 259 | *.rptproj.rsuser 260 | *- [Bb]ackup.rdl 261 | *- [Bb]ackup ([0-9]).rdl 262 | *- [Bb]ackup ([0-9][0-9]).rdl 263 | 264 | # Microsoft Fakes 265 | FakesAssemblies/ 266 | 267 | # GhostDoc plugin setting file 268 | *.GhostDoc.xml 269 | 270 | # Node.js Tools for Visual Studio 271 | .ntvs_analysis.dat 272 | node_modules/ 273 | 274 | # Visual Studio 6 build log 275 | *.plg 276 | 277 | # Visual Studio 6 workspace options file 278 | *.opt 279 | 280 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 281 | *.vbw 282 | 283 | # Visual Studio LightSwitch build output 284 | **/*.HTMLClient/GeneratedArtifacts 285 | **/*.DesktopClient/GeneratedArtifacts 286 | **/*.DesktopClient/ModelManifest.xml 287 | **/*.Server/GeneratedArtifacts 288 | **/*.Server/ModelManifest.xml 289 | _Pvt_Extensions 290 | 291 | # Paket dependency manager 292 | .paket/paket.exe 293 | paket-files/ 294 | 295 | # FAKE - F# Make 296 | .fake/ 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb 341 | 342 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 343 | MigrationBackup/ 344 | 345 | # Ionide (cross platform F# VS Code tools) working folder 346 | .ionide/ 347 | 348 | # Benchmark Results 349 | BenchmarkDotNet.Artifacts/ -------------------------------------------------------------------------------- /BinaryBenchmark.AvroConvert.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using SerializationBenchmarks.Models; 3 | using SolTechnology.Avro; 4 | 5 | public partial class BinaryBenchmark 6 | { 7 | [Benchmark, BenchmarkCategory("Serialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 8 | public byte[] AvroConvert_Serialize(DataSet data) 9 | { 10 | return DataConvert_AvroConvert(data.Payload); 11 | } 12 | 13 | [Benchmark, BenchmarkCategory("Deserialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 14 | public List AvroConvert_Deserialize(DataSet data) 15 | { 16 | return AvroConvert.Deserialize>(data.SerializedData.AvroConvert); 17 | } 18 | 19 | private byte[] DataConvert_AvroConvert(List users) => AvroConvert.Serialize(users); 20 | } -------------------------------------------------------------------------------- /BinaryBenchmark.BSON.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using MongoDB.Bson.IO; 3 | using MongoDB.Bson.Serialization; 4 | using SerializationBenchmarks.Models; 5 | 6 | public partial class BinaryBenchmark 7 | { 8 | [Benchmark, BenchmarkCategory("Serialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 9 | public byte[] BSON_Serialize(DataSet data) 10 | { 11 | return DataConvert_BSON(data.Payload); 12 | } 13 | 14 | [Benchmark, BenchmarkCategory("Deserialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 15 | public List BSON_Deserialize(DataSet data) 16 | { 17 | return BsonSerializer.Deserialize(data.SerializedData.BSON).Users; 18 | } 19 | 20 | // We need this because we cannot write an array to the root of a bson document 21 | public record UserWrapper(List Users); 22 | 23 | private byte[] DataConvert_BSON(List users) 24 | { 25 | using var ms = new MemoryStream(); 26 | var writer = new BsonBinaryWriter(ms); 27 | BsonSerializer.Serialize(writer, new UserWrapper(users)); 28 | return ms.ToArray(); 29 | } 30 | } -------------------------------------------------------------------------------- /BinaryBenchmark.Bebop.cs: -------------------------------------------------------------------------------- 1 | using System.Buffers; 2 | using System.Text.Json; 3 | using System.Text.Json.Serialization; 4 | using BenchmarkDotNet.Attributes; 5 | using SerializationBenchmarks.Models.Bebop; 6 | using Wrapper = SerializationBenchmarks.Models.Bebop.UserWrapper; 7 | 8 | public partial class BinaryBenchmark 9 | { 10 | [Benchmark, BenchmarkCategory("Serialization", "Binary"), ArgumentsSource(nameof(GenerateBebopDataSets))] 11 | public ReadOnlyMemory Bebop_Serialize(BebopDataSet data) 12 | { 13 | return DataConvert_Bebop(data.Payload); 14 | } 15 | 16 | [Benchmark, BenchmarkCategory("Deserialization", "Binary"), ArgumentsSource(nameof(GenerateBebopDataSets))] 17 | public User[] Bebop_Deserialize(BebopDataSet data) 18 | { 19 | return Wrapper.Decode(data.Data).Users; 20 | } 21 | 22 | private ReadOnlyMemory DataConvert_Bebop(User[] users) 23 | { 24 | var wrapper = new Wrapper { Users = users }; 25 | var size = wrapper.MaxByteCount; 26 | var encodeBuffer = ArrayPool.Shared.Rent(size); 27 | try 28 | { 29 | var written = wrapper.EncodeIntoBuffer(encodeBuffer); 30 | return new ReadOnlyMemory(encodeBuffer, 0, written); 31 | } finally 32 | { 33 | ArrayPool.Shared.Return(encodeBuffer); 34 | } 35 | 36 | } 37 | 38 | public IEnumerable GenerateBebopDataSets() 39 | { 40 | var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; 41 | options.Converters.Add(new JsonStringEnumConverter()); 42 | var sets = new[] 43 | { 44 | #if DATASET_SMALL 45 | new { File = "Data_Small.json", Subset = "Small" }, 46 | #endif 47 | #if DATASET_MEDIUM 48 | new { File = "Data_Medium.json", Subset = "Medium" }, 49 | #endif 50 | #if DATASET_LARGE 51 | new { File = "Data_Large.json", Subset = "Large" }, 52 | #endif 53 | }; 54 | 55 | foreach (var set in sets) 56 | { 57 | var json = File.ReadAllText(set.File); 58 | var users = JsonSerializer.Deserialize>(json, options)!.ToArray(); 59 | yield return new BebopDataSet 60 | { 61 | Name = set.Subset, 62 | Payload = users, 63 | Data = DataConvert_Bebop(users) 64 | }; 65 | } 66 | } 67 | 68 | public class BebopDataSet 69 | { 70 | public string Name { get; set; } 71 | public User[] Payload { get; set; } 72 | public ReadOnlyMemory Data { get; set; } 73 | public override string ToString() => Name; 74 | } 75 | } -------------------------------------------------------------------------------- /BinaryBenchmark.CBOR.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using Dahomey.Cbor; 3 | using SerializationBenchmarks.Converters.Cbor; 4 | using SerializationBenchmarks.Models; 5 | 6 | public partial class BinaryBenchmark 7 | { 8 | private static readonly CborOptions _options = new(); 9 | 10 | static BinaryBenchmark() 11 | { 12 | _options.Registry.ConverterRegistry.RegisterConverter(typeof(Guid), new GuidConverter()); 13 | } 14 | 15 | [Benchmark, BenchmarkCategory("Serialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 16 | public Task CBOR_Serialize(DataSet data) 17 | { 18 | return DataConvert_CBOR(data.Payload); 19 | } 20 | 21 | [Benchmark, BenchmarkCategory("Deserialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 22 | public ValueTask> CBOR_Deserialize(DataSet data) 23 | { 24 | using var ms = new MemoryStream(data.SerializedData.CBOR); 25 | return Cbor.DeserializeAsync>(ms, _options); 26 | } 27 | 28 | private async Task DataConvert_CBOR(List users) 29 | { 30 | using var ms = new MemoryStream(); 31 | await Cbor.SerializeAsync(users, ms, _options).ConfigureAwait(false); 32 | return ms.ToArray(); 33 | } 34 | } -------------------------------------------------------------------------------- /BinaryBenchmark.GroBuf.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using GroBuf; 3 | using GroBuf.DataMembersExtracters; 4 | using SerializationBenchmarks.Models; 5 | 6 | public partial class BinaryBenchmark 7 | { 8 | private readonly Serializer _groSerializer = new Serializer(new PropertiesExtractor(), options : GroBufOptions.WriteEmptyObjects); 9 | 10 | 11 | [Benchmark, BenchmarkCategory("Serialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 12 | public byte[] GroBuf_Serialize(DataSet data) 13 | { 14 | return DataConvert_GroBuf(data.Payload); 15 | } 16 | 17 | [Benchmark, BenchmarkCategory("Deserialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 18 | public List GroBuf_Deserialize(DataSet data) 19 | { 20 | return _groSerializer.Deserialize>(data.SerializedData.GroBuf); 21 | } 22 | 23 | private byte[] DataConvert_GroBuf(List users) 24 | { 25 | return _groSerializer.Serialize(users); 26 | } 27 | } -------------------------------------------------------------------------------- /BinaryBenchmark.Hyperion.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using Hyperion; 3 | using SerializationBenchmarks.Models; 4 | 5 | public partial class BinaryBenchmark 6 | { 7 | private readonly Serializer _hyperionSerializer= new Hyperion.Serializer(); 8 | 9 | 10 | [Benchmark, BenchmarkCategory("Serialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 11 | public byte[] Hyperion_Serialize(DataSet data) 12 | { 13 | return DataConvert_Hyperion(data.Payload); 14 | } 15 | 16 | [Benchmark, BenchmarkCategory("Deserialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 17 | public List Hyperion_Deserialize(DataSet data) 18 | { 19 | using var ms = new MemoryStream(data.SerializedData.Hyperion); 20 | ms.Position = 0; 21 | return _hyperionSerializer.Deserialize>(ms); 22 | } 23 | 24 | private byte[] DataConvert_Hyperion(List users) 25 | { 26 | using var ms = new MemoryStream(); 27 | _hyperionSerializer.Serialize(users, ms); 28 | return ms.ToArray(); 29 | } 30 | } -------------------------------------------------------------------------------- /BinaryBenchmark.MemoryPack.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using MemoryPack; 3 | using SerializationBenchmarks.Models; 4 | 5 | public partial class BinaryBenchmark 6 | { 7 | [Benchmark, BenchmarkCategory("Serialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 8 | public byte[] MemoryPack_Serialize(DataSet data) 9 | { 10 | return DataConvert_MemoryPack(data.Payload); 11 | } 12 | 13 | [Benchmark, BenchmarkCategory("Deserialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 14 | public List MemoryPack_Deserialize(DataSet data) 15 | { 16 | return MemoryPackSerializer.Deserialize>(data.SerializedData.MemoryPack); 17 | } 18 | 19 | private byte[] DataConvert_MemoryPack(List users) 20 | { 21 | return MemoryPackSerializer.Serialize(users); 22 | } 23 | } -------------------------------------------------------------------------------- /BinaryBenchmark.MessagePack.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using MessagePack; 3 | using SerializationBenchmarks.Models; 4 | 5 | public partial class BinaryBenchmark 6 | { 7 | [Benchmark, BenchmarkCategory("Serialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 8 | public byte[] MessagePack_Serialize(DataSet data) 9 | { 10 | return DataConvert_MessagePack(data.Payload); 11 | } 12 | 13 | [Benchmark, BenchmarkCategory("Deserialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 14 | public List MessagePack_Deserialize(DataSet data) 15 | { 16 | return MessagePackSerializer.Deserialize>(data.SerializedData.MessagePack); 17 | } 18 | 19 | private byte[] DataConvert_MessagePack(List users) 20 | { 21 | return MessagePackSerializer.Serialize(users); 22 | } 23 | } -------------------------------------------------------------------------------- /BinaryBenchmark.MsgPack.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using MsgPack.Serialization; 3 | using SerializationBenchmarks.Models; 4 | 5 | public partial class BinaryBenchmark 6 | { 7 | private readonly MessagePackSerializer> _msgPackSerializer = MessagePackSerializer.Get>(); 8 | 9 | [Benchmark, BenchmarkCategory("Serialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 10 | public byte[] MsgPack_Serialize(DataSet data) 11 | { 12 | return DataConvert_MsgPack(data.Payload); 13 | } 14 | 15 | [Benchmark, BenchmarkCategory("Deserialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 16 | public List MsgPack_Deserialize(DataSet data) 17 | { 18 | return _msgPackSerializer.UnpackSingleObject(data.SerializedData.MsgPack); 19 | } 20 | 21 | private byte[] DataConvert_MsgPack(List users) 22 | { 23 | return _msgPackSerializer.PackSingleObject(users); 24 | } 25 | } -------------------------------------------------------------------------------- /BinaryBenchmark.ProtobufNet.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using ProtoBuf; 3 | using SerializationBenchmarks.Models; 4 | 5 | public partial class BinaryBenchmark 6 | { 7 | [Benchmark, BenchmarkCategory("Serialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 8 | public byte[] ProtoBufNet_Serialize(DataSet data) 9 | { 10 | return DataConvert_ProtoBufNet(data.Payload); 11 | } 12 | 13 | [Benchmark, BenchmarkCategory("Deserialization", "Binary"), ArgumentsSource(nameof(GenerateDataSets))] 14 | public List ProtoBufNet_Deserialize(DataSet data) 15 | { 16 | using var ms = new MemoryStream(data.SerializedData.ProtoBufNet); 17 | return Serializer.Deserialize>(ms); 18 | } 19 | 20 | private byte[] DataConvert_ProtoBufNet(List users) 21 | { 22 | using var ms = new MemoryStream(); 23 | Serializer.Serialize(ms, users); 24 | return ms.ToArray(); 25 | } 26 | } -------------------------------------------------------------------------------- /BinaryBenchmark.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using System.Text.Json.Serialization; 3 | using BenchmarkDotNet.Attributes; 4 | using SerializationBenchmarks.Models; 5 | using SolTechnology.Avro; 6 | 7 | public partial class BinaryBenchmark : SerializerBenchmark 8 | { 9 | public IEnumerable GenerateDataSets() 10 | { 11 | var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; 12 | options.Converters.Add(new JsonStringEnumConverter()); 13 | var sets = new[] 14 | { 15 | #if DATASET_SMALL 16 | new { File = "Data_Small.json", Subset = "Small" }, 17 | #endif 18 | #if DATASET_MEDIUM 19 | new { File = "Data_Medium.json", Subset = "Medium" }, 20 | #endif 21 | #if DATASET_LARGE 22 | new { File = "Data_Large.json", Subset = "Large" }, 23 | #endif 24 | }; 25 | 26 | foreach (var set in sets) 27 | { 28 | var json = File.ReadAllText(set.File); 29 | var users = JsonSerializer.Deserialize>(json, options); 30 | 31 | var cborData = DataConvert_CBOR(users).GetAwaiter().GetResult(); 32 | 33 | yield return new DataSet 34 | { 35 | Name = set.Subset, 36 | Payload = users, 37 | SerializedData = new() 38 | { 39 | AvroConvert = DataConvert_AvroConvert(users), 40 | BSON = DataConvert_BSON(users), 41 | CBOR = cborData, 42 | GroBuf = DataConvert_GroBuf(users), 43 | Hyperion = DataConvert_Hyperion(users), 44 | MessagePack = DataConvert_MessagePack(users), 45 | MemoryPack = DataConvert_MemoryPack(users), 46 | MsgPack = DataConvert_MsgPack(users), 47 | ProtoBufNet = DataConvert_ProtoBufNet(users), 48 | } 49 | }; 50 | } 51 | } 52 | 53 | public class DataSet 54 | { 55 | public string Name { get; set; } 56 | public List Payload { get; set; } 57 | public SerializedData SerializedData { get; set; } 58 | public override string ToString() => Name; 59 | } 60 | 61 | public class SerializedData 62 | { 63 | public byte[] AvroConvert { get; set; } 64 | public byte[] BSON { get; set; } 65 | public byte[] CBOR { get; set; } 66 | public byte[] GroBuf { get; set; } 67 | public byte[] Hyperion { get; set; } 68 | public byte[] MessagePack { get; set; } 69 | public byte[] MsgPack { get; set; } 70 | public byte[] ProtoBufNet { get; set; } 71 | public byte[] MemoryPack { get; set; } 72 | } 73 | } -------------------------------------------------------------------------------- /Converters/Cbor/GuidConverter.cs: -------------------------------------------------------------------------------- 1 | using Dahomey.Cbor; 2 | using Dahomey.Cbor.Serialization; 3 | using Dahomey.Cbor.Serialization.Converters; 4 | 5 | namespace SerializationBenchmarks.Converters.Cbor; 6 | 7 | internal sealed class GuidConverter : CborConverterBase 8 | { 9 | private const int CBOR_ARRAY_SIZE = 16; 10 | private const ulong TAG_UUID = 37; 11 | 12 | public override Guid Read(ref CborReader reader) 13 | { 14 | var value = reader.ReadByteString(); 15 | 16 | if (value.Length != CBOR_ARRAY_SIZE) 17 | { 18 | throw new CborException("Expected a CBOR byte array with 16 elements"); 19 | } 20 | 21 | return new Guid(value); 22 | } 23 | 24 | public override void Write(ref CborWriter writer, Guid value) 25 | { 26 | writer.WriteSemanticTag(TAG_UUID); 27 | 28 | Span bytes = new byte[CBOR_ARRAY_SIZE]; 29 | if (value.TryWriteBytes(bytes)) 30 | { 31 | writer.WriteByteString(bytes); 32 | } 33 | else 34 | { 35 | throw new CborException("Cannot serialize the GUID to CBOR"); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /JsonBenchmark.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using System.Text.Json.Serialization; 3 | using SerializationBenchmarks.Models; 4 | 5 | public partial class JsonBenchmark : SerializerBenchmark 6 | { 7 | private JsonSerializerOptions _systemTextJsonOptions; 8 | 9 | public IEnumerable GenerateDataSets() 10 | { 11 | _systemTextJsonOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; 12 | _systemTextJsonOptions.Converters.Add(new JsonStringEnumConverter()); 13 | var sets = new[] 14 | { 15 | #if DATASET_SMALL 16 | new { File = "Data_Small.json", Subset = "Small" }, 17 | #endif 18 | #if DATASET_MEDIUM 19 | new { File = "Data_Medium.json", Subset = "Medium" }, 20 | #endif 21 | #if DATASET_LARGE 22 | new { File = "Data_Large.json", Subset = "Large" }, 23 | #endif 24 | }; 25 | 26 | foreach (var set in sets) 27 | { 28 | var json = File.ReadAllText(set.File); 29 | yield return new DataSet { Name = set.Subset, Json = json, Payload = JsonSerializer.Deserialize>(json, _systemTextJsonOptions) }; 30 | } 31 | } 32 | 33 | public class DataSet 34 | { 35 | public string Name { get; set; } 36 | public List Payload { get; set; } 37 | public string Json { get; set; } 38 | 39 | public override string ToString() => Name; 40 | } 41 | } -------------------------------------------------------------------------------- /JsonBenchmarks.Jil.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using SerializationBenchmarks.Models; 3 | 4 | public partial class JsonBenchmark 5 | { 6 | private Jil.Options _jilOptions = new(serializationNameFormat: Jil.SerializationNameFormat.CamelCase); 7 | 8 | [Benchmark, BenchmarkCategory("Serialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 9 | public string Jil_Serialize(DataSet data) 10 | { 11 | return Jil.JSON.Serialize(data.Payload, _jilOptions); 12 | } 13 | 14 | [Benchmark, BenchmarkCategory("Deserialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 15 | public List Jil_Deserialize(DataSet data) 16 | { 17 | return Jil.JSON.Deserialize>(data.Json, _jilOptions); 18 | } 19 | } -------------------------------------------------------------------------------- /JsonBenchmarks.NewtonsoftJson.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using SerializationBenchmarks.Models; 3 | 4 | public partial class JsonBenchmark 5 | { 6 | private readonly Newtonsoft.Json.JsonSerializerSettings _newtonsoftSettings 7 | = new() { ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver { NamingStrategy = new Newtonsoft.Json.Serialization.CamelCaseNamingStrategy() } }; 8 | 9 | [Benchmark, BenchmarkCategory("Serialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 10 | public string NewtonsoftJson_Serialize(DataSet data) 11 | { 12 | return Newtonsoft.Json.JsonConvert.SerializeObject(data.Payload, _newtonsoftSettings); 13 | } 14 | 15 | [Benchmark, BenchmarkCategory("Deserialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 16 | public List NewtonsoftJson_Deserialize(DataSet data) 17 | { 18 | return Newtonsoft.Json.JsonConvert.DeserializeObject>(data.Json, _newtonsoftSettings); 19 | } 20 | } -------------------------------------------------------------------------------- /JsonBenchmarks.ServiceStack.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using SerializationBenchmarks.Models; 3 | 4 | public partial class JsonBenchmark 5 | { 6 | [Benchmark, BenchmarkCategory("Serialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 7 | public string ServiceStack_Serialize(DataSet data) 8 | { 9 | using var config = ServiceStack.Text.JsConfig.With(new ServiceStack.Text.Config 10 | { 11 | TextCase = ServiceStack.Text.TextCase.CamelCase 12 | }); 13 | 14 | return ServiceStack.Text.JsonSerializer.SerializeToString(data.Payload); 15 | } 16 | 17 | [Benchmark, BenchmarkCategory("Deserialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 18 | public List ServiceStack_Deserialize(DataSet data) 19 | { 20 | using var config = ServiceStack.Text.JsConfig.With(new ServiceStack.Text.Config 21 | { 22 | TextCase = ServiceStack.Text.TextCase.CamelCase 23 | }); 24 | 25 | return ServiceStack.Text.JsonSerializer.DeserializeFromString>(data.Json); 26 | } 27 | } -------------------------------------------------------------------------------- /JsonBenchmarks.SpanJson.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using BenchmarkDotNet.Attributes; 3 | using SerializationBenchmarks.Models; 4 | 5 | public partial class JsonBenchmark 6 | { 7 | [Benchmark, BenchmarkCategory("Serialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 8 | public ArraySegment SpanJson_Serialize(DataSet data) 9 | { 10 | return SpanJson.JsonSerializer.Generic.Utf8.SerializeToArrayPool, SpanJson.Resolvers.ExcludeNullsCamelCaseResolver>(data.Payload); 11 | } 12 | 13 | [Benchmark, BenchmarkCategory("Deserialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 14 | public List SpanJson_Deserialize(DataSet data) 15 | { 16 | ReadOnlySpan json = Encoding.UTF8.GetBytes(data.Json); 17 | return SpanJson.JsonSerializer.Generic.Utf8.Deserialize, SpanJson.Resolvers.ExcludeNullsCamelCaseResolver>(json); 18 | } 19 | } -------------------------------------------------------------------------------- /JsonBenchmarks.System.Text.Json-SrcGen.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using System.Text.Json.Serialization; 3 | using BenchmarkDotNet.Attributes; 4 | using SerializationBenchmarks.Models; 5 | 6 | public partial class JsonBenchmark 7 | { 8 | [Benchmark, BenchmarkCategory("Serialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 9 | public string SystemTextJson_SrcGen_Serialize(DataSet data) 10 | { 11 | return System.Text.Json.JsonSerializer.Serialize(data.Payload, DatasetSerializerContext.Benchmark.ListUser); 12 | } 13 | 14 | [Benchmark, BenchmarkCategory("Deserialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 15 | public List SystemTextJson_SrcGen_Deserialize(DataSet data) 16 | { 17 | return System.Text.Json.JsonSerializer.Deserialize>(data.Json, DatasetSerializerContext.Benchmark.ListUser); 18 | } 19 | } 20 | 21 | [JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)] 22 | [JsonSerializable(typeof(List))] 23 | public partial class DatasetSerializerContext : JsonSerializerContext 24 | { 25 | internal static DatasetSerializerContext Benchmark { get; } 26 | 27 | static DatasetSerializerContext() 28 | { 29 | var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; 30 | options.Converters.Add(new JsonStringEnumConverter()); 31 | Benchmark = new DatasetSerializerContext(options); 32 | } 33 | } -------------------------------------------------------------------------------- /JsonBenchmarks.System.Text.Json.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using BenchmarkDotNet.Attributes; 3 | using SerializationBenchmarks.Models; 4 | 5 | public partial class JsonBenchmark 6 | { 7 | [Benchmark(Baseline = true), BenchmarkCategory("Serialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 8 | public string SystemTextJson_Serialize(DataSet data) 9 | { 10 | return System.Text.Json.JsonSerializer.Serialize(data.Payload, _systemTextJsonOptions); 11 | } 12 | 13 | [Benchmark(Baseline = true), BenchmarkCategory("Deserialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 14 | public List SystemTextJson_Deserialize(DataSet data) 15 | { 16 | return System.Text.Json.JsonSerializer.Deserialize>(data.Json, _systemTextJsonOptions); 17 | } 18 | } -------------------------------------------------------------------------------- /JsonBenchmarks.UTF8Json.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using SerializationBenchmarks.Models; 3 | 4 | public partial class JsonBenchmark 5 | { 6 | [Benchmark, BenchmarkCategory("Serialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 7 | public byte[] UTF8Json_Serialize(DataSet data) 8 | { 9 | return Utf8Json.JsonSerializer.Serialize(data.Payload, Utf8Json.Resolvers.StandardResolver.CamelCase); 10 | } 11 | 12 | [Benchmark, BenchmarkCategory("Deserialization", "Json"), ArgumentsSource(nameof(GenerateDataSets))] 13 | public List UTF8Json_Deserialize(DataSet data) 14 | { 15 | return Utf8Json.JsonSerializer.Deserialize>(data.Json, Utf8Json.Resolvers.StandardResolver.CamelCase); 16 | } 17 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Stuart Blackler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Models/Bebop.Models.g.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // 5 | // 6 | // bebopc version: 7 | // 3.0.14 8 | // 9 | // 10 | // bebopc source: 11 | // https://github.com/betwixt-labs/bebop 12 | // 13 | // 14 | // Changes to this file may cause incorrect behavior and will be lost if 15 | // the code is regenerated. 16 | // 17 | // 18 | // This source code was auto-generated by bebopc, Version=3.0.14. 19 | // 20 | namespace SerializationBenchmarks.Models.Bebop { 21 | 22 | [global::System.CodeDom.Compiler.GeneratedCode("bebopc", "3.0.14")] 23 | [global::Bebop.Attributes.BebopRecord(global::Bebop.Runtime.BebopKind.Enum)] 24 | public enum Gender : uint { 25 | Male = 0, 26 | Female = 1 27 | } 28 | 29 | [global::System.CodeDom.Compiler.GeneratedCode("bebopc", "3.0.14")] 30 | [global::Bebop.Attributes.BebopRecord(global::Bebop.Runtime.BebopKind.Message)] 31 | public partial class Order : global::Bebop.Runtime.BaseBebopRecord, global::Bebop.Runtime.IDecodable, global::System.IEquatable { 32 | #nullable enable 33 | /// 34 | public sealed override int MaxByteCount => GetMaxByteCount(); 35 | /// 36 | public sealed override int ByteCount => GetByteCount(); 37 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 38 | public int? OrderId { get; set; } 39 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 40 | public string? Item { get; set; } 41 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 42 | public int? Quantity { get; set; } 43 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 44 | public int? LotNumber { get; set; } 45 | 46 | /// 47 | /// 48 | public Order() : base() { } 49 | /// 50 | /// 51 | /// 52 | /// 53 | /// 54 | /// 55 | /// 56 | /// 57 | /// 58 | /// 59 | public Order([global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] int? orderId, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] string? item, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] int? quantity, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] int? lotNumber) => (OrderId, Item, Quantity, LotNumber) = (orderId, item, quantity, lotNumber); 60 | public Order([global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] Order? original) => (OrderId, Item, Quantity, LotNumber) = (original?.OrderId, original?.Item, original?.Quantity, original?.LotNumber); 61 | public void Deconstruct([global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out int? orderId, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out string? item, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out int? quantity, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out int? lotNumber) => (orderId, item, quantity, lotNumber) = (OrderId, Item, Quantity, LotNumber); 62 | 63 | /// Calculates the maximum number of bytes produced by encoding the current record. 64 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 65 | private protected int GetMaxByteCount() { 66 | int byteCount = 0; 67 | byteCount += 5; 68 | if (OrderId is not null) { 69 | byteCount += sizeof(byte); 70 | byteCount += sizeof(int); 71 | } 72 | if (Item is not null) { 73 | byteCount += sizeof(byte); 74 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetMaxByteCount(Item.Length); 75 | } 76 | if (Quantity is not null) { 77 | byteCount += sizeof(byte); 78 | byteCount += sizeof(int); 79 | } 80 | if (LotNumber is not null) { 81 | byteCount += sizeof(byte); 82 | byteCount += sizeof(int); 83 | } 84 | return byteCount; 85 | } 86 | 87 | 88 | /// Calculates the number of bytes produced by encoding the current record. 89 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 90 | private protected int GetByteCount() { 91 | int byteCount = 0; 92 | byteCount += 5; 93 | if (OrderId is not null) { 94 | byteCount += sizeof(byte); 95 | byteCount += sizeof(int); 96 | } 97 | if (Item is not null) { 98 | byteCount += sizeof(byte); 99 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetByteCount(Item); 100 | } 101 | if (Quantity is not null) { 102 | byteCount += sizeof(byte); 103 | byteCount += sizeof(int); 104 | } 105 | if (LotNumber is not null) { 106 | byteCount += sizeof(byte); 107 | byteCount += sizeof(int); 108 | } 109 | return byteCount; 110 | } 111 | 112 | #nullable disable 113 | 114 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 115 | public sealed override byte[] Encode() { 116 | var writer = global::Bebop.Runtime.BebopWriter.Create(); 117 | __EncodeInto(this, ref writer); 118 | return writer.ToArray(); 119 | } 120 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 121 | public static byte[] Encode(global::SerializationBenchmarks.Models.Bebop.Order record) { 122 | var writer = global::Bebop.Runtime.BebopWriter.Create(); 123 | __EncodeInto(record, ref writer); 124 | return writer.ToArray(); 125 | } 126 | 127 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 128 | public sealed override byte[] Encode(int initialCapacity) { 129 | var writer = global::Bebop.Runtime.BebopWriter.Create(initialCapacity); 130 | __EncodeInto(this, ref writer); 131 | return writer.ToArray(); 132 | } 133 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 134 | public static byte[] Encode(global::SerializationBenchmarks.Models.Bebop.Order record, int initialCapacity) { 135 | var writer = global::Bebop.Runtime.BebopWriter.Create(initialCapacity); 136 | __EncodeInto(record, ref writer); 137 | return writer.ToArray(); 138 | } 139 | 140 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 141 | public sealed override global::System.Collections.Immutable.ImmutableArray EncodeImmutably() { 142 | var writer = global::Bebop.Runtime.BebopWriter.Create(); 143 | __EncodeInto(this, ref writer); 144 | return writer.ToImmutableArray(); 145 | } 146 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 147 | public static global::System.Collections.Immutable.ImmutableArray EncodeImmutably(global::SerializationBenchmarks.Models.Bebop.Order record) { 148 | var writer = global::Bebop.Runtime.BebopWriter.Create(); 149 | __EncodeInto(record, ref writer); 150 | return writer.ToImmutableArray(); 151 | } 152 | 153 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 154 | public sealed override global::System.Collections.Immutable.ImmutableArray EncodeImmutably(int initialCapacity) { 155 | var writer = global::Bebop.Runtime.BebopWriter.Create(initialCapacity); 156 | __EncodeInto(this, ref writer); 157 | return writer.ToImmutableArray(); 158 | } 159 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 160 | public static global::System.Collections.Immutable.ImmutableArray EncodeImmutably(global::SerializationBenchmarks.Models.Bebop.Order record, int initialCapacity) { 161 | var writer = global::Bebop.Runtime.BebopWriter.Create(initialCapacity); 162 | __EncodeInto(record, ref writer); 163 | return writer.ToImmutableArray(); 164 | } 165 | 166 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 167 | public sealed override int EncodeIntoBuffer(byte[] outBuffer) { 168 | var writer = global::Bebop.Runtime.BebopWriter.Create(outBuffer); 169 | return __EncodeInto(this, ref writer); 170 | } 171 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 172 | public static int EncodeIntoBuffer(global::SerializationBenchmarks.Models.Bebop.Order record, byte[] outBuffer) { 173 | var writer = global::Bebop.Runtime.BebopWriter.Create(outBuffer); 174 | return __EncodeInto(record, ref writer); 175 | } 176 | 177 | #region Static Decode Methods 178 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 179 | public static global::SerializationBenchmarks.Models.Bebop.Order Decode(byte[] record) { 180 | var reader = global::Bebop.Runtime.BebopReader.From(record); 181 | return __DecodeFrom(ref reader); 182 | } 183 | 184 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 185 | public static global::SerializationBenchmarks.Models.Bebop.Order Decode(global::System.ReadOnlySpan record) { 186 | var reader = global::Bebop.Runtime.BebopReader.From(record); 187 | return __DecodeFrom(ref reader); 188 | } 189 | 190 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 191 | public static global::SerializationBenchmarks.Models.Bebop.Order Decode(global::System.ReadOnlyMemory record) { 192 | var reader = global::Bebop.Runtime.BebopReader.From(record); 193 | return __DecodeFrom(ref reader); 194 | } 195 | 196 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 197 | public static global::SerializationBenchmarks.Models.Bebop.Order Decode(global::System.ArraySegment record) { 198 | var reader = global::Bebop.Runtime.BebopReader.From(record); 199 | return __DecodeFrom(ref reader); 200 | } 201 | 202 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 203 | public static global::SerializationBenchmarks.Models.Bebop.Order Decode(global::System.Collections.Immutable.ImmutableArray record) { 204 | var reader = global::Bebop.Runtime.BebopReader.From(record); 205 | return __DecodeFrom(ref reader); 206 | } 207 | 208 | #endregion 209 | #region Internal Use 210 | /// DO NOT CALL THIS METHOD DIRECTLY! 211 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 212 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 213 | [global::System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] 214 | internal static int __EncodeInto(global::SerializationBenchmarks.Models.Bebop.Order record, ref global::Bebop.Runtime.BebopWriter writer) { 215 | var before = writer.Length; 216 | var pos = writer.ReserveRecordLength(); 217 | var start = writer.Length; 218 | 219 | if (record.OrderId is not null) { 220 | writer.WriteByte(1); 221 | writer.WriteInt32(record.OrderId.Value); 222 | } 223 | 224 | if (record.Item is not null) { 225 | writer.WriteByte(2); 226 | writer.WriteString(record.Item); 227 | } 228 | 229 | if (record.Quantity is not null) { 230 | writer.WriteByte(3); 231 | writer.WriteInt32(record.Quantity.Value); 232 | } 233 | 234 | if (record.LotNumber is not null) { 235 | writer.WriteByte(4); 236 | writer.WriteInt32(record.LotNumber.Value); 237 | } 238 | writer.WriteByte(0); 239 | var end = writer.Length; 240 | writer.FillRecordLength(pos, unchecked((uint) unchecked(end - start))); 241 | var after = writer.Length; 242 | return after - before; 243 | } 244 | 245 | 246 | /// DO NOT CALL THIS METHOD DIRECTLY! 247 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 248 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 249 | [global::System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] 250 | internal static global::SerializationBenchmarks.Models.Bebop.Order __DecodeFrom(ref global::Bebop.Runtime.BebopReader reader) { 251 | 252 | var record = new global::SerializationBenchmarks.Models.Bebop.Order(); 253 | var length = reader.ReadRecordLength(); 254 | var end = unchecked((int) (reader.Position + length)); 255 | while (true) { 256 | switch (reader.ReadByte()) { 257 | case 0: 258 | return record; 259 | case 1: 260 | record.OrderId = reader.ReadInt32(); 261 | break; 262 | case 2: 263 | record.Item = reader.ReadString(); 264 | break; 265 | case 3: 266 | record.Quantity = reader.ReadInt32(); 267 | break; 268 | case 4: 269 | record.LotNumber = reader.ReadInt32(); 270 | break; 271 | default: 272 | reader.Position = end; 273 | return record; 274 | } 275 | } 276 | } 277 | 278 | #endregion 279 | #region Equality 280 | public bool Equals(global::SerializationBenchmarks.Models.Bebop.Order other) { 281 | if (ReferenceEquals(null, other)) { 282 | return false; 283 | } 284 | if (ReferenceEquals(this, other)) { 285 | return true; 286 | } 287 | return OrderId == other.OrderId && Item == other.Item && Quantity == other.Quantity && LotNumber == other.LotNumber; 288 | } 289 | 290 | public override bool Equals(object obj) { 291 | if (ReferenceEquals(null, obj)) { 292 | return false; 293 | } 294 | if (ReferenceEquals(this, obj)) { 295 | return true; 296 | } 297 | if (obj is not global::SerializationBenchmarks.Models.Bebop.Order baseType) { 298 | return false; 299 | } 300 | return Equals(baseType); 301 | } 302 | 303 | public override int GetHashCode() { 304 | int hash = 1; 305 | if (OrderId is not null) hash ^= OrderId.Value.GetHashCode(); 306 | if (Item is not null) hash ^= Item.GetHashCode(); 307 | if (Quantity is not null) hash ^= Quantity.Value.GetHashCode(); 308 | if (LotNumber is not null) hash ^= LotNumber.Value.GetHashCode(); 309 | return hash; 310 | } 311 | 312 | public static bool operator ==(global::SerializationBenchmarks.Models.Bebop.Order left, global::SerializationBenchmarks.Models.Bebop.Order right) => Equals(left, right); 313 | public static bool operator !=(global::SerializationBenchmarks.Models.Bebop.Order left, global::SerializationBenchmarks.Models.Bebop.Order right) => !Equals(left, right); 314 | #endregion 315 | 316 | } 317 | 318 | [global::System.CodeDom.Compiler.GeneratedCode("bebopc", "3.0.14")] 319 | [global::Bebop.Attributes.BebopRecord(global::Bebop.Runtime.BebopKind.Message)] 320 | public partial class User : global::Bebop.Runtime.BaseBebopRecord, global::Bebop.Runtime.IDecodable, global::System.IEquatable { 321 | #nullable enable 322 | /// 323 | public sealed override int MaxByteCount => GetMaxByteCount(); 324 | /// 325 | public sealed override int ByteCount => GetByteCount(); 326 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 327 | public int? ID { get; set; } 328 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 329 | public string? FirstName { get; set; } 330 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 331 | public string? LastName { get; set; } 332 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 333 | public string? FullName { get; set; } 334 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 335 | public string? UserName { get; set; } 336 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 337 | public string? Email { get; set; } 338 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 339 | public string? SomethingUnique { get; set; } 340 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 341 | public global::System.Guid? SomeGuid { get; set; } 342 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 343 | public string? Avatar { get; set; } 344 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 345 | public global::System.Guid? CartId { get; set; } 346 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 347 | public string? Ssn { get; set; } 348 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 349 | public global::SerializationBenchmarks.Models.Bebop.Gender? Gender { get; set; } 350 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 351 | public global::SerializationBenchmarks.Models.Bebop.Order[]? Orders { get; set; } 352 | 353 | /// 354 | /// 355 | public User() : base() { } 356 | /// 357 | /// 358 | /// 359 | /// 360 | /// 361 | /// 362 | /// 363 | /// 364 | /// 365 | /// 366 | /// 367 | /// 368 | /// 369 | /// 370 | /// 371 | /// 372 | /// 373 | /// 374 | /// 375 | /// 376 | /// 377 | /// 378 | /// 379 | /// 380 | /// 381 | /// 382 | /// 383 | /// 384 | public User([global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] int? Id, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] string? firstName, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] string? lastName, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] string? fullName, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] string? userName, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] string? email, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] string? somethingUnique, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] global::System.Guid? someGuid, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] string? avatar, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] global::System.Guid? cartId, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] string? ssn, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] global::SerializationBenchmarks.Models.Bebop.Gender? gender, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] global::SerializationBenchmarks.Models.Bebop.Order[]? orders) => (ID, FirstName, LastName, FullName, UserName, Email, SomethingUnique, SomeGuid, Avatar, CartId, Ssn, Gender, Orders) = (Id, firstName, lastName, fullName, userName, email, somethingUnique, someGuid, avatar, cartId, ssn, gender, orders); 385 | public User([global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] User? original) => (ID, FirstName, LastName, FullName, UserName, Email, SomethingUnique, SomeGuid, Avatar, CartId, Ssn, Gender, Orders) = (original?.ID, original?.FirstName, original?.LastName, original?.FullName, original?.UserName, original?.Email, original?.SomethingUnique, original?.SomeGuid, original?.Avatar, original?.CartId, original?.Ssn, original?.Gender, original?.Orders); 386 | public void Deconstruct([global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out int? Id, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out string? firstName, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out string? lastName, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out string? fullName, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out string? userName, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out string? email, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out string? somethingUnique, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out global::System.Guid? someGuid, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out string? avatar, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out global::System.Guid? cartId, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out string? ssn, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out global::SerializationBenchmarks.Models.Bebop.Gender? gender, [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out global::SerializationBenchmarks.Models.Bebop.Order[]? orders) => (Id, firstName, lastName, fullName, userName, email, somethingUnique, someGuid, avatar, cartId, ssn, gender, orders) = (ID, FirstName, LastName, FullName, UserName, Email, SomethingUnique, SomeGuid, Avatar, CartId, Ssn, Gender, Orders); 387 | 388 | /// Calculates the maximum number of bytes produced by encoding the current record. 389 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 390 | private protected int GetMaxByteCount() { 391 | int byteCount = 0; 392 | byteCount += 5; 393 | if (ID is not null) { 394 | byteCount += sizeof(byte); 395 | byteCount += sizeof(int); 396 | } 397 | if (FirstName is not null) { 398 | byteCount += sizeof(byte); 399 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetMaxByteCount(FirstName.Length); 400 | } 401 | if (LastName is not null) { 402 | byteCount += sizeof(byte); 403 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetMaxByteCount(LastName.Length); 404 | } 405 | if (FullName is not null) { 406 | byteCount += sizeof(byte); 407 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetMaxByteCount(FullName.Length); 408 | } 409 | if (UserName is not null) { 410 | byteCount += sizeof(byte); 411 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetMaxByteCount(UserName.Length); 412 | } 413 | if (Email is not null) { 414 | byteCount += sizeof(byte); 415 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetMaxByteCount(Email.Length); 416 | } 417 | if (SomethingUnique is not null) { 418 | byteCount += sizeof(byte); 419 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetMaxByteCount(SomethingUnique.Length); 420 | } 421 | if (SomeGuid is not null) { 422 | byteCount += sizeof(byte); 423 | byteCount += 16; 424 | } 425 | if (Avatar is not null) { 426 | byteCount += sizeof(byte); 427 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetMaxByteCount(Avatar.Length); 428 | } 429 | if (CartId is not null) { 430 | byteCount += sizeof(byte); 431 | byteCount += 16; 432 | } 433 | if (Ssn is not null) { 434 | byteCount += sizeof(byte); 435 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetMaxByteCount(Ssn.Length); 436 | } 437 | if (Gender is not null) { 438 | byteCount += sizeof(byte); 439 | byteCount += sizeof(uint); 440 | } 441 | if (Orders is not null) { 442 | byteCount += sizeof(byte); 443 | { 444 | var length0 = unchecked((uint)Orders.Length); 445 | byteCount += sizeof(uint); 446 | for (var i0 = 0; i0 < length0; i0++) { 447 | byteCount += Orders[i0].MaxByteCount; 448 | } 449 | } 450 | } 451 | return byteCount; 452 | } 453 | 454 | 455 | /// Calculates the number of bytes produced by encoding the current record. 456 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 457 | private protected int GetByteCount() { 458 | int byteCount = 0; 459 | byteCount += 5; 460 | if (ID is not null) { 461 | byteCount += sizeof(byte); 462 | byteCount += sizeof(int); 463 | } 464 | if (FirstName is not null) { 465 | byteCount += sizeof(byte); 466 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetByteCount(FirstName); 467 | } 468 | if (LastName is not null) { 469 | byteCount += sizeof(byte); 470 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetByteCount(LastName); 471 | } 472 | if (FullName is not null) { 473 | byteCount += sizeof(byte); 474 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetByteCount(FullName); 475 | } 476 | if (UserName is not null) { 477 | byteCount += sizeof(byte); 478 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetByteCount(UserName); 479 | } 480 | if (Email is not null) { 481 | byteCount += sizeof(byte); 482 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetByteCount(Email); 483 | } 484 | if (SomethingUnique is not null) { 485 | byteCount += sizeof(byte); 486 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetByteCount(SomethingUnique); 487 | } 488 | if (SomeGuid is not null) { 489 | byteCount += sizeof(byte); 490 | byteCount += 16; 491 | } 492 | if (Avatar is not null) { 493 | byteCount += sizeof(byte); 494 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetByteCount(Avatar); 495 | } 496 | if (CartId is not null) { 497 | byteCount += sizeof(byte); 498 | byteCount += 16; 499 | } 500 | if (Ssn is not null) { 501 | byteCount += sizeof(byte); 502 | byteCount += sizeof(uint) + global::System.Text.Encoding.UTF8.GetByteCount(Ssn); 503 | } 504 | if (Gender is not null) { 505 | byteCount += sizeof(byte); 506 | byteCount += sizeof(uint); 507 | } 508 | if (Orders is not null) { 509 | byteCount += sizeof(byte); 510 | { 511 | var length0 = unchecked((uint)Orders.Length); 512 | byteCount += sizeof(uint); 513 | for (var i0 = 0; i0 < length0; i0++) { 514 | byteCount += Orders[i0].ByteCount; 515 | } 516 | } 517 | } 518 | return byteCount; 519 | } 520 | 521 | #nullable disable 522 | 523 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 524 | public sealed override byte[] Encode() { 525 | var writer = global::Bebop.Runtime.BebopWriter.Create(); 526 | __EncodeInto(this, ref writer); 527 | return writer.ToArray(); 528 | } 529 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 530 | public static byte[] Encode(global::SerializationBenchmarks.Models.Bebop.User record) { 531 | var writer = global::Bebop.Runtime.BebopWriter.Create(); 532 | __EncodeInto(record, ref writer); 533 | return writer.ToArray(); 534 | } 535 | 536 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 537 | public sealed override byte[] Encode(int initialCapacity) { 538 | var writer = global::Bebop.Runtime.BebopWriter.Create(initialCapacity); 539 | __EncodeInto(this, ref writer); 540 | return writer.ToArray(); 541 | } 542 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 543 | public static byte[] Encode(global::SerializationBenchmarks.Models.Bebop.User record, int initialCapacity) { 544 | var writer = global::Bebop.Runtime.BebopWriter.Create(initialCapacity); 545 | __EncodeInto(record, ref writer); 546 | return writer.ToArray(); 547 | } 548 | 549 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 550 | public sealed override global::System.Collections.Immutable.ImmutableArray EncodeImmutably() { 551 | var writer = global::Bebop.Runtime.BebopWriter.Create(); 552 | __EncodeInto(this, ref writer); 553 | return writer.ToImmutableArray(); 554 | } 555 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 556 | public static global::System.Collections.Immutable.ImmutableArray EncodeImmutably(global::SerializationBenchmarks.Models.Bebop.User record) { 557 | var writer = global::Bebop.Runtime.BebopWriter.Create(); 558 | __EncodeInto(record, ref writer); 559 | return writer.ToImmutableArray(); 560 | } 561 | 562 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 563 | public sealed override global::System.Collections.Immutable.ImmutableArray EncodeImmutably(int initialCapacity) { 564 | var writer = global::Bebop.Runtime.BebopWriter.Create(initialCapacity); 565 | __EncodeInto(this, ref writer); 566 | return writer.ToImmutableArray(); 567 | } 568 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 569 | public static global::System.Collections.Immutable.ImmutableArray EncodeImmutably(global::SerializationBenchmarks.Models.Bebop.User record, int initialCapacity) { 570 | var writer = global::Bebop.Runtime.BebopWriter.Create(initialCapacity); 571 | __EncodeInto(record, ref writer); 572 | return writer.ToImmutableArray(); 573 | } 574 | 575 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 576 | public sealed override int EncodeIntoBuffer(byte[] outBuffer) { 577 | var writer = global::Bebop.Runtime.BebopWriter.Create(outBuffer); 578 | return __EncodeInto(this, ref writer); 579 | } 580 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 581 | public static int EncodeIntoBuffer(global::SerializationBenchmarks.Models.Bebop.User record, byte[] outBuffer) { 582 | var writer = global::Bebop.Runtime.BebopWriter.Create(outBuffer); 583 | return __EncodeInto(record, ref writer); 584 | } 585 | 586 | #region Static Decode Methods 587 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 588 | public static global::SerializationBenchmarks.Models.Bebop.User Decode(byte[] record) { 589 | var reader = global::Bebop.Runtime.BebopReader.From(record); 590 | return __DecodeFrom(ref reader); 591 | } 592 | 593 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 594 | public static global::SerializationBenchmarks.Models.Bebop.User Decode(global::System.ReadOnlySpan record) { 595 | var reader = global::Bebop.Runtime.BebopReader.From(record); 596 | return __DecodeFrom(ref reader); 597 | } 598 | 599 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 600 | public static global::SerializationBenchmarks.Models.Bebop.User Decode(global::System.ReadOnlyMemory record) { 601 | var reader = global::Bebop.Runtime.BebopReader.From(record); 602 | return __DecodeFrom(ref reader); 603 | } 604 | 605 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 606 | public static global::SerializationBenchmarks.Models.Bebop.User Decode(global::System.ArraySegment record) { 607 | var reader = global::Bebop.Runtime.BebopReader.From(record); 608 | return __DecodeFrom(ref reader); 609 | } 610 | 611 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 612 | public static global::SerializationBenchmarks.Models.Bebop.User Decode(global::System.Collections.Immutable.ImmutableArray record) { 613 | var reader = global::Bebop.Runtime.BebopReader.From(record); 614 | return __DecodeFrom(ref reader); 615 | } 616 | 617 | #endregion 618 | #region Internal Use 619 | /// DO NOT CALL THIS METHOD DIRECTLY! 620 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 621 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 622 | [global::System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] 623 | internal static int __EncodeInto(global::SerializationBenchmarks.Models.Bebop.User record, ref global::Bebop.Runtime.BebopWriter writer) { 624 | var before = writer.Length; 625 | var pos = writer.ReserveRecordLength(); 626 | var start = writer.Length; 627 | 628 | if (record.ID is not null) { 629 | writer.WriteByte(1); 630 | writer.WriteInt32(record.ID.Value); 631 | } 632 | 633 | if (record.FirstName is not null) { 634 | writer.WriteByte(2); 635 | writer.WriteString(record.FirstName); 636 | } 637 | 638 | if (record.LastName is not null) { 639 | writer.WriteByte(3); 640 | writer.WriteString(record.LastName); 641 | } 642 | 643 | if (record.FullName is not null) { 644 | writer.WriteByte(4); 645 | writer.WriteString(record.FullName); 646 | } 647 | 648 | if (record.UserName is not null) { 649 | writer.WriteByte(5); 650 | writer.WriteString(record.UserName); 651 | } 652 | 653 | if (record.Email is not null) { 654 | writer.WriteByte(6); 655 | writer.WriteString(record.Email); 656 | } 657 | 658 | if (record.SomethingUnique is not null) { 659 | writer.WriteByte(7); 660 | writer.WriteString(record.SomethingUnique); 661 | } 662 | 663 | if (record.SomeGuid is not null) { 664 | writer.WriteByte(8); 665 | writer.WriteGuid(record.SomeGuid.Value); 666 | } 667 | 668 | if (record.Avatar is not null) { 669 | writer.WriteByte(9); 670 | writer.WriteString(record.Avatar); 671 | } 672 | 673 | if (record.CartId is not null) { 674 | writer.WriteByte(10); 675 | writer.WriteGuid(record.CartId.Value); 676 | } 677 | 678 | if (record.Ssn is not null) { 679 | writer.WriteByte(11); 680 | writer.WriteString(record.Ssn); 681 | } 682 | 683 | if (record.Gender is not null) { 684 | writer.WriteByte(12); 685 | writer.WriteUInt32(System.Runtime.CompilerServices.Unsafe.As(ref System.Runtime.CompilerServices.Unsafe.AsRef(record.Gender.Value))); 686 | } 687 | 688 | if (record.Orders is not null) { 689 | writer.WriteByte(13); 690 | { 691 | var length0 = unchecked((uint)record.Orders.Length); 692 | writer.WriteUInt32(length0); 693 | for (var i0 = 0; i0 < length0; i0++) { 694 | global::SerializationBenchmarks.Models.Bebop.Order.__EncodeInto(record.Orders[i0], ref writer); 695 | } 696 | } 697 | } 698 | writer.WriteByte(0); 699 | var end = writer.Length; 700 | writer.FillRecordLength(pos, unchecked((uint) unchecked(end - start))); 701 | var after = writer.Length; 702 | return after - before; 703 | } 704 | 705 | 706 | /// DO NOT CALL THIS METHOD DIRECTLY! 707 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 708 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 709 | [global::System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] 710 | internal static global::SerializationBenchmarks.Models.Bebop.User __DecodeFrom(ref global::Bebop.Runtime.BebopReader reader) { 711 | 712 | var record = new global::SerializationBenchmarks.Models.Bebop.User(); 713 | var length = reader.ReadRecordLength(); 714 | var end = unchecked((int) (reader.Position + length)); 715 | while (true) { 716 | switch (reader.ReadByte()) { 717 | case 0: 718 | return record; 719 | case 1: 720 | record.ID = reader.ReadInt32(); 721 | break; 722 | case 2: 723 | record.FirstName = reader.ReadString(); 724 | break; 725 | case 3: 726 | record.LastName = reader.ReadString(); 727 | break; 728 | case 4: 729 | record.FullName = reader.ReadString(); 730 | break; 731 | case 5: 732 | record.UserName = reader.ReadString(); 733 | break; 734 | case 6: 735 | record.Email = reader.ReadString(); 736 | break; 737 | case 7: 738 | record.SomethingUnique = reader.ReadString(); 739 | break; 740 | case 8: 741 | record.SomeGuid = reader.ReadGuid(); 742 | break; 743 | case 9: 744 | record.Avatar = reader.ReadString(); 745 | break; 746 | case 10: 747 | record.CartId = reader.ReadGuid(); 748 | break; 749 | case 11: 750 | record.Ssn = reader.ReadString(); 751 | break; 752 | case 12: 753 | record.Gender = System.Runtime.CompilerServices.Unsafe.As(ref System.Runtime.CompilerServices.Unsafe.AsRef(reader.ReadUInt32())); 754 | break; 755 | case 13: 756 | { 757 | var length0 = unchecked((int)reader.ReadUInt32()); 758 | record.Orders = new global::SerializationBenchmarks.Models.Bebop.Order[length0]; 759 | for (var i0 = 0; i0 < length0; i0++) { 760 | global::SerializationBenchmarks.Models.Bebop.Order x0; 761 | x0 = global::SerializationBenchmarks.Models.Bebop.Order.__DecodeFrom(ref reader); 762 | record.Orders[i0] = x0; 763 | } 764 | } 765 | break; 766 | default: 767 | reader.Position = end; 768 | return record; 769 | } 770 | } 771 | } 772 | 773 | #endregion 774 | #region Equality 775 | public bool Equals(global::SerializationBenchmarks.Models.Bebop.User other) { 776 | if (ReferenceEquals(null, other)) { 777 | return false; 778 | } 779 | if (ReferenceEquals(this, other)) { 780 | return true; 781 | } 782 | return ID == other.ID && FirstName == other.FirstName && LastName == other.LastName && FullName == other.FullName && UserName == other.UserName && Email == other.Email && SomethingUnique == other.SomethingUnique && SomeGuid == other.SomeGuid && Avatar == other.Avatar && CartId == other.CartId && Ssn == other.Ssn && Gender == other.Gender && (Orders is null ? other.Orders is null : other.Orders is not null && global::System.Linq.Enumerable.SequenceEqual(Orders, other.Orders)); 783 | } 784 | 785 | public override bool Equals(object obj) { 786 | if (ReferenceEquals(null, obj)) { 787 | return false; 788 | } 789 | if (ReferenceEquals(this, obj)) { 790 | return true; 791 | } 792 | if (obj is not global::SerializationBenchmarks.Models.Bebop.User baseType) { 793 | return false; 794 | } 795 | return Equals(baseType); 796 | } 797 | 798 | public override int GetHashCode() { 799 | int hash = 1; 800 | if (ID is not null) hash ^= ID.Value.GetHashCode(); 801 | if (FirstName is not null) hash ^= FirstName.GetHashCode(); 802 | if (LastName is not null) hash ^= LastName.GetHashCode(); 803 | if (FullName is not null) hash ^= FullName.GetHashCode(); 804 | if (UserName is not null) hash ^= UserName.GetHashCode(); 805 | if (Email is not null) hash ^= Email.GetHashCode(); 806 | if (SomethingUnique is not null) hash ^= SomethingUnique.GetHashCode(); 807 | if (SomeGuid is not null) hash ^= SomeGuid.Value.GetHashCode(); 808 | if (Avatar is not null) hash ^= Avatar.GetHashCode(); 809 | if (CartId is not null) hash ^= CartId.Value.GetHashCode(); 810 | if (Ssn is not null) hash ^= Ssn.GetHashCode(); 811 | if (Gender is not null) hash ^= Gender.Value.GetHashCode(); 812 | if (Orders is not null) hash ^= Orders.GetHashCode(); 813 | return hash; 814 | } 815 | 816 | public static bool operator ==(global::SerializationBenchmarks.Models.Bebop.User left, global::SerializationBenchmarks.Models.Bebop.User right) => Equals(left, right); 817 | public static bool operator !=(global::SerializationBenchmarks.Models.Bebop.User left, global::SerializationBenchmarks.Models.Bebop.User right) => !Equals(left, right); 818 | #endregion 819 | 820 | } 821 | 822 | [global::System.CodeDom.Compiler.GeneratedCode("bebopc", "3.0.14")] 823 | [global::Bebop.Attributes.BebopRecord(global::Bebop.Runtime.BebopKind.Message)] 824 | public partial class UserWrapper : global::Bebop.Runtime.BaseBebopRecord, global::Bebop.Runtime.IDecodable, global::System.IEquatable { 825 | #nullable enable 826 | /// 827 | public sealed override int MaxByteCount => GetMaxByteCount(); 828 | /// 829 | public sealed override int ByteCount => GetByteCount(); 830 | [global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] 831 | public global::SerializationBenchmarks.Models.Bebop.User[]? Users { get; set; } 832 | 833 | /// 834 | /// 835 | public UserWrapper() : base() { } 836 | /// 837 | /// 838 | /// 839 | /// 840 | public UserWrapper([global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] global::SerializationBenchmarks.Models.Bebop.User[]? users) => (Users) = (users); 841 | public UserWrapper([global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] UserWrapper? original) => (Users) = (original?.Users); 842 | public void Deconstruct([global::System.Diagnostics.CodeAnalysis.MaybeNull, global::System.Diagnostics.CodeAnalysis.AllowNull] out global::SerializationBenchmarks.Models.Bebop.User[]? users) => (users) = (Users); 843 | 844 | /// Calculates the maximum number of bytes produced by encoding the current record. 845 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 846 | private protected int GetMaxByteCount() { 847 | int byteCount = 0; 848 | byteCount += 5; 849 | if (Users is not null) { 850 | byteCount += sizeof(byte); 851 | { 852 | var length0 = unchecked((uint)Users.Length); 853 | byteCount += sizeof(uint); 854 | for (var i0 = 0; i0 < length0; i0++) { 855 | byteCount += Users[i0].MaxByteCount; 856 | } 857 | } 858 | } 859 | return byteCount; 860 | } 861 | 862 | 863 | /// Calculates the number of bytes produced by encoding the current record. 864 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 865 | private protected int GetByteCount() { 866 | int byteCount = 0; 867 | byteCount += 5; 868 | if (Users is not null) { 869 | byteCount += sizeof(byte); 870 | { 871 | var length0 = unchecked((uint)Users.Length); 872 | byteCount += sizeof(uint); 873 | for (var i0 = 0; i0 < length0; i0++) { 874 | byteCount += Users[i0].ByteCount; 875 | } 876 | } 877 | } 878 | return byteCount; 879 | } 880 | 881 | #nullable disable 882 | 883 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 884 | public sealed override byte[] Encode() { 885 | var writer = global::Bebop.Runtime.BebopWriter.Create(); 886 | __EncodeInto(this, ref writer); 887 | return writer.ToArray(); 888 | } 889 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 890 | public static byte[] Encode(global::SerializationBenchmarks.Models.Bebop.UserWrapper record) { 891 | var writer = global::Bebop.Runtime.BebopWriter.Create(); 892 | __EncodeInto(record, ref writer); 893 | return writer.ToArray(); 894 | } 895 | 896 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 897 | public sealed override byte[] Encode(int initialCapacity) { 898 | var writer = global::Bebop.Runtime.BebopWriter.Create(initialCapacity); 899 | __EncodeInto(this, ref writer); 900 | return writer.ToArray(); 901 | } 902 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 903 | public static byte[] Encode(global::SerializationBenchmarks.Models.Bebop.UserWrapper record, int initialCapacity) { 904 | var writer = global::Bebop.Runtime.BebopWriter.Create(initialCapacity); 905 | __EncodeInto(record, ref writer); 906 | return writer.ToArray(); 907 | } 908 | 909 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 910 | public sealed override global::System.Collections.Immutable.ImmutableArray EncodeImmutably() { 911 | var writer = global::Bebop.Runtime.BebopWriter.Create(); 912 | __EncodeInto(this, ref writer); 913 | return writer.ToImmutableArray(); 914 | } 915 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 916 | public static global::System.Collections.Immutable.ImmutableArray EncodeImmutably(global::SerializationBenchmarks.Models.Bebop.UserWrapper record) { 917 | var writer = global::Bebop.Runtime.BebopWriter.Create(); 918 | __EncodeInto(record, ref writer); 919 | return writer.ToImmutableArray(); 920 | } 921 | 922 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 923 | public sealed override global::System.Collections.Immutable.ImmutableArray EncodeImmutably(int initialCapacity) { 924 | var writer = global::Bebop.Runtime.BebopWriter.Create(initialCapacity); 925 | __EncodeInto(this, ref writer); 926 | return writer.ToImmutableArray(); 927 | } 928 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 929 | public static global::System.Collections.Immutable.ImmutableArray EncodeImmutably(global::SerializationBenchmarks.Models.Bebop.UserWrapper record, int initialCapacity) { 930 | var writer = global::Bebop.Runtime.BebopWriter.Create(initialCapacity); 931 | __EncodeInto(record, ref writer); 932 | return writer.ToImmutableArray(); 933 | } 934 | 935 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 936 | public sealed override int EncodeIntoBuffer(byte[] outBuffer) { 937 | var writer = global::Bebop.Runtime.BebopWriter.Create(outBuffer); 938 | return __EncodeInto(this, ref writer); 939 | } 940 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 941 | public static int EncodeIntoBuffer(global::SerializationBenchmarks.Models.Bebop.UserWrapper record, byte[] outBuffer) { 942 | var writer = global::Bebop.Runtime.BebopWriter.Create(outBuffer); 943 | return __EncodeInto(record, ref writer); 944 | } 945 | 946 | #region Static Decode Methods 947 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 948 | public static global::SerializationBenchmarks.Models.Bebop.UserWrapper Decode(byte[] record) { 949 | var reader = global::Bebop.Runtime.BebopReader.From(record); 950 | return __DecodeFrom(ref reader); 951 | } 952 | 953 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 954 | public static global::SerializationBenchmarks.Models.Bebop.UserWrapper Decode(global::System.ReadOnlySpan record) { 955 | var reader = global::Bebop.Runtime.BebopReader.From(record); 956 | return __DecodeFrom(ref reader); 957 | } 958 | 959 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 960 | public static global::SerializationBenchmarks.Models.Bebop.UserWrapper Decode(global::System.ReadOnlyMemory record) { 961 | var reader = global::Bebop.Runtime.BebopReader.From(record); 962 | return __DecodeFrom(ref reader); 963 | } 964 | 965 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 966 | public static global::SerializationBenchmarks.Models.Bebop.UserWrapper Decode(global::System.ArraySegment record) { 967 | var reader = global::Bebop.Runtime.BebopReader.From(record); 968 | return __DecodeFrom(ref reader); 969 | } 970 | 971 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 972 | public static global::SerializationBenchmarks.Models.Bebop.UserWrapper Decode(global::System.Collections.Immutable.ImmutableArray record) { 973 | var reader = global::Bebop.Runtime.BebopReader.From(record); 974 | return __DecodeFrom(ref reader); 975 | } 976 | 977 | #endregion 978 | #region Internal Use 979 | /// DO NOT CALL THIS METHOD DIRECTLY! 980 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 981 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 982 | [global::System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] 983 | internal static int __EncodeInto(global::SerializationBenchmarks.Models.Bebop.UserWrapper record, ref global::Bebop.Runtime.BebopWriter writer) { 984 | var before = writer.Length; 985 | var pos = writer.ReserveRecordLength(); 986 | var start = writer.Length; 987 | 988 | if (record.Users is not null) { 989 | writer.WriteByte(1); 990 | { 991 | var length0 = unchecked((uint)record.Users.Length); 992 | writer.WriteUInt32(length0); 993 | for (var i0 = 0; i0 < length0; i0++) { 994 | global::SerializationBenchmarks.Models.Bebop.User.__EncodeInto(record.Users[i0], ref writer); 995 | } 996 | } 997 | } 998 | writer.WriteByte(0); 999 | var end = writer.Length; 1000 | writer.FillRecordLength(pos, unchecked((uint) unchecked(end - start))); 1001 | var after = writer.Length; 1002 | return after - before; 1003 | } 1004 | 1005 | 1006 | /// DO NOT CALL THIS METHOD DIRECTLY! 1007 | [global::System.Runtime.CompilerServices.MethodImpl(global::Bebop.Runtime.BebopConstants.HotPath)] 1008 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 1009 | [global::System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] 1010 | internal static global::SerializationBenchmarks.Models.Bebop.UserWrapper __DecodeFrom(ref global::Bebop.Runtime.BebopReader reader) { 1011 | 1012 | var record = new global::SerializationBenchmarks.Models.Bebop.UserWrapper(); 1013 | var length = reader.ReadRecordLength(); 1014 | var end = unchecked((int) (reader.Position + length)); 1015 | while (true) { 1016 | switch (reader.ReadByte()) { 1017 | case 0: 1018 | return record; 1019 | case 1: 1020 | { 1021 | var length0 = unchecked((int)reader.ReadUInt32()); 1022 | record.Users = new global::SerializationBenchmarks.Models.Bebop.User[length0]; 1023 | for (var i0 = 0; i0 < length0; i0++) { 1024 | global::SerializationBenchmarks.Models.Bebop.User x0; 1025 | x0 = global::SerializationBenchmarks.Models.Bebop.User.__DecodeFrom(ref reader); 1026 | record.Users[i0] = x0; 1027 | } 1028 | } 1029 | break; 1030 | default: 1031 | reader.Position = end; 1032 | return record; 1033 | } 1034 | } 1035 | } 1036 | 1037 | #endregion 1038 | #region Equality 1039 | public bool Equals(global::SerializationBenchmarks.Models.Bebop.UserWrapper other) { 1040 | if (ReferenceEquals(null, other)) { 1041 | return false; 1042 | } 1043 | if (ReferenceEquals(this, other)) { 1044 | return true; 1045 | } 1046 | return (Users is null ? other.Users is null : other.Users is not null && global::System.Linq.Enumerable.SequenceEqual(Users, other.Users)); 1047 | } 1048 | 1049 | public override bool Equals(object obj) { 1050 | if (ReferenceEquals(null, obj)) { 1051 | return false; 1052 | } 1053 | if (ReferenceEquals(this, obj)) { 1054 | return true; 1055 | } 1056 | if (obj is not global::SerializationBenchmarks.Models.Bebop.UserWrapper baseType) { 1057 | return false; 1058 | } 1059 | return Equals(baseType); 1060 | } 1061 | 1062 | public override int GetHashCode() { 1063 | int hash = 1; 1064 | if (Users is not null) hash ^= Users.GetHashCode(); 1065 | return hash; 1066 | } 1067 | 1068 | public static bool operator ==(global::SerializationBenchmarks.Models.Bebop.UserWrapper left, global::SerializationBenchmarks.Models.Bebop.UserWrapper right) => Equals(left, right); 1069 | public static bool operator !=(global::SerializationBenchmarks.Models.Bebop.UserWrapper left, global::SerializationBenchmarks.Models.Bebop.UserWrapper right) => !Equals(left, right); 1070 | #endregion 1071 | 1072 | } 1073 | 1074 | } 1075 | -------------------------------------------------------------------------------- /Models/Gender.cs: -------------------------------------------------------------------------------- 1 | namespace SerializationBenchmarks.Models; 2 | 3 | public enum Gender 4 | { 5 | Male, 6 | Female 7 | } -------------------------------------------------------------------------------- /Models/Models.bop: -------------------------------------------------------------------------------- 1 | //bebopc --cs Bebop.cs --namespace SerializationBenchmarks.Models.Bebop --files Models.bop --no-warn 200 2 | enum Gender { 3 | Male = 0; 4 | Female = 1; 5 | } 6 | 7 | message Order { 8 | 1 -> int32 OrderId; 9 | 2 -> string Item; 10 | 3 -> int32 Quantity; 11 | 4 -> int32 LotNumber; 12 | } 13 | 14 | message User { 15 | 1 -> int32 Id; 16 | 2 -> string FirstName; 17 | 3 -> string LastName; 18 | 4 -> string FullName; 19 | 5 -> string UserName; 20 | 6 -> string Email; 21 | 7 -> string SomethingUnique; 22 | 8 -> guid SomeGuid; 23 | 9 -> string Avatar; 24 | 10 -> guid CartId; 25 | 11 -> string SSN; 26 | 12 -> Gender Gender; 27 | 13 -> Order[] Orders; 28 | } 29 | 30 | message UserWrapper { 31 | 1 -> User[] Users; 32 | } -------------------------------------------------------------------------------- /Models/Order.cs: -------------------------------------------------------------------------------- 1 | using MemoryPack; 2 | using MessagePack; 3 | using ProtoBuf; 4 | 5 | namespace SerializationBenchmarks.Models; 6 | 7 | [MessagePackObject, ProtoContract, MemoryPackable] 8 | public partial class Order 9 | { 10 | [Key(0), ProtoMember(1)] 11 | public int OrderId { get; set; } 12 | [Key(1), ProtoMember(2)] 13 | public string Item { get; set; } 14 | [Key(2), ProtoMember(3)] 15 | public int Quantity { get; set; } 16 | [Key(3), ProtoMember(4)] 17 | public int? LotNumber { get; set; } 18 | } -------------------------------------------------------------------------------- /Models/User.cs: -------------------------------------------------------------------------------- 1 | using MemoryPack; 2 | using MessagePack; 3 | using ProtoBuf; 4 | 5 | namespace SerializationBenchmarks.Models; 6 | 7 | [MessagePackObject, ProtoContract, MemoryPackable] 8 | public partial class User 9 | { 10 | [Key(0), ProtoMember(1)] 11 | public int Id { get; set; } 12 | [Key(1), ProtoMember(2)] 13 | public string FirstName { get; set; } 14 | [Key(2), ProtoMember(3)] 15 | public string LastName { get; set; } 16 | [Key(3), ProtoMember(4)] 17 | public string FullName { get; set; } 18 | [Key(4), ProtoMember(5)] 19 | public string UserName { get; set; } 20 | [Key(5), ProtoMember(6)] 21 | public string Email { get; set; } 22 | [Key(6), ProtoMember(7)] 23 | public string SomethingUnique { get; set; } 24 | [Key(7), ProtoMember(8)] 25 | public Guid SomeGuid { get; set; } 26 | [Key(8), ProtoMember(9)] 27 | public string Avatar { get; set; } 28 | [Key(9), ProtoMember(10)] 29 | public Guid CartId { get; set; } 30 | [Key(10), ProtoMember(11)] 31 | public string SSN { get; set; } 32 | [Key(11), ProtoMember(12)] 33 | public Gender Gender { get; set; } 34 | [Key(12), ProtoMember(13)] 35 | public List Orders { get; set; } 36 | } -------------------------------------------------------------------------------- /Program.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using System.Text.Json; 3 | using System.Text.Json.Serialization; 4 | using BenchmarkDotNet.Running; 5 | using Bogus; 6 | using SerializationBenchmarks.Models; 7 | 8 | internal static class Program 9 | { 10 | private static void Main() 11 | { 12 | //GenerateDataSet(); 13 | VerifySerializedSizes(); 14 | BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(); 15 | } 16 | 17 | // ReSharper disable once UnusedMember.Local 18 | private static void VerifySerializedSizes() 19 | { 20 | var b = new BinaryBenchmark(); 21 | var j = new JsonBenchmark(); 22 | 23 | var binaryDataSets = b.GenerateDataSets().ToList(); 24 | var bebopDataSets = b.GenerateBebopDataSets().ToList(); 25 | var jsonDataSets = j.GenerateDataSets().ToList(); 26 | 27 | var binaryResults = new Dictionary>(StringComparer.OrdinalIgnoreCase) 28 | { 29 | ["Small"] = new(), 30 | ["Medium"] = new(), 31 | ["Large"] = new(), 32 | }; 33 | var jsonResults = new Dictionary>(StringComparer.OrdinalIgnoreCase) 34 | { 35 | ["Small"] = new(), 36 | ["Medium"] = new(), 37 | ["Large"] = new(), 38 | }; 39 | 40 | foreach (var bds in binaryDataSets) 41 | { 42 | var results = binaryResults[bds.Name]; 43 | results["AvroConvert"] = bds.SerializedData.AvroConvert.Length; 44 | results["BSON"] = bds.SerializedData.BSON.Length; 45 | results["CBOR"] = bds.SerializedData.CBOR.Length; 46 | results["GroBuf"] = bds.SerializedData.GroBuf.Length; 47 | results["Hyperion"] = bds.SerializedData.Hyperion.Length; 48 | results["MessagePack"] = bds.SerializedData.MessagePack.Length; 49 | results["MsgPack"] = bds.SerializedData.MsgPack.Length; 50 | results["ProtoBufNet"] = bds.SerializedData.ProtoBufNet.Length; 51 | } 52 | 53 | foreach (var bds in bebopDataSets) 54 | { 55 | binaryResults[bds.Name]["Bebop"] = bds.Data.Length; 56 | } 57 | 58 | foreach (var jds in jsonDataSets) 59 | { 60 | var results = jsonResults[jds.Name]; 61 | results["Jil"] = Encoding.UTF8.GetBytes(j.Jil_Serialize(jds)).Length; 62 | results["Newtonsoft.Json"] = Encoding.UTF8.GetBytes(j.NewtonsoftJson_Serialize(jds)).Length; 63 | results["ServiceStack"] = Encoding.UTF8.GetBytes(j.ServiceStack_Serialize(jds)).Length; 64 | results["SpanJson"] = j.SpanJson_Serialize(jds).ToArray().Length; 65 | results["SystemTextJson"] = Encoding.UTF8.GetBytes(j.SystemTextJson_Serialize(jds)).Length; 66 | results["UTF8Json"] = j.UTF8Json_Serialize(jds).Length; 67 | } 68 | 69 | Console.WriteLine("Binary:"); 70 | foreach (var section in binaryResults) 71 | { 72 | Console.WriteLine($" {section.Key}:"); 73 | foreach (var result in section.Value.OrderBy(x => x.Value)) 74 | { 75 | Console.WriteLine($" - {(result.Key + ":").PadRight(15)} {result.Value}"); 76 | } 77 | } 78 | 79 | Console.WriteLine("Json:"); 80 | foreach (var section in jsonResults) 81 | { 82 | Console.WriteLine($" {section.Key}:"); 83 | foreach (var result in section.Value.OrderBy(x => x.Value)) 84 | { 85 | Console.WriteLine($" - {(result.Key + ":").PadRight(15)} {result.Value}"); 86 | } 87 | } 88 | } 89 | 90 | // ReSharper disable once UnusedMember.Local 91 | private static void GenerateDataSet() 92 | { 93 | // Copied from: https://github.com/bchavez/Bogus/blob/master/Examples/GettingStarted/Program.cs 94 | Randomizer.Seed = new Random(3897234); 95 | 96 | var fruit = new[] { "apple", "banana", "orange", "strawberry", "kiwi" }; 97 | 98 | var orderIds = 0; 99 | var testOrders = new Faker() 100 | .StrictMode(true) 101 | .RuleFor(o => o.OrderId, f => orderIds++) 102 | .RuleFor(o => o.Item, f => f.PickRandom(fruit)) 103 | .RuleFor(o => o.Quantity, f => f.Random.Number(1, 10)) 104 | .RuleFor(o => o.LotNumber, f => f.Random.Int(0, 100).OrNull(f, .8f)); 105 | 106 | var userIds = 0; 107 | var testUsers = new Faker() 108 | .RuleFor(u => u.Id, f => userIds++) 109 | .RuleFor(u => u.FirstName, f => f.Name.FirstName()) 110 | .RuleFor(u => u.LastName, f => f.Name.LastName()) 111 | .RuleFor(u => u.Avatar, f => f.Internet.Avatar()) 112 | .RuleFor(u => u.UserName, (f, u) => f.Internet.UserName(u.FirstName, u.LastName)) 113 | .RuleFor(u => u.Email, (f, u) => f.Internet.Email(u.FirstName, u.LastName)) 114 | .RuleFor(u => u.SomethingUnique, f => $"Value {f.UniqueIndex}") 115 | .RuleFor(u => u.SomeGuid, Guid.NewGuid) 116 | .RuleFor(u => u.Gender, f => f.PickRandom()) 117 | .RuleFor(u => u.CartId, f => Guid.NewGuid()) 118 | .RuleFor(u => u.FullName, (f, u) => u.FirstName + " " + u.LastName) 119 | .RuleFor(u => u.Orders, f => testOrders.Generate(Random.Shared.Next(5, 10))); 120 | 121 | var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; 122 | options.Converters.Add(new JsonStringEnumConverter()); 123 | 124 | File.WriteAllText("Data_Small.json", JsonSerializer.Serialize(testUsers.Generate(200), options)); 125 | File.WriteAllText("Data_Medium.json", JsonSerializer.Serialize(testUsers.Generate(5_000), options)); 126 | File.WriteAllText("Data_Large.json", JsonSerializer.Serialize(testUsers.Generate(20_000), options)); 127 | } 128 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SerializationBenchmarks 2 | 3 | As part of a [YouTube video](https://www.youtube.com/watch?v=XMoNYQPi2k8), I went through a bunch of serializers to see their current levels of performance. I'm happy for this repository to be improved in terms of fixing any minor issues, adding new scenarios or adding serialization frameworks. 4 | 5 | ## Serializers 6 | 7 | ### JSON 8 | 9 | - [Jil](https://www.nuget.org/packages/Jil/) 10 | - [Newtonsoft.Json](https://www.nuget.org/packages/Newtonsoft.Json/) 11 | - [ServiceStack.Text](https://www.nuget.org/packages/ServiceStack.Text/) 12 | - [SpanJson](https://www.nuget.org/packages/SpanJson) 13 | - System.Text.Json (with & without Source Generator) 14 | - [UTF8Json](https://www.nuget.org/packages/Utf8Json) 15 | 16 | ### Binary 17 | 18 | - [AvroConvert](https://www.nuget.org/packages/AvroConvert/) 19 | - [Bebop](https://www.nuget.org/packages/bebop) 20 | - [BSON](https://www.nuget.org/packages/MongoDB.Bson) 21 | - [CBOR](https://www.nuget.org/packages/Dahomey.Cbor) 22 | - [GroBuf](https://www.nuget.org/packages/GroBuf) 23 | - [Hyperion](https://www.nuget.org/packages/Hyperion) 24 | - [MessagePack](https://www.nuget.org/packages/MessagePack) 25 | - [MemoryPack](https://www.nuget.org/packages/MemoryPack) 26 | - [MsgPack](https://www.nuget.org/packages/MsgPack) 27 | - [protobuf-net](https://www.nuget.org/packages/protobuf-net) 28 | 29 | ## Current JSON Serializer Results (2023-02-26) 30 | 31 | ``` 32 | BenchmarkDotNet=v0.13.5, OS=Windows 11 (10.0.22621.1265/22H2/2022Update/SunValley2) 33 | Intel Core i9-9900K CPU 3.60GHz (Coffee Lake), 1 CPU, 8 logical and 4 physical cores 34 | .NET SDK=7.0.200 35 | [Host] : .NET 7.0.3 (7.0.323.6910), X64 RyuJIT AVX2 36 | DefaultJob : .NET 7.0.3 (7.0.323.6910), X64 RyuJIT AVX2 37 | ``` 38 | 39 | | Method | data | Mean | Error | StdDev | Median | Min | Max | Ratio | RatioSD | Gen0 | Gen1 | Gen2 | Allocated | Alloc Ratio | 40 | |---------------------------------- |------- |-------------:|------------:|------------:|-------------:|-------------:|-------------:|------:|--------:|----------:|----------:|---------:|------------:|------------:| 41 | | SpanJson_Deserialize | Large | 91,190.8 us | 1,811.48 us | 4,374.94 us | 89,969.2 us | 83,768.1 us | 104,369.6 us | 0.66 | 0.05 | 4000.0000 | 3833.3333 | 666.6667 | 44667.44 KB | 1.00 | 42 | | Jil_Deserialize | Large | 100,230.1 us | 1,943.11 us | 2,237.69 us | 100,638.2 us | 96,002.4 us | 103,568.0 us | 0.72 | 0.02 | 4000.0000 | 3833.3333 | 666.6667 | 27753.73 KB | 0.62 | 43 | | UTF8Json_Deserialize | Large | 109,200.0 us | 2,085.04 us | 2,047.79 us | 109,092.9 us | 105,728.9 us | 113,311.5 us | 0.79 | 0.02 | 3800.0000 | 3600.0000 | 600.0000 | 44666.62 KB | 1.00 | 44 | | SystemTextJson_Deserialize | Large | 138,832.0 us | 1,958.74 us | 1,832.20 us | 138,740.8 us | 136,207.2 us | 141,876.0 us | 1.00 | 0.00 | 3750.0000 | 3500.0000 | 500.0000 | 44668.96 KB | 1.00 | 45 | | SystemTextJson_SrcGen_Deserialize | Large | 140,451.0 us | 2,175.38 us | 2,034.85 us | 140,515.7 us | 137,389.1 us | 144,502.9 us | 1.01 | 0.02 | 3750.0000 | 3500.0000 | 500.0000 | 44668.96 KB | 1.00 | 46 | | ServiceStack_Deserialize | Large | 220,351.1 us | 4,329.13 us | 7,112.88 us | 218,680.2 us | 210,853.8 us | 238,109.4 us | 1.58 | 0.06 | 4666.6667 | 2333.3333 | 333.3333 | 37471.89 KB | 0.84 | 47 | | NewtonsoftJson_Deserialize | Large | 249,970.0 us | 4,223.49 us | 4,519.08 us | 248,670.5 us | 244,194.6 us | 260,768.2 us | 1.80 | 0.04 | 5000.0000 | 2500.0000 | 500.0000 | 39137.85 KB | 0.88 | 48 | | | | | | | | | | | | | | | | | 49 | | Jil_Deserialize | Medium | 16,157.2 us | 266.15 us | 316.83 us | 16,072.6 us | 15,767.3 us | 16,985.5 us | 0.59 | 0.02 | 843.7500 | 750.0000 | - | 6935.28 KB | 0.62 | 50 | | SpanJson_Deserialize | Medium | 16,572.0 us | 267.62 us | 237.24 us | 16,686.7 us | 16,136.5 us | 16,803.6 us | 0.61 | 0.01 | 1093.7500 | 968.7500 | 250.0000 | 11124.97 KB | 1.00 | 51 | | UTF8Json_Deserialize | Medium | 21,231.9 us | 414.06 us | 552.76 us | 21,134.0 us | 20,066.9 us | 22,387.3 us | 0.78 | 0.03 | 1093.7500 | 968.7500 | 250.0000 | 11125.04 KB | 1.00 | 52 | | SystemTextJson_Deserialize | Medium | 27,273.0 us | 329.03 us | 307.77 us | 27,179.3 us | 26,864.5 us | 28,011.8 us | 1.00 | 0.00 | 1093.7500 | 968.7500 | 250.0000 | 11125.72 KB | 1.00 | 53 | | SystemTextJson_SrcGen_Deserialize | Medium | 27,648.3 us | 241.70 us | 214.26 us | 27,591.1 us | 27,366.2 us | 28,085.3 us | 1.01 | 0.02 | 1093.7500 | 968.7500 | 250.0000 | 11126.42 KB | 1.00 | 54 | | ServiceStack_Deserialize | Medium | 48,323.4 us | 734.66 us | 687.20 us | 48,138.1 us | 47,236.9 us | 49,689.3 us | 1.77 | 0.03 | 1181.8182 | 1000.0000 | 90.9091 | 9357.83 KB | 0.84 | 55 | | NewtonsoftJson_Deserialize | Medium | 55,349.4 us | 1,089.57 us | 2,298.27 us | 55,172.9 us | 51,556.2 us | 60,647.0 us | 2.05 | 0.07 | 1100.0000 | 900.0000 | - | 9776.74 KB | 0.88 | 56 | | | | | | | | | | | | | | | | | 57 | | SpanJson_Deserialize | Small | 511.2 us | 9.20 us | 8.15 us | 509.2 us | 501.2 us | 528.3 us | 0.54 | 0.01 | 51.7578 | 51.7578 | 51.7578 | 446.93 KB | 1.60 | 58 | | Jil_Deserialize | Small | 564.0 us | 2.39 us | 2.00 us | 563.5 us | 561.7 us | 567.8 us | 0.60 | 0.00 | 34.1797 | 10.7422 | - | 279.63 KB | 1.00 | 59 | | UTF8Json_Deserialize | Small | 665.7 us | 5.09 us | 4.76 us | 665.6 us | 658.7 us | 673.7 us | 0.71 | 0.00 | 83.0078 | 61.5234 | 48.8281 | 447.05 KB | 1.60 | 60 | | SystemTextJson_Deserialize | Small | 939.9 us | 1.45 us | 1.21 us | 939.7 us | 937.5 us | 941.7 us | 1.00 | 0.00 | 34.1797 | 11.7188 | - | 279.71 KB | 1.00 | 61 | | SystemTextJson_SrcGen_Deserialize | Small | 983.0 us | 2.19 us | 1.94 us | 983.0 us | 979.7 us | 985.9 us | 1.05 | 0.00 | 33.2031 | 11.7188 | - | 279.71 KB | 1.00 | 62 | | ServiceStack_Deserialize | Small | 1,551.9 us | 13.64 us | 12.76 us | 1,546.8 us | 1,535.9 us | 1,578.3 us | 1.65 | 0.01 | 44.9219 | 13.6719 | - | 379.04 KB | 1.36 | 63 | | NewtonsoftJson_Deserialize | Small | 1,880.9 us | 28.69 us | 26.84 us | 1,886.8 us | 1,831.2 us | 1,914.5 us | 2.00 | 0.03 | 46.8750 | 19.5313 | - | 398.46 KB | 1.42 | 64 | | | | | | | | | | | | | | | | | 65 | | SpanJson_Serialize | Large | 24,379.2 us | 67.39 us | 56.27 us | 24,383.5 us | 24,263.1 us | 24,476.9 us | 0.48 | 0.00 | 125.0000 | 125.0000 | 125.0000 | 16384.13 KB | 0.48 | 66 | | UTF8Json_Serialize | Large | 39,032.1 us | 765.63 us | 1,419.15 us | 38,884.8 us | 36,683.0 us | 42,188.1 us | 0.80 | 0.03 | 615.3846 | 615.3846 | 615.3846 | 82319.57 KB | 2.40 | 67 | | SystemTextJson_SrcGen_Serialize | Large | 49,655.5 us | 217.47 us | 181.60 us | 49,619.5 us | 49,443.4 us | 50,147.9 us | 0.98 | 0.00 | - | - | - | 34296.93 KB | 1.00 | 68 | | SystemTextJson_Serialize | Large | 50,513.3 us | 170.93 us | 151.53 us | 50,520.8 us | 50,184.7 us | 50,817.3 us | 1.00 | 0.00 | - | - | - | 34296.93 KB | 1.00 | 69 | | Jil_Serialize | Large | 53,530.0 us | 1,067.88 us | 1,425.59 us | 53,763.7 us | 50,595.6 us | 55,955.4 us | 1.07 | 0.03 | 5000.0000 | 4888.8889 | 888.8889 | 67819 KB | 1.98 | 70 | | NewtonsoftJson_Serialize | Large | 125,169.9 us | 2,045.01 us | 1,812.85 us | 125,387.6 us | 122,390.9 us | 128,757.7 us | 2.48 | 0.04 | 6600.0000 | 3600.0000 | 800.0000 | 81290.58 KB | 2.37 | 71 | | ServiceStack_Serialize | Large | 146,043.9 us | 293.87 us | 274.89 us | 145,935.9 us | 145,687.9 us | 146,551.0 us | 2.89 | 0.01 | 6000.0000 | - | - | 78487.63 KB | 2.29 | 72 | | | | | | | | | | | | | | | | | 73 | | SpanJson_Serialize | Medium | 6,141.6 us | 56.25 us | 52.61 us | 6,155.3 us | 5,993.7 us | 6,201.1 us | 0.48 | 0.01 | 117.1875 | 117.1875 | 117.1875 | 4096.11 KB | 0.48 | 74 | | UTF8Json_Serialize | Medium | 10,055.7 us | 199.79 us | 177.11 us | 10,020.6 us | 9,819.5 us | 10,372.9 us | 0.78 | 0.02 | 500.0000 | 500.0000 | 500.0000 | 20445.27 KB | 2.41 | 75 | | SystemTextJson_Serialize | Medium | 12,890.4 us | 203.52 us | 190.38 us | 12,866.9 us | 12,676.6 us | 13,272.9 us | 1.00 | 0.00 | 187.5000 | 187.5000 | 187.5000 | 8496.96 KB | 1.00 | 76 | | SystemTextJson_SrcGen_Serialize | Medium | 13,029.8 us | 164.63 us | 153.99 us | 13,040.7 us | 12,804.6 us | 13,314.2 us | 1.01 | 0.02 | 187.5000 | 187.5000 | 187.5000 | 8496.96 KB | 1.00 | 77 | | Jil_Serialize | Medium | 16,192.0 us | 315.34 us | 410.04 us | 16,162.8 us | 15,534.3 us | 17,039.5 us | 1.26 | 0.05 | 1906.2500 | 1812.5000 | 875.0000 | 16806.86 KB | 1.98 | 78 | | NewtonsoftJson_Serialize | Medium | 31,214.2 us | 558.44 us | 948.28 us | 30,899.0 us | 30,212.6 us | 33,347.0 us | 2.41 | 0.07 | 2312.5000 | 1875.0000 | 875.0000 | 20170.37 KB | 2.37 | 79 | | ServiceStack_Serialize | Medium | 38,538.6 us | 314.84 us | 294.50 us | 38,582.1 us | 38,049.6 us | 39,009.7 us | 2.99 | 0.04 | 1571.4286 | 142.8571 | 142.8571 | 19358.84 KB | 2.28 | 80 | | | | | | | | | | | | | | | | | 81 | | SpanJson_Serialize | Small | 234.9 us | 0.43 us | 0.38 us | 234.9 us | 234.1 us | 235.3 us | 0.47 | 0.00 | 75.6836 | 75.6836 | 75.6836 | 256.07 KB | 0.75 | 82 | | UTF8Json_Serialize | Small | 303.2 us | 0.89 us | 0.84 us | 303.3 us | 301.8 us | 304.4 us | 0.61 | 0.00 | 148.9258 | 148.9258 | 148.9258 | 551.72 KB | 1.62 | 83 | | Jil_Serialize | Small | 436.1 us | 19.80 us | 58.37 us | 473.4 us | 322.6 us | 486.5 us | 0.70 | 0.03 | 99.6094 | 99.6094 | 99.6094 | 673.91 KB | 1.98 | 84 | | SystemTextJson_Serialize | Small | 499.2 us | 3.20 us | 2.84 us | 499.9 us | 492.4 us | 502.9 us | 1.00 | 0.00 | 89.8438 | 89.8438 | 89.8438 | 340.86 KB | 1.00 | 85 | | SystemTextJson_SrcGen_Serialize | Small | 503.1 us | 2.69 us | 2.38 us | 503.0 us | 498.8 us | 507.4 us | 1.01 | 0.01 | 89.8438 | 89.8438 | 89.8438 | 340.85 KB | 1.00 | 86 | | NewtonsoftJson_Serialize | Small | 1,102.0 us | 11.72 us | 9.15 us | 1,104.2 us | 1,081.5 us | 1,110.3 us | 2.21 | 0.03 | 148.4375 | 113.2813 | 89.8438 | 821.44 KB | 2.41 | 87 | | ServiceStack_Serialize | Small | 1,581.4 us | 17.93 us | 16.77 us | 1,577.9 us | 1,562.8 us | 1,617.2 us | 3.17 | 0.04 | 142.5781 | 82.0313 | 82.0313 | 784.99 KB | 2.30 | 88 | 89 | ## Current Binary Serializer Results (2023-02-26) 90 | 91 | ``` 92 | BenchmarkDotNet=v0.13.5, OS=Windows 11 (10.0.22621.1265/22H2/2022Update/SunValley2) 93 | Intel Core i9-9900K CPU 3.60GHz (Coffee Lake), 1 CPU, 8 logical and 4 physical cores 94 | .NET SDK=7.0.200 95 | [Host] : .NET 7.0.3 (7.0.323.6910), X64 RyuJIT AVX2 96 | DefaultJob : .NET 7.0.3 (7.0.323.6910), X64 RyuJIT AVX2 97 | ``` 98 | 99 | | Method | data | Mean | Error | StdDev | Min | Max | Gen0 | Gen1 | Gen2 | Allocated | 100 | |------------------------ |------- |--------------:|-------------:|-------------:|--------------:|--------------:|-----------:|----------:|---------:|-----------:| 101 | | GroBuf_Deserialize | Large | 47,243.86 us | 825.702 us | 772.362 us | 45,642.06 us | 48,513.91 us | 3636.3636 | 3545.4545 | 545.4545 | 26179193 B | 102 | | Bebop_Deserialize | Large | 48,244.74 us | 748.848 us | 700.473 us | 47,523.21 us | 49,245.47 us | 3909.0909 | 3818.1818 | 727.2727 | 26980756 B | 103 | | MemoryPack_Deserialize | Large | 48,738.47 us | 911.477 us | 852.597 us | 47,061.95 us | 50,501.60 us | 3636.3636 | 3545.4545 | 545.4545 | 26179103 B | 104 | | MessagePack_Deserialize | Large | 62,726.35 us | 1,155.674 us | 1,330.876 us | 60,548.57 us | 65,081.39 us | 3500.0000 | 3375.0000 | 500.0000 | 26179115 B | 105 | | ProtoBufNet_Deserialize | Large | 71,688.15 us | 1,416.613 us | 2,031.664 us | 69,305.33 us | 76,257.39 us | 3714.2857 | 3571.4286 | 571.4286 | 26820875 B | 106 | | Hyperion_Deserialize | Large | 87,696.21 us | 1,700.080 us | 1,889.634 us | 85,881.60 us | 91,572.22 us | 4166.6667 | 4000.0000 | 500.0000 | 31180175 B | 107 | | MsgPack_Deserialize | Large | 92,672.91 us | 1,770.147 us | 1,817.811 us | 89,019.35 us | 96,053.55 us | 4166.6667 | 4000.0000 | 500.0000 | 32018907 B | 108 | | AvroConvert_Deserialize | Large | 196,401.45 us | 3,830.642 us | 4,980.917 us | 187,416.40 us | 203,311.00 us | 10000.0000 | 3666.6667 | 333.3333 | 96425000 B | 109 | | BSON_Deserialize | Large | 235,586.13 us | 3,199.265 us | 2,836.065 us | 229,802.00 us | 240,312.37 us | 8333.3333 | 4333.3333 | 333.3333 | 69298835 B | 110 | | | | | | | | | | | | | 111 | | GroBuf_Deserialize | Medium | 4,257.91 us | 62.966 us | 52.579 us | 4,179.05 us | 4,336.40 us | 773.4375 | 703.1250 | - | 6533041 B | 112 | | Bebop_Deserialize | Medium | 4,402.57 us | 60.201 us | 56.312 us | 4,308.14 us | 4,478.53 us | 804.6875 | 750.0000 | - | 6732454 B | 113 | | MemoryPack_Deserialize | Medium | 4,425.59 us | 43.134 us | 40.347 us | 4,370.96 us | 4,497.73 us | 773.4375 | 703.1250 | - | 6532969 B | 114 | | ProtoBufNet_Deserialize | Medium | 8,896.05 us | 44.146 us | 39.134 us | 8,804.73 us | 8,960.84 us | 796.8750 | 593.7500 | - | 6693108 B | 115 | | MessagePack_Deserialize | Medium | 8,967.02 us | 74.913 us | 66.408 us | 8,843.58 us | 9,075.46 us | 765.6250 | 687.5000 | - | 6532978 B | 116 | | Hyperion_Deserialize | Medium | 13,124.22 us | 46.479 us | 41.203 us | 13,063.96 us | 13,210.24 us | 921.8750 | 843.7500 | - | 7789506 B | 117 | | MsgPack_Deserialize | Medium | 13,680.20 us | 189.208 us | 202.450 us | 13,328.87 us | 14,038.78 us | 953.1250 | 906.2500 | - | 7992954 B | 118 | | AvroConvert_Deserialize | Medium | 43,866.48 us | 713.613 us | 667.514 us | 42,987.47 us | 45,111.19 us | 2692.3077 | 1076.9231 | 230.7692 | 24169490 B | 119 | | BSON_Deserialize | Medium | 59,161.54 us | 1,155.333 us | 1,080.699 us | 57,379.79 us | 60,921.69 us | 2222.2222 | 1222.2222 | 222.2222 | 17298596 B | 120 | | | | | | | | | | | | | 121 | | GroBuf_Deserialize | Small | 113.90 us | 1.860 us | 1.649 us | 111.64 us | 117.01 us | 31.4941 | 10.4980 | - | 263784 B | 122 | | Bebop_Deserialize | Small | 116.13 us | 1.069 us | 1.000 us | 114.89 us | 118.71 us | 32.4707 | 12.0850 | - | 272000 B | 123 | | MemoryPack_Deserialize | Small | 121.76 us | 0.376 us | 0.314 us | 120.74 us | 121.99 us | 31.4941 | 10.4980 | - | 263712 B | 124 | | MessagePack_Deserialize | Small | 299.24 us | 0.495 us | 0.439 us | 298.79 us | 300.21 us | 31.2500 | 10.2539 | - | 263713 B | 125 | | ProtoBufNet_Deserialize | Small | 302.80 us | 4.197 us | 6.152 us | 298.31 us | 321.27 us | 32.2266 | 10.7422 | - | 270233 B | 126 | | Hyperion_Deserialize | Small | 354.44 us | 1.090 us | 1.019 us | 353.28 us | 356.81 us | 37.5977 | 12.6953 | - | 315425 B | 127 | | MsgPack_Deserialize | Small | 463.82 us | 4.525 us | 4.232 us | 458.79 us | 472.56 us | 38.0859 | 12.6953 | - | 322225 B | 128 | | AvroConvert_Deserialize | Small | 1,516.93 us | 8.215 us | 7.684 us | 1,504.66 us | 1,527.68 us | 134.7656 | 48.8281 | - | 1135455 B | 129 | | BSON_Deserialize | Small | 1,697.43 us | 19.415 us | 18.161 us | 1,666.60 us | 1,727.83 us | 82.0313 | 27.3438 | - | 701884 B | 130 | | | | | | | | | | | | | 131 | | MemoryPack_Serialize | Large | 9,668.02 us | 11.755 us | 9.816 us | 9,649.58 us | 9,682.30 us | 31.2500 | 31.2500 | 31.2500 | 9818513 B | 132 | | GroBuf_Serialize | Large | 10,991.49 us | 13.141 us | 11.649 us | 10,968.58 us | 11,013.30 us | 62.5000 | 62.5000 | 62.5000 | 18824229 B | 133 | | Bebop_Serialize | Large | 12,556.43 us | 55.511 us | 46.354 us | 12,493.10 us | 12,641.42 us | - | - | - | 36 B | 134 | | MessagePack_Serialize | Large | 16,490.02 us | 66.105 us | 61.834 us | 16,413.60 us | 16,612.91 us | - | - | - | 7196899 B | 135 | | ProtoBufNet_Serialize | Large | 27,214.02 us | 270.428 us | 239.727 us | 26,966.38 us | 27,802.83 us | 156.2500 | 156.2500 | 156.2500 | 27893153 B | 136 | | Hyperion_Serialize | Large | 34,844.59 us | 425.809 us | 398.302 us | 34,004.25 us | 35,126.87 us | 600.0000 | 66.6667 | 66.6667 | 28827900 B | 137 | | MsgPack_Serialize | Large | 40,435.03 us | 372.214 us | 329.958 us | 39,724.02 us | 40,921.32 us | 1230.7692 | 384.6154 | 307.6923 | 67710617 B | 138 | | AvroConvert_Serialize | Large | 55,918.00 us | 640.324 us | 598.960 us | 54,529.86 us | 56,514.13 us | 4111.1111 | 111.1111 | 111.1111 | 78042956 B | 139 | | BSON_Serialize | Large | 139,522.40 us | 1,145.433 us | 1,071.439 us | 137,698.95 us | 141,130.38 us | 4750.0000 | - | - | 90285250 B | 140 | | | | | | | | | | | | | 141 | | MemoryPack_Serialize | Medium | 2,344.52 us | 27.653 us | 24.514 us | 2,318.72 us | 2,405.98 us | 85.9375 | 85.9375 | 85.9375 | 2446033 B | 142 | | GroBuf_Serialize | Medium | 2,594.14 us | 51.653 us | 59.484 us | 2,480.14 us | 2,687.87 us | 109.3750 | 109.3750 | 109.3750 | 4688436 B | 143 | | Bebop_Serialize | Medium | 2,874.85 us | 8.709 us | 6.800 us | 2,869.72 us | 2,887.92 us | - | - | - | 27 B | 144 | | MessagePack_Serialize | Medium | 4,229.39 us | 82.978 us | 77.618 us | 4,104.00 us | 4,339.72 us | 31.2500 | 31.2500 | 31.2500 | 1737144 B | 145 | | ProtoBufNet_Serialize | Medium | 7,162.14 us | 45.605 us | 40.428 us | 7,107.72 us | 7,238.80 us | 140.6250 | 125.0000 | 125.0000 | 7090069 B | 146 | | Hyperion_Serialize | Medium | 8,857.20 us | 29.018 us | 25.724 us | 8,821.47 us | 8,914.76 us | 296.8750 | 156.2500 | 156.2500 | 7197143 B | 147 | | MsgPack_Serialize | Medium | 9,629.06 us | 188.542 us | 376.539 us | 8,914.96 us | 10,518.29 us | 671.8750 | 406.2500 | 390.6250 | 15023469 B | 148 | | AvroConvert_Serialize | Medium | 16,328.77 us | 310.634 us | 305.085 us | 15,725.40 us | 16,876.81 us | 1375.0000 | 562.5000 | 343.7500 | 19539986 B | 149 | | BSON_Serialize | Medium | 37,320.81 us | 603.465 us | 564.481 us | 36,480.74 us | 38,157.81 us | 1428.5714 | 285.7143 | 285.7143 | 22510582 B | 150 | | | | | | | | | | | | | 151 | | MemoryPack_Serialize | Small | 86.05 us | 0.790 us | 0.701 us | 85.32 us | 87.32 us | 16.1133 | 16.1133 | 16.1133 | 98798 B | 152 | | GroBuf_Serialize | Small | 90.58 us | 1.163 us | 1.088 us | 89.51 us | 92.61 us | 27.2217 | 27.2217 | 27.2217 | 189554 B | 153 | | Bebop_Serialize | Small | 114.32 us | 0.799 us | 0.748 us | 113.45 us | 116.12 us | - | - | - | 24 B | 154 | | MessagePack_Serialize | Small | 159.42 us | 1.411 us | 1.178 us | 157.78 us | 161.28 us | 8.0566 | - | - | 69336 B | 155 | | ProtoBufNet_Serialize | Small | 259.28 us | 3.939 us | 3.492 us | 252.99 us | 266.47 us | 26.8555 | 4.3945 | - | 228617 B | 156 | | MsgPack_Serialize | Small | 281.98 us | 2.989 us | 2.496 us | 278.27 us | 285.97 us | 70.8008 | 12.2070 | - | 596033 B | 157 | | Hyperion_Serialize | Small | 339.40 us | 2.626 us | 2.193 us | 335.48 us | 342.36 us | 52.2461 | 25.8789 | 22.4609 | 384295 B | 158 | | AvroConvert_Serialize | Small | 773.36 us | 8.749 us | 8.184 us | 763.25 us | 792.67 us | 129.8828 | 61.5234 | 44.9219 | 983877 B | 159 | | BSON_Serialize | Small | 1,449.58 us | 28.409 us | 29.174 us | 1,417.69 us | 1,504.62 us | 158.2031 | 101.5625 | 95.7031 | 1093695 B | 160 | -------------------------------------------------------------------------------- /SerializationBenchmarks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | disable 8 | $(DefineConstants);DATASET_SMALL; 9 | $(DefineConstants);DATASET_MEDIUM; 10 | $(DefineConstants);DATASET_LARGE; 11 | 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Always 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /SerializationBenchmarks.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.4.32804.182 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SerializationBenchmarks", "SerializationBenchmarks.csproj", "{60C8F385-0FF6-4288-89DB-6E0F318A07A0}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {60C8F385-0FF6-4288-89DB-6E0F318A07A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {60C8F385-0FF6-4288-89DB-6E0F318A07A0}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {60C8F385-0FF6-4288-89DB-6E0F318A07A0}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {60C8F385-0FF6-4288-89DB-6E0F318A07A0}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {575C3A64-C192-457C-9E84-86A8ECCCCE33} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /SerializerBenchmark.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using BenchmarkDotNet.Configs; 3 | using BenchmarkDotNet.Order; 4 | 5 | [MemoryDiagnoser] 6 | [MinColumn, MaxColumn] 7 | [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory), Orderer(SummaryOrderPolicy.FastestToSlowest)] 8 | public abstract class SerializerBenchmark 9 | { 10 | } --------------------------------------------------------------------------------