diff --git a/.build-and-publish-nuget-package.cmd b/.build-and-publish-nuget-package.cmd new file mode 100644 index 0000000..2954f59 --- /dev/null +++ b/.build-and-publish-nuget-package.cmd @@ -0,0 +1,5 @@ +dotnet build --force --no-incremental --configuration Release ./GroBuf.sln +dotnet pack --no-build --configuration Release ./GroBuf.sln +cd ./GroBuf/bin/Release +dotnet nuget push *.nupkg -s https://nuget.org +pause \ No newline at end of file diff --git a/.cake/packages.config b/.cake/packages.config deleted file mode 100644 index e0dd39b..0000000 --- a/.cake/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..26b6c1c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +; 4-column space indentation +[*.cs] +indent_style = space +indent_size = 4 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8337662..a15dd92 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,322 @@ -bin -obj -[Dd]ebug -[Rr]elease -*.user +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files *.suo -GroBuf.dll -GroBuf.pdb -_ReSharper.* -Output/ -.cake/* -!.cake/packages.config -packages/ -.vs/ \ No newline at end of file +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# TypeScript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +#.cake/** +#!.cake/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog diff --git a/.rebuild.cmd b/.rebuild.cmd index eec1c4d..1a49857 100644 --- a/.rebuild.cmd +++ b/.rebuild.cmd @@ -1,3 +1,2 @@ -@echo off -PowerShell.exe -ExecutionPolicy ByPass -Command "& { %~dp0build.ps1 -Script %~dp0build.cake -Target Build-And-Merge -Configuration Release; exit $LASTEXITCODE }" +dotnet build --force --no-incremental --configuration Release ./GroBuf.sln pause diff --git a/.run-all-tests.cmd b/.run-all-tests.cmd index 22df998..ae6b9ab 100644 --- a/.run-all-tests.cmd +++ b/.run-all-tests.cmd @@ -1,3 +1,2 @@ -@echo off -PowerShell.exe -ExecutionPolicy ByPass -Command "& { %~dp0build.ps1 -Script %~dp0build.cake -Target Run-All-Tests -Configuration Release; exit $LASTEXITCODE }" +dotnet test --configuration Release ./GroBuf.Tests/GroBuf.Tests.csproj pause \ No newline at end of file diff --git a/.run-unit-tests.cmd b/.run-unit-tests.cmd index 874dbeb..5f29970 100644 --- a/.run-unit-tests.cmd +++ b/.run-unit-tests.cmd @@ -1,3 +1,2 @@ -@echo off -PowerShell.exe -ExecutionPolicy ByPass -Command "& { %~dp0build.ps1 -Script %~dp0build.cake -Target Run-Unit-Tests -Configuration Release; exit $LASTEXITCODE }" +dotnet test --configuration Release --filter TestCategory!=LongRunning ./GroBuf.Tests/GroBuf.Tests.csproj pause \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..888f257 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +dist: trusty +sudo: false +language: csharp +dotnet: 2.0.0 +mono: none +script: + - dotnet restore ./GroBuf.sln --verbosity m + - dotnet build --configuration Release --framework netstandard2.0 ./GroBuf/GroBuf.csproj + - dotnet build --configuration Release --framework netcoreapp2.0 ./GroBuf.Tests/GroBuf.Tests.csproj + - dotnet test --no-build --configuration Release --framework netcoreapp2.0 --filter TestCategory!=LongRunning ./GroBuf.Tests/GroBuf.Tests.csproj + + diff --git a/Common.DotSettings b/Common.DotSettings index 05e90f6..a0ab47d 100644 --- a/Common.DotSettings +++ b/Common.DotSettings @@ -24,8 +24,11 @@ NEXT_LINE_SHIFTED_2 NEXT_LINE_SHIFTED_2 NEXT_LINE_SHIFTED_2 + NEVER + NEVER 120 False + False <?xml version="1.0" encoding="utf-16"?> <Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> <TypePattern DisplayName="Default Pattern"> @@ -161,11 +164,17 @@ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> False + True True + True + True + True True True + True True True + True True True True diff --git a/GroBuf/Tests/DataSchemeChangedTest.cs b/GroBuf.Tests/DataSchemeChangedTest.cs similarity index 96% rename from GroBuf/Tests/DataSchemeChangedTest.cs rename to GroBuf.Tests/DataSchemeChangedTest.cs index 0087b4d..cabe18c 100644 --- a/GroBuf/Tests/DataSchemeChangedTest.cs +++ b/GroBuf.Tests/DataSchemeChangedTest.cs @@ -1,277 +1,277 @@ -using System; -using System.Runtime.Serialization; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class DataSchemeChangedTest - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.MergeOnRead); - } - - [Test] - public void PropertyHasBeenAdded() - { - var o = new C1_Old {S = "zzz", X = 123}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.S); - Assert.AreEqual(123, oo.X); - Assert.IsNull(oo.D); - } - - [Test] - public void PropertyHasBeenRemoved() - { - var o = new C2_Old {S = "zzz", X = 123, D = 3.14}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.S); - Assert.AreEqual(3.14, oo.D); - } - - [Test] - public void PropertyHasBecomeArray() - { - var o = new C3_Old {S = "zzz", X = 123, C3 = new C3_Subclass {S = "qxx"}}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - - Assert.IsNotNull(oo.S); - Assert.AreEqual(1, oo.S.Length); - Assert.AreEqual("zzz", oo.S[0]); - Assert.IsNotNull(oo.X); - Assert.AreEqual(1, oo.X.Length); - Assert.AreEqual(123, oo.X[0]); - Assert.IsNotNull(oo.C3); - Assert.AreEqual(1, oo.C3.Length); - Assert.IsNotNull(oo.C3[0]); - Assert.AreEqual("qxx", oo.C3[0].S); - - oo = new C3_New {S = new string[0], X = new int[0], C3 = new C3_Subclass[0]}; - serializer.Merge(o, ref oo); - Assert.IsNotNull(oo.S); - Assert.AreEqual(1, oo.S.Length); - Assert.AreEqual("zzz", oo.S[0]); - Assert.IsNotNull(oo.X); - Assert.AreEqual(1, oo.X.Length); - Assert.AreEqual(123, oo.X[0]); - Assert.IsNotNull(oo.C3); - Assert.AreEqual(1, oo.C3.Length); - Assert.IsNotNull(oo.C3[0]); - Assert.AreEqual("qxx", oo.C3[0].S); - - oo = new C3_New {S = new string[1], X = new int[1], C3 = new C3_Subclass[1]}; - serializer.Merge(o, ref oo); - Assert.IsNotNull(oo.S); - Assert.AreEqual(1, oo.S.Length); - Assert.AreEqual("zzz", oo.S[0]); - Assert.IsNotNull(oo.X); - Assert.AreEqual(1, oo.X.Length); - Assert.AreEqual(123, oo.X[0]); - Assert.IsNotNull(oo.C3); - Assert.AreEqual(1, oo.C3.Length); - Assert.IsNotNull(oo.C3[0]); - Assert.AreEqual("qxx", oo.C3[0].S); - - oo = new C3_New {S = new string[2], X = new int[2], C3 = new C3_Subclass[2]}; - serializer.Merge(o, ref oo); - Assert.IsNotNull(oo.S); - Assert.AreEqual(2, oo.S.Length); - Assert.AreEqual("zzz", oo.S[0]); - Assert.IsNotNull(oo.X); - Assert.AreEqual(2, oo.X.Length); - Assert.AreEqual(123, oo.X[0]); - Assert.IsNotNull(oo.C3); - Assert.AreEqual(2, oo.C3.Length); - Assert.IsNotNull(oo.C3[0]); - Assert.AreEqual("qxx", oo.C3[0].S); - } - - [Test] - public void TestReadWriteToId() - { - var o = new C4_Old {S = "zzz", X = 123}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.Zzz); - Assert.AreEqual(123, oo.Qxx); - } - - [Test] - public void TestReadWriteFromId() - { - var o = new C4_New {Zzz = "zzz", Qxx = 123}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.S); - Assert.AreEqual(123, oo.X); - } - - [Test] - public void Test_GroboMember_IdCollision() - { - var o = new C5_GroboMember_IdCollision(); - var e = Assert.Throws(() => serializer.Serialize(o)); - Assert.That(e.Message, Is.EqualTo("Hash code collision: members 'C5_GroboMember_IdCollision.X' and 'C5_GroboMember_IdCollision.S' have the same hash code = 1")); - } - - [Test] - public void Test_GroboMember_EmptyName() - { - var o = new C6_GroboMember_EmptyName(); - var e = Assert.Throws(() => serializer.Serialize(o)); - Assert.That(e.Message, Is.EqualTo("Empty grobo name of member 'C6_GroboMember_EmptyName.S'")); - } - - [Test] - public void Test_GroboMember_EmptyId() - { - var o = new C7_GroboMember_EmptyId(); - var e = Assert.Throws(() => serializer.Serialize(o)); - Assert.That(e.Message, Is.EqualTo("Hash code of 'C7_GroboMember_EmptyId.S' equals to zero")); - } - - [Test] - public void Test_MixedAnnotationAttributes() - { - var o = new C8_MixedAnnotationAttributes {S = "zzz", X = 123, Q = -1}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.S); - Assert.AreEqual(123, oo.X); - Assert.AreEqual(-1, oo.Q); - } - - [Test] - public void Test_GroboMember_ReadonlyProperty() - { - var o = new C9_GroboMember_ReadonlyProperty_Old("GRobas"); - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("GRobas", oo.Zzz); - } - - public class C1_Old - { - public string S { get; set; } - public int X { get; set; } - } - - public class C1_New - { - public int X { get; set; } - public double? D { get; set; } - public string S { get; set; } - } - - public class C2_Old - { - public int X { get; set; } - public double? D { get; set; } - public string S { get; set; } - } - - public class C2_New - { - public string S { get; set; } - public double? D { get; set; } - } - - public class C3_Subclass - { - public string S { get; set; } - } - - public class C3_Old - { - public string S { get; set; } - public int X { get; set; } - public C3_Subclass C3 { get; set; } - } - - public class C3_New - { - public string[] S { get; set; } - public int[] X { get; set; } - public C3_Subclass[] C3 { get; set; } - } - - public class C4_Old - { - public string S { get; set; } - public int X { get; set; } - } - - public class C4_New - { - [GroboMember(7770670552212394539)] - public string Zzz { get; set; } - - [GroboMember("X")] - public int Qxx { get; set; } - } - - public class C5_GroboMember_IdCollision - { - [GroboMember(1)] - public string S { get; set; } - - [GroboMember(1)] - public int X { get; set; } - } - - public class C6_GroboMember_EmptyName - { - [GroboMember("")] - public string S { get; set; } - } - - public class C7_GroboMember_EmptyId - { - [GroboMember(0)] - public string S { get; set; } - } - - public class C8_MixedAnnotationAttributes - { - public string S { get; set; } - - [DataMember(Name = "Z")] - public int X { get; set; } - - [GroboMember(1)] - public int? Q { get; set; } - } - - public class C9_GroboMember_ReadonlyProperty_Old - { - public C9_GroboMember_ReadonlyProperty_Old(string qxx) - { - Qxx = qxx; - } - - public string Qxx { get; } - } - - public class C9_GroboMember_ReadonlyProperty_New - { - public C9_GroboMember_ReadonlyProperty_New(string gRobas) - { - Zzz = gRobas; - } - - [GroboMember("Qxx")] - public string Zzz { get; } - } - - private Serializer serializer; - } +using System; +using System.Runtime.Serialization; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class DataSchemeChangedTest + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.MergeOnRead); + } + + [Test] + public void PropertyHasBeenAdded() + { + var o = new C1_Old {S = "zzz", X = 123}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.S); + Assert.AreEqual(123, oo.X); + Assert.IsNull(oo.D); + } + + [Test] + public void PropertyHasBeenRemoved() + { + var o = new C2_Old {S = "zzz", X = 123, D = 3.14}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.S); + Assert.AreEqual(3.14, oo.D); + } + + [Test] + public void PropertyHasBecomeArray() + { + var o = new C3_Old {S = "zzz", X = 123, C3 = new C3_Subclass {S = "qxx"}}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + + Assert.IsNotNull(oo.S); + Assert.AreEqual(1, oo.S.Length); + Assert.AreEqual("zzz", oo.S[0]); + Assert.IsNotNull(oo.X); + Assert.AreEqual(1, oo.X.Length); + Assert.AreEqual(123, oo.X[0]); + Assert.IsNotNull(oo.C3); + Assert.AreEqual(1, oo.C3.Length); + Assert.IsNotNull(oo.C3[0]); + Assert.AreEqual("qxx", oo.C3[0].S); + + oo = new C3_New {S = new string[0], X = new int[0], C3 = new C3_Subclass[0]}; + serializer.Merge(o, ref oo); + Assert.IsNotNull(oo.S); + Assert.AreEqual(1, oo.S.Length); + Assert.AreEqual("zzz", oo.S[0]); + Assert.IsNotNull(oo.X); + Assert.AreEqual(1, oo.X.Length); + Assert.AreEqual(123, oo.X[0]); + Assert.IsNotNull(oo.C3); + Assert.AreEqual(1, oo.C3.Length); + Assert.IsNotNull(oo.C3[0]); + Assert.AreEqual("qxx", oo.C3[0].S); + + oo = new C3_New {S = new string[1], X = new int[1], C3 = new C3_Subclass[1]}; + serializer.Merge(o, ref oo); + Assert.IsNotNull(oo.S); + Assert.AreEqual(1, oo.S.Length); + Assert.AreEqual("zzz", oo.S[0]); + Assert.IsNotNull(oo.X); + Assert.AreEqual(1, oo.X.Length); + Assert.AreEqual(123, oo.X[0]); + Assert.IsNotNull(oo.C3); + Assert.AreEqual(1, oo.C3.Length); + Assert.IsNotNull(oo.C3[0]); + Assert.AreEqual("qxx", oo.C3[0].S); + + oo = new C3_New {S = new string[2], X = new int[2], C3 = new C3_Subclass[2]}; + serializer.Merge(o, ref oo); + Assert.IsNotNull(oo.S); + Assert.AreEqual(2, oo.S.Length); + Assert.AreEqual("zzz", oo.S[0]); + Assert.IsNotNull(oo.X); + Assert.AreEqual(2, oo.X.Length); + Assert.AreEqual(123, oo.X[0]); + Assert.IsNotNull(oo.C3); + Assert.AreEqual(2, oo.C3.Length); + Assert.IsNotNull(oo.C3[0]); + Assert.AreEqual("qxx", oo.C3[0].S); + } + + [Test] + public void TestReadWriteToId() + { + var o = new C4_Old {S = "zzz", X = 123}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.Zzz); + Assert.AreEqual(123, oo.Qxx); + } + + [Test] + public void TestReadWriteFromId() + { + var o = new C4_New {Zzz = "zzz", Qxx = 123}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.S); + Assert.AreEqual(123, oo.X); + } + + [Test] + public void Test_GroboMember_IdCollision() + { + var o = new C5_GroboMember_IdCollision(); + var e = Assert.Throws(() => serializer.Serialize(o)); + Assert.That(e.Message, Is.EqualTo("Hash code collision: members 'C5_GroboMember_IdCollision.X' and 'C5_GroboMember_IdCollision.S' have the same hash code = 1")); + } + + [Test] + public void Test_GroboMember_EmptyName() + { + var o = new C6_GroboMember_EmptyName(); + var e = Assert.Throws(() => serializer.Serialize(o)); + Assert.That(e.Message, Is.EqualTo("Empty grobo name of member 'C6_GroboMember_EmptyName.S'")); + } + + [Test] + public void Test_GroboMember_EmptyId() + { + var o = new C7_GroboMember_EmptyId(); + var e = Assert.Throws(() => serializer.Serialize(o)); + Assert.That(e.Message, Is.EqualTo("Hash code of 'C7_GroboMember_EmptyId.S' equals to zero")); + } + + [Test] + public void Test_MixedAnnotationAttributes() + { + var o = new C8_MixedAnnotationAttributes {S = "zzz", X = 123, Q = -1}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.S); + Assert.AreEqual(123, oo.X); + Assert.AreEqual(-1, oo.Q); + } + + [Test] + public void Test_GroboMember_ReadonlyProperty() + { + var o = new C9_GroboMember_ReadonlyProperty_Old("GRobas"); + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("GRobas", oo.Zzz); + } + + public class C1_Old + { + public string S { get; set; } + public int X { get; set; } + } + + public class C1_New + { + public int X { get; set; } + public double? D { get; set; } + public string S { get; set; } + } + + public class C2_Old + { + public int X { get; set; } + public double? D { get; set; } + public string S { get; set; } + } + + public class C2_New + { + public string S { get; set; } + public double? D { get; set; } + } + + public class C3_Subclass + { + public string S { get; set; } + } + + public class C3_Old + { + public string S { get; set; } + public int X { get; set; } + public C3_Subclass C3 { get; set; } + } + + public class C3_New + { + public string[] S { get; set; } + public int[] X { get; set; } + public C3_Subclass[] C3 { get; set; } + } + + public class C4_Old + { + public string S { get; set; } + public int X { get; set; } + } + + public class C4_New + { + [GroboMember(7770670552212394539)] + public string Zzz { get; set; } + + [GroboMember("X")] + public int Qxx { get; set; } + } + + public class C5_GroboMember_IdCollision + { + [GroboMember(1)] + public string S { get; set; } + + [GroboMember(1)] + public int X { get; set; } + } + + public class C6_GroboMember_EmptyName + { + [GroboMember("")] + public string S { get; set; } + } + + public class C7_GroboMember_EmptyId + { + [GroboMember(0)] + public string S { get; set; } + } + + public class C8_MixedAnnotationAttributes + { + public string S { get; set; } + + [DataMember(Name = "Z")] + public int X { get; set; } + + [GroboMember(1)] + public int? Q { get; set; } + } + + public class C9_GroboMember_ReadonlyProperty_Old + { + public C9_GroboMember_ReadonlyProperty_Old(string qxx) + { + Qxx = qxx; + } + + public string Qxx { get; } + } + + public class C9_GroboMember_ReadonlyProperty_New + { + public C9_GroboMember_ReadonlyProperty_New(string gRobas) + { + Zzz = gRobas; + } + + [GroboMember("Qxx")] + public string Zzz { get; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf.Tests/GroBuf.Tests.csproj b/GroBuf.Tests/GroBuf.Tests.csproj new file mode 100644 index 0000000..2451441 --- /dev/null +++ b/GroBuf.Tests/GroBuf.Tests.csproj @@ -0,0 +1,15 @@ + + + false + netcoreapp2.0;net45 + + + + + + + + + + + diff --git a/GroBuf/Tests/ImmutableObjectChangedBugTest.cs b/GroBuf.Tests/ImmutableObjectChangedBugTest.cs similarity index 97% rename from GroBuf/Tests/ImmutableObjectChangedBugTest.cs rename to GroBuf.Tests/ImmutableObjectChangedBugTest.cs index 4b209f6..df91d8c 100644 --- a/GroBuf/Tests/ImmutableObjectChangedBugTest.cs +++ b/GroBuf.Tests/ImmutableObjectChangedBugTest.cs @@ -1,82 +1,82 @@ -using System; -using System.Runtime.Serialization; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class ImmutableObjectChangedBugTest - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void Test() - { - Console.WriteLine(DebugViewBuilder.DebugView(serializer.Serialize(new[] - { - new RSV1DisabledPerson {Validation = new ValidationResult("zaa", ValidationResultType.Error)}, - new RSV1DisabledPerson {Validation = ValidationResult.Ok}, - new RSV1DisabledPerson {Validation = new ValidationResult("qs", ValidationResultType.Warning)}, - }))); - } - - [Test] - public void TestValidationResultBug() - { - var expected = new[] - { - new RSV1DisabledPerson {Validation = new ValidationResult("zaa", ValidationResultType.Error)}, - new RSV1DisabledPerson {Validation = ValidationResult.Ok}, - new RSV1DisabledPerson {Validation = new ValidationResult("qs", ValidationResultType.Warning)}, - }; - Assert.AreEqual(ValidationResultType.Ok, ValidationResult.Ok.Type); - Assert.AreEqual(null, ValidationResult.Ok.Message); - var actual = serializer.Deserialize(serializer.Serialize(expected)); - Assert.AreEqual(ValidationResultType.Error, actual[0].Validation.Type); - Assert.AreEqual("zaa", actual[0].Validation.Message); - Assert.AreEqual(ValidationResultType.Ok, actual[1].Validation.Type); - Assert.AreEqual(null, actual[1].Validation.Message); - Assert.AreEqual(ValidationResultType.Warning, actual[2].Validation.Type); - Assert.AreEqual("qs", actual[2].Validation.Message); - } - - private Serializer serializer; - - private class ValidationResult - { - public ValidationResult(string message, ValidationResultType type) - { - Message = message; - Type = type; - } - - public string Message { get; private set; } - - public ValidationResultType Type { get; private set; } - public static readonly ValidationResult Ok = new ValidationResult(null, ValidationResultType.Ok); - } - - private class RSV1DisabledPerson - { - [DataMember] - public ValidationResult Validation { get { return validation ?? ValidationResult.Ok; } set { validation = value; } } - - private ValidationResult validation; - } - - private enum ValidationResultType - { - Ok = 0, - Warning = 1, - Error = 2, - Fatal = 3 - } - } +using System; +using System.Runtime.Serialization; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class ImmutableObjectChangedBugTest + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void Test() + { + Console.WriteLine(DebugViewBuilder.DebugView(serializer.Serialize(new[] + { + new RSV1DisabledPerson {Validation = new ValidationResult("zaa", ValidationResultType.Error)}, + new RSV1DisabledPerson {Validation = ValidationResult.Ok}, + new RSV1DisabledPerson {Validation = new ValidationResult("qs", ValidationResultType.Warning)}, + }))); + } + + [Test] + public void TestValidationResultBug() + { + var expected = new[] + { + new RSV1DisabledPerson {Validation = new ValidationResult("zaa", ValidationResultType.Error)}, + new RSV1DisabledPerson {Validation = ValidationResult.Ok}, + new RSV1DisabledPerson {Validation = new ValidationResult("qs", ValidationResultType.Warning)}, + }; + Assert.AreEqual(ValidationResultType.Ok, ValidationResult.Ok.Type); + Assert.AreEqual(null, ValidationResult.Ok.Message); + var actual = serializer.Deserialize(serializer.Serialize(expected)); + Assert.AreEqual(ValidationResultType.Error, actual[0].Validation.Type); + Assert.AreEqual("zaa", actual[0].Validation.Message); + Assert.AreEqual(ValidationResultType.Ok, actual[1].Validation.Type); + Assert.AreEqual(null, actual[1].Validation.Message); + Assert.AreEqual(ValidationResultType.Warning, actual[2].Validation.Type); + Assert.AreEqual("qs", actual[2].Validation.Message); + } + + private Serializer serializer; + + private class ValidationResult + { + public ValidationResult(string message, ValidationResultType type) + { + Message = message; + Type = type; + } + + public string Message { get; private set; } + + public ValidationResultType Type { get; private set; } + public static readonly ValidationResult Ok = new ValidationResult(null, ValidationResultType.Ok); + } + + private class RSV1DisabledPerson + { + [DataMember] + public ValidationResult Validation { get { return validation ?? ValidationResult.Ok; } set { validation = value; } } + + private ValidationResult validation; + } + + private enum ValidationResultType + { + Ok = 0, + Warning = 1, + Error = 2, + Fatal = 3 + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/IntegrationTest.cs b/GroBuf.Tests/IntegrationTest.cs similarity index 95% rename from GroBuf/Tests/IntegrationTest.cs rename to GroBuf.Tests/IntegrationTest.cs index ba99793..b549376 100644 --- a/GroBuf/Tests/IntegrationTest.cs +++ b/GroBuf.Tests/IntegrationTest.cs @@ -1,145 +1,147 @@ -using System; -using System.Threading; - -using GroBuf.DataMembersExtracters; -using GroBuf.Tests.TestData.Desadv; -using GroBuf.Tests.TestData.Orders; -using GroBuf.Tests.TestTools; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class IntegrationTest - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test, Ignore] - [Category("LongRunning")] - public void TestChangeObjectDuringSerialization() - { - var random = new Random(54717651); - var data = TestHelpers.GenerateRandomTrash(random, 75, 10, 2); - var thread = new Thread(FillWithRandomTrash); - thread.Start(data); - while(true) - { - try - { - var serializedData = serializer.Serialize(data); - } - catch(Exception e) - { - Console.WriteLine(e); - } - } - } - - public void FillWithRandomTrash(object param) - { - var data = (Orders)param; - var random = new Random(1231241); - while(true) - TestHelpers.FillWithRandomTrash(data, random, 75, 10, 2); - } - - [Test] - [Category("LongRunning")] - public void Test() - { - const int numberOfMessages = 10000; - var random = new Random(54717651); - var datas = new Orders[numberOfMessages]; - datas[0] = TestHelpers.GenerateRandomTrash(random, 75, 10, 2); - for(int i = 1; i < datas.Length; ++i) - datas[i] = TestHelpers.GenerateRandomTrash(random, 75, 10, 2); - - var messages = new byte[numberOfMessages][]; - for(int i = 0; i < datas.Length; ++i) - messages[i] = serializer.Serialize(datas[i]); - - var deserializedMessages = new Orders[numberOfMessages]; - for(int i = 0; i < messages.Length; ++i) - deserializedMessages[i] = serializer.Deserialize(messages[i]) ?? new Orders(); - - for(int i = 0; i < numberOfMessages; ++i) - { - TestHelpers.Extend(deserializedMessages[i]); - TestHelpers.Extend(datas[i]); - deserializedMessages[i].AssertEqualsTo(datas[i]); - } - } - - [Test] - [Category("LongRunning")] - public void TestWithGarbageCollection() - { - const int numberOfMessages = 100000; - var random = new Random(54717651); - var datas = new Orders[numberOfMessages]; - datas[0] = TestHelpers.GenerateRandomTrash(random, 75, 10, 2); - for(int i = 1; i < datas.Length; ++i) - datas[i] = TestHelpers.GenerateRandomTrash(random, 75, 10, 2); - - stop = false; - var thread = new Thread(Collect); - thread.Start(); - - var messages = new byte[numberOfMessages][]; - for(int i = 0; i < datas.Length; ++i) - messages[i] = serializer.Serialize(datas[i]); - - var deserializedMessages = new Orders[numberOfMessages]; - for(int i = 0; i < messages.Length; ++i) - deserializedMessages[i] = serializer.Deserialize(messages[i]); - - stop = true; - } - - [Test, Ignore] - [Category("LongRunning")] - public void TestWithGarbageCollection2() - { - const int numberOfMessages = 1000000; - - stop = false; - var thread = new Thread(Collect); - thread.Start(); - - for (int i = 0; i < 10; ++i ) - new Thread(Zzz).Start(serializer); - Zzz(serializer); - - stop = true; - } - - private void Zzz(object param) - { - var serializer = (Serializer)param; - var random = new Random(Guid.NewGuid().GetHashCode()); - for (int i = 0; i < 1000000; ++i) - { - var data = TestHelpers.GenerateRandomTrash(random, 75, 10, 2); - var message = serializer.Serialize(data); - var deserializedData = serializer.Deserialize(message); - } - } - - private void Collect() - { - while(!stop) - { - Thread.Sleep(100); - GC.Collect(); - } - } - - private Serializer serializer; - private volatile bool stop; - } +using System; +using System.Threading; + +using GroBuf.DataMembersExtracters; +using GroBuf.Tests.TestData.Desadv; +using GroBuf.Tests.TestData.Orders; +using GroBuf.Tests.TestTools; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class IntegrationTest + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + [Category("LongRunning")] + [Ignore("Is used for debugging")] + public void TestChangeObjectDuringSerialization() + { + var random = new Random(54717651); + var data = TestHelpers.GenerateRandomTrash(random, 75, 10, 2); + var thread = new Thread(FillWithRandomTrash); + thread.Start(data); + while(true) + { + try + { + var serializedData = serializer.Serialize(data); + } + catch(Exception e) + { + Console.WriteLine(e); + } + } + } + + public void FillWithRandomTrash(object param) + { + var data = (Orders)param; + var random = new Random(1231241); + while(true) + TestHelpers.FillWithRandomTrash(data, random, 75, 10, 2); + } + + [Test] + [Category("LongRunning")] + public void Test() + { + const int numberOfMessages = 10000; + var random = new Random(54717651); + var datas = new Orders[numberOfMessages]; + datas[0] = TestHelpers.GenerateRandomTrash(random, 75, 10, 2); + for(int i = 1; i < datas.Length; ++i) + datas[i] = TestHelpers.GenerateRandomTrash(random, 75, 10, 2); + + var messages = new byte[numberOfMessages][]; + for(int i = 0; i < datas.Length; ++i) + messages[i] = serializer.Serialize(datas[i]); + + var deserializedMessages = new Orders[numberOfMessages]; + for(int i = 0; i < messages.Length; ++i) + deserializedMessages[i] = serializer.Deserialize(messages[i]) ?? new Orders(); + + for(int i = 0; i < numberOfMessages; ++i) + { + TestHelpers.Extend(deserializedMessages[i]); + TestHelpers.Extend(datas[i]); + deserializedMessages[i].AssertEqualsTo(datas[i]); + } + } + + [Test] + [Category("LongRunning")] + public void TestWithGarbageCollection() + { + const int numberOfMessages = 100000; + var random = new Random(54717651); + var datas = new Orders[numberOfMessages]; + datas[0] = TestHelpers.GenerateRandomTrash(random, 75, 10, 2); + for(int i = 1; i < datas.Length; ++i) + datas[i] = TestHelpers.GenerateRandomTrash(random, 75, 10, 2); + + stop = false; + var thread = new Thread(Collect); + thread.Start(); + + var messages = new byte[numberOfMessages][]; + for(int i = 0; i < datas.Length; ++i) + messages[i] = serializer.Serialize(datas[i]); + + var deserializedMessages = new Orders[numberOfMessages]; + for(int i = 0; i < messages.Length; ++i) + deserializedMessages[i] = serializer.Deserialize(messages[i]); + + stop = true; + } + + [Test] + [Category("LongRunning")] + [Ignore("Is used for debugging")] + public void TestWithGarbageCollection2() + { + const int numberOfMessages = 1000000; + + stop = false; + var thread = new Thread(Collect); + thread.Start(); + + for (int i = 0; i < 10; ++i ) + new Thread(Zzz).Start(serializer); + Zzz(serializer); + + stop = true; + } + + private void Zzz(object param) + { + var serializer = (Serializer)param; + var random = new Random(Guid.NewGuid().GetHashCode()); + for (int i = 0; i < 1000000; ++i) + { + var data = TestHelpers.GenerateRandomTrash(random, 75, 10, 2); + var message = serializer.Serialize(data); + var deserializedData = serializer.Deserialize(message); + } + } + + private void Collect() + { + while(!stop) + { + Thread.Sleep(100); + GC.Collect(); + } + } + + private Serializer serializer; + private volatile bool stop; + } } \ No newline at end of file diff --git a/GroBuf/Tests/ObjectConstructionHelperTest.cs b/GroBuf.Tests/ObjectConstructionHelperTest.cs similarity index 96% rename from GroBuf/Tests/ObjectConstructionHelperTest.cs rename to GroBuf.Tests/ObjectConstructionHelperTest.cs index eae16a1..b006d45 100644 --- a/GroBuf/Tests/ObjectConstructionHelperTest.cs +++ b/GroBuf.Tests/ObjectConstructionHelperTest.cs @@ -1,43 +1,43 @@ -using System; - -using GroBuf.Readers; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class ObjectConstructionHelperTest - { - [Test] - public void TestEnptyConstructor() - { - Func constructType = ObjectConstructionHelper.ConstructType(typeof(QueryWithEntities)); - Assert.IsNotNull(constructType()); - Assert.IsNotNull(constructType()); - } - - [Test] - public void TestNoEmptyConstructor() - { - Func constructType = ObjectConstructionHelper.ConstructType(typeof(QueryNotEmptyCtror)); - object anObject = constructType(); - Assert.IsNotNull(anObject); - Assert.AreEqual(0, ((QueryNotEmptyCtror)anObject).A); - } - - private class QueryWithEntities - { - } - - private class QueryNotEmptyCtror - { - public QueryNotEmptyCtror(int a) - { - A = a; - } - - public readonly int A; - } - } +using System; + +using GroBuf.Readers; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class ObjectConstructionHelperTest + { + [Test] + public void TestEnptyConstructor() + { + Func constructType = ObjectConstructionHelper.ConstructType(typeof(QueryWithEntities)); + Assert.IsNotNull(constructType()); + Assert.IsNotNull(constructType()); + } + + [Test] + public void TestNoEmptyConstructor() + { + Func constructType = ObjectConstructionHelper.ConstructType(typeof(QueryNotEmptyCtror)); + object anObject = constructType(); + Assert.IsNotNull(anObject); + Assert.AreEqual(0, ((QueryNotEmptyCtror)anObject).A); + } + + private class QueryWithEntities + { + } + + private class QueryNotEmptyCtror + { + public QueryNotEmptyCtror(int a) + { + A = a; + } + + public readonly int A; + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/SerializeInterfaceTest.cs b/GroBuf.Tests/SerializeInterfaceTest.cs similarity index 96% rename from GroBuf/Tests/SerializeInterfaceTest.cs rename to GroBuf.Tests/SerializeInterfaceTest.cs index d132ef2..4857704 100644 --- a/GroBuf/Tests/SerializeInterfaceTest.cs +++ b/GroBuf.Tests/SerializeInterfaceTest.cs @@ -1,49 +1,49 @@ -using System; -using System.Linq; -using System.Reflection; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class SerializeInterfaceTest - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new AllPropertiesExtractor()); - } - - [Test] - public void TestInterfaceArray() - { - byte[] serialize = serializer.Serialize(new I1[] {new C1 {Data = 2}}); - var deserialize = serializer.Deserialize(serialize); - Assert.AreEqual(1, deserialize.Length); - Assert.AreEqual(2, deserialize[0].Data); - } - - public class AllPropertiesExtractor : IDataMembersExtractor - { - public IDataMember[] GetMembers(Type type) - { - return type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(DataMember.Create).ToArray(); - } - } - - private Serializer serializer; - - private class C1 : I1 - { - public int Data { get; set; } - } - - private interface I1 - { - int Data { get; } - } - } +using System; +using System.Linq; +using System.Reflection; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class SerializeInterfaceTest + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new AllPropertiesExtractor()); + } + + [Test] + public void TestInterfaceArray() + { + byte[] serialize = serializer.Serialize(new I1[] {new C1 {Data = 2}}); + var deserialize = serializer.Deserialize(serialize); + Assert.AreEqual(1, deserialize.Length); + Assert.AreEqual(2, deserialize[0].Data); + } + + public class AllPropertiesExtractor : IDataMembersExtractor + { + public IDataMember[] GetMembers(Type type) + { + return type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(DataMember.Create).ToArray(); + } + } + + private Serializer serializer; + + private class C1 : I1 + { + public int Data { get; set; } + } + + private interface I1 + { + int Data { get; } + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestArraySegment.cs b/GroBuf.Tests/TestArraySegment.cs similarity index 100% rename from GroBuf/Tests/TestArraySegment.cs rename to GroBuf.Tests/TestArraySegment.cs diff --git a/GroBuf/Tests/TestChangeType.cs b/GroBuf.Tests/TestChangeType.cs similarity index 97% rename from GroBuf/Tests/TestChangeType.cs rename to GroBuf.Tests/TestChangeType.cs index e58e326..927815a 100644 --- a/GroBuf/Tests/TestChangeType.cs +++ b/GroBuf.Tests/TestChangeType.cs @@ -1,129 +1,129 @@ -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestChangeType - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void TestCopyGeneric() - { - var obj = new TestClassA {S = "qxx", B = new TestClassB {S = "zzz"}}; - var copiedObj = serializer.Copy(obj); - Assert.IsNotNull(copiedObj); - Assert.AreNotSame(obj, copiedObj); - Assert.AreEqual("qxx", copiedObj.S); - Assert.IsNotNull(copiedObj.B); - Assert.AreEqual("zzz", copiedObj.B.S); - } - - [Test] - public void TestCopyGenericWriteEmptyObject() - { - var obj = new TestClassA {S = "qxx", B = new TestClassB()}; - var copiedObj = serializer.Copy(obj); - Assert.IsNotNull(copiedObj); - Assert.AreNotSame(obj, copiedObj); - Assert.AreEqual("qxx", copiedObj.S); - Assert.IsNotNull(copiedObj.B); - Assert.IsNull(copiedObj.B.S); - } - - [Test] - public void TestCopyNonGeneric() - { - var obj = new TestClassA {S = "qxx", B = new TestClassB {S = "zzz"}}; - var copiedObj = (TestClassA)serializer.Copy(typeof(TestClassA), obj); - Assert.IsNotNull(copiedObj); - Assert.AreNotSame(obj, copiedObj); - Assert.AreEqual("qxx", copiedObj.S); - Assert.IsNotNull(copiedObj.B); - Assert.AreEqual("zzz", copiedObj.B.S); - } - - [Test] - public void TestCopyNonGenericWriteEmptyObject() - { - var obj = new TestClassA {S = "qxx", B = new TestClassB()}; - var copiedObj = (TestClassA)serializer.Copy(typeof(TestClassA), obj); - Assert.IsNotNull(copiedObj); - Assert.AreNotSame(obj, copiedObj); - Assert.AreEqual("qxx", copiedObj.S); - Assert.IsNotNull(copiedObj.B); - Assert.IsNull(copiedObj.B.S); - } - - [Test] - public void TestChangeTypeGeneric() - { - var obj = new TestClassA {S = "qxx", B = new TestClassB {S = "zzz"}}; - var copiedObj = serializer.ChangeType(obj); - Assert.IsNotNull(copiedObj); - Assert.AreNotSame(obj, copiedObj); - Assert.AreEqual("qxx", copiedObj.S); - Assert.IsNotNull(copiedObj.B); - Assert.AreEqual("zzz", copiedObj.B.S); - } - - [Test] - public void TestChangeTypeGenericWriteEmptyObject() - { - var obj = new TestClassA {S = "qxx", B = new TestClassB()}; - var copiedObj = serializer.ChangeType(obj); - Assert.IsNotNull(copiedObj); - Assert.AreNotSame(obj, copiedObj); - Assert.AreEqual("qxx", copiedObj.S); - Assert.IsNotNull(copiedObj.B); - Assert.IsNull(copiedObj.B.S); - } - - [Test] - public void TestChangeTypeNonGeneric() - { - var obj = new TestClassA {S = "qxx", B = new TestClassB {S = "zzz"}}; - var copiedObj = (TestClassADerived)serializer.ChangeType(typeof(TestClassA), typeof(TestClassADerived), obj); - Assert.IsNotNull(copiedObj); - Assert.AreNotSame(obj, copiedObj); - Assert.AreEqual("qxx", copiedObj.S); - Assert.IsNotNull(copiedObj.B); - Assert.AreEqual("zzz", copiedObj.B.S); - } - - [Test] - public void TestChangeTypeNonGenericWriteEmptyObject() - { - var obj = new TestClassA {S = "qxx", B = new TestClassB()}; - var copiedObj = (TestClassADerived)serializer.ChangeType(typeof(TestClassA), typeof(TestClassADerived), obj); - Assert.IsNotNull(copiedObj); - Assert.AreNotSame(obj, copiedObj); - Assert.AreEqual("qxx", copiedObj.S); - Assert.IsNotNull(copiedObj.B); - Assert.IsNull(copiedObj.B.S); - } - - public class TestClassA - { - public string S { get; set; } - public TestClassB B { get; set; } - } - - public class TestClassB - { - public string S { get; set; } - } - - public class TestClassADerived : TestClassA - { - } - - private Serializer serializer; - } +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestChangeType + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestCopyGeneric() + { + var obj = new TestClassA {S = "qxx", B = new TestClassB {S = "zzz"}}; + var copiedObj = serializer.Copy(obj); + Assert.IsNotNull(copiedObj); + Assert.AreNotSame(obj, copiedObj); + Assert.AreEqual("qxx", copiedObj.S); + Assert.IsNotNull(copiedObj.B); + Assert.AreEqual("zzz", copiedObj.B.S); + } + + [Test] + public void TestCopyGenericWriteEmptyObject() + { + var obj = new TestClassA {S = "qxx", B = new TestClassB()}; + var copiedObj = serializer.Copy(obj); + Assert.IsNotNull(copiedObj); + Assert.AreNotSame(obj, copiedObj); + Assert.AreEqual("qxx", copiedObj.S); + Assert.IsNotNull(copiedObj.B); + Assert.IsNull(copiedObj.B.S); + } + + [Test] + public void TestCopyNonGeneric() + { + var obj = new TestClassA {S = "qxx", B = new TestClassB {S = "zzz"}}; + var copiedObj = (TestClassA)serializer.Copy(typeof(TestClassA), obj); + Assert.IsNotNull(copiedObj); + Assert.AreNotSame(obj, copiedObj); + Assert.AreEqual("qxx", copiedObj.S); + Assert.IsNotNull(copiedObj.B); + Assert.AreEqual("zzz", copiedObj.B.S); + } + + [Test] + public void TestCopyNonGenericWriteEmptyObject() + { + var obj = new TestClassA {S = "qxx", B = new TestClassB()}; + var copiedObj = (TestClassA)serializer.Copy(typeof(TestClassA), obj); + Assert.IsNotNull(copiedObj); + Assert.AreNotSame(obj, copiedObj); + Assert.AreEqual("qxx", copiedObj.S); + Assert.IsNotNull(copiedObj.B); + Assert.IsNull(copiedObj.B.S); + } + + [Test] + public void TestChangeTypeGeneric() + { + var obj = new TestClassA {S = "qxx", B = new TestClassB {S = "zzz"}}; + var copiedObj = serializer.ChangeType(obj); + Assert.IsNotNull(copiedObj); + Assert.AreNotSame(obj, copiedObj); + Assert.AreEqual("qxx", copiedObj.S); + Assert.IsNotNull(copiedObj.B); + Assert.AreEqual("zzz", copiedObj.B.S); + } + + [Test] + public void TestChangeTypeGenericWriteEmptyObject() + { + var obj = new TestClassA {S = "qxx", B = new TestClassB()}; + var copiedObj = serializer.ChangeType(obj); + Assert.IsNotNull(copiedObj); + Assert.AreNotSame(obj, copiedObj); + Assert.AreEqual("qxx", copiedObj.S); + Assert.IsNotNull(copiedObj.B); + Assert.IsNull(copiedObj.B.S); + } + + [Test] + public void TestChangeTypeNonGeneric() + { + var obj = new TestClassA {S = "qxx", B = new TestClassB {S = "zzz"}}; + var copiedObj = (TestClassADerived)serializer.ChangeType(typeof(TestClassA), typeof(TestClassADerived), obj); + Assert.IsNotNull(copiedObj); + Assert.AreNotSame(obj, copiedObj); + Assert.AreEqual("qxx", copiedObj.S); + Assert.IsNotNull(copiedObj.B); + Assert.AreEqual("zzz", copiedObj.B.S); + } + + [Test] + public void TestChangeTypeNonGenericWriteEmptyObject() + { + var obj = new TestClassA {S = "qxx", B = new TestClassB()}; + var copiedObj = (TestClassADerived)serializer.ChangeType(typeof(TestClassA), typeof(TestClassADerived), obj); + Assert.IsNotNull(copiedObj); + Assert.AreNotSame(obj, copiedObj); + Assert.AreEqual("qxx", copiedObj.S); + Assert.IsNotNull(copiedObj.B); + Assert.IsNull(copiedObj.B.S); + } + + public class TestClassA + { + public string S { get; set; } + public TestClassB B { get; set; } + } + + public class TestClassB + { + public string S { get; set; } + } + + public class TestClassADerived : TestClassA + { + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestCubstomSerializerAndBaseBug.cs b/GroBuf.Tests/TestCubstomSerializerAndBaseBug.cs similarity index 97% rename from GroBuf/Tests/TestCubstomSerializerAndBaseBug.cs rename to GroBuf.Tests/TestCubstomSerializerAndBaseBug.cs index 7c77ead..ecf5984 100644 --- a/GroBuf/Tests/TestCubstomSerializerAndBaseBug.cs +++ b/GroBuf.Tests/TestCubstomSerializerAndBaseBug.cs @@ -1,138 +1,138 @@ -using System; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestCubstomSerializerAndBaseBug - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor(), new GroBufCustomSerializerCollection()); - } - - [Test] - public void TestBug() - { - I1 i1 = new I1Impl {Person = new Person {Date = new Date2 {Xxx = 1}}}; - i1.Person.Date.Do(); - var deserialize = serializer.Deserialize(serializer.Serialize(i1)); - Assert.AreEqual(i1.Person.Date.Xxx, deserialize.Person.Date.Xxx); - Assert.AreEqual(i1.Person.Date.qxx, deserialize.Person.Date.qxx); - } - - [Test] - public void TestNoBug() - { - var i1 = new I1Impl {Person = new Person {Date = new Date2 {Xxx = 1}}}; - i1.Person.Date.Do(); - var deserialize = serializer.Deserialize(serializer.Serialize(i1)); - Assert.AreEqual(i1.Person.Date.Xxx, deserialize.Person.Date.Xxx); - Assert.AreEqual(i1.Person.Date.qxx, deserialize.Person.Date.qxx); - } - - private Serializer serializer; - - private class DateGroBufCustomSerializer : IGroBufCustomSerializer - { - public DateGroBufCustomSerializer(IGroBufCustomSerializer baseSerializer) - { - this.baseSerializer = baseSerializer; - } - - #region IGroBufCustomSerializer Members - - public int CountSize(object obj, bool writeEmpty, WriterContext context) - { - return baseSerializer.CountSize(obj, writeEmpty, context); - } - - public void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) - { - baseSerializer.Write(obj, writeEmpty, result, ref index, context); - } - - public void Read(IntPtr data, ref int index, ref object result, ReaderContext context) - { - var date = new Date2(); - result = date; - baseSerializer.Read(data, ref index, ref result, context); - date.Do(); //hack - } - - #endregion - - private readonly IGroBufCustomSerializer baseSerializer; - } - - private class I1Impl : I1 - { - public Person Person { get; set; } - } - - private class Person - { - public Date2 Date { get; set; } - } - - private class Date2 - { - public void Do() - { - qxx = 1; - } - - public int qxx; - public int Xxx { get; set; } - } - - private class GroBufCustomSerializerCollection : IGroBufCustomSerializerCollection - { - public IGroBufCustomSerializer Get(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer) - { - if(declaredType == typeof(I1)) - return new GroBufCustomSerializerI1(factory, baseSerializer); - if(declaredType == typeof(Date2)) - return new DateGroBufCustomSerializer(baseSerializer); - return null; - } - } - - private class GroBufCustomSerializerI1 : IGroBufCustomSerializer - { - public GroBufCustomSerializerI1(Func factory, IGroBufCustomSerializer baseSerializer) - { - this.factory = factory; - this.baseSerializer = baseSerializer; - } - - public int CountSize(object obj, bool writeEmpty, WriterContext context) - { - return baseSerializer.CountSize(obj, writeEmpty, context); - } - - public void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) - { - baseSerializer.Write(obj, writeEmpty, result, ref index, context); - } - - public void Read(IntPtr data, ref int index, ref object result, ReaderContext context) - { - result = Activator.CreateInstance(typeof(I1Impl)); - factory(typeof(I1Impl)).Read(data, ref index, ref result, context); - } - - private readonly Func factory; - private readonly IGroBufCustomSerializer baseSerializer; - } - - private interface I1 - { - Person Person { get; set; } - } - } +using System; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestCubstomSerializerAndBaseBug + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor(), new GroBufCustomSerializerCollection()); + } + + [Test] + public void TestBug() + { + I1 i1 = new I1Impl {Person = new Person {Date = new Date2 {Xxx = 1}}}; + i1.Person.Date.Do(); + var deserialize = serializer.Deserialize(serializer.Serialize(i1)); + Assert.AreEqual(i1.Person.Date.Xxx, deserialize.Person.Date.Xxx); + Assert.AreEqual(i1.Person.Date.qxx, deserialize.Person.Date.qxx); + } + + [Test] + public void TestNoBug() + { + var i1 = new I1Impl {Person = new Person {Date = new Date2 {Xxx = 1}}}; + i1.Person.Date.Do(); + var deserialize = serializer.Deserialize(serializer.Serialize(i1)); + Assert.AreEqual(i1.Person.Date.Xxx, deserialize.Person.Date.Xxx); + Assert.AreEqual(i1.Person.Date.qxx, deserialize.Person.Date.qxx); + } + + private Serializer serializer; + + private class DateGroBufCustomSerializer : IGroBufCustomSerializer + { + public DateGroBufCustomSerializer(IGroBufCustomSerializer baseSerializer) + { + this.baseSerializer = baseSerializer; + } + + #region IGroBufCustomSerializer Members + + public int CountSize(object obj, bool writeEmpty, WriterContext context) + { + return baseSerializer.CountSize(obj, writeEmpty, context); + } + + public void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) + { + baseSerializer.Write(obj, writeEmpty, result, ref index, context); + } + + public void Read(IntPtr data, ref int index, ref object result, ReaderContext context) + { + var date = new Date2(); + result = date; + baseSerializer.Read(data, ref index, ref result, context); + date.Do(); //hack + } + + #endregion + + private readonly IGroBufCustomSerializer baseSerializer; + } + + private class I1Impl : I1 + { + public Person Person { get; set; } + } + + private class Person + { + public Date2 Date { get; set; } + } + + private class Date2 + { + public void Do() + { + qxx = 1; + } + + public int qxx; + public int Xxx { get; set; } + } + + private class GroBufCustomSerializerCollection : IGroBufCustomSerializerCollection + { + public IGroBufCustomSerializer Get(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer) + { + if(declaredType == typeof(I1)) + return new GroBufCustomSerializerI1(factory, baseSerializer); + if(declaredType == typeof(Date2)) + return new DateGroBufCustomSerializer(baseSerializer); + return null; + } + } + + private class GroBufCustomSerializerI1 : IGroBufCustomSerializer + { + public GroBufCustomSerializerI1(Func factory, IGroBufCustomSerializer baseSerializer) + { + this.factory = factory; + this.baseSerializer = baseSerializer; + } + + public int CountSize(object obj, bool writeEmpty, WriterContext context) + { + return baseSerializer.CountSize(obj, writeEmpty, context); + } + + public void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) + { + baseSerializer.Write(obj, writeEmpty, result, ref index, context); + } + + public void Read(IntPtr data, ref int index, ref object result, ReaderContext context) + { + result = Activator.CreateInstance(typeof(I1Impl)); + factory(typeof(I1Impl)).Read(data, ref index, ref result, context); + } + + private readonly Func factory; + private readonly IGroBufCustomSerializer baseSerializer; + } + + private interface I1 + { + Person Person { get; set; } + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestCustomReadWrite.cs b/GroBuf.Tests/TestCustomReadWrite.cs similarity index 97% rename from GroBuf/Tests/TestCustomReadWrite.cs rename to GroBuf.Tests/TestCustomReadWrite.cs index 45b0661..a4a41ef 100644 --- a/GroBuf/Tests/TestCustomReadWrite.cs +++ b/GroBuf.Tests/TestCustomReadWrite.cs @@ -1,207 +1,207 @@ -using System; -using System.Runtime.InteropServices; - -using GroBuf.DataMembersExtracters; -using GroBuf.Tests.TestTools; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestCustomReadWrite - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void TestSizeCounter() - { - var a = new A {B = new C {Z = "zzz"}}; - var size = serializer.GetSize(a); - Assert.AreEqual((1 + 4 + 8) + (1 + 4 + 2) + (1 + 4 + 8 + 1 + 4 + 6) + 5, size); - } - - [Test] - public void TestWriter() - { - var a = new A {B = new C {Z = "zzz"}}; - var data = serializer.Serialize(a); - Assert.AreEqual((1 + 4 + 8) + (1 + 4 + 2) + (1 + 4 + 8 + 1 + 4 + 6) + 5, data.Length); - } - - [Test] - public void TestReaderC() - { - var a = new A {B = new C {Z = "zzz"}, ArrB = new BB[] {new C {Z = "qxx"}, new D {Z = 123}}}; - var data = serializer.Serialize(a); - var za = serializer.Deserialize(data); - za.AssertEqualsTo(a); - } - - [Test] - public void TestReaderD() - { - var a = new A {B = new D {Z = 146}, ArrB = new BB[] {new C {Z = "qxx"}, new D {Z = 123}}}; - var data = serializer.Serialize(a); - var za = serializer.Deserialize(data); - za.AssertEqualsTo(a); - } - - [Test] - public void TestStruct() - { - var date = new Date {Year = 2012, Month = 12, Day = 21}; - var data = serializer.Serialize(date); - var zdate = serializer.Deserialize(data); - zdate.AssertEqualsTo(date); - } - - [Test] - public void TestBase() - { - var z = new Z {X = 5, S = "zzz"}; - var data = serializer.Serialize(z); - var zz = serializer.Deserialize(data); - Assert.AreEqual(5, zz.X); - Assert.AreEqual("5", zz.S); - } - - [GroBufCustomSerialization] - public class Z - { - [GroBufSizeCounter] - public static SizeCounterDelegate GetSizeCounter(Func sizeCountersFactory, SizeCounterDelegate baseSizeCounter) - { - return baseSizeCounter; - } - - [GroBufWriter] - public static WriterDelegate GetWriter(Func writersFactory, WriterDelegate baseWriter) - { - return baseWriter; - } - - [GroBufReader] - public static ReaderDelegate GetReader(Func readersFactory, ReaderDelegate baseReader) - { - return (IntPtr data, ref int index, ref object result, ReaderContext context) => - { - baseReader(data, ref index, ref result, context); - var z = result as Z; - if(z != null) - z.S = z.X.ToString(); - return; - }; - } - - public int X { get; set; } - public string S; - } - - public class A - { - public BB B { get; set; } - public BB[] ArrB { get; set; } - } - - [GroBufCustomSerialization] - public abstract class B - { - [GroBufSizeCounter] - public static SizeCounterDelegate GetSizeCounter(Func sizeCountersFactory, SizeCounterDelegate baseSizeCounter) - { - return (o, writeEmpty, context) => - { - Type type = o.GetType(); - return sizeCountersFactory(typeof(string))(type.Name, writeEmpty, context) + sizeCountersFactory(type)(o, writeEmpty, context); - }; - } - - [GroBufWriter] - public static WriterDelegate GetWriter(Func writersFactory, WriterDelegate baseWriter) - { - return (object o, bool writeEmpty, IntPtr result, ref int index, WriterContext context) => - { - Type type = o.GetType(); - writersFactory(typeof(string))(type.Name, writeEmpty, result, ref index, context); - writersFactory(type)(o, writeEmpty, result, ref index, context); - }; - } - - [GroBufReader] - public static ReaderDelegate GetReader(Func readersFactory, ReaderDelegate baseReader) - { - return (IntPtr data, ref int index, ref object result, ReaderContext context) => - { - object type = null; - readersFactory(typeof(string))(data, ref index, ref type, context); - if((string)type == typeof(C).Name) - result = new C(); - else if((string)type == typeof(D).Name) - result = new D(); - else throw new InvalidOperationException("Unknown type " + type); - readersFactory(result.GetType())(data, ref index, ref result, context); - }; - } - } - - [GroBufCustomSerialization] - public abstract class BB : B - { - } - - public class C : BB - { - public string Z { get; set; } - } - - public class D : BB - { - public int Z { get; set; } - } - - public struct Date - { - [GroBufSizeCounter] - public static SizeCounterDelegate GetSizeCounter(Func sizeCountersFactory, SizeCounterDelegate baseSizeCounter) - { - return (o, writeEmpty, context) => 8; - } - - [GroBufWriter] - public static WriterDelegate GetWriter(Func writersFactory, WriterDelegate baseWriter) - { - return (object o, bool writeEmpty, IntPtr result, ref int index, WriterContext context) => - { - var date = (Date)o; - var bytes = BitConverter.GetBytes(new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Utc).Ticks); - Marshal.Copy(bytes, 0, result + index, bytes.Length); - index += bytes.Length; - }; - } - - [GroBufReader] - public static ReaderDelegate GetReader(Func readersFactory, ReaderDelegate baseReader) - { - return (IntPtr data, ref int index, ref object result, ReaderContext context) => - { - var bytes = new byte[8]; - Marshal.Copy(data + index, bytes, 0, 8); - var dateTime = new DateTime(BitConverter.ToInt64(bytes, 0), DateTimeKind.Utc); - result = new Date {Year = dateTime.Year, Month = dateTime.Month, Day = dateTime.Day}; - index += 8; - }; - } - - public int Year { get; set; } - public int Month { get; set; } - public int Day { get; set; } - } - - private Serializer serializer; - } +using System; +using System.Runtime.InteropServices; + +using GroBuf.DataMembersExtracters; +using GroBuf.Tests.TestTools; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestCustomReadWrite + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestSizeCounter() + { + var a = new A {B = new C {Z = "zzz"}}; + var size = serializer.GetSize(a); + Assert.AreEqual((1 + 4 + 8) + (1 + 4 + 2) + (1 + 4 + 8 + 1 + 4 + 6) + 5, size); + } + + [Test] + public void TestWriter() + { + var a = new A {B = new C {Z = "zzz"}}; + var data = serializer.Serialize(a); + Assert.AreEqual((1 + 4 + 8) + (1 + 4 + 2) + (1 + 4 + 8 + 1 + 4 + 6) + 5, data.Length); + } + + [Test] + public void TestReaderC() + { + var a = new A {B = new C {Z = "zzz"}, ArrB = new BB[] {new C {Z = "qxx"}, new D {Z = 123}}}; + var data = serializer.Serialize(a); + var za = serializer.Deserialize(data); + za.AssertEqualsTo(a); + } + + [Test] + public void TestReaderD() + { + var a = new A {B = new D {Z = 146}, ArrB = new BB[] {new C {Z = "qxx"}, new D {Z = 123}}}; + var data = serializer.Serialize(a); + var za = serializer.Deserialize(data); + za.AssertEqualsTo(a); + } + + [Test] + public void TestStruct() + { + var date = new Date {Year = 2012, Month = 12, Day = 21}; + var data = serializer.Serialize(date); + var zdate = serializer.Deserialize(data); + zdate.AssertEqualsTo(date); + } + + [Test] + public void TestBase() + { + var z = new Z {X = 5, S = "zzz"}; + var data = serializer.Serialize(z); + var zz = serializer.Deserialize(data); + Assert.AreEqual(5, zz.X); + Assert.AreEqual("5", zz.S); + } + + [GroBufCustomSerialization] + public class Z + { + [GroBufSizeCounter] + public static SizeCounterDelegate GetSizeCounter(Func sizeCountersFactory, SizeCounterDelegate baseSizeCounter) + { + return baseSizeCounter; + } + + [GroBufWriter] + public static WriterDelegate GetWriter(Func writersFactory, WriterDelegate baseWriter) + { + return baseWriter; + } + + [GroBufReader] + public static ReaderDelegate GetReader(Func readersFactory, ReaderDelegate baseReader) + { + return (IntPtr data, ref int index, ref object result, ReaderContext context) => + { + baseReader(data, ref index, ref result, context); + var z = result as Z; + if(z != null) + z.S = z.X.ToString(); + return; + }; + } + + public int X { get; set; } + public string S; + } + + public class A + { + public BB B { get; set; } + public BB[] ArrB { get; set; } + } + + [GroBufCustomSerialization] + public abstract class B + { + [GroBufSizeCounter] + public static SizeCounterDelegate GetSizeCounter(Func sizeCountersFactory, SizeCounterDelegate baseSizeCounter) + { + return (o, writeEmpty, context) => + { + Type type = o.GetType(); + return sizeCountersFactory(typeof(string))(type.Name, writeEmpty, context) + sizeCountersFactory(type)(o, writeEmpty, context); + }; + } + + [GroBufWriter] + public static WriterDelegate GetWriter(Func writersFactory, WriterDelegate baseWriter) + { + return (object o, bool writeEmpty, IntPtr result, ref int index, WriterContext context) => + { + Type type = o.GetType(); + writersFactory(typeof(string))(type.Name, writeEmpty, result, ref index, context); + writersFactory(type)(o, writeEmpty, result, ref index, context); + }; + } + + [GroBufReader] + public static ReaderDelegate GetReader(Func readersFactory, ReaderDelegate baseReader) + { + return (IntPtr data, ref int index, ref object result, ReaderContext context) => + { + object type = null; + readersFactory(typeof(string))(data, ref index, ref type, context); + if((string)type == typeof(C).Name) + result = new C(); + else if((string)type == typeof(D).Name) + result = new D(); + else throw new InvalidOperationException("Unknown type " + type); + readersFactory(result.GetType())(data, ref index, ref result, context); + }; + } + } + + [GroBufCustomSerialization] + public abstract class BB : B + { + } + + public class C : BB + { + public string Z { get; set; } + } + + public class D : BB + { + public int Z { get; set; } + } + + public struct Date + { + [GroBufSizeCounter] + public static SizeCounterDelegate GetSizeCounter(Func sizeCountersFactory, SizeCounterDelegate baseSizeCounter) + { + return (o, writeEmpty, context) => 8; + } + + [GroBufWriter] + public static WriterDelegate GetWriter(Func writersFactory, WriterDelegate baseWriter) + { + return (object o, bool writeEmpty, IntPtr result, ref int index, WriterContext context) => + { + var date = (Date)o; + var bytes = BitConverter.GetBytes(new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Utc).Ticks); + Marshal.Copy(bytes, 0, result + index, bytes.Length); + index += bytes.Length; + }; + } + + [GroBufReader] + public static ReaderDelegate GetReader(Func readersFactory, ReaderDelegate baseReader) + { + return (IntPtr data, ref int index, ref object result, ReaderContext context) => + { + var bytes = new byte[8]; + Marshal.Copy(data + index, bytes, 0, 8); + var dateTime = new DateTime(BitConverter.ToInt64(bytes, 0), DateTimeKind.Utc); + result = new Date {Year = dateTime.Year, Month = dateTime.Month, Day = dateTime.Day}; + index += 8; + }; + } + + public int Year { get; set; } + public int Month { get; set; } + public int Day { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestCustomReadWriteCustomSerializer.cs b/GroBuf.Tests/TestCustomReadWriteCustomSerializer.cs similarity index 97% rename from GroBuf/Tests/TestCustomReadWriteCustomSerializer.cs rename to GroBuf.Tests/TestCustomReadWriteCustomSerializer.cs index 769ebb7..28921e8 100644 --- a/GroBuf/Tests/TestCustomReadWriteCustomSerializer.cs +++ b/GroBuf.Tests/TestCustomReadWriteCustomSerializer.cs @@ -1,111 +1,111 @@ -using System; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestCustomReadWriteCustomSerializer - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor(), new GroBufCustomSerializerCollection()); - } - - [Test] - public void Test() - { - var o = new C1 {Data = 42}; - var data = serializer.Serialize>(o); - var oo = serializer.Deserialize>(data); - Assert.AreEqual(42, oo.Data); - } - - [Test] - public void Test2() - { - var o = new C2 {Arr = new I1[] {new C1 {Data = 42}}}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize>(data); - Assert.IsNotNull(oo.Arr); - Assert.AreEqual(1, oo.Arr.Length); - Assert.AreEqual(42, oo.Arr[0].Data); - } - - [Test] - public void Test3() - { - var o = new C3 {Z = new Lazy>(() => new C1 {Data = 42})}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize>(data); - Assert.IsNotNull(oo.Z); - Assert.AreEqual(42, oo.Z.Value.Data); - } - - private Serializer serializer; - - private class C1 : I1 - { - public T Data { get; set; } - } - - private class C2 - { - public I1[] Arr { get; set; } - } - - public class C3 - { - public Lazy> Z { get; set; } - } - - private class GroBufCustomSerializerCollection : IGroBufCustomSerializerCollection - { - public IGroBufCustomSerializer Get(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer) - { - if(declaredType.IsGenericType && declaredType.GetGenericTypeDefinition() == typeof(I1<>)) - return new GroBufCustomSerializer(declaredType, factory, baseSerializer); - return null; - } - } - - private class GroBufCustomSerializer : IGroBufCustomSerializer - { - public GroBufCustomSerializer(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer) - { - argumentType = declaredType.GetGenericArguments()[0]; - this.factory = factory; - this.baseSerializer = baseSerializer; - } - - public int CountSize(object obj, bool writeEmpty, WriterContext context) - { - return baseSerializer.CountSize(obj, writeEmpty, context); - } - - public void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) - { - baseSerializer.Write(obj, writeEmpty, result, ref index, context); - } - - public void Read(IntPtr data, ref int index, ref object result, ReaderContext context) - { - var resultType = typeof(C1<>).MakeGenericType(argumentType); - result = Activator.CreateInstance(resultType); - factory(resultType).Read(data, ref index, ref result, context); - } - - private readonly Type argumentType; - private readonly Func factory; - private readonly IGroBufCustomSerializer baseSerializer; - } - - public interface I1 - { - T Data { get; set; } - } - } +using System; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestCustomReadWriteCustomSerializer + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor(), new GroBufCustomSerializerCollection()); + } + + [Test] + public void Test() + { + var o = new C1 {Data = 42}; + var data = serializer.Serialize>(o); + var oo = serializer.Deserialize>(data); + Assert.AreEqual(42, oo.Data); + } + + [Test] + public void Test2() + { + var o = new C2 {Arr = new I1[] {new C1 {Data = 42}}}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize>(data); + Assert.IsNotNull(oo.Arr); + Assert.AreEqual(1, oo.Arr.Length); + Assert.AreEqual(42, oo.Arr[0].Data); + } + + [Test] + public void Test3() + { + var o = new C3 {Z = new Lazy>(() => new C1 {Data = 42})}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize>(data); + Assert.IsNotNull(oo.Z); + Assert.AreEqual(42, oo.Z.Value.Data); + } + + private Serializer serializer; + + private class C1 : I1 + { + public T Data { get; set; } + } + + private class C2 + { + public I1[] Arr { get; set; } + } + + public class C3 + { + public Lazy> Z { get; set; } + } + + private class GroBufCustomSerializerCollection : IGroBufCustomSerializerCollection + { + public IGroBufCustomSerializer Get(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer) + { + if(declaredType.IsGenericType && declaredType.GetGenericTypeDefinition() == typeof(I1<>)) + return new GroBufCustomSerializer(declaredType, factory, baseSerializer); + return null; + } + } + + private class GroBufCustomSerializer : IGroBufCustomSerializer + { + public GroBufCustomSerializer(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer) + { + argumentType = declaredType.GetGenericArguments()[0]; + this.factory = factory; + this.baseSerializer = baseSerializer; + } + + public int CountSize(object obj, bool writeEmpty, WriterContext context) + { + return baseSerializer.CountSize(obj, writeEmpty, context); + } + + public void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) + { + baseSerializer.Write(obj, writeEmpty, result, ref index, context); + } + + public void Read(IntPtr data, ref int index, ref object result, ReaderContext context) + { + var resultType = typeof(C1<>).MakeGenericType(argumentType); + result = Activator.CreateInstance(resultType); + factory(resultType).Read(data, ref index, ref result, context); + } + + private readonly Type argumentType; + private readonly Func factory; + private readonly IGroBufCustomSerializer baseSerializer; + } + + public interface I1 + { + T Data { get; set; } + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestCustomReadWriteCustomSerializerWithLazy.cs b/GroBuf.Tests/TestCustomReadWriteCustomSerializerWithLazy.cs similarity index 97% rename from GroBuf/Tests/TestCustomReadWriteCustomSerializerWithLazy.cs rename to GroBuf.Tests/TestCustomReadWriteCustomSerializerWithLazy.cs index 12ba509..e1832b4 100644 --- a/GroBuf/Tests/TestCustomReadWriteCustomSerializerWithLazy.cs +++ b/GroBuf.Tests/TestCustomReadWriteCustomSerializerWithLazy.cs @@ -1,118 +1,118 @@ -using System; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestCustomReadWriteCustomSerializerWithLazy - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor(), new GroBufCustomSerializerCollection()); - } - - [Test] - public void Test_C() - { - var o = new Data { B = new Lazy(() => new C { S = "zzz" }) }; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", ((C)oo.B.Value).S); - } - - [Test] - public void Test_D() - { - var o = new Data { B = new Lazy(() => new D { X = 42 }) }; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(42, ((D)oo.B.Value).X); - } - - [Test] - public void Test_DataIsNotLostWhenSerializingWithNoContract() - { - var o = new Data { B = new Lazy(() => new C { S = "zzz" }) }; - var data = serializer.Serialize(o); - var serializerWithNoContract = new Serializer(new AllPropertiesExtractor()); - var oo = serializerWithNoContract.Deserialize(data); - var ddata = serializerWithNoContract.Serialize(oo); - Assert.IsNull(oo.B.Value); - var ooo = serializer.Deserialize(ddata); - Assert.AreEqual("zzz", ((C)ooo.B.Value).S); - } - - private Serializer serializer; - - private class GroBufCustomSerializerCollection : IGroBufCustomSerializerCollection - { - public IGroBufCustomSerializer Get(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer) - { - if(typeof(B) == (declaredType)) - return new GroBufCustomSerializer(factory, baseSerializer); - return null; - } - } - - private class GroBufCustomSerializer : IGroBufCustomSerializer - { - public GroBufCustomSerializer(Func factory, IGroBufCustomSerializer baseSerializer) - { - this.factory = factory; - this.baseSerializer = baseSerializer; - } - - public int CountSize(object obj, bool writeEmpty, WriterContext context) - { - Type type = obj.GetType(); - return factory(typeof(string)).CountSize(type.Name, writeEmpty, context) + factory(type).CountSize(obj, writeEmpty, context); - } - - public void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) - { - Type type = obj.GetType(); - factory(typeof(string)).Write(type.Name, writeEmpty, result, ref index, context); - factory(type).Write(obj, writeEmpty, result, ref index, context); - } - - public void Read(IntPtr data, ref int index, ref object result, ReaderContext context) - { - object typeName = null; - Type type; - factory(typeof(string)).Read(data, ref index, ref typeName, context); - if((string)typeName == typeof(C).Name) - type = typeof(C); - else if((string)typeName == typeof(D).Name) - type = typeof(D); - else throw new InvalidOperationException("Unknown type " + typeName); - factory(type).Read(data, ref index, ref result, context); - } - - private readonly Func factory; - private readonly IGroBufCustomSerializer baseSerializer; - } - - public abstract class B - { - } - - public class C : B - { - public string S { get; set; } - } - - public class D : B - { - public int X { get; set; } - } - - public class Data - { - public Lazy B { get; set; } - } - } +using System; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestCustomReadWriteCustomSerializerWithLazy + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor(), new GroBufCustomSerializerCollection()); + } + + [Test] + public void Test_C() + { + var o = new Data { B = new Lazy(() => new C { S = "zzz" }) }; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", ((C)oo.B.Value).S); + } + + [Test] + public void Test_D() + { + var o = new Data { B = new Lazy(() => new D { X = 42 }) }; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(42, ((D)oo.B.Value).X); + } + + [Test] + public void Test_DataIsNotLostWhenSerializingWithNoContract() + { + var o = new Data { B = new Lazy(() => new C { S = "zzz" }) }; + var data = serializer.Serialize(o); + var serializerWithNoContract = new Serializer(new AllPropertiesExtractor()); + var oo = serializerWithNoContract.Deserialize(data); + var ddata = serializerWithNoContract.Serialize(oo); + Assert.IsNull(oo.B.Value); + var ooo = serializer.Deserialize(ddata); + Assert.AreEqual("zzz", ((C)ooo.B.Value).S); + } + + private Serializer serializer; + + private class GroBufCustomSerializerCollection : IGroBufCustomSerializerCollection + { + public IGroBufCustomSerializer Get(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer) + { + if(typeof(B) == (declaredType)) + return new GroBufCustomSerializer(factory, baseSerializer); + return null; + } + } + + private class GroBufCustomSerializer : IGroBufCustomSerializer + { + public GroBufCustomSerializer(Func factory, IGroBufCustomSerializer baseSerializer) + { + this.factory = factory; + this.baseSerializer = baseSerializer; + } + + public int CountSize(object obj, bool writeEmpty, WriterContext context) + { + Type type = obj.GetType(); + return factory(typeof(string)).CountSize(type.Name, writeEmpty, context) + factory(type).CountSize(obj, writeEmpty, context); + } + + public void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) + { + Type type = obj.GetType(); + factory(typeof(string)).Write(type.Name, writeEmpty, result, ref index, context); + factory(type).Write(obj, writeEmpty, result, ref index, context); + } + + public void Read(IntPtr data, ref int index, ref object result, ReaderContext context) + { + object typeName = null; + Type type; + factory(typeof(string)).Read(data, ref index, ref typeName, context); + if((string)typeName == typeof(C).Name) + type = typeof(C); + else if((string)typeName == typeof(D).Name) + type = typeof(D); + else throw new InvalidOperationException("Unknown type " + typeName); + factory(type).Read(data, ref index, ref result, context); + } + + private readonly Func factory; + private readonly IGroBufCustomSerializer baseSerializer; + } + + public abstract class B + { + } + + public class C : B + { + public string S { get; set; } + } + + public class D : B + { + public int X { get; set; } + } + + public class Data + { + public Lazy B { get; set; } + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestCustomReadWriteInterface.cs b/GroBuf.Tests/TestCustomReadWriteInterface.cs similarity index 97% rename from GroBuf/Tests/TestCustomReadWriteInterface.cs rename to GroBuf.Tests/TestCustomReadWriteInterface.cs index 1b52649..0c5f910 100644 --- a/GroBuf/Tests/TestCustomReadWriteInterface.cs +++ b/GroBuf.Tests/TestCustomReadWriteInterface.cs @@ -1,126 +1,126 @@ -using System; - -using GroBuf.DataMembersExtracters; -using GroBuf.Tests.TestTools; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestCustomReadWriteInterface - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void TestSizeCounter() - { - var a = new A {Z = new C {Z = "zzz"}}; - var size = serializer.GetSize(a); - Assert.AreEqual((1 + 4 + 8) + (1 + 4 + 2) + (1 + 4 + 8 + 1 + 4 + 6) + 5, size); - } - - [Test] - public void TestWriter() - { - var a = new A {Z = new C {Z = "zzz"}}; - var data = serializer.Serialize(a); - Assert.AreEqual((1 + 4 + 8) + (1 + 4 + 2) + (1 + 4 + 8 + 1 + 4 + 6) + 5, data.Length); - } - - [Test] - public void TestReaderC() - { - var a = new A {Z = new C {Z = "zzz"}, ArrZ = new IZ[] {new C {Z = "qxx"}, new D {Z = "123"}}}; - var data = serializer.Serialize(a); - var za = serializer.Deserialize(data); - za.AssertEqualsTo(a); - } - - [Test] - public void TestReaderD() - { - var a = new A {Z = new D {Z = "146"}, ArrZ = new IZ[] {new C {Z = "qxx"}, new D {Z = "123"}}}; - var data = serializer.Serialize(a); - var za = serializer.Deserialize(data); - za.AssertEqualsTo(a); - } - - [Test] - public void TestReaderCRoot() - { - IZ z = new C{Z = "zzz"}; - var data = serializer.Serialize(z); - var zz = serializer.Deserialize(data); - zz.AssertEqualsTo(z); - } - - public class A - { - public IZ Z { get; set; } - public IZ[] ArrZ { get; set; } - } - - public class B - { - [GroBufSizeCounter] - public static SizeCounterDelegate GetSizeCounter(Func sizeCountersFactory, SizeCounterDelegate baseSizeCounter) - { - return (o, writeEmpty, context) => - { - Type type = o.GetType(); - return sizeCountersFactory(typeof(string))(type.Name, writeEmpty, context) + sizeCountersFactory(type)(o, writeEmpty, context); - }; - } - - [GroBufWriter] - public static WriterDelegate GetWriter(Func writersFactory, WriterDelegate baseWriter) - { - return (object o, bool writeEmpty, IntPtr result, ref int index, WriterContext context) => - { - Type type = o.GetType(); - writersFactory(typeof(string))(type.Name, writeEmpty, result, ref index, context); - writersFactory(type)(o, writeEmpty, result, ref index, context); - }; - } - - [GroBufReader] - public static ReaderDelegate GetReader(Func readersFactory, ReaderDelegate baseReader) - { - return (IntPtr data, ref int index, ref object result, ReaderContext context) => - { - object type = null; - readersFactory(typeof(string))(data, ref index, ref type, context); - if((string)type == typeof(C).Name) - result = new C(); - else if((string)type == typeof(D).Name) - result = new D(); - else throw new InvalidOperationException("Unknown type " + type); - readersFactory(result.GetType())(data, ref index, ref result, context); - }; - } - } - - public class C : IZ - { - public string Z { get; set; } - } - - public class D : IZ - { - public string Z { get; set; } - } - - [GroBufCustomSerialization(typeof(B))] - public interface IZ - { - string Z { get; set; } - } - - private Serializer serializer; - } +using System; + +using GroBuf.DataMembersExtracters; +using GroBuf.Tests.TestTools; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestCustomReadWriteInterface + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestSizeCounter() + { + var a = new A {Z = new C {Z = "zzz"}}; + var size = serializer.GetSize(a); + Assert.AreEqual((1 + 4 + 8) + (1 + 4 + 2) + (1 + 4 + 8 + 1 + 4 + 6) + 5, size); + } + + [Test] + public void TestWriter() + { + var a = new A {Z = new C {Z = "zzz"}}; + var data = serializer.Serialize(a); + Assert.AreEqual((1 + 4 + 8) + (1 + 4 + 2) + (1 + 4 + 8 + 1 + 4 + 6) + 5, data.Length); + } + + [Test] + public void TestReaderC() + { + var a = new A {Z = new C {Z = "zzz"}, ArrZ = new IZ[] {new C {Z = "qxx"}, new D {Z = "123"}}}; + var data = serializer.Serialize(a); + var za = serializer.Deserialize(data); + za.AssertEqualsTo(a); + } + + [Test] + public void TestReaderD() + { + var a = new A {Z = new D {Z = "146"}, ArrZ = new IZ[] {new C {Z = "qxx"}, new D {Z = "123"}}}; + var data = serializer.Serialize(a); + var za = serializer.Deserialize(data); + za.AssertEqualsTo(a); + } + + [Test] + public void TestReaderCRoot() + { + IZ z = new C{Z = "zzz"}; + var data = serializer.Serialize(z); + var zz = serializer.Deserialize(data); + zz.AssertEqualsTo(z); + } + + public class A + { + public IZ Z { get; set; } + public IZ[] ArrZ { get; set; } + } + + public class B + { + [GroBufSizeCounter] + public static SizeCounterDelegate GetSizeCounter(Func sizeCountersFactory, SizeCounterDelegate baseSizeCounter) + { + return (o, writeEmpty, context) => + { + Type type = o.GetType(); + return sizeCountersFactory(typeof(string))(type.Name, writeEmpty, context) + sizeCountersFactory(type)(o, writeEmpty, context); + }; + } + + [GroBufWriter] + public static WriterDelegate GetWriter(Func writersFactory, WriterDelegate baseWriter) + { + return (object o, bool writeEmpty, IntPtr result, ref int index, WriterContext context) => + { + Type type = o.GetType(); + writersFactory(typeof(string))(type.Name, writeEmpty, result, ref index, context); + writersFactory(type)(o, writeEmpty, result, ref index, context); + }; + } + + [GroBufReader] + public static ReaderDelegate GetReader(Func readersFactory, ReaderDelegate baseReader) + { + return (IntPtr data, ref int index, ref object result, ReaderContext context) => + { + object type = null; + readersFactory(typeof(string))(data, ref index, ref type, context); + if((string)type == typeof(C).Name) + result = new C(); + else if((string)type == typeof(D).Name) + result = new D(); + else throw new InvalidOperationException("Unknown type " + type); + readersFactory(result.GetType())(data, ref index, ref result, context); + }; + } + } + + public class C : IZ + { + public string Z { get; set; } + } + + public class D : IZ + { + public string Z { get; set; } + } + + [GroBufCustomSerialization(typeof(B))] + public interface IZ + { + string Z { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestCycle.cs b/GroBuf.Tests/TestCycle.cs similarity index 96% rename from GroBuf/Tests/TestCycle.cs rename to GroBuf.Tests/TestCycle.cs index ed6bf26..8a51dc5 100644 --- a/GroBuf/Tests/TestCycle.cs +++ b/GroBuf.Tests/TestCycle.cs @@ -1,64 +1,64 @@ -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestCycle - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void Test1() - { - var o = new A {S = "First", Next = new A {S = "Second", Next = new A {S = "Third"}}}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("First", oo.S); - Assert.IsNotNull(oo.Next); - Assert.AreEqual("Second", oo.Next.S); - Assert.IsNotNull(oo.Next.Next); - Assert.AreEqual("Third", oo.Next.Next.S); - Assert.IsNull(oo.Next.Next.Next); - } - - [Test] - public void Test2() - { - var o = new B {S = "First", C = new C {S = "Second", B = new B {S = "Third"}}}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("First", oo.S); - Assert.IsNotNull(oo.C); - Assert.AreEqual("Second", oo.C.S); - Assert.IsNotNull(oo.C.B); - Assert.AreEqual("Third", oo.C.B.S); - Assert.IsNull(oo.C.B.C); - } - - public class A - { - public string S { get; set; } - public A Next { get; set; } - } - - public class B - { - public string S { get; set; } - public C C { get; set; } - } - - public class C - { - public string S { get; set; } - public B B { get; set; } - } - - private Serializer serializer; - } +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestCycle + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void Test1() + { + var o = new A {S = "First", Next = new A {S = "Second", Next = new A {S = "Third"}}}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("First", oo.S); + Assert.IsNotNull(oo.Next); + Assert.AreEqual("Second", oo.Next.S); + Assert.IsNotNull(oo.Next.Next); + Assert.AreEqual("Third", oo.Next.Next.S); + Assert.IsNull(oo.Next.Next.Next); + } + + [Test] + public void Test2() + { + var o = new B {S = "First", C = new C {S = "Second", B = new B {S = "Third"}}}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("First", oo.S); + Assert.IsNotNull(oo.C); + Assert.AreEqual("Second", oo.C.S); + Assert.IsNotNull(oo.C.B); + Assert.AreEqual("Third", oo.C.B.S); + Assert.IsNull(oo.C.B.C); + } + + public class A + { + public string S { get; set; } + public A Next { get; set; } + } + + public class B + { + public string S { get; set; } + public C C { get; set; } + } + + public class C + { + public string S { get; set; } + public B B { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/AdditionalInformation.cs b/GroBuf.Tests/TestData/Desadv/AdditionalInformation.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/AdditionalInformation.cs rename to GroBuf.Tests/TestData/Desadv/AdditionalInformation.cs index 311c4ed..774b296 100644 --- a/GroBuf/Tests/TestData/Desadv/AdditionalInformation.cs +++ b/GroBuf.Tests/TestData/Desadv/AdditionalInformation.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class AdditionalInformation - { - [DataMember] - [ProtoMember(1)] - public byte[] CountryOfOriginNameCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public int[] DutyRegimeTypeCode { get; set; } - - [DataMember] - [ProtoMember(3)] - public string[] SpecialConditionCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class AdditionalInformation + { + [DataMember] + [ProtoMember(1)] + public byte[] CountryOfOriginNameCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public int[] DutyRegimeTypeCode { get; set; } + + [DataMember] + [ProtoMember(3)] + public string[] SpecialConditionCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/AllowanceChargeInformation.cs b/GroBuf.Tests/TestData/Desadv/AllowanceChargeInformation.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/AllowanceChargeInformation.cs rename to GroBuf.Tests/TestData/Desadv/AllowanceChargeInformation.cs index 13f0b6a..f18164b 100644 --- a/GroBuf/Tests/TestData/Desadv/AllowanceChargeInformation.cs +++ b/GroBuf.Tests/TestData/Desadv/AllowanceChargeInformation.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class AllowanceChargeInformation - { - [DataMember] - [ProtoMember(1)] - public byte[] AllowanceOrChargeIdentifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public byte[] AllowanceOrChargeIdentificationCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class AllowanceChargeInformation + { + [DataMember] + [ProtoMember(1)] + public byte[] AllowanceOrChargeIdentifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public byte[] AllowanceOrChargeIdentificationCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/AllowanceOrCharge.cs b/GroBuf.Tests/TestData/Desadv/AllowanceOrCharge.cs similarity index 96% rename from GroBuf/Tests/TestData/Desadv/AllowanceOrCharge.cs rename to GroBuf.Tests/TestData/Desadv/AllowanceOrCharge.cs index 98f1e45..9257b36 100644 --- a/GroBuf/Tests/TestData/Desadv/AllowanceOrCharge.cs +++ b/GroBuf.Tests/TestData/Desadv/AllowanceOrCharge.cs @@ -1,31 +1,31 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class AllowanceOrCharge - { - [DataMember] - [ProtoMember(1)] - public byte[] AllowanceOrChargeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public AllowanceChargeInformation AllowanceChargeInformation { get; set; } - - [DataMember] - [ProtoMember(3)] - public byte[] SettlementMeansCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public byte[] CalculationSequenceCode { get; set; } - - [DataMember] - [ProtoMember(5)] - public SpecialServicesIdentification SpecialServicesIdentification { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class AllowanceOrCharge + { + [DataMember] + [ProtoMember(1)] + public byte[] AllowanceOrChargeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public AllowanceChargeInformation AllowanceChargeInformation { get; set; } + + [DataMember] + [ProtoMember(3)] + public byte[] SettlementMeansCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public byte[] CalculationSequenceCode { get; set; } + + [DataMember] + [ProtoMember(5)] + public SpecialServicesIdentification SpecialServicesIdentification { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/DateTimePeriod.cs b/GroBuf.Tests/TestData/Desadv/DateTimePeriod.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/DateTimePeriod.cs rename to GroBuf.Tests/TestData/Desadv/DateTimePeriod.cs index 46fb7d8..9f55d22 100644 --- a/GroBuf/Tests/TestData/Desadv/DateTimePeriod.cs +++ b/GroBuf.Tests/TestData/Desadv/DateTimePeriod.cs @@ -1,15 +1,15 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class DateTimePeriod - { - [DataMember] - [ProtoMember(1)] - public DateTimePeriodGroup DateTimePeriodGroup { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class DateTimePeriod + { + [DataMember] + [ProtoMember(1)] + public DateTimePeriodGroup DateTimePeriodGroup { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/DateTimePeriodGroup.cs b/GroBuf.Tests/TestData/Desadv/DateTimePeriodGroup.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/DateTimePeriodGroup.cs rename to GroBuf.Tests/TestData/Desadv/DateTimePeriodGroup.cs index ea076a8..05912d1 100644 --- a/GroBuf/Tests/TestData/Desadv/DateTimePeriodGroup.cs +++ b/GroBuf.Tests/TestData/Desadv/DateTimePeriodGroup.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class DateTimePeriodGroup - { - [DataMember] - [ProtoMember(1)] - public byte[] FunctionCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public byte[] Value { get; set; } - - [DataMember] - [ProtoMember(3)] - public byte[] FormatCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class DateTimePeriodGroup + { + [DataMember] + [ProtoMember(1)] + public byte[] FunctionCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public byte[] Value { get; set; } + + [DataMember] + [ProtoMember(3)] + public byte[] FormatCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/Desadv.cs b/GroBuf.Tests/TestData/Desadv/Desadv.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/Desadv.cs rename to GroBuf.Tests/TestData/Desadv/Desadv.cs index bd06610..8a7a169 100644 --- a/GroBuf/Tests/TestData/Desadv/Desadv.cs +++ b/GroBuf.Tests/TestData/Desadv/Desadv.cs @@ -1,43 +1,43 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class Desadv - { - [DataMember] - [ProtoMember(1)] - public AllowanceOrCharge AllowanceOrCharge { get; set; } - - [DataMember] - [ProtoMember(2)] - public AdditionalInformation[] AdditionalInformation { get; set; } - - [DataMember] - [ProtoMember(3)] - public DateTimePeriod[] DateTimePeriod { get; set; } - - [DataMember] - [ProtoMember(4)] - public SG44 SG44 { get; set; } - - [DataMember] - [ProtoMember(5)] - public SG45 SG45 { get; set; } - - [DataMember] - [ProtoMember(6)] - public SG46[] SG46 { get; set; } - - [DataMember] - [ProtoMember(7)] - public SG47 SG47 { get; set; } - - [DataMember] - [ProtoMember(8)] - public SG48[] SG48 { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class Desadv + { + [DataMember] + [ProtoMember(1)] + public AllowanceOrCharge AllowanceOrCharge { get; set; } + + [DataMember] + [ProtoMember(2)] + public AdditionalInformation[] AdditionalInformation { get; set; } + + [DataMember] + [ProtoMember(3)] + public DateTimePeriod[] DateTimePeriod { get; set; } + + [DataMember] + [ProtoMember(4)] + public SG44 SG44 { get; set; } + + [DataMember] + [ProtoMember(5)] + public SG45 SG45 { get; set; } + + [DataMember] + [ProtoMember(6)] + public SG46[] SG46 { get; set; } + + [DataMember] + [ProtoMember(7)] + public SG47 SG47 { get; set; } + + [DataMember] + [ProtoMember(8)] + public SG48[] SG48 { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/DutyTaxFeeAccountDetail.cs b/GroBuf.Tests/TestData/Desadv/DutyTaxFeeAccountDetail.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/DutyTaxFeeAccountDetail.cs rename to GroBuf.Tests/TestData/Desadv/DutyTaxFeeAccountDetail.cs index 660ee48..b185775 100644 --- a/GroBuf/Tests/TestData/Desadv/DutyTaxFeeAccountDetail.cs +++ b/GroBuf.Tests/TestData/Desadv/DutyTaxFeeAccountDetail.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class DutyTaxFeeAccountDetail - { - [DataMember] - [ProtoMember(1)] - public byte[] DutyTaxFeeAccountCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public byte[] CodeListIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(3)] - public byte[] CodeListResponsibleAgencyCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class DutyTaxFeeAccountDetail + { + [DataMember] + [ProtoMember(1)] + public byte[] DutyTaxFeeAccountCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public byte[] CodeListIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(3)] + public byte[] CodeListResponsibleAgencyCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/DutyTaxFeeDetail.cs b/GroBuf.Tests/TestData/Desadv/DutyTaxFeeDetail.cs similarity index 96% rename from GroBuf/Tests/TestData/Desadv/DutyTaxFeeDetail.cs rename to GroBuf.Tests/TestData/Desadv/DutyTaxFeeDetail.cs index 8e60a19..d65d243 100644 --- a/GroBuf/Tests/TestData/Desadv/DutyTaxFeeDetail.cs +++ b/GroBuf.Tests/TestData/Desadv/DutyTaxFeeDetail.cs @@ -1,39 +1,39 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class DutyTaxFeeDetail - { - [DataMember] - [ProtoMember(1)] - public byte[] DutyTaxFeeRateCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public byte[] CodeListIdentificationCode1 { get; set; } - - [DataMember] - [ProtoMember(3)] - public byte[] CodeListResponsibleAgencyCode1 { get; set; } - - [DataMember] - [ProtoMember(4)] - public byte[] DutyTaxFeeRate { get; set; } - - [DataMember] - [ProtoMember(5)] - public byte[] DutyTaxFeeRateBasisCode { get; set; } - - [DataMember] - [ProtoMember(6)] - public byte[] CodeListIdentificationCode2 { get; set; } - - [DataMember] - [ProtoMember(7)] - public byte[] CodeListResponsibleAgencyCode2 { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class DutyTaxFeeDetail + { + [DataMember] + [ProtoMember(1)] + public byte[] DutyTaxFeeRateCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public byte[] CodeListIdentificationCode1 { get; set; } + + [DataMember] + [ProtoMember(3)] + public byte[] CodeListResponsibleAgencyCode1 { get; set; } + + [DataMember] + [ProtoMember(4)] + public byte[] DutyTaxFeeRate { get; set; } + + [DataMember] + [ProtoMember(5)] + public byte[] DutyTaxFeeRateBasisCode { get; set; } + + [DataMember] + [ProtoMember(6)] + public byte[] CodeListIdentificationCode2 { get; set; } + + [DataMember] + [ProtoMember(7)] + public byte[] CodeListResponsibleAgencyCode2 { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/DutyTaxFeeDetails.cs b/GroBuf.Tests/TestData/Desadv/DutyTaxFeeDetails.cs similarity index 96% rename from GroBuf/Tests/TestData/Desadv/DutyTaxFeeDetails.cs rename to GroBuf.Tests/TestData/Desadv/DutyTaxFeeDetails.cs index 96514f8..eada7d6 100644 --- a/GroBuf/Tests/TestData/Desadv/DutyTaxFeeDetails.cs +++ b/GroBuf.Tests/TestData/Desadv/DutyTaxFeeDetails.cs @@ -1,43 +1,43 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class DutyTaxFeeDetails - { - [DataMember] - [ProtoMember(1)] - public byte[] DutyTaxFeeFunctionCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public DutyTaxFeeType DutyTaxFeeType { get; set; } - - [DataMember] - [ProtoMember(3)] - public DutyTaxFeeAccountDetail DutyTaxFeeAccountDetail { get; set; } - - [DataMember] - [ProtoMember(4)] - public byte[] DutyTaxFeeAssessmentBasisValue { get; set; } - - [DataMember] - [ProtoMember(5)] - public DutyTaxFeeDetail DutyTaxFeeDetail { get; set; } - - [DataMember] - [ProtoMember(6)] - public byte[] DutyTaxFeeCategoryCode { get; set; } - - [DataMember] - [ProtoMember(7)] - public byte[] PartyTaxIdentifier { get; set; } - - [DataMember] - [ProtoMember(8)] - public byte[] CalculationSequenceCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class DutyTaxFeeDetails + { + [DataMember] + [ProtoMember(1)] + public byte[] DutyTaxFeeFunctionCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public DutyTaxFeeType DutyTaxFeeType { get; set; } + + [DataMember] + [ProtoMember(3)] + public DutyTaxFeeAccountDetail DutyTaxFeeAccountDetail { get; set; } + + [DataMember] + [ProtoMember(4)] + public byte[] DutyTaxFeeAssessmentBasisValue { get; set; } + + [DataMember] + [ProtoMember(5)] + public DutyTaxFeeDetail DutyTaxFeeDetail { get; set; } + + [DataMember] + [ProtoMember(6)] + public byte[] DutyTaxFeeCategoryCode { get; set; } + + [DataMember] + [ProtoMember(7)] + public byte[] PartyTaxIdentifier { get; set; } + + [DataMember] + [ProtoMember(8)] + public byte[] CalculationSequenceCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/DutyTaxFeeType.cs b/GroBuf.Tests/TestData/Desadv/DutyTaxFeeType.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/DutyTaxFeeType.cs rename to GroBuf.Tests/TestData/Desadv/DutyTaxFeeType.cs index 8fd4239..f323fca 100644 --- a/GroBuf/Tests/TestData/Desadv/DutyTaxFeeType.cs +++ b/GroBuf.Tests/TestData/Desadv/DutyTaxFeeType.cs @@ -1,27 +1,27 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class DutyTaxFeeType - { - [DataMember] - [ProtoMember(1)] - public byte[] DutyTaxFeeTypeNameCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public byte[] CodeListIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(3)] - public byte[] CodeListResponsibleAgencyCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public byte[] DutyTaxFeeTypeName { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class DutyTaxFeeType + { + [DataMember] + [ProtoMember(1)] + public byte[] DutyTaxFeeTypeNameCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public byte[] CodeListIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(3)] + public byte[] CodeListResponsibleAgencyCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public byte[] DutyTaxFeeTypeName { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/MonetaryAmount.cs b/GroBuf.Tests/TestData/Desadv/MonetaryAmount.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/MonetaryAmount.cs rename to GroBuf.Tests/TestData/Desadv/MonetaryAmount.cs index 0a79e9a..c8e64e6 100644 --- a/GroBuf/Tests/TestData/Desadv/MonetaryAmount.cs +++ b/GroBuf.Tests/TestData/Desadv/MonetaryAmount.cs @@ -1,15 +1,15 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class MonetaryAmount - { - [DataMember] - [ProtoMember(1)] - public MonetaryAmountGroup MonetaryAmountGroup { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class MonetaryAmount + { + [DataMember] + [ProtoMember(1)] + public MonetaryAmountGroup MonetaryAmountGroup { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/MonetaryAmountGroup.cs b/GroBuf.Tests/TestData/Desadv/MonetaryAmountGroup.cs similarity index 96% rename from GroBuf/Tests/TestData/Desadv/MonetaryAmountGroup.cs rename to GroBuf.Tests/TestData/Desadv/MonetaryAmountGroup.cs index 4953057..3a11b7b 100644 --- a/GroBuf/Tests/TestData/Desadv/MonetaryAmountGroup.cs +++ b/GroBuf.Tests/TestData/Desadv/MonetaryAmountGroup.cs @@ -1,31 +1,31 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class MonetaryAmountGroup - { - [DataMember] - [ProtoMember(1)] - public byte[] MonetaryAmountTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public byte[] MonetaryAmount { get; set; } - - [DataMember] - [ProtoMember(3)] - public byte[] CurrencyIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public byte[] CurrencyTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(5)] - public byte[] StatusDescriptionCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class MonetaryAmountGroup + { + [DataMember] + [ProtoMember(1)] + public byte[] MonetaryAmountTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public byte[] MonetaryAmount { get; set; } + + [DataMember] + [ProtoMember(3)] + public byte[] CurrencyIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public byte[] CurrencyTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(5)] + public byte[] StatusDescriptionCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/PercentageDetails.cs b/GroBuf.Tests/TestData/Desadv/PercentageDetails.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/PercentageDetails.cs rename to GroBuf.Tests/TestData/Desadv/PercentageDetails.cs index 3726877..f32d67f 100644 --- a/GroBuf/Tests/TestData/Desadv/PercentageDetails.cs +++ b/GroBuf.Tests/TestData/Desadv/PercentageDetails.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class PercentageDetails - { - [DataMember] - [ProtoMember(1)] - public PercentageDetailsGroup PercentageDetailsGroup { get; set; } - - [DataMember] - [ProtoMember(2)] - public byte[] StatusDescriptionCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class PercentageDetails + { + [DataMember] + [ProtoMember(1)] + public PercentageDetailsGroup PercentageDetailsGroup { get; set; } + + [DataMember] + [ProtoMember(2)] + public byte[] StatusDescriptionCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/PercentageDetailsGroup.cs b/GroBuf.Tests/TestData/Desadv/PercentageDetailsGroup.cs similarity index 96% rename from GroBuf/Tests/TestData/Desadv/PercentageDetailsGroup.cs rename to GroBuf.Tests/TestData/Desadv/PercentageDetailsGroup.cs index b973dd6..a7ea84f 100644 --- a/GroBuf/Tests/TestData/Desadv/PercentageDetailsGroup.cs +++ b/GroBuf.Tests/TestData/Desadv/PercentageDetailsGroup.cs @@ -1,31 +1,31 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class PercentageDetailsGroup - { - [DataMember] - [ProtoMember(1)] - public byte[] PercentageTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public byte[] Percentage { get; set; } - - [DataMember] - [ProtoMember(3)] - public byte[] PercentageBasisIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public byte[] CodeListIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(5)] - public byte[] CodeListResponsibleAgencyCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class PercentageDetailsGroup + { + [DataMember] + [ProtoMember(1)] + public byte[] PercentageTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public byte[] Percentage { get; set; } + + [DataMember] + [ProtoMember(3)] + public byte[] PercentageBasisIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public byte[] CodeListIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(5)] + public byte[] CodeListResponsibleAgencyCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/Quantity.cs b/GroBuf.Tests/TestData/Desadv/Quantity.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/Quantity.cs rename to GroBuf.Tests/TestData/Desadv/Quantity.cs index c6f759c..ce82538 100644 --- a/GroBuf/Tests/TestData/Desadv/Quantity.cs +++ b/GroBuf.Tests/TestData/Desadv/Quantity.cs @@ -1,15 +1,15 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class Quantity - { - [DataMember] - [ProtoMember(1)] - public QuantityDetails QuantityDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class Quantity + { + [DataMember] + [ProtoMember(1)] + public QuantityDetails QuantityDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/QuantityDetails.cs b/GroBuf.Tests/TestData/Desadv/QuantityDetails.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/QuantityDetails.cs rename to GroBuf.Tests/TestData/Desadv/QuantityDetails.cs index b75f5e0..5db4ab6 100644 --- a/GroBuf/Tests/TestData/Desadv/QuantityDetails.cs +++ b/GroBuf.Tests/TestData/Desadv/QuantityDetails.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class QuantityDetails - { - [DataMember] - [ProtoMember(1)] - public byte[] QuantityTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public byte[] Quantity { get; set; } - - [DataMember] - [ProtoMember(3)] - public byte[] MeasurementUnitCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class QuantityDetails + { + [DataMember] + [ProtoMember(1)] + public byte[] QuantityTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public byte[] Quantity { get; set; } + + [DataMember] + [ProtoMember(3)] + public byte[] MeasurementUnitCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/Range.cs b/GroBuf.Tests/TestData/Desadv/Range.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/Range.cs rename to GroBuf.Tests/TestData/Desadv/Range.cs index 705197f..334e3b7 100644 --- a/GroBuf/Tests/TestData/Desadv/Range.cs +++ b/GroBuf.Tests/TestData/Desadv/Range.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class Range - { - [DataMember] - [ProtoMember(1)] - public byte[] MeasurementUnitCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public byte[] RangeMinimumValue { get; set; } - - [DataMember] - [ProtoMember(3)] - public byte[] RangeMaximumValue { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class Range + { + [DataMember] + [ProtoMember(1)] + public byte[] MeasurementUnitCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public byte[] RangeMinimumValue { get; set; } + + [DataMember] + [ProtoMember(3)] + public byte[] RangeMaximumValue { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/RangeDetails.cs b/GroBuf.Tests/TestData/Desadv/RangeDetails.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/RangeDetails.cs rename to GroBuf.Tests/TestData/Desadv/RangeDetails.cs index a525f91..1e39ee2 100644 --- a/GroBuf/Tests/TestData/Desadv/RangeDetails.cs +++ b/GroBuf.Tests/TestData/Desadv/RangeDetails.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class RangeDetails - { - [DataMember] - [ProtoMember(1)] - public byte[] RangeTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public Range Range { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class RangeDetails + { + [DataMember] + [ProtoMember(1)] + public byte[] RangeTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public Range Range { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/RateDetails.cs b/GroBuf.Tests/TestData/Desadv/RateDetails.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/RateDetails.cs rename to GroBuf.Tests/TestData/Desadv/RateDetails.cs index a7ea71a..7a83332 100644 --- a/GroBuf/Tests/TestData/Desadv/RateDetails.cs +++ b/GroBuf.Tests/TestData/Desadv/RateDetails.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class RateDetails - { - [DataMember] - [ProtoMember(1)] - public RateDetailsGroup RateDetailsGroup { get; set; } - - [DataMember] - [ProtoMember(2)] - public byte[] StatusDescriptionCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class RateDetails + { + [DataMember] + [ProtoMember(1)] + public RateDetailsGroup RateDetailsGroup { get; set; } + + [DataMember] + [ProtoMember(2)] + public byte[] StatusDescriptionCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/RateDetailsGroup.cs b/GroBuf.Tests/TestData/Desadv/RateDetailsGroup.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/RateDetailsGroup.cs rename to GroBuf.Tests/TestData/Desadv/RateDetailsGroup.cs index c5fefe4..56dc9e1 100644 --- a/GroBuf/Tests/TestData/Desadv/RateDetailsGroup.cs +++ b/GroBuf.Tests/TestData/Desadv/RateDetailsGroup.cs @@ -1,27 +1,27 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class RateDetailsGroup - { - [DataMember] - [ProtoMember(1)] - public byte[] RateTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public byte[] UnitPriceBasisRate { get; set; } - - [DataMember] - [ProtoMember(3)] - public byte[] UnitPriceBasisValue { get; set; } - - [DataMember] - [ProtoMember(4)] - public byte[] MeasurementUnitCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class RateDetailsGroup + { + [DataMember] + [ProtoMember(1)] + public byte[] RateTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public byte[] UnitPriceBasisRate { get; set; } + + [DataMember] + [ProtoMember(3)] + public byte[] UnitPriceBasisValue { get; set; } + + [DataMember] + [ProtoMember(4)] + public byte[] MeasurementUnitCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/SG44.cs b/GroBuf.Tests/TestData/Desadv/SG44.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/SG44.cs rename to GroBuf.Tests/TestData/Desadv/SG44.cs index 38114bc..1b8c4b9 100644 --- a/GroBuf/Tests/TestData/Desadv/SG44.cs +++ b/GroBuf.Tests/TestData/Desadv/SG44.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class SG44 - { - [DataMember] - [ProtoMember(1)] - public Quantity Quantity { get; set; } - - [DataMember] - [ProtoMember(2)] - public RangeDetails RangeDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class SG44 + { + [DataMember] + [ProtoMember(1)] + public Quantity Quantity { get; set; } + + [DataMember] + [ProtoMember(2)] + public RangeDetails RangeDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/SG45.cs b/GroBuf.Tests/TestData/Desadv/SG45.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/SG45.cs rename to GroBuf.Tests/TestData/Desadv/SG45.cs index a1b21f4..796ec60 100644 --- a/GroBuf/Tests/TestData/Desadv/SG45.cs +++ b/GroBuf.Tests/TestData/Desadv/SG45.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class SG45 - { - [DataMember] - [ProtoMember(1)] - public PercentageDetails PercentageDetails { get; set; } - - [DataMember] - [ProtoMember(2)] - public RangeDetails RangeDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class SG45 + { + [DataMember] + [ProtoMember(1)] + public PercentageDetails PercentageDetails { get; set; } + + [DataMember] + [ProtoMember(2)] + public RangeDetails RangeDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/SG46.cs b/GroBuf.Tests/TestData/Desadv/SG46.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/SG46.cs rename to GroBuf.Tests/TestData/Desadv/SG46.cs index 185a5e6..36a7691 100644 --- a/GroBuf/Tests/TestData/Desadv/SG46.cs +++ b/GroBuf.Tests/TestData/Desadv/SG46.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class SG46 - { - [DataMember] - [ProtoMember(1)] - public MonetaryAmount MonetaryAmount { get; set; } - - [DataMember] - [ProtoMember(2)] - public RangeDetails RangeDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class SG46 + { + [DataMember] + [ProtoMember(1)] + public MonetaryAmount MonetaryAmount { get; set; } + + [DataMember] + [ProtoMember(2)] + public RangeDetails RangeDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/SG47.cs b/GroBuf.Tests/TestData/Desadv/SG47.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/SG47.cs rename to GroBuf.Tests/TestData/Desadv/SG47.cs index 8d29aa8..6dbfe29 100644 --- a/GroBuf/Tests/TestData/Desadv/SG47.cs +++ b/GroBuf.Tests/TestData/Desadv/SG47.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class SG47 - { - [DataMember] - [ProtoMember(1)] - public RateDetails RateDetails { get; set; } - - [DataMember] - [ProtoMember(2)] - public RangeDetails RangeDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class SG47 + { + [DataMember] + [ProtoMember(1)] + public RateDetails RateDetails { get; set; } + + [DataMember] + [ProtoMember(2)] + public RangeDetails RangeDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/SG48.cs b/GroBuf.Tests/TestData/Desadv/SG48.cs similarity index 95% rename from GroBuf/Tests/TestData/Desadv/SG48.cs rename to GroBuf.Tests/TestData/Desadv/SG48.cs index 7784280..69c1eda 100644 --- a/GroBuf/Tests/TestData/Desadv/SG48.cs +++ b/GroBuf.Tests/TestData/Desadv/SG48.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class SG48 - { - [DataMember] - [ProtoMember(1)] - public DutyTaxFeeDetails DutyTaxFeeDetails { get; set; } - - [DataMember] - [ProtoMember(2)] - public MonetaryAmount MonetaryAmount { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class SG48 + { + [DataMember] + [ProtoMember(1)] + public DutyTaxFeeDetails DutyTaxFeeDetails { get; set; } + + [DataMember] + [ProtoMember(2)] + public MonetaryAmount MonetaryAmount { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Desadv/SpecialServicesIdentification.cs b/GroBuf.Tests/TestData/Desadv/SpecialServicesIdentification.cs similarity index 96% rename from GroBuf/Tests/TestData/Desadv/SpecialServicesIdentification.cs rename to GroBuf.Tests/TestData/Desadv/SpecialServicesIdentification.cs index 30a05a2..1080ba0 100644 --- a/GroBuf/Tests/TestData/Desadv/SpecialServicesIdentification.cs +++ b/GroBuf.Tests/TestData/Desadv/SpecialServicesIdentification.cs @@ -1,27 +1,27 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Desadv -{ - [DataContract] - [ProtoContract] - public class SpecialServicesIdentification - { - [DataMember] - [ProtoMember(1)] - public int[] SpecialServiceDescriptionCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public sbyte[] CodeListIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(3)] - public short[] CodeListResponsibleAgencyCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public ushort[] SpecialServiceDescription { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Desadv +{ + [DataContract] + [ProtoContract] + public class SpecialServicesIdentification + { + [DataMember] + [ProtoMember(1)] + public int[] SpecialServiceDescriptionCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public sbyte[] CodeListIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(3)] + public short[] CodeListResponsibleAgencyCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public ushort[] SpecialServiceDescription { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/AdditionalInformation.cs b/GroBuf.Tests/TestData/Invoic/AdditionalInformation.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/AdditionalInformation.cs rename to GroBuf.Tests/TestData/Invoic/AdditionalInformation.cs index 3eaf002..0b9320c 100644 --- a/GroBuf/Tests/TestData/Invoic/AdditionalInformation.cs +++ b/GroBuf.Tests/TestData/Invoic/AdditionalInformation.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class AdditionalInformation - { - [DataMember] - [ProtoMember(1)] - public string CountryOfOriginNameCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public string DutyRegimeTypeCode { get; set; } - - [DataMember] - [ProtoMember(3)] - public string[] SpecialConditionCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class AdditionalInformation + { + [DataMember] + [ProtoMember(1)] + public string CountryOfOriginNameCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public string DutyRegimeTypeCode { get; set; } + + [DataMember] + [ProtoMember(3)] + public string[] SpecialConditionCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/AllowanceChargeInformation.cs b/GroBuf.Tests/TestData/Invoic/AllowanceChargeInformation.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/AllowanceChargeInformation.cs rename to GroBuf.Tests/TestData/Invoic/AllowanceChargeInformation.cs index 6c1e5ed..8c095cf 100644 --- a/GroBuf/Tests/TestData/Invoic/AllowanceChargeInformation.cs +++ b/GroBuf.Tests/TestData/Invoic/AllowanceChargeInformation.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class AllowanceChargeInformation - { - [DataMember] - [ProtoMember(1)] - public string AllowanceOrChargeIdentifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public string AllowanceOrChargeIdentificationCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class AllowanceChargeInformation + { + [DataMember] + [ProtoMember(1)] + public string AllowanceOrChargeIdentifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public string AllowanceOrChargeIdentificationCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/AllowanceOrCharge.cs b/GroBuf.Tests/TestData/Invoic/AllowanceOrCharge.cs similarity index 96% rename from GroBuf/Tests/TestData/Invoic/AllowanceOrCharge.cs rename to GroBuf.Tests/TestData/Invoic/AllowanceOrCharge.cs index 4e058c4..93b022b 100644 --- a/GroBuf/Tests/TestData/Invoic/AllowanceOrCharge.cs +++ b/GroBuf.Tests/TestData/Invoic/AllowanceOrCharge.cs @@ -1,31 +1,31 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class AllowanceOrCharge - { - [DataMember] - [ProtoMember(1)] - public string AllowanceOrChargeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public AllowanceChargeInformation AllowanceChargeInformation { get; set; } - - [DataMember] - [ProtoMember(3)] - public string SettlementMeansCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public string CalculationSequenceCode { get; set; } - - [DataMember] - [ProtoMember(5)] - public SpecialServicesIdentification SpecialServicesIdentification { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class AllowanceOrCharge + { + [DataMember] + [ProtoMember(1)] + public string AllowanceOrChargeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public AllowanceChargeInformation AllowanceChargeInformation { get; set; } + + [DataMember] + [ProtoMember(3)] + public string SettlementMeansCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public string CalculationSequenceCode { get; set; } + + [DataMember] + [ProtoMember(5)] + public SpecialServicesIdentification SpecialServicesIdentification { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/DateTimePeriod.cs b/GroBuf.Tests/TestData/Invoic/DateTimePeriod.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/DateTimePeriod.cs rename to GroBuf.Tests/TestData/Invoic/DateTimePeriod.cs index d53956f..b86724a 100644 --- a/GroBuf/Tests/TestData/Invoic/DateTimePeriod.cs +++ b/GroBuf.Tests/TestData/Invoic/DateTimePeriod.cs @@ -1,15 +1,15 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class DateTimePeriod - { - [DataMember] - [ProtoMember(1)] - public DateTimePeriodGroup DateTimePeriodGroup { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class DateTimePeriod + { + [DataMember] + [ProtoMember(1)] + public DateTimePeriodGroup DateTimePeriodGroup { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/DateTimePeriodGroup.cs b/GroBuf.Tests/TestData/Invoic/DateTimePeriodGroup.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/DateTimePeriodGroup.cs rename to GroBuf.Tests/TestData/Invoic/DateTimePeriodGroup.cs index 8aacca1..6d38c4e 100644 --- a/GroBuf/Tests/TestData/Invoic/DateTimePeriodGroup.cs +++ b/GroBuf.Tests/TestData/Invoic/DateTimePeriodGroup.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class DateTimePeriodGroup - { - [DataMember] - [ProtoMember(1)] - public string FunctionCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public string Value { get; set; } - - [DataMember] - [ProtoMember(3)] - public string FormatCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class DateTimePeriodGroup + { + [DataMember] + [ProtoMember(1)] + public string FunctionCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public string Value { get; set; } + + [DataMember] + [ProtoMember(3)] + public string FormatCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/DutyTaxFeeAccountDetail.cs b/GroBuf.Tests/TestData/Invoic/DutyTaxFeeAccountDetail.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/DutyTaxFeeAccountDetail.cs rename to GroBuf.Tests/TestData/Invoic/DutyTaxFeeAccountDetail.cs index e02b062..3012bed 100644 --- a/GroBuf/Tests/TestData/Invoic/DutyTaxFeeAccountDetail.cs +++ b/GroBuf.Tests/TestData/Invoic/DutyTaxFeeAccountDetail.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class DutyTaxFeeAccountDetail - { - [DataMember] - [ProtoMember(1)] - public string DutyTaxFeeAccountCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public string CodeListIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(3)] - public string CodeListResponsibleAgencyCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class DutyTaxFeeAccountDetail + { + [DataMember] + [ProtoMember(1)] + public string DutyTaxFeeAccountCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public string CodeListIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(3)] + public string CodeListResponsibleAgencyCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/DutyTaxFeeDetail.cs b/GroBuf.Tests/TestData/Invoic/DutyTaxFeeDetail.cs similarity index 96% rename from GroBuf/Tests/TestData/Invoic/DutyTaxFeeDetail.cs rename to GroBuf.Tests/TestData/Invoic/DutyTaxFeeDetail.cs index 8400fa3..c5c1aa0 100644 --- a/GroBuf/Tests/TestData/Invoic/DutyTaxFeeDetail.cs +++ b/GroBuf.Tests/TestData/Invoic/DutyTaxFeeDetail.cs @@ -1,39 +1,39 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class DutyTaxFeeDetail - { - [DataMember] - [ProtoMember(1)] - public string DutyTaxFeeRateCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public string CodeListIdentificationCode1 { get; set; } - - [DataMember] - [ProtoMember(3)] - public string CodeListResponsibleAgencyCode1 { get; set; } - - [DataMember] - [ProtoMember(4)] - public string DutyTaxFeeRate { get; set; } - - [DataMember] - [ProtoMember(5)] - public string DutyTaxFeeRateBasisCode { get; set; } - - [DataMember] - [ProtoMember(6)] - public string CodeListIdentificationCode2 { get; set; } - - [DataMember] - [ProtoMember(7)] - public string CodeListResponsibleAgencyCode2 { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class DutyTaxFeeDetail + { + [DataMember] + [ProtoMember(1)] + public string DutyTaxFeeRateCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public string CodeListIdentificationCode1 { get; set; } + + [DataMember] + [ProtoMember(3)] + public string CodeListResponsibleAgencyCode1 { get; set; } + + [DataMember] + [ProtoMember(4)] + public string DutyTaxFeeRate { get; set; } + + [DataMember] + [ProtoMember(5)] + public string DutyTaxFeeRateBasisCode { get; set; } + + [DataMember] + [ProtoMember(6)] + public string CodeListIdentificationCode2 { get; set; } + + [DataMember] + [ProtoMember(7)] + public string CodeListResponsibleAgencyCode2 { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/DutyTaxFeeDetails.cs b/GroBuf.Tests/TestData/Invoic/DutyTaxFeeDetails.cs similarity index 96% rename from GroBuf/Tests/TestData/Invoic/DutyTaxFeeDetails.cs rename to GroBuf.Tests/TestData/Invoic/DutyTaxFeeDetails.cs index a7b1fa4..4275bbe 100644 --- a/GroBuf/Tests/TestData/Invoic/DutyTaxFeeDetails.cs +++ b/GroBuf.Tests/TestData/Invoic/DutyTaxFeeDetails.cs @@ -1,43 +1,43 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class DutyTaxFeeDetails - { - [DataMember] - [ProtoMember(1)] - public string DutyTaxFeeFunctionCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public DutyTaxFeeType DutyTaxFeeType { get; set; } - - [DataMember] - [ProtoMember(3)] - public DutyTaxFeeAccountDetail DutyTaxFeeAccountDetail { get; set; } - - [DataMember] - [ProtoMember(4)] - public string DutyTaxFeeAssessmentBasisValue { get; set; } - - [DataMember] - [ProtoMember(5)] - public DutyTaxFeeDetail DutyTaxFeeDetail { get; set; } - - [DataMember] - [ProtoMember(6)] - public string DutyTaxFeeCategoryCode { get; set; } - - [DataMember] - [ProtoMember(7)] - public string PartyTaxIdentifier { get; set; } - - [DataMember] - [ProtoMember(8)] - public string CalculationSequenceCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class DutyTaxFeeDetails + { + [DataMember] + [ProtoMember(1)] + public string DutyTaxFeeFunctionCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public DutyTaxFeeType DutyTaxFeeType { get; set; } + + [DataMember] + [ProtoMember(3)] + public DutyTaxFeeAccountDetail DutyTaxFeeAccountDetail { get; set; } + + [DataMember] + [ProtoMember(4)] + public string DutyTaxFeeAssessmentBasisValue { get; set; } + + [DataMember] + [ProtoMember(5)] + public DutyTaxFeeDetail DutyTaxFeeDetail { get; set; } + + [DataMember] + [ProtoMember(6)] + public string DutyTaxFeeCategoryCode { get; set; } + + [DataMember] + [ProtoMember(7)] + public string PartyTaxIdentifier { get; set; } + + [DataMember] + [ProtoMember(8)] + public string CalculationSequenceCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/DutyTaxFeeType.cs b/GroBuf.Tests/TestData/Invoic/DutyTaxFeeType.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/DutyTaxFeeType.cs rename to GroBuf.Tests/TestData/Invoic/DutyTaxFeeType.cs index bffaa9d..c200ab2 100644 --- a/GroBuf/Tests/TestData/Invoic/DutyTaxFeeType.cs +++ b/GroBuf.Tests/TestData/Invoic/DutyTaxFeeType.cs @@ -1,27 +1,27 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class DutyTaxFeeType - { - [DataMember] - [ProtoMember(1)] - public string DutyTaxFeeTypeNameCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public string CodeListIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(3)] - public string CodeListResponsibleAgencyCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public string DutyTaxFeeTypeName { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class DutyTaxFeeType + { + [DataMember] + [ProtoMember(1)] + public string DutyTaxFeeTypeNameCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public string CodeListIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(3)] + public string CodeListResponsibleAgencyCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public string DutyTaxFeeTypeName { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/Invoic.cs b/GroBuf.Tests/TestData/Invoic/Invoic.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/Invoic.cs rename to GroBuf.Tests/TestData/Invoic/Invoic.cs index 9b6d54d..3e4e15a 100644 --- a/GroBuf/Tests/TestData/Invoic/Invoic.cs +++ b/GroBuf.Tests/TestData/Invoic/Invoic.cs @@ -1,43 +1,43 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class Invoic - { - [DataMember] - [ProtoMember(1)] - public AllowanceOrCharge AllowanceOrCharge { get; set; } - - [DataMember] - [ProtoMember(2)] - public AdditionalInformation[] AdditionalInformation { get; set; } - - [DataMember] - [ProtoMember(3)] - public DateTimePeriod[] DateTimePeriod { get; set; } - - [DataMember] - [ProtoMember(4)] - public SG44 SG44 { get; set; } - - [DataMember] - [ProtoMember(5)] - public SG45 SG45 { get; set; } - - [DataMember] - [ProtoMember(6)] - public SG46[] SG46 { get; set; } - - [DataMember] - [ProtoMember(7)] - public SG47 SG47 { get; set; } - - [DataMember] - [ProtoMember(8)] - public SG48[] SG48 { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class Invoic + { + [DataMember] + [ProtoMember(1)] + public AllowanceOrCharge AllowanceOrCharge { get; set; } + + [DataMember] + [ProtoMember(2)] + public AdditionalInformation[] AdditionalInformation { get; set; } + + [DataMember] + [ProtoMember(3)] + public DateTimePeriod[] DateTimePeriod { get; set; } + + [DataMember] + [ProtoMember(4)] + public SG44 SG44 { get; set; } + + [DataMember] + [ProtoMember(5)] + public SG45 SG45 { get; set; } + + [DataMember] + [ProtoMember(6)] + public SG46[] SG46 { get; set; } + + [DataMember] + [ProtoMember(7)] + public SG47 SG47 { get; set; } + + [DataMember] + [ProtoMember(8)] + public SG48[] SG48 { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/MonetaryAmount.cs b/GroBuf.Tests/TestData/Invoic/MonetaryAmount.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/MonetaryAmount.cs rename to GroBuf.Tests/TestData/Invoic/MonetaryAmount.cs index 677281c..8c44cfe 100644 --- a/GroBuf/Tests/TestData/Invoic/MonetaryAmount.cs +++ b/GroBuf.Tests/TestData/Invoic/MonetaryAmount.cs @@ -1,15 +1,15 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class MonetaryAmount - { - [DataMember] - [ProtoMember(1)] - public MonetaryAmountGroup MonetaryAmountGroup { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class MonetaryAmount + { + [DataMember] + [ProtoMember(1)] + public MonetaryAmountGroup MonetaryAmountGroup { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/MonetaryAmountGroup.cs b/GroBuf.Tests/TestData/Invoic/MonetaryAmountGroup.cs similarity index 96% rename from GroBuf/Tests/TestData/Invoic/MonetaryAmountGroup.cs rename to GroBuf.Tests/TestData/Invoic/MonetaryAmountGroup.cs index 5c422e9..04d7d28 100644 --- a/GroBuf/Tests/TestData/Invoic/MonetaryAmountGroup.cs +++ b/GroBuf.Tests/TestData/Invoic/MonetaryAmountGroup.cs @@ -1,31 +1,31 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class MonetaryAmountGroup - { - [DataMember] - [ProtoMember(1)] - public string MonetaryAmountTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public string MonetaryAmount { get; set; } - - [DataMember] - [ProtoMember(3)] - public string CurrencyIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public string CurrencyTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(5)] - public string StatusDescriptionCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class MonetaryAmountGroup + { + [DataMember] + [ProtoMember(1)] + public string MonetaryAmountTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public string MonetaryAmount { get; set; } + + [DataMember] + [ProtoMember(3)] + public string CurrencyIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public string CurrencyTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(5)] + public string StatusDescriptionCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/PercentageDetails.cs b/GroBuf.Tests/TestData/Invoic/PercentageDetails.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/PercentageDetails.cs rename to GroBuf.Tests/TestData/Invoic/PercentageDetails.cs index d270d13..5bed549 100644 --- a/GroBuf/Tests/TestData/Invoic/PercentageDetails.cs +++ b/GroBuf.Tests/TestData/Invoic/PercentageDetails.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class PercentageDetails - { - [DataMember] - [ProtoMember(1)] - public PercentageDetailsGroup PercentageDetailsGroup { get; set; } - - [DataMember] - [ProtoMember(2)] - public string StatusDescriptionCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class PercentageDetails + { + [DataMember] + [ProtoMember(1)] + public PercentageDetailsGroup PercentageDetailsGroup { get; set; } + + [DataMember] + [ProtoMember(2)] + public string StatusDescriptionCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/PercentageDetailsGroup.cs b/GroBuf.Tests/TestData/Invoic/PercentageDetailsGroup.cs similarity index 96% rename from GroBuf/Tests/TestData/Invoic/PercentageDetailsGroup.cs rename to GroBuf.Tests/TestData/Invoic/PercentageDetailsGroup.cs index 91de511..3e9a4cf 100644 --- a/GroBuf/Tests/TestData/Invoic/PercentageDetailsGroup.cs +++ b/GroBuf.Tests/TestData/Invoic/PercentageDetailsGroup.cs @@ -1,31 +1,31 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class PercentageDetailsGroup - { - [DataMember] - [ProtoMember(1)] - public string PercentageTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public string Percentage { get; set; } - - [DataMember] - [ProtoMember(3)] - public string PercentageBasisIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public string CodeListIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(5)] - public string CodeListResponsibleAgencyCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class PercentageDetailsGroup + { + [DataMember] + [ProtoMember(1)] + public string PercentageTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public string Percentage { get; set; } + + [DataMember] + [ProtoMember(3)] + public string PercentageBasisIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public string CodeListIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(5)] + public string CodeListResponsibleAgencyCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/Quantity.cs b/GroBuf.Tests/TestData/Invoic/Quantity.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/Quantity.cs rename to GroBuf.Tests/TestData/Invoic/Quantity.cs index fdcd1d1..9788dbf 100644 --- a/GroBuf/Tests/TestData/Invoic/Quantity.cs +++ b/GroBuf.Tests/TestData/Invoic/Quantity.cs @@ -1,15 +1,15 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class Quantity - { - [DataMember] - [ProtoMember(1)] - public QuantityDetails QuantityDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class Quantity + { + [DataMember] + [ProtoMember(1)] + public QuantityDetails QuantityDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/QuantityDetails.cs b/GroBuf.Tests/TestData/Invoic/QuantityDetails.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/QuantityDetails.cs rename to GroBuf.Tests/TestData/Invoic/QuantityDetails.cs index 1c338fc..447bc05 100644 --- a/GroBuf/Tests/TestData/Invoic/QuantityDetails.cs +++ b/GroBuf.Tests/TestData/Invoic/QuantityDetails.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class QuantityDetails - { - [DataMember] - [ProtoMember(1)] - public string QuantityTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public string Quantity { get; set; } - - [DataMember] - [ProtoMember(3)] - public string MeasurementUnitCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class QuantityDetails + { + [DataMember] + [ProtoMember(1)] + public string QuantityTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public string Quantity { get; set; } + + [DataMember] + [ProtoMember(3)] + public string MeasurementUnitCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/Range.cs b/GroBuf.Tests/TestData/Invoic/Range.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/Range.cs rename to GroBuf.Tests/TestData/Invoic/Range.cs index 2a2df03..7fda389 100644 --- a/GroBuf/Tests/TestData/Invoic/Range.cs +++ b/GroBuf.Tests/TestData/Invoic/Range.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class Range - { - [DataMember] - [ProtoMember(1)] - public string MeasurementUnitCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public string RangeMinimumValue { get; set; } - - [DataMember] - [ProtoMember(3)] - public string RangeMaximumValue { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class Range + { + [DataMember] + [ProtoMember(1)] + public string MeasurementUnitCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public string RangeMinimumValue { get; set; } + + [DataMember] + [ProtoMember(3)] + public string RangeMaximumValue { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/RangeDetails.cs b/GroBuf.Tests/TestData/Invoic/RangeDetails.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/RangeDetails.cs rename to GroBuf.Tests/TestData/Invoic/RangeDetails.cs index 0d1bfea..d6a283f 100644 --- a/GroBuf/Tests/TestData/Invoic/RangeDetails.cs +++ b/GroBuf.Tests/TestData/Invoic/RangeDetails.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class RangeDetails - { - [DataMember] - [ProtoMember(1)] - public string RangeTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public Range Range { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class RangeDetails + { + [DataMember] + [ProtoMember(1)] + public string RangeTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public Range Range { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/RateDetails.cs b/GroBuf.Tests/TestData/Invoic/RateDetails.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/RateDetails.cs rename to GroBuf.Tests/TestData/Invoic/RateDetails.cs index 82c87a4..0a0006e 100644 --- a/GroBuf/Tests/TestData/Invoic/RateDetails.cs +++ b/GroBuf.Tests/TestData/Invoic/RateDetails.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class RateDetails - { - [DataMember] - [ProtoMember(1)] - public RateDetailsGroup RateDetailsGroup { get; set; } - - [DataMember] - [ProtoMember(2)] - public string StatusDescriptionCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class RateDetails + { + [DataMember] + [ProtoMember(1)] + public RateDetailsGroup RateDetailsGroup { get; set; } + + [DataMember] + [ProtoMember(2)] + public string StatusDescriptionCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/RateDetailsGroup.cs b/GroBuf.Tests/TestData/Invoic/RateDetailsGroup.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/RateDetailsGroup.cs rename to GroBuf.Tests/TestData/Invoic/RateDetailsGroup.cs index 0d55e94..e7fb669 100644 --- a/GroBuf/Tests/TestData/Invoic/RateDetailsGroup.cs +++ b/GroBuf.Tests/TestData/Invoic/RateDetailsGroup.cs @@ -1,27 +1,27 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class RateDetailsGroup - { - [DataMember] - [ProtoMember(1)] - public string RateTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public string UnitPriceBasisRate { get; set; } - - [DataMember] - [ProtoMember(3)] - public string UnitPriceBasisValue { get; set; } - - [DataMember] - [ProtoMember(4)] - public string MeasurementUnitCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class RateDetailsGroup + { + [DataMember] + [ProtoMember(1)] + public string RateTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public string UnitPriceBasisRate { get; set; } + + [DataMember] + [ProtoMember(3)] + public string UnitPriceBasisValue { get; set; } + + [DataMember] + [ProtoMember(4)] + public string MeasurementUnitCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/SG44.cs b/GroBuf.Tests/TestData/Invoic/SG44.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/SG44.cs rename to GroBuf.Tests/TestData/Invoic/SG44.cs index beef491..e0dfdc8 100644 --- a/GroBuf/Tests/TestData/Invoic/SG44.cs +++ b/GroBuf.Tests/TestData/Invoic/SG44.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class SG44 - { - [DataMember] - [ProtoMember(1)] - public Quantity Quantity { get; set; } - - [DataMember] - [ProtoMember(2)] - public RangeDetails RangeDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class SG44 + { + [DataMember] + [ProtoMember(1)] + public Quantity Quantity { get; set; } + + [DataMember] + [ProtoMember(2)] + public RangeDetails RangeDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/SG45.cs b/GroBuf.Tests/TestData/Invoic/SG45.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/SG45.cs rename to GroBuf.Tests/TestData/Invoic/SG45.cs index 6657450..5f37d68 100644 --- a/GroBuf/Tests/TestData/Invoic/SG45.cs +++ b/GroBuf.Tests/TestData/Invoic/SG45.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class SG45 - { - [DataMember] - [ProtoMember(1)] - public PercentageDetails PercentageDetails { get; set; } - - [DataMember] - [ProtoMember(2)] - public RangeDetails RangeDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class SG45 + { + [DataMember] + [ProtoMember(1)] + public PercentageDetails PercentageDetails { get; set; } + + [DataMember] + [ProtoMember(2)] + public RangeDetails RangeDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/SG46.cs b/GroBuf.Tests/TestData/Invoic/SG46.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/SG46.cs rename to GroBuf.Tests/TestData/Invoic/SG46.cs index 2c547f4..1aa1c62 100644 --- a/GroBuf/Tests/TestData/Invoic/SG46.cs +++ b/GroBuf.Tests/TestData/Invoic/SG46.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class SG46 - { - [DataMember] - [ProtoMember(1)] - public MonetaryAmount MonetaryAmount { get; set; } - - [DataMember] - [ProtoMember(2)] - public RangeDetails RangeDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class SG46 + { + [DataMember] + [ProtoMember(1)] + public MonetaryAmount MonetaryAmount { get; set; } + + [DataMember] + [ProtoMember(2)] + public RangeDetails RangeDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/SG47.cs b/GroBuf.Tests/TestData/Invoic/SG47.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/SG47.cs rename to GroBuf.Tests/TestData/Invoic/SG47.cs index bd421f5..02485b5 100644 --- a/GroBuf/Tests/TestData/Invoic/SG47.cs +++ b/GroBuf.Tests/TestData/Invoic/SG47.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class SG47 - { - [DataMember] - [ProtoMember(1)] - public RateDetails RateDetails { get; set; } - - [DataMember] - [ProtoMember(2)] - public RangeDetails RangeDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class SG47 + { + [DataMember] + [ProtoMember(1)] + public RateDetails RateDetails { get; set; } + + [DataMember] + [ProtoMember(2)] + public RangeDetails RangeDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/SG48.cs b/GroBuf.Tests/TestData/Invoic/SG48.cs similarity index 95% rename from GroBuf/Tests/TestData/Invoic/SG48.cs rename to GroBuf.Tests/TestData/Invoic/SG48.cs index 3bce783..2a1c513 100644 --- a/GroBuf/Tests/TestData/Invoic/SG48.cs +++ b/GroBuf.Tests/TestData/Invoic/SG48.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class SG48 - { - [DataMember] - [ProtoMember(1)] - public DutyTaxFeeDetails DutyTaxFeeDetails { get; set; } - - [DataMember] - [ProtoMember(2)] - public MonetaryAmount MonetaryAmount { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class SG48 + { + [DataMember] + [ProtoMember(1)] + public DutyTaxFeeDetails DutyTaxFeeDetails { get; set; } + + [DataMember] + [ProtoMember(2)] + public MonetaryAmount MonetaryAmount { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Invoic/SpecialServicesIdentification.cs b/GroBuf.Tests/TestData/Invoic/SpecialServicesIdentification.cs similarity index 96% rename from GroBuf/Tests/TestData/Invoic/SpecialServicesIdentification.cs rename to GroBuf.Tests/TestData/Invoic/SpecialServicesIdentification.cs index 7e54862..88c083a 100644 --- a/GroBuf/Tests/TestData/Invoic/SpecialServicesIdentification.cs +++ b/GroBuf.Tests/TestData/Invoic/SpecialServicesIdentification.cs @@ -1,27 +1,27 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Invoic -{ - [DataContract] - [ProtoContract] - public class SpecialServicesIdentification - { - [DataMember] - [ProtoMember(1)] - public string SpecialServiceDescriptionCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public string CodeListIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(3)] - public string CodeListResponsibleAgencyCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public string[] SpecialServiceDescription { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Invoic +{ + [DataContract] + [ProtoContract] + public class SpecialServicesIdentification + { + [DataMember] + [ProtoMember(1)] + public string SpecialServiceDescriptionCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public string CodeListIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(3)] + public string CodeListResponsibleAgencyCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public string[] SpecialServiceDescription { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/AdditionalInformation.cs b/GroBuf.Tests/TestData/Orders/AdditionalInformation.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/AdditionalInformation.cs rename to GroBuf.Tests/TestData/Orders/AdditionalInformation.cs index f2d92fc..5165bf4 100644 --- a/GroBuf/Tests/TestData/Orders/AdditionalInformation.cs +++ b/GroBuf.Tests/TestData/Orders/AdditionalInformation.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class AdditionalInformation - { - [DataMember] - [ProtoMember(1)] - public int? CountryOfOriginNameCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public sbyte DutyRegimeTypeCode { get; set; } - - [DataMember] - [ProtoMember(3)] - public string[] SpecialConditionCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class AdditionalInformation + { + [DataMember] + [ProtoMember(1)] + public int? CountryOfOriginNameCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public sbyte DutyRegimeTypeCode { get; set; } + + [DataMember] + [ProtoMember(3)] + public string[] SpecialConditionCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/AllowanceChargeInformation.cs b/GroBuf.Tests/TestData/Orders/AllowanceChargeInformation.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/AllowanceChargeInformation.cs rename to GroBuf.Tests/TestData/Orders/AllowanceChargeInformation.cs index 4ad1011..4613da5 100644 --- a/GroBuf/Tests/TestData/Orders/AllowanceChargeInformation.cs +++ b/GroBuf.Tests/TestData/Orders/AllowanceChargeInformation.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class AllowanceChargeInformation - { - [DataMember] - [ProtoMember(1)] - public uint AllowanceOrChargeIdentifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public string AllowanceOrChargeIdentificationCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class AllowanceChargeInformation + { + [DataMember] + [ProtoMember(1)] + public uint AllowanceOrChargeIdentifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public string AllowanceOrChargeIdentificationCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/AllowanceOrCharge.cs b/GroBuf.Tests/TestData/Orders/AllowanceOrCharge.cs similarity index 96% rename from GroBuf/Tests/TestData/Orders/AllowanceOrCharge.cs rename to GroBuf.Tests/TestData/Orders/AllowanceOrCharge.cs index 1f6863f..8d0f9fa 100644 --- a/GroBuf/Tests/TestData/Orders/AllowanceOrCharge.cs +++ b/GroBuf.Tests/TestData/Orders/AllowanceOrCharge.cs @@ -1,31 +1,31 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class AllowanceOrCharge - { - [DataMember] - [ProtoMember(1)] - public byte AllowanceOrChargeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public AllowanceChargeInformation AllowanceChargeInformation { get; set; } - - [DataMember] - [ProtoMember(3)] - public short SettlementMeansCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public ushort CalculationSequenceCode { get; set; } - - [DataMember] - [ProtoMember(5)] - public SpecialServicesIdentification SpecialServicesIdentification { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class AllowanceOrCharge + { + [DataMember] + [ProtoMember(1)] + public byte AllowanceOrChargeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public AllowanceChargeInformation AllowanceChargeInformation { get; set; } + + [DataMember] + [ProtoMember(3)] + public short SettlementMeansCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public ushort CalculationSequenceCode { get; set; } + + [DataMember] + [ProtoMember(5)] + public SpecialServicesIdentification SpecialServicesIdentification { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/DateTimePeriod.cs b/GroBuf.Tests/TestData/Orders/DateTimePeriod.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/DateTimePeriod.cs rename to GroBuf.Tests/TestData/Orders/DateTimePeriod.cs index ff5ca5e..3668401 100644 --- a/GroBuf/Tests/TestData/Orders/DateTimePeriod.cs +++ b/GroBuf.Tests/TestData/Orders/DateTimePeriod.cs @@ -1,15 +1,15 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class DateTimePeriod - { - [DataMember] - [ProtoMember(1)] - public DateTimePeriodGroup DateTimePeriodGroup { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class DateTimePeriod + { + [DataMember] + [ProtoMember(1)] + public DateTimePeriodGroup DateTimePeriodGroup { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/DateTimePeriodGroup.cs b/GroBuf.Tests/TestData/Orders/DateTimePeriodGroup.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/DateTimePeriodGroup.cs rename to GroBuf.Tests/TestData/Orders/DateTimePeriodGroup.cs index 921db84..2d16c1b 100644 --- a/GroBuf/Tests/TestData/Orders/DateTimePeriodGroup.cs +++ b/GroBuf.Tests/TestData/Orders/DateTimePeriodGroup.cs @@ -1,24 +1,24 @@ -using System; -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class DateTimePeriodGroup - { - [DataMember] - [ProtoMember(1)] - public sbyte? FunctionCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public DateTime Value { get; set; } - - [DataMember] - [ProtoMember(3)] - public byte? FormatCode { get; set; } - } +using System; +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class DateTimePeriodGroup + { + [DataMember] + [ProtoMember(1)] + public sbyte? FunctionCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public DateTime Value { get; set; } + + [DataMember] + [ProtoMember(3)] + public byte? FormatCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/DutyTaxFeeAccountDetail.cs b/GroBuf.Tests/TestData/Orders/DutyTaxFeeAccountDetail.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/DutyTaxFeeAccountDetail.cs rename to GroBuf.Tests/TestData/Orders/DutyTaxFeeAccountDetail.cs index 50affb4..7869a28 100644 --- a/GroBuf/Tests/TestData/Orders/DutyTaxFeeAccountDetail.cs +++ b/GroBuf.Tests/TestData/Orders/DutyTaxFeeAccountDetail.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class DutyTaxFeeAccountDetail - { - [DataMember] - [ProtoMember(1)] - public short? DutyTaxFeeAccountCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public ushort? CodeListIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(3)] - public char CodeListResponsibleAgencyCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class DutyTaxFeeAccountDetail + { + [DataMember] + [ProtoMember(1)] + public short? DutyTaxFeeAccountCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public ushort? CodeListIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(3)] + public char CodeListResponsibleAgencyCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/DutyTaxFeeDetail.cs b/GroBuf.Tests/TestData/Orders/DutyTaxFeeDetail.cs similarity index 96% rename from GroBuf/Tests/TestData/Orders/DutyTaxFeeDetail.cs rename to GroBuf.Tests/TestData/Orders/DutyTaxFeeDetail.cs index 287c02f..4cce4de 100644 --- a/GroBuf/Tests/TestData/Orders/DutyTaxFeeDetail.cs +++ b/GroBuf.Tests/TestData/Orders/DutyTaxFeeDetail.cs @@ -1,39 +1,39 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class DutyTaxFeeDetail - { - [DataMember] - [ProtoMember(1)] - public char? DutyTaxFeeRateCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public int?[] CodeListIdentificationCode1 { get; set; } - - [DataMember] - [ProtoMember(3)] - public uint? CodeListResponsibleAgencyCode1 { get; set; } - - [DataMember] - [ProtoMember(4)] - public long? DutyTaxFeeRate { get; set; } - - [DataMember] - [ProtoMember(5)] - public ulong DutyTaxFeeRateBasisCode { get; set; } - - [DataMember] - [ProtoMember(6)] - public long CodeListIdentificationCode2 { get; set; } - - [DataMember] - [ProtoMember(7)] - public ulong? CodeListResponsibleAgencyCode2 { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class DutyTaxFeeDetail + { + [DataMember] + [ProtoMember(1)] + public char? DutyTaxFeeRateCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public int?[] CodeListIdentificationCode1 { get; set; } + + [DataMember] + [ProtoMember(3)] + public uint? CodeListResponsibleAgencyCode1 { get; set; } + + [DataMember] + [ProtoMember(4)] + public long? DutyTaxFeeRate { get; set; } + + [DataMember] + [ProtoMember(5)] + public ulong DutyTaxFeeRateBasisCode { get; set; } + + [DataMember] + [ProtoMember(6)] + public long CodeListIdentificationCode2 { get; set; } + + [DataMember] + [ProtoMember(7)] + public ulong? CodeListResponsibleAgencyCode2 { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/DutyTaxFeeDetails.cs b/GroBuf.Tests/TestData/Orders/DutyTaxFeeDetails.cs similarity index 96% rename from GroBuf/Tests/TestData/Orders/DutyTaxFeeDetails.cs rename to GroBuf.Tests/TestData/Orders/DutyTaxFeeDetails.cs index 12eccda..2ea008b 100644 --- a/GroBuf/Tests/TestData/Orders/DutyTaxFeeDetails.cs +++ b/GroBuf.Tests/TestData/Orders/DutyTaxFeeDetails.cs @@ -1,43 +1,43 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class DutyTaxFeeDetails - { - [DataMember] - [ProtoMember(1)] - public int[] DutyTaxFeeFunctionCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public DutyTaxFeeType DutyTaxFeeType { get; set; } - - [DataMember] - [ProtoMember(3)] - public DutyTaxFeeAccountDetail DutyTaxFeeAccountDetail { get; set; } - - [DataMember] - [ProtoMember(4)] - public ulong?[] DutyTaxFeeAssessmentBasisValue { get; set; } - - [DataMember] - [ProtoMember(5)] - public DutyTaxFeeDetail DutyTaxFeeDetail { get; set; } - - [DataMember] - [ProtoMember(6)] - public byte[] DutyTaxFeeCategoryCode { get; set; } - - [DataMember] - [ProtoMember(7)] - public sbyte[] PartyTaxIdentifier { get; set; } - - [DataMember] - [ProtoMember(8)] - public sbyte?[] CalculationSequenceCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class DutyTaxFeeDetails + { + [DataMember] + [ProtoMember(1)] + public int[] DutyTaxFeeFunctionCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public DutyTaxFeeType DutyTaxFeeType { get; set; } + + [DataMember] + [ProtoMember(3)] + public DutyTaxFeeAccountDetail DutyTaxFeeAccountDetail { get; set; } + + [DataMember] + [ProtoMember(4)] + public ulong?[] DutyTaxFeeAssessmentBasisValue { get; set; } + + [DataMember] + [ProtoMember(5)] + public DutyTaxFeeDetail DutyTaxFeeDetail { get; set; } + + [DataMember] + [ProtoMember(6)] + public byte[] DutyTaxFeeCategoryCode { get; set; } + + [DataMember] + [ProtoMember(7)] + public sbyte[] PartyTaxIdentifier { get; set; } + + [DataMember] + [ProtoMember(8)] + public sbyte?[] CalculationSequenceCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/DutyTaxFeeType.cs b/GroBuf.Tests/TestData/Orders/DutyTaxFeeType.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/DutyTaxFeeType.cs rename to GroBuf.Tests/TestData/Orders/DutyTaxFeeType.cs index 694c906..ced66f4 100644 --- a/GroBuf/Tests/TestData/Orders/DutyTaxFeeType.cs +++ b/GroBuf.Tests/TestData/Orders/DutyTaxFeeType.cs @@ -1,27 +1,27 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class DutyTaxFeeType - { - [DataMember] - [ProtoMember(1)] - public byte?[] DutyTaxFeeTypeNameCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public long[] CodeListIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(3)] - public ulong[] CodeListResponsibleAgencyCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public ushort?[] DutyTaxFeeTypeName { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class DutyTaxFeeType + { + [DataMember] + [ProtoMember(1)] + public byte?[] DutyTaxFeeTypeNameCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public long[] CodeListIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(3)] + public ulong[] CodeListResponsibleAgencyCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public ushort?[] DutyTaxFeeTypeName { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/MonetaryAmount.cs b/GroBuf.Tests/TestData/Orders/MonetaryAmount.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/MonetaryAmount.cs rename to GroBuf.Tests/TestData/Orders/MonetaryAmount.cs index f241654..124f427 100644 --- a/GroBuf/Tests/TestData/Orders/MonetaryAmount.cs +++ b/GroBuf.Tests/TestData/Orders/MonetaryAmount.cs @@ -1,15 +1,15 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class MonetaryAmount - { - [DataMember] - [ProtoMember(1)] - public MonetaryAmountGroup MonetaryAmountGroup { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class MonetaryAmount + { + [DataMember] + [ProtoMember(1)] + public MonetaryAmountGroup MonetaryAmountGroup { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/MonetaryAmountGroup.cs b/GroBuf.Tests/TestData/Orders/MonetaryAmountGroup.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/MonetaryAmountGroup.cs rename to GroBuf.Tests/TestData/Orders/MonetaryAmountGroup.cs index 1a34c04..4e638d3 100644 --- a/GroBuf/Tests/TestData/Orders/MonetaryAmountGroup.cs +++ b/GroBuf.Tests/TestData/Orders/MonetaryAmountGroup.cs @@ -1,32 +1,32 @@ -using System; -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class MonetaryAmountGroup - { - [DataMember] - [ProtoMember(1)] - public char[] MonetaryAmountTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public char?[] MonetaryAmount { get; set; } - - [DataMember] - [ProtoMember(3)] - public uint?[] CurrencyIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public long?[] CurrencyTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(5)] - public DateTime?[] StatusDescriptionCode { get; set; } - } +using System; +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class MonetaryAmountGroup + { + [DataMember] + [ProtoMember(1)] + public char[] MonetaryAmountTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public char?[] MonetaryAmount { get; set; } + + [DataMember] + [ProtoMember(3)] + public uint?[] CurrencyIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public long?[] CurrencyTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(5)] + public DateTime?[] StatusDescriptionCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/Orders.cs b/GroBuf.Tests/TestData/Orders/Orders.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/Orders.cs rename to GroBuf.Tests/TestData/Orders/Orders.cs index b7e57e9..8191eb9 100644 --- a/GroBuf/Tests/TestData/Orders/Orders.cs +++ b/GroBuf.Tests/TestData/Orders/Orders.cs @@ -1,43 +1,43 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class Orders - { - [DataMember] - [ProtoMember(1)] - public AllowanceOrCharge AllowanceOrCharge { get; set; } - - [DataMember] - [ProtoMember(2)] - public AdditionalInformation[] AdditionalInformation { get; set; } - - [DataMember] - [ProtoMember(3)] - public DateTimePeriod[] DateTimePeriod { get; set; } - - [DataMember] - [ProtoMember(4)] - public SG44 SG44 { get; set; } - - [DataMember] - [ProtoMember(5)] - public SG45 SG45 { get; set; } - - [DataMember] - [ProtoMember(6)] - public SG46[] SG46 { get; set; } - - [DataMember] - [ProtoMember(7)] - public SG47 SG47 { get; set; } - - [DataMember] - [ProtoMember(8)] - public SG48[] SG48 { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class Orders + { + [DataMember] + [ProtoMember(1)] + public AllowanceOrCharge AllowanceOrCharge { get; set; } + + [DataMember] + [ProtoMember(2)] + public AdditionalInformation[] AdditionalInformation { get; set; } + + [DataMember] + [ProtoMember(3)] + public DateTimePeriod[] DateTimePeriod { get; set; } + + [DataMember] + [ProtoMember(4)] + public SG44 SG44 { get; set; } + + [DataMember] + [ProtoMember(5)] + public SG45 SG45 { get; set; } + + [DataMember] + [ProtoMember(6)] + public SG46[] SG46 { get; set; } + + [DataMember] + [ProtoMember(7)] + public SG47 SG47 { get; set; } + + [DataMember] + [ProtoMember(8)] + public SG48[] SG48 { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/PercentageDetails.cs b/GroBuf.Tests/TestData/Orders/PercentageDetails.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/PercentageDetails.cs rename to GroBuf.Tests/TestData/Orders/PercentageDetails.cs index 3a8b53f..9c1ee96 100644 --- a/GroBuf/Tests/TestData/Orders/PercentageDetails.cs +++ b/GroBuf.Tests/TestData/Orders/PercentageDetails.cs @@ -1,20 +1,20 @@ -using System; -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class PercentageDetails - { - [DataMember] - [ProtoMember(1)] - public PercentageDetailsGroup PercentageDetailsGroup { get; set; } - - [DataMember] - [ProtoMember(2)] - public DateTime[] StatusDescriptionCode { get; set; } - } +using System; +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class PercentageDetails + { + [DataMember] + [ProtoMember(1)] + public PercentageDetailsGroup PercentageDetailsGroup { get; set; } + + [DataMember] + [ProtoMember(2)] + public DateTime[] StatusDescriptionCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/PercentageDetailsGroup.cs b/GroBuf.Tests/TestData/Orders/PercentageDetailsGroup.cs similarity index 96% rename from GroBuf/Tests/TestData/Orders/PercentageDetailsGroup.cs rename to GroBuf.Tests/TestData/Orders/PercentageDetailsGroup.cs index 149e09e..2e5045f 100644 --- a/GroBuf/Tests/TestData/Orders/PercentageDetailsGroup.cs +++ b/GroBuf.Tests/TestData/Orders/PercentageDetailsGroup.cs @@ -1,32 +1,32 @@ -using System; -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class PercentageDetailsGroup - { - [DataMember] - [ProtoMember(1)] - public uint[] PercentageTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public DateTime? Percentage { get; set; } - - [DataMember] - [ProtoMember(3)] - public float PercentageBasisIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public float? CodeListIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(5)] - public string CodeListResponsibleAgencyCode { get; set; } - } +using System; +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class PercentageDetailsGroup + { + [DataMember] + [ProtoMember(1)] + public uint[] PercentageTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public DateTime? Percentage { get; set; } + + [DataMember] + [ProtoMember(3)] + public float PercentageBasisIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public float? CodeListIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(5)] + public string CodeListResponsibleAgencyCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/Quantity.cs b/GroBuf.Tests/TestData/Orders/Quantity.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/Quantity.cs rename to GroBuf.Tests/TestData/Orders/Quantity.cs index 411be20..66147f4 100644 --- a/GroBuf/Tests/TestData/Orders/Quantity.cs +++ b/GroBuf.Tests/TestData/Orders/Quantity.cs @@ -1,15 +1,15 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class Quantity - { - [DataMember] - [ProtoMember(1)] - public QuantityDetails QuantityDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class Quantity + { + [DataMember] + [ProtoMember(1)] + public QuantityDetails QuantityDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/QuantityDetails.cs b/GroBuf.Tests/TestData/Orders/QuantityDetails.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/QuantityDetails.cs rename to GroBuf.Tests/TestData/Orders/QuantityDetails.cs index 5da754d..77b3de3 100644 --- a/GroBuf/Tests/TestData/Orders/QuantityDetails.cs +++ b/GroBuf.Tests/TestData/Orders/QuantityDetails.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class QuantityDetails - { - [DataMember] - [ProtoMember(1)] - public double? QuantityTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public float[] Quantity { get; set; } - - [DataMember] - [ProtoMember(3)] - public float? MeasurementUnitCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class QuantityDetails + { + [DataMember] + [ProtoMember(1)] + public double? QuantityTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public float[] Quantity { get; set; } + + [DataMember] + [ProtoMember(3)] + public float? MeasurementUnitCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/Range.cs b/GroBuf.Tests/TestData/Orders/Range.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/Range.cs rename to GroBuf.Tests/TestData/Orders/Range.cs index 899e37d..9a1a4bd 100644 --- a/GroBuf/Tests/TestData/Orders/Range.cs +++ b/GroBuf.Tests/TestData/Orders/Range.cs @@ -1,23 +1,23 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class Range - { - [DataMember] - [ProtoMember(1)] - public double[] MeasurementUnitCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public double?[] RangeMinimumValue { get; set; } - - [DataMember] - [ProtoMember(3)] - public float RangeMaximumValue { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class Range + { + [DataMember] + [ProtoMember(1)] + public double[] MeasurementUnitCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public double?[] RangeMinimumValue { get; set; } + + [DataMember] + [ProtoMember(3)] + public float RangeMaximumValue { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/RangeDetails.cs b/GroBuf.Tests/TestData/Orders/RangeDetails.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/RangeDetails.cs rename to GroBuf.Tests/TestData/Orders/RangeDetails.cs index f876a0b..8a4e9ba 100644 --- a/GroBuf/Tests/TestData/Orders/RangeDetails.cs +++ b/GroBuf.Tests/TestData/Orders/RangeDetails.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class RangeDetails - { - [DataMember] - [ProtoMember(1)] - public short[] RangeTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public Range Range { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class RangeDetails + { + [DataMember] + [ProtoMember(1)] + public short[] RangeTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public Range Range { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/RateDetails.cs b/GroBuf.Tests/TestData/Orders/RateDetails.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/RateDetails.cs rename to GroBuf.Tests/TestData/Orders/RateDetails.cs index b64c121..820edf6 100644 --- a/GroBuf/Tests/TestData/Orders/RateDetails.cs +++ b/GroBuf.Tests/TestData/Orders/RateDetails.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class RateDetails - { - [DataMember] - [ProtoMember(1)] - public RateDetailsGroup RateDetailsGroup { get; set; } - - [DataMember] - [ProtoMember(2)] - public double StatusDescriptionCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class RateDetails + { + [DataMember] + [ProtoMember(1)] + public RateDetailsGroup RateDetailsGroup { get; set; } + + [DataMember] + [ProtoMember(2)] + public double StatusDescriptionCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/RateDetailsGroup.cs b/GroBuf.Tests/TestData/Orders/RateDetailsGroup.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/RateDetailsGroup.cs rename to GroBuf.Tests/TestData/Orders/RateDetailsGroup.cs index cb23c5f..c68c740 100644 --- a/GroBuf/Tests/TestData/Orders/RateDetailsGroup.cs +++ b/GroBuf.Tests/TestData/Orders/RateDetailsGroup.cs @@ -1,27 +1,27 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class RateDetailsGroup - { - [DataMember] - [ProtoMember(1)] - public bool RateTypeCodeQualifier { get; set; } - - [DataMember] - [ProtoMember(2)] - public float?[] UnitPriceBasisRate { get; set; } - - [DataMember] - [ProtoMember(3)] - public ushort[] UnitPriceBasisValue { get; set; } - - [DataMember] - [ProtoMember(4)] - public short?[] MeasurementUnitCode { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class RateDetailsGroup + { + [DataMember] + [ProtoMember(1)] + public bool RateTypeCodeQualifier { get; set; } + + [DataMember] + [ProtoMember(2)] + public float?[] UnitPriceBasisRate { get; set; } + + [DataMember] + [ProtoMember(3)] + public ushort[] UnitPriceBasisValue { get; set; } + + [DataMember] + [ProtoMember(4)] + public short?[] MeasurementUnitCode { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/SG44.cs b/GroBuf.Tests/TestData/Orders/SG44.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/SG44.cs rename to GroBuf.Tests/TestData/Orders/SG44.cs index 8493830..5a1136f 100644 --- a/GroBuf/Tests/TestData/Orders/SG44.cs +++ b/GroBuf.Tests/TestData/Orders/SG44.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class SG44 - { - [DataMember] - [ProtoMember(1)] - public Quantity Quantity { get; set; } - - [DataMember] - [ProtoMember(2)] - public RangeDetails RangeDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class SG44 + { + [DataMember] + [ProtoMember(1)] + public Quantity Quantity { get; set; } + + [DataMember] + [ProtoMember(2)] + public RangeDetails RangeDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/SG45.cs b/GroBuf.Tests/TestData/Orders/SG45.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/SG45.cs rename to GroBuf.Tests/TestData/Orders/SG45.cs index 1c3d453..ca98d5e 100644 --- a/GroBuf/Tests/TestData/Orders/SG45.cs +++ b/GroBuf.Tests/TestData/Orders/SG45.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class SG45 - { - [DataMember] - [ProtoMember(1)] - public PercentageDetails PercentageDetails { get; set; } - - [DataMember] - [ProtoMember(2)] - public RangeDetails RangeDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class SG45 + { + [DataMember] + [ProtoMember(1)] + public PercentageDetails PercentageDetails { get; set; } + + [DataMember] + [ProtoMember(2)] + public RangeDetails RangeDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/SG46.cs b/GroBuf.Tests/TestData/Orders/SG46.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/SG46.cs rename to GroBuf.Tests/TestData/Orders/SG46.cs index a261060..dab832e 100644 --- a/GroBuf/Tests/TestData/Orders/SG46.cs +++ b/GroBuf.Tests/TestData/Orders/SG46.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class SG46 - { - [DataMember] - [ProtoMember(1)] - public MonetaryAmount MonetaryAmount { get; set; } - - [DataMember] - [ProtoMember(2)] - public RangeDetails RangeDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class SG46 + { + [DataMember] + [ProtoMember(1)] + public MonetaryAmount MonetaryAmount { get; set; } + + [DataMember] + [ProtoMember(2)] + public RangeDetails RangeDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/SG47.cs b/GroBuf.Tests/TestData/Orders/SG47.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/SG47.cs rename to GroBuf.Tests/TestData/Orders/SG47.cs index 4f46cd7..654da8c 100644 --- a/GroBuf/Tests/TestData/Orders/SG47.cs +++ b/GroBuf.Tests/TestData/Orders/SG47.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class SG47 - { - [DataMember] - [ProtoMember(1)] - public RateDetails RateDetails { get; set; } - - [DataMember] - [ProtoMember(2)] - public RangeDetails RangeDetails { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class SG47 + { + [DataMember] + [ProtoMember(1)] + public RateDetails RateDetails { get; set; } + + [DataMember] + [ProtoMember(2)] + public RangeDetails RangeDetails { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/SG48.cs b/GroBuf.Tests/TestData/Orders/SG48.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/SG48.cs rename to GroBuf.Tests/TestData/Orders/SG48.cs index 2f23ebb..7c9d92b 100644 --- a/GroBuf/Tests/TestData/Orders/SG48.cs +++ b/GroBuf.Tests/TestData/Orders/SG48.cs @@ -1,19 +1,19 @@ -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class SG48 - { - [DataMember] - [ProtoMember(1)] - public DutyTaxFeeDetails DutyTaxFeeDetails { get; set; } - - [DataMember] - [ProtoMember(2)] - public MonetaryAmount MonetaryAmount { get; set; } - } +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class SG48 + { + [DataMember] + [ProtoMember(1)] + public DutyTaxFeeDetails DutyTaxFeeDetails { get; set; } + + [DataMember] + [ProtoMember(2)] + public MonetaryAmount MonetaryAmount { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestData/Orders/SpecialServicesIdentification.cs b/GroBuf.Tests/TestData/Orders/SpecialServicesIdentification.cs similarity index 95% rename from GroBuf/Tests/TestData/Orders/SpecialServicesIdentification.cs rename to GroBuf.Tests/TestData/Orders/SpecialServicesIdentification.cs index 2076412..a089213 100644 --- a/GroBuf/Tests/TestData/Orders/SpecialServicesIdentification.cs +++ b/GroBuf.Tests/TestData/Orders/SpecialServicesIdentification.cs @@ -1,44 +1,44 @@ -using System; -using System.Runtime.Serialization; - -using ProtoBuf; - -namespace GroBuf.Tests.TestData.Orders -{ - [DataContract] - [ProtoContract] - public class SpecialServicesIdentification - { - [DataMember] - [ProtoMember(1)] - public bool[] SpecialServiceDescriptionCode { get; set; } - - [DataMember] - [ProtoMember(2)] - public sbyte CodeListIdentificationCode { get; set; } - - [DataMember] - [ProtoMember(3)] - public bool? CodeListResponsibleAgencyCode { get; set; } - - [DataMember] - [ProtoMember(4)] - public bool?[] SpecialServiceDescription { get; set; } - - [DataMember] - [ProtoMember(5)] - public Guid Id { get; set; } - - [DataMember] - [ProtoMember(6)] - public Guid[] ChildrenIds { get; set; } - - [DataMember] - [ProtoMember(7)] - public Guid? ParentId { get; set; } - - [DataMember] - [ProtoMember(8)] - public Guid?[] ParentChildrenIds { get; set; } - } +using System; +using System.Runtime.Serialization; + +using ProtoBuf; + +namespace GroBuf.Tests.TestData.Orders +{ + [DataContract] + [ProtoContract] + public class SpecialServicesIdentification + { + [DataMember] + [ProtoMember(1)] + public bool[] SpecialServiceDescriptionCode { get; set; } + + [DataMember] + [ProtoMember(2)] + public sbyte CodeListIdentificationCode { get; set; } + + [DataMember] + [ProtoMember(3)] + public bool? CodeListResponsibleAgencyCode { get; set; } + + [DataMember] + [ProtoMember(4)] + public bool?[] SpecialServiceDescription { get; set; } + + [DataMember] + [ProtoMember(5)] + public Guid Id { get; set; } + + [DataMember] + [ProtoMember(6)] + public Guid[] ChildrenIds { get; set; } + + [DataMember] + [ProtoMember(7)] + public Guid? ParentId { get; set; } + + [DataMember] + [ProtoMember(8)] + public Guid?[] ParentChildrenIds { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestDataMembersWithCustomName.cs b/GroBuf.Tests/TestDataMembersWithCustomName.cs similarity index 96% rename from GroBuf/Tests/TestDataMembersWithCustomName.cs rename to GroBuf.Tests/TestDataMembersWithCustomName.cs index 968a17f..2ddd30a 100644 --- a/GroBuf/Tests/TestDataMembersWithCustomName.cs +++ b/GroBuf.Tests/TestDataMembersWithCustomName.cs @@ -1,39 +1,39 @@ -using System.Runtime.Serialization; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestDataMembersWithCustomName - { - [Test] - public void Test() - { - var serializer = new Serializer(new DataMembersByAttributeExtractor(false)); - var a = new TestClassA {S = "zzz", X = 5}; - var data = serializer.Serialize(a); - var b = serializer.Deserialize(data); - Assert.AreEqual("zzz", b.T); - Assert.AreEqual(5, b.Y); - } - - public class TestClassA - { - public string S { get; set; } - - [DataMember(Name = "Y")] - public int X { get; set; } - } - - public class TestClassB - { - [DataMember(Name = "S")] - public string T { get; set; } - - public int Y { get; set; } - } - } +using System.Runtime.Serialization; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestDataMembersWithCustomName + { + [Test] + public void Test() + { + var serializer = new Serializer(new DataMembersByAttributeExtractor(false)); + var a = new TestClassA {S = "zzz", X = 5}; + var data = serializer.Serialize(a); + var b = serializer.Deserialize(data); + Assert.AreEqual("zzz", b.T); + Assert.AreEqual(5, b.Y); + } + + public class TestClassA + { + public string S { get; set; } + + [DataMember(Name = "Y")] + public int X { get; set; } + } + + public class TestClassB + { + [DataMember(Name = "S")] + public string T { get; set; } + + public int Y { get; set; } + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestDateTime.cs b/GroBuf.Tests/TestDateTime.cs similarity index 61% rename from GroBuf/Tests/TestDateTime.cs rename to GroBuf.Tests/TestDateTime.cs index c6dde4f..7a2c15f 100644 --- a/GroBuf/Tests/TestDateTime.cs +++ b/GroBuf.Tests/TestDateTime.cs @@ -1,185 +1,130 @@ -using System; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestDateTime - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - -// public enum TaskState -// { -// Unknown = 0, -// -// New, -// -// WaitingForRerun, -// -// WaitingForRerunAfterError, -// -// Finished, -// -// InProcess, -// -// Fatal, -// -// Canceled, -// } -// -// public class TaskMetaInformation -// { -// public override string ToString() -// { -// return string.Format("Name: {0}, Id: {1}, Attempts: {2}, ParentTaskId: {3}", Name, Id, Attempts, ParentTaskId); -// } -// -// public string Name { get; set; } -// public string Id { get; set; } -// public long Ticks { get; set; } -// -// //[Indexed] -// public long MinimalStartTicks { get; set; } -// //[Indexed] -// public long? StartExecutingTicks { get; set; } -// //[Indexed] -// public TaskState State { get; set; } -// //[Indexed] -// public int Attempts { get; set; } -// //[Indexed] -// public string ParentTaskId { get; set; } -// } -// -// [Test] -// public void Test() -// { -// var bytes = Convert.FromBase64String("AcYAAAD0Zlbntp8ivA4kAAAAUwB0AGEAcgB0AEMAaABlAGMAawBQAGEAYwBrAFQAYQBzAGsAUt22K2BnLl8OSAAAADAAYwBlADIAMwBmADAAOAAtADkANgA3AGMALQA0AGYAOQBkAC0AOQA2ADEAMAAtADQANAAwADUAYQAzAGUAMQA2AGYANwAxAKmp6gI2dO8BCeRQWdO72M8IzsUB5ibZfjkJ5VBZ07vYzwhoFV/g/66KdhAk+/Hk+IRuEE/gBJLjUzaiBwAAAAA="); -//// unsafe -//// { -//// fixed(byte* b = &bytes[0]) -//// { -//// //sbyte* sb = (sbyte*)b; -//// //Console.WriteLine(new string(sb, 67, 72, Encoding.Unicode)); -//// } -//// } -//// Console.WriteLine(BitConverter.ToUInt64(bytes, 190)); -// var meta = serializer.Deserialize(bytes); -// var hashes = GroBufHelpers.CalcHashAndCheck(new PropertiesExtractor().GetMembers(typeof(TaskMetaInformation)).Select(member => member.Name)); -// foreach(var hash in hashes) -// Console.WriteLine((ulong)hash); -// -// Console.WriteLine(meta); -// } - - [Test] - public void TestUtc() - { - var o = new DateTime(12735641765, DateTimeKind.Utc); - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(DateTimeKind.Utc, oo.Kind); - Assert.AreEqual(12735641765, oo.Ticks); - } - - [Test] - public void TestLong() - { - var o = 12735641765; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(DateTimeKind.Utc, oo.Kind); - Assert.AreEqual(12735641765, oo.Ticks); - } - - [Test] - public void TestLong2() - { - var data = serializer.Serialize(long.MinValue); - Assert.Throws(() => serializer.Deserialize(data)); - } - - [Test] - public void TestLocal() - { - var o = new DateTime(12735641765, DateTimeKind.Local); - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(DateTimeKind.Local, oo.Kind); - Assert.AreEqual(12735641765, oo.Ticks); - } - - [Test] - public void TestLocalOldFormat() - { - var data = new byte[10]; - data[0] = (byte)GroBufTypeCode.DateTimeOld; - Array.Copy(BitConverter.GetBytes(1234567891234 | long.MinValue), 0, data, 1, 8); - data[9] = (byte)DateTimeKind.Local; - var o = serializer.Deserialize(data); - Assert.AreEqual(DateTimeKind.Local, o.Kind); - Assert.AreEqual(1234567891234, o.Ticks); - } - - [Test] - public void TestUnspecified() - { - var o = new DateTime(12735641765, DateTimeKind.Unspecified); - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(DateTimeKind.Unspecified, oo.Kind); - Assert.AreEqual(12735641765, oo.Ticks); - } - - [Test] - public void TestSkipDateTimeLocal() - { - var o = new TestClassA {S = "zzz", DateTime = new DateTime(12387401892734, DateTimeKind.Local), Z = "qxx"}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.S); - Assert.AreEqual("qxx", oo.Z); - } - - [Test] - public void TestSkipDateTimeUtc() - { - var o = new TestClassA {S = "zzz", DateTime = new DateTime(12387401892734, DateTimeKind.Utc), Z = "qxx"}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.S); - Assert.AreEqual("qxx", oo.Z); - } - - [Test] - public void TestSkipDateTimeUnspecified() - { - var o = new TestClassA {S = "zzz", DateTime = new DateTime(12387401892734, DateTimeKind.Unspecified), Z = "qxx"}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.S); - Assert.AreEqual("qxx", oo.Z); - } - - public class TestClassA - { - public string S { get; set; } - public DateTime DateTime { get; set; } - public string Z { get; set; } - } - - public class TestClassB - { - public string S { get; set; } - public string Z { get; set; } - } - - private Serializer serializer; - } +using System; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestDateTime + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestSize() + { + var dateTime = new DateTime(2010, 1, 1); + var size = serializer.GetSize(dateTime); + Assert.AreEqual(9, size); + } + + [Test] + public void TestUtc() + { + var o = new DateTime(12735641765, DateTimeKind.Utc); + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(DateTimeKind.Utc, oo.Kind); + Assert.AreEqual(12735641765, oo.Ticks); + } + + [Test] + public void TestLong() + { + var o = 12735641765; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(DateTimeKind.Utc, oo.Kind); + Assert.AreEqual(12735641765, oo.Ticks); + } + + [Test] + public void TestLong2() + { + var data = serializer.Serialize(long.MinValue); + Assert.Throws(() => serializer.Deserialize(data)); + } + + [Test] + public void TestLocal() + { + var o = new DateTime(12735641765, DateTimeKind.Local); + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(DateTimeKind.Local, oo.Kind); + Assert.AreEqual(12735641765, oo.Ticks); + } + + [Test] + public void TestLocalOldFormat() + { + var data = new byte[10]; + data[0] = (byte)GroBufTypeCode.DateTimeOld; + Array.Copy(BitConverter.GetBytes(1234567891234 | long.MinValue), 0, data, 1, 8); + data[9] = (byte)DateTimeKind.Local; + var o = serializer.Deserialize(data); + Assert.AreEqual(DateTimeKind.Local, o.Kind); + Assert.AreEqual(1234567891234, o.Ticks); + } + + [Test] + public void TestUnspecified() + { + var o = new DateTime(12735641765, DateTimeKind.Unspecified); + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(DateTimeKind.Unspecified, oo.Kind); + Assert.AreEqual(12735641765, oo.Ticks); + } + + [Test] + public void TestSkipDateTimeLocal() + { + var o = new TestClassA {S = "zzz", DateTime = new DateTime(12387401892734, DateTimeKind.Local), Z = "qxx"}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.S); + Assert.AreEqual("qxx", oo.Z); + } + + [Test] + public void TestSkipDateTimeUtc() + { + var o = new TestClassA {S = "zzz", DateTime = new DateTime(12387401892734, DateTimeKind.Utc), Z = "qxx"}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.S); + Assert.AreEqual("qxx", oo.Z); + } + + [Test] + public void TestSkipDateTimeUnspecified() + { + var o = new TestClassA {S = "zzz", DateTime = new DateTime(12387401892734, DateTimeKind.Unspecified), Z = "qxx"}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.S); + Assert.AreEqual("qxx", oo.Z); + } + + public class TestClassA + { + public string S { get; set; } + public DateTime DateTime { get; set; } + public string Z { get; set; } + } + + public class TestClassB + { + public string S { get; set; } + public string Z { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestDateTimeOffset.cs b/GroBuf.Tests/TestDateTimeOffset.cs similarity index 96% rename from GroBuf/Tests/TestDateTimeOffset.cs rename to GroBuf.Tests/TestDateTimeOffset.cs index 69ce49b..4ebe2c3 100644 --- a/GroBuf/Tests/TestDateTimeOffset.cs +++ b/GroBuf.Tests/TestDateTimeOffset.cs @@ -1,51 +1,51 @@ -using System; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestDateTimeOffset - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new AllPropertiesExtractor()); - } - - [Test] - public void TestSize() - { - var dateTimeOffset = new DateTimeOffset(new DateTime(2010, 1, 1), new TimeSpan(0, 1, 1, 0)); - var size = serializer.GetSize(dateTimeOffset); - Assert.AreEqual(13, size); - } - - [Test] - public void TestReadWrite() - { - var dateTimeOffset = new DateTimeOffset(new DateTime(2010, 1, 1), new TimeSpan(0, 1, 1, 0)); - var data = serializer.Serialize(dateTimeOffset); - var dateTimeOffset2 = serializer.Deserialize(data); - Assert.AreEqual(dateTimeOffset, dateTimeOffset2); - } - - [Test] - public void TestReadWrite2() - { - var zzz = new Zzz {DateTimeOffset = new DateTimeOffset(new DateTime(2010, 1, 1), new TimeSpan(0, 1, 1, 0))}; - var data = serializer.Serialize(zzz); - var zzz2 = serializer.Deserialize(data); - Assert.AreEqual(zzz.DateTimeOffset, zzz2.DateTimeOffset); - } - - private Serializer serializer; - - public class Zzz - { - public DateTimeOffset DateTimeOffset { get; set; } - } - } +using System; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestDateTimeOffset + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new AllPropertiesExtractor()); + } + + [Test] + public void TestSize() + { + var dateTimeOffset = new DateTimeOffset(new DateTime(2010, 1, 1), new TimeSpan(0, 1, 1, 0)); + var size = serializer.GetSize(dateTimeOffset); + Assert.AreEqual(13, size); + } + + [Test] + public void TestReadWrite() + { + var dateTimeOffset = new DateTimeOffset(new DateTime(2010, 1, 1), new TimeSpan(0, 1, 1, 0)); + var data = serializer.Serialize(dateTimeOffset); + var dateTimeOffset2 = serializer.Deserialize(data); + Assert.AreEqual(dateTimeOffset, dateTimeOffset2); + } + + [Test] + public void TestReadWrite2() + { + var zzz = new Zzz {DateTimeOffset = new DateTimeOffset(new DateTime(2010, 1, 1), new TimeSpan(0, 1, 1, 0))}; + var data = serializer.Serialize(zzz); + var zzz2 = serializer.Deserialize(data); + Assert.AreEqual(zzz.DateTimeOffset, zzz2.DateTimeOffset); + } + + private Serializer serializer; + + public class Zzz + { + public DateTimeOffset DateTimeOffset { get; set; } + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestDictionary.cs b/GroBuf.Tests/TestDictionary.cs similarity index 97% rename from GroBuf/Tests/TestDictionary.cs rename to GroBuf.Tests/TestDictionary.cs index 118f34c..7542f95 100644 --- a/GroBuf/Tests/TestDictionary.cs +++ b/GroBuf.Tests/TestDictionary.cs @@ -1,111 +1,111 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestDictionary - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void TestGetSize() - { - var dict = new Dictionary {{"1", 1}, {"2", 2}}; - var size = serializer.GetSize(dict); - Console.WriteLine(size); - } - - [Test] - public void TestWrite() - { - var dict = new Dictionary {{"1", 1}, {"2", 2}}; - var buf = serializer.Serialize(dict); - Console.WriteLine(buf.Length); - } - - [Test] - public void TestRead() - { - var dict = new Dictionary {{"1", 1}, {"2", 2}}; - var buf = serializer.Serialize(dict); - var dict2 = serializer.Deserialize>(buf); - Assert.AreEqual(2, dict2.Count); - Assert.AreEqual(1, dict2["1"]); - Assert.AreEqual(2, dict2["2"]); - } - - [Test] - public void TestAddRemoveElements() - { - var dict = new Dictionary {{"1", 1}, {"2", 2}}; - dict.Remove("1"); - var buf = serializer.Serialize(dict); - var dict2 = serializer.Deserialize>(buf); - Assert.AreEqual(1, dict2.Count); - Assert.AreEqual(2, dict2["2"]); - } - - [Test] - public void TestArray() - { - var zzz = new Zzz(); - zzz.Properties.Add("zzz", serializer.Serialize(true)); - zzz.Properties.Add("qxx", serializer.Serialize(false)); - var data = serializer.Serialize(zzz); - var zzz3 = serializer.Deserialize(data); - Assert.AreEqual(2, zzz3.Properties.Count); - Assert.AreEqual(true, serializer.Deserialize(zzz3.Properties["zzz"])); - Assert.AreEqual(false, serializer.Deserialize(zzz3.Properties["qxx"])); - } - - [Test] - [Category("LongRunning")] - public void TestPerformance() - { - var dict = new Dictionary(); - for(int i = 0; i < 10000; ++i) - dict.Add(i, i); - Console.WriteLine(serializer.GetSize(dict)); - serializer.Deserialize>(serializer.Serialize(dict)); - var stopwatch = Stopwatch.StartNew(); - const int iterations = 10000; - for(int iter = 0; iter < iterations; ++iter) - serializer.GetSize(dict); - var elapsed = stopwatch.Elapsed; - Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - serializer.Serialize(dict); - elapsed = stopwatch.Elapsed; - Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); - var buf = serializer.Serialize(dict); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - serializer.Deserialize>(buf); - elapsed = stopwatch.Elapsed; - Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); - } - - public class Zzz - { - public Zzz() - { - Properties = new Dictionary(); - } - - public Dictionary Properties { get; set; } - } - - private Serializer serializer; - } +using System; +using System.Collections.Generic; +using System.Diagnostics; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestDictionary + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestGetSize() + { + var dict = new Dictionary {{"1", 1}, {"2", 2}}; + var size = serializer.GetSize(dict); + Console.WriteLine(size); + } + + [Test] + public void TestWrite() + { + var dict = new Dictionary {{"1", 1}, {"2", 2}}; + var buf = serializer.Serialize(dict); + Console.WriteLine(buf.Length); + } + + [Test] + public void TestRead() + { + var dict = new Dictionary {{"1", 1}, {"2", 2}}; + var buf = serializer.Serialize(dict); + var dict2 = serializer.Deserialize>(buf); + Assert.AreEqual(2, dict2.Count); + Assert.AreEqual(1, dict2["1"]); + Assert.AreEqual(2, dict2["2"]); + } + + [Test] + public void TestAddRemoveElements() + { + var dict = new Dictionary {{"1", 1}, {"2", 2}}; + dict.Remove("1"); + var buf = serializer.Serialize(dict); + var dict2 = serializer.Deserialize>(buf); + Assert.AreEqual(1, dict2.Count); + Assert.AreEqual(2, dict2["2"]); + } + + [Test] + public void TestArray() + { + var zzz = new Zzz(); + zzz.Properties.Add("zzz", serializer.Serialize(true)); + zzz.Properties.Add("qxx", serializer.Serialize(false)); + var data = serializer.Serialize(zzz); + var zzz3 = serializer.Deserialize(data); + Assert.AreEqual(2, zzz3.Properties.Count); + Assert.AreEqual(true, serializer.Deserialize(zzz3.Properties["zzz"])); + Assert.AreEqual(false, serializer.Deserialize(zzz3.Properties["qxx"])); + } + + [Test] + [Category("LongRunning")] + public void TestPerformance() + { + var dict = new Dictionary(); + for(int i = 0; i < 10000; ++i) + dict.Add(i, i); + Console.WriteLine(serializer.GetSize(dict)); + serializer.Deserialize>(serializer.Serialize(dict)); + var stopwatch = Stopwatch.StartNew(); + const int iterations = 10000; + for(int iter = 0; iter < iterations; ++iter) + serializer.GetSize(dict); + var elapsed = stopwatch.Elapsed; + Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + serializer.Serialize(dict); + elapsed = stopwatch.Elapsed; + Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); + var buf = serializer.Serialize(dict); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + serializer.Deserialize>(buf); + elapsed = stopwatch.Elapsed; + Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); + } + + public class Zzz + { + public Zzz() + { + Properties = new Dictionary(); + } + + public Dictionary Properties { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestEnum.cs b/GroBuf.Tests/TestEnum.cs similarity index 96% rename from GroBuf/Tests/TestEnum.cs rename to GroBuf.Tests/TestEnum.cs index 652eda0..c0c59bf 100644 --- a/GroBuf/Tests/TestEnum.cs +++ b/GroBuf.Tests/TestEnum.cs @@ -1,386 +1,386 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Runtime.Serialization; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestEnum - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void TestSerializeDeserialize() - { - var o = Enum1.Million; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(o, oo); - } - - [Test] - public void TestSerializeEnumAsInt() - { - var o = (Enum1)200; - byte[] data = serializer.Serialize(o); - Assert.AreEqual(200, serializer.Deserialize(data)); - } - - [Test] - public void TestDeserializeIntAsEnum() - { - int o = 123456789; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual((Enum1)123456789, oo); - o = (int)Enum1.Thousand; - data = serializer.Serialize(o); - oo = serializer.Deserialize(data); - Assert.AreEqual(Enum1.Thousand, oo); - } - - [Test] - public void TestDeserializeStringAsEnum() - { - string o = Enum1.Thousand.ToString(); - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(Enum1.Thousand, oo); - o = "zzz"; - data = serializer.Serialize(o); - oo = serializer.Deserialize(data); - Assert.AreEqual((Enum1)0, oo); - } - - [Test] - public void EnumItemAdded() - { - var o = Enum2_Old.Seven; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(Enum2_New.Seven, oo); - } - - [Test] - public void EnumEnumBug1() - { - byte[] data = serializer.Serialize(new PrintParameters {}); - var oo = serializer.Deserialize(data); - Assert.AreEqual((KopfPrintType)0, oo.PrintType); - } - - [Test] - public void EnumEnumBug2() - { - byte[] data = serializer.Serialize(new PrintParameters2 {}); - var oo = serializer.Deserialize(data); - Assert.AreEqual((KopfPrintType2)0, oo.PrintType); - } - - [Test] - public void TestMultipleItemsHasSameValue() - { - var o = Enum3.Одиннадцать; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.IsTrue(oo == Enum3.Eleven || oo == Enum3.Одиннадцать); - } - - [Test] - public void TestReadWriteToId() - { - var o = Enum1.One; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(Enum1x.OneX, oo); - } - - [Test] - public void TestReadWriteFromId() - { - var o = Enum1x.OneX; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(Enum1.One, oo); - } - - [Test] - public void Test() - { - var o = Enum_BadSort1.X; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(Enum_BadSort2.X, oo); - } - - [Test] - public void TestZ() - { - var values = Enum.GetValues(typeof(TaskState)); - for(int i = 0; i < values.Length; ++i) - Console.WriteLine(values.GetValue(i)); - Console.WriteLine(typeof(TaskState).GetField("Finished", BindingFlags.Public | BindingFlags.Static)); - var fields = typeof(TaskState).GetFields(BindingFlags.Public | BindingFlags.Static); - for (int i = 0; i < fields.Length; ++i) - Console.WriteLine(fields.GetValue(i)); - } - - [Test] - public void TestEnumWithNegative() - { - var o = serializer.Serialize(EnumWithNegative.Positive); - var oo = serializer.Deserialize(o); - Assert.AreEqual(EnumWithNegative.Positive, oo); - } - - [Test] - public void TestInt8() - { - foreach(var o in Enum.GetValues(typeof(Int8Enum)).Cast().Concat(new[] {(Int8Enum)sbyte.MaxValue})) - { - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.That(oo, Is.EqualTo(o)); - } - } - - [Test] - public void TestUInt8() - { - foreach(var o in Enum.GetValues(typeof(UInt8Enum)).Cast().Concat(new[] {(UInt8Enum)byte.MaxValue})) - { - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.That(oo, Is.EqualTo(o)); - } - } - - [Test] - public void TestInt16() - { - foreach(var o in Enum.GetValues(typeof(Int16Enum)).Cast().Concat(new[] {(Int16Enum)short.MaxValue})) - { - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.That(oo, Is.EqualTo(o)); - } - } - - [Test] - public void TestUInt16() - { - foreach(var o in Enum.GetValues(typeof(UInt16Enum)).Cast().Concat(new[] {(UInt16Enum)ushort.MaxValue})) - { - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.That(oo, Is.EqualTo(o)); - } - } - - [Test] - public void TestInt32() - { - foreach(var o in Enum.GetValues(typeof(Int32Enum)).Cast().Concat(new[] {(Int32Enum)int.MaxValue})) - { - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.That(oo, Is.EqualTo(o)); - } - } - - [Test] - public void TestUInt32() - { - foreach(var o in Enum.GetValues(typeof(UInt32Enum)).Cast().Concat(new[] {(UInt32Enum)uint.MaxValue})) - { - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.That(oo, Is.EqualTo(o)); - } - } - - public enum TaskState - { - Unknown = 0, - - New, - - WaitingForRerun, - - WaitingForRerunAfterError, - - Finished, - - InProcess, - - Fatal, - - Canceled, - } - - - public enum Enum_BadSort1 - { - X = 3, - Y = 1 - } - - public enum Enum_BadSort2 - { - X, - Z, - Y - } - - public enum Enum1 - { - One = 1, - Three = 3, - Five = 5, - Seven = 7, - Nine = 9, - Eleven = 11, - Hundred = 100, - Thousand = 1000, - Million = 1000000, - Billion = 1000000000 - } - - public enum Enum1x - { - [GroboMember(9186681566302519059)] - OneX = 1 - } - - public enum Enum2_Old - { - One, - Three, - Five, - Seven, - Nine - } - - public enum Enum2_New - { - One, - Two, - Three, - Four, - Five, - Six, - Seven, - Eight, - Nine - } - - public enum Enum3 - { - One = 1, - Один = 1, - Three = 3, - Три = 3, - Five = 5, - Пять = 5, - Seven = 7, - Семь = 7, - Nine = 9, - Девять = 9, - Eleven = 11, - Одиннадцать = 11, - Hundred = 100, - Сто = 100, - Thousand = 1000, - Тысяча = 1000, - Million = 1000000, - Миллион = 1000000, - Billion = 1000000000, - Миллиард = 1000000000 - } - - private enum Int8Enum : sbyte - { - X = -1, - Y = 1, - Z = 100, - Q = -100 - } - - private enum UInt8Enum : byte - { - X = 1, - Y = 2, - Z = 200 - } - - private enum Int16Enum : short - { - X = -1, - Y = 1, - Z = 1000, - Q = -1000 - } - - private enum UInt16Enum : ushort - { - X = 1, - Y = 2, - Z = 60000 - } - - private enum Int32Enum : int - { - X = -1, - Y = 1, - Z = 2000000000, - Q = -2000000000 - } - - private enum UInt32Enum : uint - { - X = 1, - Y = 2, - Z = 4000000000 - } - - private Serializer serializer; - - private class PrintParameters - { - public KopfPrintType PrintType { get; set; } - } - - private class PrintParameters2 - { - public KopfPrintType2 PrintType { get; set; } - } - - private enum KopfPrintType - { - Pdf = 1, - Excel = 2 - } - - private enum KopfPrintType2 - { - Pdf = 4, - Excel = 5 - } - - private enum EnumWithNegative - { - Negative = -1, - Zero = 0, - Positive = 1 - } - } +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestEnum + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestSerializeDeserialize() + { + var o = Enum1.Million; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(o, oo); + } + + [Test] + public void TestSerializeEnumAsInt() + { + var o = (Enum1)200; + byte[] data = serializer.Serialize(o); + Assert.AreEqual(200, serializer.Deserialize(data)); + } + + [Test] + public void TestDeserializeIntAsEnum() + { + int o = 123456789; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual((Enum1)123456789, oo); + o = (int)Enum1.Thousand; + data = serializer.Serialize(o); + oo = serializer.Deserialize(data); + Assert.AreEqual(Enum1.Thousand, oo); + } + + [Test] + public void TestDeserializeStringAsEnum() + { + string o = Enum1.Thousand.ToString(); + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(Enum1.Thousand, oo); + o = "zzz"; + data = serializer.Serialize(o); + oo = serializer.Deserialize(data); + Assert.AreEqual((Enum1)0, oo); + } + + [Test] + public void EnumItemAdded() + { + var o = Enum2_Old.Seven; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(Enum2_New.Seven, oo); + } + + [Test] + public void EnumEnumBug1() + { + byte[] data = serializer.Serialize(new PrintParameters {}); + var oo = serializer.Deserialize(data); + Assert.AreEqual((KopfPrintType)0, oo.PrintType); + } + + [Test] + public void EnumEnumBug2() + { + byte[] data = serializer.Serialize(new PrintParameters2 {}); + var oo = serializer.Deserialize(data); + Assert.AreEqual((KopfPrintType2)0, oo.PrintType); + } + + [Test] + public void TestMultipleItemsHasSameValue() + { + var o = Enum3.Одиннадцать; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.IsTrue(oo == Enum3.Eleven || oo == Enum3.Одиннадцать); + } + + [Test] + public void TestReadWriteToId() + { + var o = Enum1.One; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(Enum1x.OneX, oo); + } + + [Test] + public void TestReadWriteFromId() + { + var o = Enum1x.OneX; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(Enum1.One, oo); + } + + [Test] + public void Test() + { + var o = Enum_BadSort1.X; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(Enum_BadSort2.X, oo); + } + + [Test] + public void TestZ() + { + var values = Enum.GetValues(typeof(TaskState)); + for(int i = 0; i < values.Length; ++i) + Console.WriteLine(values.GetValue(i)); + Console.WriteLine(typeof(TaskState).GetField("Finished", BindingFlags.Public | BindingFlags.Static)); + var fields = typeof(TaskState).GetFields(BindingFlags.Public | BindingFlags.Static); + for (int i = 0; i < fields.Length; ++i) + Console.WriteLine(fields.GetValue(i)); + } + + [Test] + public void TestEnumWithNegative() + { + var o = serializer.Serialize(EnumWithNegative.Positive); + var oo = serializer.Deserialize(o); + Assert.AreEqual(EnumWithNegative.Positive, oo); + } + + [Test] + public void TestInt8() + { + foreach(var o in Enum.GetValues(typeof(Int8Enum)).Cast().Concat(new[] {(Int8Enum)sbyte.MaxValue})) + { + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.That(oo, Is.EqualTo(o)); + } + } + + [Test] + public void TestUInt8() + { + foreach(var o in Enum.GetValues(typeof(UInt8Enum)).Cast().Concat(new[] {(UInt8Enum)byte.MaxValue})) + { + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.That(oo, Is.EqualTo(o)); + } + } + + [Test] + public void TestInt16() + { + foreach(var o in Enum.GetValues(typeof(Int16Enum)).Cast().Concat(new[] {(Int16Enum)short.MaxValue})) + { + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.That(oo, Is.EqualTo(o)); + } + } + + [Test] + public void TestUInt16() + { + foreach(var o in Enum.GetValues(typeof(UInt16Enum)).Cast().Concat(new[] {(UInt16Enum)ushort.MaxValue})) + { + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.That(oo, Is.EqualTo(o)); + } + } + + [Test] + public void TestInt32() + { + foreach(var o in Enum.GetValues(typeof(Int32Enum)).Cast().Concat(new[] {(Int32Enum)int.MaxValue})) + { + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.That(oo, Is.EqualTo(o)); + } + } + + [Test] + public void TestUInt32() + { + foreach(var o in Enum.GetValues(typeof(UInt32Enum)).Cast().Concat(new[] {(UInt32Enum)uint.MaxValue})) + { + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.That(oo, Is.EqualTo(o)); + } + } + + public enum TaskState + { + Unknown = 0, + + New, + + WaitingForRerun, + + WaitingForRerunAfterError, + + Finished, + + InProcess, + + Fatal, + + Canceled, + } + + + public enum Enum_BadSort1 + { + X = 3, + Y = 1 + } + + public enum Enum_BadSort2 + { + X, + Z, + Y + } + + public enum Enum1 + { + One = 1, + Three = 3, + Five = 5, + Seven = 7, + Nine = 9, + Eleven = 11, + Hundred = 100, + Thousand = 1000, + Million = 1000000, + Billion = 1000000000 + } + + public enum Enum1x + { + [GroboMember(9186681566302519059)] + OneX = 1 + } + + public enum Enum2_Old + { + One, + Three, + Five, + Seven, + Nine + } + + public enum Enum2_New + { + One, + Two, + Three, + Four, + Five, + Six, + Seven, + Eight, + Nine + } + + public enum Enum3 + { + One = 1, + Один = 1, + Three = 3, + Три = 3, + Five = 5, + Пять = 5, + Seven = 7, + Семь = 7, + Nine = 9, + Девять = 9, + Eleven = 11, + Одиннадцать = 11, + Hundred = 100, + Сто = 100, + Thousand = 1000, + Тысяча = 1000, + Million = 1000000, + Миллион = 1000000, + Billion = 1000000000, + Миллиард = 1000000000 + } + + private enum Int8Enum : sbyte + { + X = -1, + Y = 1, + Z = 100, + Q = -100 + } + + private enum UInt8Enum : byte + { + X = 1, + Y = 2, + Z = 200 + } + + private enum Int16Enum : short + { + X = -1, + Y = 1, + Z = 1000, + Q = -1000 + } + + private enum UInt16Enum : ushort + { + X = 1, + Y = 2, + Z = 60000 + } + + private enum Int32Enum : int + { + X = -1, + Y = 1, + Z = 2000000000, + Q = -2000000000 + } + + private enum UInt32Enum : uint + { + X = 1, + Y = 2, + Z = 4000000000 + } + + private Serializer serializer; + + private class PrintParameters + { + public KopfPrintType PrintType { get; set; } + } + + private class PrintParameters2 + { + public KopfPrintType2 PrintType { get; set; } + } + + private enum KopfPrintType + { + Pdf = 1, + Excel = 2 + } + + private enum KopfPrintType2 + { + Pdf = 4, + Excel = 5 + } + + private enum EnumWithNegative + { + Negative = -1, + Zero = 0, + Positive = 1 + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestFields.cs b/GroBuf.Tests/TestFields.cs similarity index 96% rename from GroBuf/Tests/TestFields.cs rename to GroBuf.Tests/TestFields.cs index eab9a5e..8ce1f3b 100644 --- a/GroBuf/Tests/TestFields.cs +++ b/GroBuf.Tests/TestFields.cs @@ -1,71 +1,71 @@ -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestFields - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new FieldsExtractor()); - } - - [Test] - public void Test() - { - var o = new A {Bool = true, Ints = new[] {10, 2, 4}, B = new B {S = "zzz", Long = 123456789123456789}}; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(true, oo.Bool); - Assert.IsNotNull(oo.Ints); - Assert.AreEqual(3, oo.Ints.Length); - Assert.AreEqual(10, oo.Ints[0]); - Assert.AreEqual(2, oo.Ints[1]); - Assert.AreEqual(4, oo.Ints[2]); - Assert.IsNotNull(oo.B); - Assert.AreEqual("zzz", oo.B.S); - Assert.AreEqual(123456789123456789, oo.B.Long); - } - - [Test] - public void TestReadonlyField() - { - var o = new C("zzz"); - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.S); - } - - public class A - { - public int[] Ints; - public bool? Bool; - public B B; - } - - public class B - { - public string S; - public long? Long; - } - - public class C - { - public C(string s) - { - S = s; - } - - public C() - { - } - - public readonly string S; - } - - private Serializer serializer; - } +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestFields + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new FieldsExtractor()); + } + + [Test] + public void Test() + { + var o = new A {Bool = true, Ints = new[] {10, 2, 4}, B = new B {S = "zzz", Long = 123456789123456789}}; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(true, oo.Bool); + Assert.IsNotNull(oo.Ints); + Assert.AreEqual(3, oo.Ints.Length); + Assert.AreEqual(10, oo.Ints[0]); + Assert.AreEqual(2, oo.Ints[1]); + Assert.AreEqual(4, oo.Ints[2]); + Assert.IsNotNull(oo.B); + Assert.AreEqual("zzz", oo.B.S); + Assert.AreEqual(123456789123456789, oo.B.Long); + } + + [Test] + public void TestReadonlyField() + { + var o = new C("zzz"); + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.S); + } + + public class A + { + public int[] Ints; + public bool? Bool; + public B B; + } + + public class B + { + public string S; + public long? Long; + } + + public class C + { + public C(string s) + { + S = s; + } + + public C() + { + } + + public readonly string S; + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestGetHashMultiThread.cs b/GroBuf.Tests/TestGetHashMultiThread.cs similarity index 95% rename from GroBuf/Tests/TestGetHashMultiThread.cs rename to GroBuf.Tests/TestGetHashMultiThread.cs index ed940e0..8a0a714 100644 --- a/GroBuf/Tests/TestGetHashMultiThread.cs +++ b/GroBuf.Tests/TestGetHashMultiThread.cs @@ -1,35 +1,35 @@ -using System; -using System.Threading.Tasks; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestGetHashMultiThread - { - [Test] - public void Test() - { - wasBug = false; - Parallel.Invoke(Zzz, Zzz, Zzz, Zzz, Zzz, Zzz, Zzz); - Assert.IsFalse(wasBug); - } - - private void Zzz() - { - try - { - for(int i = 1; i < 1000; ++i) - GroBufHelpers.CalcHash(new string('z', i)); - } - catch(Exception e) - { - Console.WriteLine(e.ToString()); - wasBug = true; - } - } - - private volatile bool wasBug; - } +using System; +using System.Threading.Tasks; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestGetHashMultiThread + { + [Test] + public void Test() + { + wasBug = false; + Parallel.Invoke(Zzz, Zzz, Zzz, Zzz, Zzz, Zzz, Zzz); + Assert.IsFalse(wasBug); + } + + private void Zzz() + { + try + { + for(int i = 1; i < 1000; ++i) + GroBufHelpers.CalcHash(new string('z', i)); + } + catch(Exception e) + { + Console.WriteLine(e.ToString()); + wasBug = true; + } + } + + private volatile bool wasBug; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestHashCompatibility.cs b/GroBuf.Tests/TestHashCompatibility.cs similarity index 97% rename from GroBuf/Tests/TestHashCompatibility.cs rename to GroBuf.Tests/TestHashCompatibility.cs index f54d096..e37049b 100644 --- a/GroBuf/Tests/TestHashCompatibility.cs +++ b/GroBuf.Tests/TestHashCompatibility.cs @@ -1,54 +1,54 @@ -using System; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestHashCompatibility - { - [Test] - public void TestValues() - { - HashCalculator hashCalculator = GroBufHelpers.HashCalculator; - Assert.AreEqual(4840038476803469422L, hashCalculator.CalcHash("zzz")); - Assert.AreEqual(815294827239093585L, hashCalculator.CalcHash("Prop")); - Assert.AreEqual(2001271914681603707L, hashCalculator.CalcHash("1234567890")); - Assert.AreEqual(14727305760438073051L, hashCalculator.CalcHash("TRASH")); - Assert.AreEqual(5580606048428013952L, hashCalculator.CalcHash("trash")); - Assert.AreEqual(0, hashCalculator.CalcHash("")); - } - - [Test] - public void TestCalcHash() - { - Console.WriteLine(GroBufHelpers.HashCalculator.CalcHash("X")); - } - - [Test] - public void TestMaxLenNotAffectsHash() - { - var h20 = new HashCalculator(GroBufHelpers.Seed, 20); - var h10 = new HashCalculator(GroBufHelpers.Seed, 10); - Assert.AreEqual(h20.CalcHash("qxx"), h10.CalcHash("qxx")); - } - - [Test] - public void TestLimits() - { - var h = new HashCalculator(GroBufHelpers.Seed, 3); - Assert.AreEqual(17829415923593557195L, h.CalcHash("z")); - Assert.AreEqual(1402044078693333494L, h.CalcHash("zz")); - Assert.AreEqual(4840038476803469422L, h.CalcHash("zzz")); - try - { - Assert.AreEqual(4840038476803469422L, h.CalcHash("zzzz")); - Assert.Fail("NO CRASH"); - } - catch(NotSupportedException e) - { - Assert.AreEqual("Names with length greater than 3", e.Message); - } - } - } +using System; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestHashCompatibility + { + [Test] + public void TestValues() + { + HashCalculator hashCalculator = GroBufHelpers.HashCalculator; + Assert.AreEqual(4840038476803469422L, hashCalculator.CalcHash("zzz")); + Assert.AreEqual(815294827239093585L, hashCalculator.CalcHash("Prop")); + Assert.AreEqual(2001271914681603707L, hashCalculator.CalcHash("1234567890")); + Assert.AreEqual(14727305760438073051L, hashCalculator.CalcHash("TRASH")); + Assert.AreEqual(5580606048428013952L, hashCalculator.CalcHash("trash")); + Assert.AreEqual(0, hashCalculator.CalcHash("")); + } + + [Test] + public void TestCalcHash() + { + Console.WriteLine(GroBufHelpers.HashCalculator.CalcHash("X")); + } + + [Test] + public void TestMaxLenNotAffectsHash() + { + var h20 = new HashCalculator(GroBufHelpers.Seed, 20); + var h10 = new HashCalculator(GroBufHelpers.Seed, 10); + Assert.AreEqual(h20.CalcHash("qxx"), h10.CalcHash("qxx")); + } + + [Test] + public void TestLimits() + { + var h = new HashCalculator(GroBufHelpers.Seed, 3); + Assert.AreEqual(17829415923593557195L, h.CalcHash("z")); + Assert.AreEqual(1402044078693333494L, h.CalcHash("zz")); + Assert.AreEqual(4840038476803469422L, h.CalcHash("zzz")); + try + { + Assert.AreEqual(4840038476803469422L, h.CalcHash("zzzz")); + Assert.Fail("NO CRASH"); + } + catch(NotSupportedException e) + { + Assert.AreEqual("Names with length greater than 3", e.Message); + } + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestHashSet.cs b/GroBuf.Tests/TestHashSet.cs similarity index 97% rename from GroBuf/Tests/TestHashSet.cs rename to GroBuf.Tests/TestHashSet.cs index 35f28e5..1c32234 100644 --- a/GroBuf/Tests/TestHashSet.cs +++ b/GroBuf.Tests/TestHashSet.cs @@ -1,232 +1,232 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestHashSet - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void TestGetSize() - { - var hashSet = new HashSet {"1", "2"}; - int size = serializer.GetSize(hashSet); - Console.WriteLine(size); - } - - [Test] - public void TestWriteNotEmptyWithWriteEmptyObjects() - { - serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.WriteEmptyObjects); - var arr = new[] {Guid.NewGuid(), Guid.NewGuid()}; - - var c = new TestWithHashSet {H = new HashSet(arr)}; - byte[] bytes = serializer.Serialize(c); - var actual = serializer.Deserialize(bytes); - Assert.IsNotNull(actual.H); - CollectionAssert.AreEquivalent(arr, actual.H.ToArray()); - } - - [Test] - public void TestWriteEmptyWithWriteEmptyObjects() - { - serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.WriteEmptyObjects); - var c = new TestWithHashSet {H = new HashSet()}; - byte[] bytes = serializer.Serialize(c); - var actual = serializer.Deserialize(bytes); - Assert.IsNotNull(actual.H); - CollectionAssert.IsEmpty(actual.H.ToArray()); - } - - [Test] - public void TestWriteEmptyWithWriteEmptyObjectsPrimitives() - { - serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.WriteEmptyObjects); - var c = new TestWithHashSet {H2 = new HashSet()}; - byte[] bytes = serializer.Serialize(c); - var actual = serializer.Deserialize(bytes); - Assert.IsNotNull(actual.H2); - CollectionAssert.IsEmpty(actual.H2.ToArray()); - } - - [Test] - public void TestGetSizePrimitive() - { - var hashSet = new HashSet {1, 2}; - int size = serializer.GetSize(hashSet); - Console.WriteLine(size); - } - - [Test] - public void TestWrite() - { - var hashSet = new HashSet {"1", "2"}; - byte[] buf = serializer.Serialize(hashSet); - Console.WriteLine(buf.Length); - } - - [Test] - public void TestWritePrimitive() - { - var hashSet = new HashSet {1, 2}; - byte[] buf = serializer.Serialize(hashSet); - Console.WriteLine(buf.Length); - } - - [Test] - public void TestRead() - { - var hashSet = new HashSet {"1", "2"}; - var buf = serializer.Serialize(hashSet); - var hashSet2 = serializer.Deserialize>(buf); - Assert.AreEqual(2, hashSet2.Count); - Assert.IsTrue(hashSet2.Contains("1")); - Assert.IsTrue(hashSet2.Contains("2")); - } - - [Test] - public void TestAddRemoveElements() - { - var hashSet = new HashSet {"1", "2"}; - hashSet.Remove("1"); - var buf = serializer.Serialize(hashSet); - var hashSet2 = serializer.Deserialize>(buf); - Assert.AreEqual(1, hashSet2.Count); - Assert.IsTrue(hashSet2.Contains("2")); - } - - [Test] - public void TestAddRemoveElementsPrimitive() - { - var hashSet = new HashSet { 1, 2 }; - hashSet.Remove(1); - byte[] buf = serializer.Serialize(hashSet); - var hashSet2 = serializer.Deserialize>(buf); - Assert.AreEqual(1, hashSet2.Count); - Assert.IsTrue(hashSet2.Contains(2)); - } - - [Test] - public void TestReadPrimitive() - { - var hashSet = new HashSet {1, 2}; - byte[] buf = serializer.Serialize(hashSet); - var hashSet2 = serializer.Deserialize>(buf); - Assert.AreEqual(2, hashSet2.Count); - Assert.IsTrue(hashSet2.Contains(1)); - Assert.IsTrue(hashSet2.Contains(2)); - } - - [Test] - public void TestCompatibilityWithArray() - { - var hashSet = new HashSet {"1", "2"}; - byte[] data = serializer.Serialize(hashSet); - var array = serializer.Deserialize(data); - Assert.AreEqual(2, array.Length); - Assert.AreEqual("1", array[0]); - Assert.AreEqual("2", array[1]); - array = new[] {"3", "2", "1"}; - data = serializer.Serialize(array); - hashSet = serializer.Deserialize>(data); - Assert.AreEqual(3, hashSet.Count); - Assert.IsTrue(hashSet.Contains("1")); - Assert.IsTrue(hashSet.Contains("2")); - Assert.IsTrue(hashSet.Contains("3")); - } - - [Test] - public void TestCompatibilityWithArrayOfPrimitives() - { - var hashSet = new HashSet {1, 2}; - byte[] data = serializer.Serialize(hashSet); - var array = serializer.Deserialize(data); - Assert.AreEqual(2, array.Length); - Assert.AreEqual(1, array[0]); - Assert.AreEqual(2, array[1]); - array = new[] {3, 2, 1}; - data = serializer.Serialize(array); - hashSet = serializer.Deserialize>(data); - Assert.AreEqual(3, hashSet.Count); - Assert.IsTrue(hashSet.Contains(1)); - Assert.IsTrue(hashSet.Contains(2)); - Assert.IsTrue(hashSet.Contains(3)); - } - - [Test] - [Category("LongRunning")] - public void TestPerformance() - { - var hashSet = new HashSet(); - for(int i = 0; i < 10000; ++i) - hashSet.Add(i); - Console.WriteLine(serializer.GetSize(hashSet)); - serializer.Deserialize>(serializer.Serialize(hashSet)); - Stopwatch stopwatch = Stopwatch.StartNew(); - const int iterations = 10000; - for(int iter = 0; iter < iterations; ++iter) - serializer.GetSize(hashSet); - TimeSpan elapsed = stopwatch.Elapsed; - Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - serializer.Serialize(hashSet); - elapsed = stopwatch.Elapsed; - Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); - byte[] buf = serializer.Serialize(hashSet); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - serializer.Deserialize>(buf); - elapsed = stopwatch.Elapsed; - Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); - } - - [Test] - [Category("LongRunning")] - public void TestPerformanceGuid() - { - var hashSet = new HashSet(); - for(int i = 0; i < 10000; ++i) - hashSet.Add(Guid.NewGuid()); - Console.WriteLine(serializer.GetSize(hashSet)); - serializer.Deserialize>(serializer.Serialize(hashSet)); - Stopwatch stopwatch = Stopwatch.StartNew(); - const int iterations = 10000; - for(int iter = 0; iter < iterations; ++iter) - serializer.GetSize(hashSet); - TimeSpan elapsed = stopwatch.Elapsed; - Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - serializer.Serialize(hashSet); - elapsed = stopwatch.Elapsed; - Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); - byte[] buf = serializer.Serialize(hashSet); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - serializer.Deserialize>(buf); - elapsed = stopwatch.Elapsed; - Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); - } - - private Serializer serializer; - - private class TestWithHashSet - { - public HashSet H { get; set; } - public HashSet H2 { get; set; } - } - } +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestHashSet + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestGetSize() + { + var hashSet = new HashSet {"1", "2"}; + int size = serializer.GetSize(hashSet); + Console.WriteLine(size); + } + + [Test] + public void TestWriteNotEmptyWithWriteEmptyObjects() + { + serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.WriteEmptyObjects); + var arr = new[] {Guid.NewGuid(), Guid.NewGuid()}; + + var c = new TestWithHashSet {H = new HashSet(arr)}; + byte[] bytes = serializer.Serialize(c); + var actual = serializer.Deserialize(bytes); + Assert.IsNotNull(actual.H); + CollectionAssert.AreEquivalent(arr, actual.H.ToArray()); + } + + [Test] + public void TestWriteEmptyWithWriteEmptyObjects() + { + serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.WriteEmptyObjects); + var c = new TestWithHashSet {H = new HashSet()}; + byte[] bytes = serializer.Serialize(c); + var actual = serializer.Deserialize(bytes); + Assert.IsNotNull(actual.H); + CollectionAssert.IsEmpty(actual.H.ToArray()); + } + + [Test] + public void TestWriteEmptyWithWriteEmptyObjectsPrimitives() + { + serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.WriteEmptyObjects); + var c = new TestWithHashSet {H2 = new HashSet()}; + byte[] bytes = serializer.Serialize(c); + var actual = serializer.Deserialize(bytes); + Assert.IsNotNull(actual.H2); + CollectionAssert.IsEmpty(actual.H2.ToArray()); + } + + [Test] + public void TestGetSizePrimitive() + { + var hashSet = new HashSet {1, 2}; + int size = serializer.GetSize(hashSet); + Console.WriteLine(size); + } + + [Test] + public void TestWrite() + { + var hashSet = new HashSet {"1", "2"}; + byte[] buf = serializer.Serialize(hashSet); + Console.WriteLine(buf.Length); + } + + [Test] + public void TestWritePrimitive() + { + var hashSet = new HashSet {1, 2}; + byte[] buf = serializer.Serialize(hashSet); + Console.WriteLine(buf.Length); + } + + [Test] + public void TestRead() + { + var hashSet = new HashSet {"1", "2"}; + var buf = serializer.Serialize(hashSet); + var hashSet2 = serializer.Deserialize>(buf); + Assert.AreEqual(2, hashSet2.Count); + Assert.IsTrue(hashSet2.Contains("1")); + Assert.IsTrue(hashSet2.Contains("2")); + } + + [Test] + public void TestAddRemoveElements() + { + var hashSet = new HashSet {"1", "2"}; + hashSet.Remove("1"); + var buf = serializer.Serialize(hashSet); + var hashSet2 = serializer.Deserialize>(buf); + Assert.AreEqual(1, hashSet2.Count); + Assert.IsTrue(hashSet2.Contains("2")); + } + + [Test] + public void TestAddRemoveElementsPrimitive() + { + var hashSet = new HashSet { 1, 2 }; + hashSet.Remove(1); + byte[] buf = serializer.Serialize(hashSet); + var hashSet2 = serializer.Deserialize>(buf); + Assert.AreEqual(1, hashSet2.Count); + Assert.IsTrue(hashSet2.Contains(2)); + } + + [Test] + public void TestReadPrimitive() + { + var hashSet = new HashSet {1, 2}; + byte[] buf = serializer.Serialize(hashSet); + var hashSet2 = serializer.Deserialize>(buf); + Assert.AreEqual(2, hashSet2.Count); + Assert.IsTrue(hashSet2.Contains(1)); + Assert.IsTrue(hashSet2.Contains(2)); + } + + [Test] + public void TestCompatibilityWithArray() + { + var hashSet = new HashSet {"1", "2"}; + byte[] data = serializer.Serialize(hashSet); + var array = serializer.Deserialize(data); + Assert.AreEqual(2, array.Length); + Assert.AreEqual("1", array[0]); + Assert.AreEqual("2", array[1]); + array = new[] {"3", "2", "1"}; + data = serializer.Serialize(array); + hashSet = serializer.Deserialize>(data); + Assert.AreEqual(3, hashSet.Count); + Assert.IsTrue(hashSet.Contains("1")); + Assert.IsTrue(hashSet.Contains("2")); + Assert.IsTrue(hashSet.Contains("3")); + } + + [Test] + public void TestCompatibilityWithArrayOfPrimitives() + { + var hashSet = new HashSet {1, 2}; + byte[] data = serializer.Serialize(hashSet); + var array = serializer.Deserialize(data); + Assert.AreEqual(2, array.Length); + Assert.AreEqual(1, array[0]); + Assert.AreEqual(2, array[1]); + array = new[] {3, 2, 1}; + data = serializer.Serialize(array); + hashSet = serializer.Deserialize>(data); + Assert.AreEqual(3, hashSet.Count); + Assert.IsTrue(hashSet.Contains(1)); + Assert.IsTrue(hashSet.Contains(2)); + Assert.IsTrue(hashSet.Contains(3)); + } + + [Test] + [Category("LongRunning")] + public void TestPerformance() + { + var hashSet = new HashSet(); + for(int i = 0; i < 10000; ++i) + hashSet.Add(i); + Console.WriteLine(serializer.GetSize(hashSet)); + serializer.Deserialize>(serializer.Serialize(hashSet)); + Stopwatch stopwatch = Stopwatch.StartNew(); + const int iterations = 10000; + for(int iter = 0; iter < iterations; ++iter) + serializer.GetSize(hashSet); + TimeSpan elapsed = stopwatch.Elapsed; + Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + serializer.Serialize(hashSet); + elapsed = stopwatch.Elapsed; + Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); + byte[] buf = serializer.Serialize(hashSet); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + serializer.Deserialize>(buf); + elapsed = stopwatch.Elapsed; + Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); + } + + [Test] + [Category("LongRunning")] + public void TestPerformanceGuid() + { + var hashSet = new HashSet(); + for(int i = 0; i < 10000; ++i) + hashSet.Add(Guid.NewGuid()); + Console.WriteLine(serializer.GetSize(hashSet)); + serializer.Deserialize>(serializer.Serialize(hashSet)); + Stopwatch stopwatch = Stopwatch.StartNew(); + const int iterations = 10000; + for(int iter = 0; iter < iterations; ++iter) + serializer.GetSize(hashSet); + TimeSpan elapsed = stopwatch.Elapsed; + Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + serializer.Serialize(hashSet); + elapsed = stopwatch.Elapsed; + Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); + byte[] buf = serializer.Serialize(hashSet); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + serializer.Deserialize>(buf); + elapsed = stopwatch.Elapsed; + Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); + } + + private Serializer serializer; + + private class TestWithHashSet + { + public HashSet H { get; set; } + public HashSet H2 { get; set; } + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestHashtable.cs b/GroBuf.Tests/TestHashtable.cs similarity index 97% rename from GroBuf/Tests/TestHashtable.cs rename to GroBuf.Tests/TestHashtable.cs index fb85d1c..8fc7071 100644 --- a/GroBuf/Tests/TestHashtable.cs +++ b/GroBuf.Tests/TestHashtable.cs @@ -1,125 +1,125 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestHashtable - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void TestGetSize() - { - var dict = new Hashtable {{"1", 1}, {"2", 2}}; - var size = serializer.GetSize(dict); - Console.WriteLine(size); - } - - [Test] - public void TestWrite() - { - var dict = new Hashtable {{"1", 1}, {"2", 2}}; - var buf = serializer.Serialize(dict); - Console.WriteLine(buf.Length); - } - - [Test] - public void TestRead() - { - var dict = new Hashtable {{"1", 1}, {"2", 2}, {"3", "3"}}; - var buf = serializer.Serialize(dict); - var dict2 = serializer.Deserialize(buf); - Assert.AreEqual(3, dict2.Count); - Assert.AreEqual(1, dict2["1"]); - Assert.AreEqual(2, dict2["2"]); - Assert.AreEqual("3", dict2["3"]); - } - - [Test] - public void TestAddRemoveElements() - { - var dict = new Hashtable { { "1", 1 }, { "2", 2 }, { "3", "3" } }; - dict.Remove("1"); - var buf = serializer.Serialize(dict); - var dict2 = serializer.Deserialize(buf); - Assert.AreEqual(2, dict2.Count); - Assert.AreEqual(2, dict2["2"]); - Assert.AreEqual("3", dict2["3"]); - } - - [Test] - public void TestReadAsDict() - { - var dict = new Hashtable {{"1", 1}, {"2", 2}}; - var buf = serializer.Serialize(dict); - var dict2 = serializer.Deserialize>(buf); - Assert.AreEqual(2, dict2.Count); - Assert.AreEqual(1, dict2["1"]); - Assert.AreEqual(2, dict2["2"]); - } - - [Test] - public void TestArray() - { - var zzz = new Zzz(); - zzz.Properties.Add("zzz", serializer.Serialize(true)); - zzz.Properties.Add("qxx", serializer.Serialize(false)); - var data = serializer.Serialize(zzz); - var zzz3 = serializer.Deserialize(data); - Assert.AreEqual(2, zzz3.Properties.Count); - Assert.AreEqual(true, serializer.Deserialize(zzz3.Properties["zzz"])); - Assert.AreEqual(false, serializer.Deserialize(zzz3.Properties["qxx"])); - } - - [Test] - [Category("LongRunning")] - public void TestPerformance() - { - var hashtable = new Hashtable(); - for(int i = 0; i < 10000; ++i) - hashtable.Add(i, i); - Console.WriteLine(serializer.GetSize(hashtable)); - serializer.Deserialize(serializer.Serialize(hashtable)); - var stopwatch = Stopwatch.StartNew(); - const int iterations = 10000; - for(int iter = 0; iter < iterations; ++iter) - serializer.GetSize(hashtable); - var elapsed = stopwatch.Elapsed; - Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - serializer.Serialize(hashtable); - elapsed = stopwatch.Elapsed; - Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); - var buf = serializer.Serialize(hashtable); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - serializer.Deserialize(buf); - elapsed = stopwatch.Elapsed; - Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); - } - - public class Zzz - { - public Zzz() - { - Properties = new Dictionary(); - } - - public Dictionary Properties { get; set; } - } - - private Serializer serializer; - } +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestHashtable + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestGetSize() + { + var dict = new Hashtable {{"1", 1}, {"2", 2}}; + var size = serializer.GetSize(dict); + Console.WriteLine(size); + } + + [Test] + public void TestWrite() + { + var dict = new Hashtable {{"1", 1}, {"2", 2}}; + var buf = serializer.Serialize(dict); + Console.WriteLine(buf.Length); + } + + [Test] + public void TestRead() + { + var dict = new Hashtable {{"1", 1}, {"2", 2}, {"3", "3"}}; + var buf = serializer.Serialize(dict); + var dict2 = serializer.Deserialize(buf); + Assert.AreEqual(3, dict2.Count); + Assert.AreEqual(1, dict2["1"]); + Assert.AreEqual(2, dict2["2"]); + Assert.AreEqual("3", dict2["3"]); + } + + [Test] + public void TestAddRemoveElements() + { + var dict = new Hashtable { { "1", 1 }, { "2", 2 }, { "3", "3" } }; + dict.Remove("1"); + var buf = serializer.Serialize(dict); + var dict2 = serializer.Deserialize(buf); + Assert.AreEqual(2, dict2.Count); + Assert.AreEqual(2, dict2["2"]); + Assert.AreEqual("3", dict2["3"]); + } + + [Test] + public void TestReadAsDict() + { + var dict = new Hashtable {{"1", 1}, {"2", 2}}; + var buf = serializer.Serialize(dict); + var dict2 = serializer.Deserialize>(buf); + Assert.AreEqual(2, dict2.Count); + Assert.AreEqual(1, dict2["1"]); + Assert.AreEqual(2, dict2["2"]); + } + + [Test] + public void TestArray() + { + var zzz = new Zzz(); + zzz.Properties.Add("zzz", serializer.Serialize(true)); + zzz.Properties.Add("qxx", serializer.Serialize(false)); + var data = serializer.Serialize(zzz); + var zzz3 = serializer.Deserialize(data); + Assert.AreEqual(2, zzz3.Properties.Count); + Assert.AreEqual(true, serializer.Deserialize(zzz3.Properties["zzz"])); + Assert.AreEqual(false, serializer.Deserialize(zzz3.Properties["qxx"])); + } + + [Test] + [Category("LongRunning")] + public void TestPerformance() + { + var hashtable = new Hashtable(); + for(int i = 0; i < 10000; ++i) + hashtable.Add(i, i); + Console.WriteLine(serializer.GetSize(hashtable)); + serializer.Deserialize(serializer.Serialize(hashtable)); + var stopwatch = Stopwatch.StartNew(); + const int iterations = 10000; + for(int iter = 0; iter < iterations; ++iter) + serializer.GetSize(hashtable); + var elapsed = stopwatch.Elapsed; + Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + serializer.Serialize(hashtable); + elapsed = stopwatch.Elapsed; + Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); + var buf = serializer.Serialize(hashtable); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + serializer.Deserialize(buf); + elapsed = stopwatch.Elapsed; + Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); + } + + public class Zzz + { + public Zzz() + { + Properties = new Dictionary(); + } + + public Dictionary Properties { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestIPAddress.cs b/GroBuf.Tests/TestIPAddress.cs similarity index 80% rename from GroBuf/Tests/TestIPAddress.cs rename to GroBuf.Tests/TestIPAddress.cs index 805f506..3f7dc5b 100644 --- a/GroBuf/Tests/TestIPAddress.cs +++ b/GroBuf.Tests/TestIPAddress.cs @@ -1,63 +1,71 @@ -using System; -using System.Net; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestIPAddress - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new AllPropertiesExtractor()); - } - - [Test] - public void TestSize() - { - var address = new IPAddress(new byte[] {123, 1, 2, 3}); - var size = serializer.GetSize(address); - Assert.AreEqual(9, size); - address = new IPAddress(Guid.NewGuid().ToByteArray()); - size = serializer.GetSize(address); - Assert.AreEqual(21, size); - } - - [Test] - public void TestReadWrite() - { - var address = new IPAddress(new byte[] {123, 1, 2, 3}); - var data = serializer.Serialize(address); - var address2 = serializer.Deserialize(data); - Assert.AreEqual(address, address2); - address = new IPAddress(Guid.NewGuid().ToByteArray()); - data = serializer.Serialize(address); - address2 = serializer.Deserialize(data); - Assert.AreEqual(address, address2); - } - - [Test] - public void TestReadWrite2() - { - var zzz = new Zzz {Address = new IPAddress(new byte[] {123, 1, 2, 3})}; - var data = serializer.Serialize(zzz); - var zzz2 = serializer.Deserialize(data); - Assert.AreEqual(zzz.Address, zzz2.Address); - zzz = new Zzz {Address = new IPAddress(Guid.NewGuid().ToByteArray())}; - data = serializer.Serialize(zzz); - zzz2 = serializer.Deserialize(data); - Assert.AreEqual(zzz.Address, zzz2.Address); - } - - public class Zzz - { - public IPAddress Address { get; set; } - } - - private Serializer serializer; - } +using System; +using System.Net; +using System.Net.Sockets; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestIPAddress + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new AllPropertiesExtractor()); + } + + [Test] + public void TestSizeIPv4() + { + var address = new IPAddress(new byte[] {123, 1, 2, 3}); + Assert.That(address.AddressFamily, Is.EqualTo(AddressFamily.InterNetwork)); + var size = serializer.GetSize(address); + Assert.AreEqual(9, size); + } + + [Test] + public void TestSizeIPv6() + { + var address = new IPAddress(Guid.NewGuid().ToByteArray()); + Assert.That(address.AddressFamily, Is.EqualTo(AddressFamily.InterNetworkV6)); + var size = serializer.GetSize(address); + Assert.AreEqual(21, size); + } + + [Test] + public void TestReadWrite() + { + var address = new IPAddress(new byte[] {123, 1, 2, 3}); + var data = serializer.Serialize(address); + var address2 = serializer.Deserialize(data); + Assert.AreEqual(address, address2); + address = new IPAddress(Guid.NewGuid().ToByteArray()); + data = serializer.Serialize(address); + address2 = serializer.Deserialize(data); + Assert.AreEqual(address, address2); + } + + [Test] + public void TestReadWrite2() + { + var zzz = new Zzz {Address = new IPAddress(new byte[] {123, 1, 2, 3})}; + var data = serializer.Serialize(zzz); + var zzz2 = serializer.Deserialize(data); + Assert.AreEqual(zzz.Address, zzz2.Address); + zzz = new Zzz {Address = new IPAddress(Guid.NewGuid().ToByteArray())}; + data = serializer.Serialize(zzz); + zzz2 = serializer.Deserialize(data); + Assert.AreEqual(zzz.Address, zzz2.Address); + } + + public class Zzz + { + public IPAddress Address { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestIPEndPoint.cs b/GroBuf.Tests/TestIPEndPoint.cs similarity index 97% rename from GroBuf/Tests/TestIPEndPoint.cs rename to GroBuf.Tests/TestIPEndPoint.cs index 3c3caa3..e99572f 100644 --- a/GroBuf/Tests/TestIPEndPoint.cs +++ b/GroBuf.Tests/TestIPEndPoint.cs @@ -1,52 +1,52 @@ -using System; -using System.Net; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestIPEndPoint - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new AllPropertiesExtractor()); - } - - [Test] - public void TestReadWrite() - { - var endPoint = new IPEndPoint(new IPAddress(new byte[] {123, 1, 2, 3}), 146); - var data = serializer.Serialize(endPoint); - var endPoint2 = serializer.Deserialize(data); - Assert.AreEqual(endPoint, endPoint2); - endPoint = new IPEndPoint(new IPAddress(Guid.NewGuid().ToByteArray()), 146); - data = serializer.Serialize(endPoint); - endPoint2 = serializer.Deserialize(data); - Assert.AreEqual(endPoint, endPoint2); - } - - [Test] - public void TestReadWrite2() - { - var zzz = new Zzz {EndPoint = new IPEndPoint(new IPAddress(new byte[] {123, 1, 2, 3}), 146)}; - var data = serializer.Serialize(zzz); - var zzz2 = serializer.Deserialize(data); - Assert.AreEqual(zzz.EndPoint, zzz2.EndPoint); - zzz = new Zzz {EndPoint = new IPEndPoint(new IPAddress(Guid.NewGuid().ToByteArray()), 146)}; - data = serializer.Serialize(zzz); - zzz2 = serializer.Deserialize(data); - Assert.AreEqual(zzz.EndPoint, zzz2.EndPoint); - } - - public class Zzz - { - public IPEndPoint EndPoint { get; set; } - } - - private Serializer serializer; - } +using System; +using System.Net; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestIPEndPoint + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new AllPropertiesExtractor()); + } + + [Test] + public void TestReadWrite() + { + var endPoint = new IPEndPoint(new IPAddress(new byte[] {123, 1, 2, 3}), 146); + var data = serializer.Serialize(endPoint); + var endPoint2 = serializer.Deserialize(data); + Assert.AreEqual(endPoint, endPoint2); + endPoint = new IPEndPoint(new IPAddress(Guid.NewGuid().ToByteArray()), 146); + data = serializer.Serialize(endPoint); + endPoint2 = serializer.Deserialize(data); + Assert.AreEqual(endPoint, endPoint2); + } + + [Test] + public void TestReadWrite2() + { + var zzz = new Zzz {EndPoint = new IPEndPoint(new IPAddress(new byte[] {123, 1, 2, 3}), 146)}; + var data = serializer.Serialize(zzz); + var zzz2 = serializer.Deserialize(data); + Assert.AreEqual(zzz.EndPoint, zzz2.EndPoint); + zzz = new Zzz {EndPoint = new IPEndPoint(new IPAddress(Guid.NewGuid().ToByteArray()), 146)}; + data = serializer.Serialize(zzz); + zzz2 = serializer.Deserialize(data); + Assert.AreEqual(zzz.EndPoint, zzz2.EndPoint); + } + + public class Zzz + { + public IPEndPoint EndPoint { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestLazy.cs b/GroBuf.Tests/TestLazy.cs similarity index 90% rename from GroBuf/Tests/TestLazy.cs rename to GroBuf.Tests/TestLazy.cs index 9cf3aff..54fe557 100644 --- a/GroBuf/Tests/TestLazy.cs +++ b/GroBuf.Tests/TestLazy.cs @@ -1,126 +1,125 @@ -using System; -using System.Linq; -using System.Reflection; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestLazy - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new AllPropertiesExtractor()); - } - - [Test] - public void Test_WriteLazyReadWithoutLazy() - { - var o = new A {B = new Lazy(() => new B {S = "zzz"})}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.IsNotNull(oo.B); - Assert.That(oo.B.S, Is.EqualTo("zzz")); - } - - [Test] - public void Test_WriteReadSameSerializer() - { - var o = new A { B = new Lazy(() => new B { S = "qxx" }) }; - var data = serializer.Serialize(o); - o = serializer.Deserialize(data); - data = serializer.Serialize(o); - Assert.That(o.B.IsValueCreated, Is.EqualTo(false)); - var oo = serializer.Deserialize(data); - Assert.IsNotNull(oo.B); - Assert.That(oo.B.S, Is.EqualTo("qxx")); - } - - [Test] - public void Test_WriteReadDifferentSerializers() - { - var o = new A { B = new Lazy(() => new B { S = "qxx" }) }; - var data = serializer.Serialize(o); - o = serializer.Deserialize(data); - var serializer2 = new Serializer(new AllPropertiesExtractor()); - data = serializer2.Serialize(o); - Assert.That(o.B.IsValueCreated, Is.EqualTo(true)); - var oo = serializer2.Deserialize(data); - Assert.IsNotNull(oo.B); - Assert.That(oo.B.S, Is.EqualTo("qxx")); - } - - [Test] - public void Test_ReadLazyAsRawData() - { - var o = new A() {B = new Lazy(() => new B {S = "zzz"})}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - var valueFactoryField = typeof(Lazy).GetField("m_valueFactory", BindingFlags.Instance | BindingFlags.NonPublic); - string targetFieldName = GroBufHelpers.IsMono ? "m_target" : "_target"; - var targetField = typeof(Delegate).GetField(targetFieldName, BindingFlags.Instance | BindingFlags.NonPublic); - var rawDataType = typeof(Serializer).Assembly.GetTypes().Single(type => type.Name == "RawData`1"); - var dataField = rawDataType.MakeGenericType(typeof(B)).GetField("data", BindingFlags.Instance | BindingFlags.NonPublic); - var func = (Func)valueFactoryField.GetValue(oo.B); - var target = targetField.GetValue(func); - Assert.That(target, Is.InstanceOf(rawDataType.MakeGenericType(typeof(B)))); - data = (byte[])dataField.GetValue(target); - var b = serializer.Deserialize(data); - Assert.That(b.S, Is.EqualTo("zzz")); - b = oo.B.Value; - Assert.That(b.S, Is.EqualTo("zzz")); - } - - [Test] - public void Test_WriteLazyWithoutFactory() - { - var o = new A() { B = new Lazy() }; - var data = serializer.Serialize(o); - } - - [Test] - public void Test_ValueType() - { - var guid = Guid.NewGuid(); - var o = new C {Guid = new Lazy(() => guid)}; - var data = serializer.Serialize(o); - Console.WriteLine(DebugViewBuilder.DebugView(data)); - var oo = serializer.Deserialize(data); - Assert.That(oo.Guid.Value, Is.EqualTo(guid)); - } - - private static long GetWriterId(Serializer serializer) - { - var grobufWriterType = typeof(Serializer).Assembly.GetTypes().Single(type => type.Name == "GroBufWriter"); - var writerField = typeof(Serializer).GetField("writer", BindingFlags.Instance | BindingFlags.NonPublic); - var serializerIdField = grobufWriterType.GetField("serializerId", BindingFlags.Instance | BindingFlags.NonPublic); - return (long)serializerIdField.GetValue(writerField.GetValue(serializer)); - } - - private Serializer serializer; - - public class A - { - public Lazy B { get; set; } - } - - public class A_WithoutLazy - { - public B B { get; set; } - } - - public class B - { - public string S { get; set; } - } - - public class C - { - public Lazy Guid { get; set; } - } - } +using System; +using System.Linq; +using System.Reflection; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestLazy + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new AllPropertiesExtractor()); + } + + [Test] + public void Test_WriteLazyReadWithoutLazy() + { + var o = new A {B = new Lazy(() => new B {S = "zzz"})}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.IsNotNull(oo.B); + Assert.That(oo.B.S, Is.EqualTo("zzz")); + } + + [Test] + public void Test_WriteReadSameSerializer() + { + var o = new A { B = new Lazy(() => new B { S = "qxx" }) }; + var data = serializer.Serialize(o); + o = serializer.Deserialize(data); + data = serializer.Serialize(o); + Assert.That(o.B.IsValueCreated, Is.EqualTo(false)); + var oo = serializer.Deserialize(data); + Assert.IsNotNull(oo.B); + Assert.That(oo.B.S, Is.EqualTo("qxx")); + } + + [Test] + public void Test_WriteReadDifferentSerializers() + { + var o = new A { B = new Lazy(() => new B { S = "qxx" }) }; + var data = serializer.Serialize(o); + o = serializer.Deserialize(data); + var serializer2 = new Serializer(new AllPropertiesExtractor()); + data = serializer2.Serialize(o); + Assert.That(o.B.IsValueCreated, Is.EqualTo(true)); + var oo = serializer2.Deserialize(data); + Assert.IsNotNull(oo.B); + Assert.That(oo.B.S, Is.EqualTo("qxx")); + } + + [Test] + public void Test_ReadLazyAsRawData() + { + var o = new A() {B = new Lazy(() => new B {S = "zzz"})}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + var valueFactoryField = typeof(Lazy).GetField(PlatformHelpers.LazyValueFactoryFieldName, BindingFlags.Instance | BindingFlags.NonPublic); + var targetField = typeof(Delegate).GetField(PlatformHelpers.DelegateTargetFieldName, BindingFlags.Instance | BindingFlags.NonPublic); + var rawDataType = typeof(Serializer).Assembly.GetTypes().Single(type => type.Name == "RawData`1"); + var dataField = rawDataType.MakeGenericType(typeof(B)).GetField("data", BindingFlags.Instance | BindingFlags.NonPublic); + var func = (Func)valueFactoryField.GetValue(oo.B); + var target = targetField.GetValue(func); + Assert.That(target, Is.InstanceOf(rawDataType.MakeGenericType(typeof(B)))); + data = (byte[])dataField.GetValue(target); + var b = serializer.Deserialize(data); + Assert.That(b.S, Is.EqualTo("zzz")); + b = oo.B.Value; + Assert.That(b.S, Is.EqualTo("zzz")); + } + + [Test] + public void Test_WriteLazyWithoutFactory() + { + var o = new A() { B = new Lazy() }; + var data = serializer.Serialize(o); + } + + [Test] + public void Test_ValueType() + { + var guid = Guid.NewGuid(); + var o = new C {Guid = new Lazy(() => guid)}; + var data = serializer.Serialize(o); + Console.WriteLine(DebugViewBuilder.DebugView(data)); + var oo = serializer.Deserialize(data); + Assert.That(oo.Guid.Value, Is.EqualTo(guid)); + } + + private static long GetWriterId(Serializer serializer) + { + var grobufWriterType = typeof(Serializer).Assembly.GetTypes().Single(type => type.Name == "GroBufWriter"); + var writerField = typeof(Serializer).GetField("writer", BindingFlags.Instance | BindingFlags.NonPublic); + var serializerIdField = grobufWriterType.GetField("serializerId", BindingFlags.Instance | BindingFlags.NonPublic); + return (long)serializerIdField.GetValue(writerField.GetValue(serializer)); + } + + private Serializer serializer; + + public class A + { + public Lazy B { get; set; } + } + + public class A_WithoutLazy + { + public B B { get; set; } + } + + public class B + { + public string S { get; set; } + } + + public class C + { + public Lazy Guid { get; set; } + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestList.cs b/GroBuf.Tests/TestList.cs similarity index 96% rename from GroBuf/Tests/TestList.cs rename to GroBuf.Tests/TestList.cs index 46f401d..6fda10b 100644 --- a/GroBuf/Tests/TestList.cs +++ b/GroBuf.Tests/TestList.cs @@ -1,383 +1,390 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -using ProtoBuf; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestList - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void TestGetSize() - { - var list = new List {"1", "2"}; - int size = serializer.GetSize(list); - Console.WriteLine(size); - } - - [Test] - public void TestGetSizePrimitives() - { - var list = new List {1, 2}; - int size = serializer.GetSize(list); - Console.WriteLine(size); - } - - [Test] - public void TestWrite() - { - var list = new List {"1", "2"}; - byte[] buf = serializer.Serialize(list); - Console.WriteLine(buf.Length); - } - - [Test] - public void TestWritePrimitives() - { - var list = new List {1, 2}; - byte[] buf = serializer.Serialize(list); - Console.WriteLine(buf.Length); - } - - [Test] - public void TestRead() - { - var list = new List {"1", "2"}; - byte[] buf = serializer.Serialize(list); - var list2 = serializer.Deserialize>(buf); - Assert.AreEqual(2, list2.Count); - Assert.AreEqual("1", list2[0]); - Assert.AreEqual("2", list2[1]); - } - - [Test] - public void TestAddRemoveElements() - { - var list = new List {"1", "2"}; - list.Remove("1"); - byte[] buf = serializer.Serialize(list); - var list2 = serializer.Deserialize>(buf); - Assert.AreEqual(1, list2.Count); - Assert.AreEqual("2", list2[0]); - } - - [Test] - public void TestReadPrimitives() - { - var list = new List {1, 2}; - byte[] buf = serializer.Serialize(list); - var list2 = serializer.Deserialize>(buf); - Assert.AreEqual(2, list2.Count); - Assert.AreEqual(1, list2[0]); - Assert.AreEqual(2, list2[1]); - } - - [Test] - public void TestCanAddRemove() - { - var list = new List {1, 2}; - byte[] buf = serializer.Serialize(list); - var list2 = serializer.Deserialize>(buf); - Assert.AreEqual(2, list2.Count); - Assert.AreEqual(1, list2[0]); - Assert.AreEqual(2, list2[1]); - for(int i = 3; i <= 100; ++i) - list2.Add(i); - Assert.AreEqual(100, list2.Count); - for(int i = 1; i <= 100; ++i) - Assert.AreEqual(i, list2[i - 1]); - buf = serializer.Serialize(list2); - list = serializer.Deserialize>(buf); - Assert.AreEqual(100, list.Count); - for(int i = 1; i <= 100; ++i) - Assert.AreEqual(i, list2[i - 1]); - list.RemoveRange(10, 90); - Assert.AreEqual(10, list.Count); - for(int i = 1; i <= 10; ++i) - Assert.AreEqual(i, list2[i - 1]); - } - - [Test] - public void TestCompatibilityWithArray() - { - var list = new List {"1", "2"}; - byte[] data = serializer.Serialize(list); - var array = serializer.Deserialize(data); - Assert.AreEqual(2, array.Length); - Assert.AreEqual("1", array[0]); - Assert.AreEqual("2", array[1]); - array = new[] {"3", "2", "1"}; - data = serializer.Serialize(array); - list = serializer.Deserialize>(data); - Assert.AreEqual(3, list.Count); - Assert.AreEqual("3", list[0]); - Assert.AreEqual("2", list[1]); - Assert.AreEqual("1", list[2]); - } - - [Test] - public void TestCompatibilityWithArrayOfPrimitives() - { - var list = new List {1, 2}; - byte[] data = serializer.Serialize(list); - var array = serializer.Deserialize(data); - Assert.AreEqual(2, array.Length); - Assert.AreEqual(1, array[0]); - Assert.AreEqual(2, array[1]); - array = new[] {3, 2, 1}; - data = serializer.Serialize(array); - list = serializer.Deserialize>(data); - Assert.AreEqual(3, list.Count); - Assert.AreEqual(3, list[0]); - Assert.AreEqual(2, list[1]); - Assert.AreEqual(1, list[2]); - } - - [Test, Ignore] - public void TestPerformance() - { - var list = new List(); - for(int i = 0; i < 10000; ++i) - list.Add(i); - - Console.WriteLine(serializer.GetSize(list)); - serializer.Deserialize>(serializer.Serialize(list)); - Stopwatch stopwatch = Stopwatch.StartNew(); - const int iterations = 1000000; - for(int iter = 0; iter < iterations; ++iter) - serializer.GetSize(list); - TimeSpan elapsed = stopwatch.Elapsed; - Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - { - serializer.Serialize(list); - } - elapsed = stopwatch.Elapsed; - Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); - byte[] buf = serializer.Serialize(list); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - { - serializer.Deserialize>(buf); - } - elapsed = stopwatch.Elapsed; - Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); - } - - [Test, Ignore] - public void TestPerformance2() - { - var obj = new A{Items = new List()}; - for(int i = 0; i < 10000; ++i) - obj.Items.Add(new Item{X = i}); - - Console.WriteLine(serializer.GetSize(obj)); - serializer.Deserialize(serializer.Serialize(obj)); - Stopwatch stopwatch = Stopwatch.StartNew(); - const int iterations = 100000; - for(int iter = 0; iter < iterations; ++iter) - serializer.GetSize(obj); - TimeSpan elapsed = stopwatch.Elapsed; - Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - { - serializer.Serialize(obj); - } - elapsed = stopwatch.Elapsed; - Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); - byte[] buf = serializer.Serialize(obj); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - { - serializer.Deserialize(buf); - } - elapsed = stopwatch.Elapsed; - Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); - } - - [Test, Ignore] - public void TestPerformanceGuid() - { - var list = new List(); - for(int i = 0; i < 10000; ++i) - list.Add(Guid.NewGuid()); - - var stream = new MemoryStream(128 * 1024); - - Console.WriteLine(serializer.GetSize(list)); - serializer.Deserialize>(serializer.Serialize(list)); - Stopwatch stopwatch = Stopwatch.StartNew(); - const int iterations = 10000; - for(int iter = 0; iter < iterations; ++iter) - serializer.GetSize(list); - TimeSpan elapsed = stopwatch.Elapsed; - Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - { - stream.Position = 0; - stream.SetLength(0); - serializer.Serialize(list); - } - elapsed = stopwatch.Elapsed; - Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); - byte[] buf = serializer.Serialize(list); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - { - stream.Position = 0; - stream.SetLength(0); - serializer.Deserialize>(buf); - } - elapsed = stopwatch.Elapsed; - Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); - } - - [Test, Ignore] - public void TestPerformanceProtobuf() - { - var list = new List(); - for(int i = 0; i < 10000; ++i) - list.Add(i); - - var stream = new MemoryStream(128 * 1024); - ProtoBuf.Serializer.Serialize(stream, list); - stream.Position = 0; - //stream.SetLength(0); - ProtoBuf.Serializer.Deserialize>(stream); - - const int iterations = 10000; - Stopwatch stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - { - stream.Position = 0; - //stream.SetLength(0); - ProtoBuf.Serializer.Serialize(stream, list); - } - TimeSpan elapsed = stopwatch.Elapsed; - Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - { - stream.Position = 0; - //stream.SetLength(0); - ProtoBuf.Serializer.Deserialize>(stream); - } - elapsed = stopwatch.Elapsed; - Assert.AreEqual(10000, list.Count); - for (int i = 0; i < 10000; ++i) - Assert.AreEqual(i, list[i]); - Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); - } - - [Test, Ignore] - public void TestPerformanceProtobuf2() - { - var obj = new A {Items = new List()}; - for(int i = 0; i < 10000; ++i) - obj.Items.Add(new Item{X = i}); - - var stream = new MemoryStream(128 * 1024); - ProtoBuf.Serializer.Serialize(stream, obj); - stream.Position = 0; - var a = ProtoBuf.Serializer.Deserialize(stream); - Assert.AreEqual(10000, a.Items.Count); - - const int iterations = 10000; - Stopwatch stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - { - stream.Position = 0; - //stream.SetLength(0); - ProtoBuf.Serializer.Serialize(stream, obj); - } - TimeSpan elapsed = stopwatch.Elapsed; - Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); - stopwatch = Stopwatch.StartNew(); - for(int iter = 0; iter < iterations; ++iter) - { - stream.Position = 0; - //stream.SetLength(0); - a = ProtoBuf.Serializer.Deserialize(stream); - } - elapsed = stopwatch.Elapsed; - Assert.AreEqual(10000, a.Items.Count); - for(int i = 0; i < 10000; ++i) - Assert.AreEqual(i, a.Items[i].X); - Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); - } - - [Test] - public void TestListGetSizeBug() - { - serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.WriteEmptyObjects); - var contract = new BadContract - { - List = new List() - }; - byte[] serialized = serializer.Serialize(contract); - int size = serializer.GetSize(contract); - Assert.AreEqual(serialized.Length, size); - - int index = 0; - var dst = new byte[size]; - serializer.Serialize(contract, dst, ref index); - Assert.AreEqual(index, size); - } - - [Test] - public void TestPrimitivesListGetSizeBug() - { - serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.WriteEmptyObjects); - var contract = new BadContract - { - IntList = new List() - }; - byte[] serialized = serializer.Serialize(contract); - int size = serializer.GetSize(contract); - Assert.AreEqual(serialized.Length, size); - - int index = 0; - var dst = new byte[size]; - serializer.Serialize(contract, dst, ref index); - Assert.AreEqual(index, size); - } - - private Serializer serializer; - - [ProtoContract] - private class A - { - [ProtoMember(1)] - public List Items { get; set; } - } - - [ProtoContract] - private class Item - { - [ProtoMember(1)] - public int X { get; set; } - } - - private class BadContract - { - public List List { get; set; } - public List IntList { get; set; } - } - } +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +using ProtoBuf; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestList + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestGetSize() + { + var list = new List {"1", "2"}; + int size = serializer.GetSize(list); + Console.WriteLine(size); + } + + [Test] + public void TestGetSizePrimitives() + { + var list = new List {1, 2}; + int size = serializer.GetSize(list); + Console.WriteLine(size); + } + + [Test] + public void TestWrite() + { + var list = new List {"1", "2"}; + byte[] buf = serializer.Serialize(list); + Console.WriteLine(buf.Length); + } + + [Test] + public void TestWritePrimitives() + { + var list = new List {1, 2}; + byte[] buf = serializer.Serialize(list); + Console.WriteLine(buf.Length); + } + + [Test] + public void TestRead() + { + var list = new List {"1", "2"}; + byte[] buf = serializer.Serialize(list); + var list2 = serializer.Deserialize>(buf); + Assert.AreEqual(2, list2.Count); + Assert.AreEqual("1", list2[0]); + Assert.AreEqual("2", list2[1]); + } + + [Test] + public void TestAddRemoveElements() + { + var list = new List {"1", "2"}; + list.Remove("1"); + byte[] buf = serializer.Serialize(list); + var list2 = serializer.Deserialize>(buf); + Assert.AreEqual(1, list2.Count); + Assert.AreEqual("2", list2[0]); + } + + [Test] + public void TestReadPrimitives() + { + var list = new List {1, 2}; + byte[] buf = serializer.Serialize(list); + var list2 = serializer.Deserialize>(buf); + Assert.AreEqual(2, list2.Count); + Assert.AreEqual(1, list2[0]); + Assert.AreEqual(2, list2[1]); + } + + [Test] + public void TestCanAddRemove() + { + var list = new List {1, 2}; + byte[] buf = serializer.Serialize(list); + var list2 = serializer.Deserialize>(buf); + Assert.AreEqual(2, list2.Count); + Assert.AreEqual(1, list2[0]); + Assert.AreEqual(2, list2[1]); + for(int i = 3; i <= 100; ++i) + list2.Add(i); + Assert.AreEqual(100, list2.Count); + for(int i = 1; i <= 100; ++i) + Assert.AreEqual(i, list2[i - 1]); + buf = serializer.Serialize(list2); + list = serializer.Deserialize>(buf); + Assert.AreEqual(100, list.Count); + for(int i = 1; i <= 100; ++i) + Assert.AreEqual(i, list2[i - 1]); + list.RemoveRange(10, 90); + Assert.AreEqual(10, list.Count); + for(int i = 1; i <= 10; ++i) + Assert.AreEqual(i, list2[i - 1]); + } + + [Test] + public void TestCompatibilityWithArray() + { + var list = new List {"1", "2"}; + byte[] data = serializer.Serialize(list); + var array = serializer.Deserialize(data); + Assert.AreEqual(2, array.Length); + Assert.AreEqual("1", array[0]); + Assert.AreEqual("2", array[1]); + array = new[] {"3", "2", "1"}; + data = serializer.Serialize(array); + list = serializer.Deserialize>(data); + Assert.AreEqual(3, list.Count); + Assert.AreEqual("3", list[0]); + Assert.AreEqual("2", list[1]); + Assert.AreEqual("1", list[2]); + } + + [Test] + public void TestCompatibilityWithArrayOfPrimitives() + { + var list = new List {1, 2}; + byte[] data = serializer.Serialize(list); + var array = serializer.Deserialize(data); + Assert.AreEqual(2, array.Length); + Assert.AreEqual(1, array[0]); + Assert.AreEqual(2, array[1]); + array = new[] {3, 2, 1}; + data = serializer.Serialize(array); + list = serializer.Deserialize>(data); + Assert.AreEqual(3, list.Count); + Assert.AreEqual(3, list[0]); + Assert.AreEqual(2, list[1]); + Assert.AreEqual(1, list[2]); + } + + [Test] + [Category("LongRunning")] + public void TestPerformance() + { + var list = new List(); + for(int i = 0; i < 10000; ++i) + list.Add(i); + + Console.WriteLine(serializer.GetSize(list)); + serializer.Deserialize>(serializer.Serialize(list)); + Stopwatch stopwatch = Stopwatch.StartNew(); + const int iterations = 1000000; + for(int iter = 0; iter < iterations; ++iter) + serializer.GetSize(list); + TimeSpan elapsed = stopwatch.Elapsed; + Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + { + serializer.Serialize(list); + } + elapsed = stopwatch.Elapsed; + Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); + byte[] buf = serializer.Serialize(list); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + { + serializer.Deserialize>(buf); + } + elapsed = stopwatch.Elapsed; + Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); + } + + [Test] + [Category("LongRunning")] + public void TestPerformance2() + { + var obj = new A{Items = new List()}; + for(int i = 0; i < 10000; ++i) + obj.Items.Add(new Item{X = i}); + + Console.WriteLine(serializer.GetSize(obj)); + serializer.Deserialize(serializer.Serialize(obj)); + Stopwatch stopwatch = Stopwatch.StartNew(); + const int iterations = 100000; + for(int iter = 0; iter < iterations; ++iter) + serializer.GetSize(obj); + TimeSpan elapsed = stopwatch.Elapsed; + Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + { + serializer.Serialize(obj); + } + elapsed = stopwatch.Elapsed; + Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); + byte[] buf = serializer.Serialize(obj); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + { + serializer.Deserialize(buf); + } + elapsed = stopwatch.Elapsed; + Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); + } + + [Test] + [Category("LongRunning")] + public void TestPerformanceGuid() + { + var list = new List(); + for(int i = 0; i < 10000; ++i) + list.Add(Guid.NewGuid()); + + var stream = new MemoryStream(128 * 1024); + + Console.WriteLine(serializer.GetSize(list)); + serializer.Deserialize>(serializer.Serialize(list)); + Stopwatch stopwatch = Stopwatch.StartNew(); + const int iterations = 10000; + for(int iter = 0; iter < iterations; ++iter) + serializer.GetSize(list); + TimeSpan elapsed = stopwatch.Elapsed; + Console.WriteLine("Size computing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " size computations per second)"); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + { + stream.Position = 0; + stream.SetLength(0); + serializer.Serialize(list); + } + elapsed = stopwatch.Elapsed; + Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); + byte[] buf = serializer.Serialize(list); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + { + stream.Position = 0; + stream.SetLength(0); + serializer.Deserialize>(buf); + } + elapsed = stopwatch.Elapsed; + Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); + } + + [Test] + [Category("LongRunning")] + [Ignore("Is used for debugging")] + public void TestPerformanceProtobuf() + { + var list = new List(); + for(int i = 0; i < 10000; ++i) + list.Add(i); + + var stream = new MemoryStream(128 * 1024); + ProtoBuf.Serializer.Serialize(stream, list); + stream.Position = 0; + //stream.SetLength(0); + ProtoBuf.Serializer.Deserialize>(stream); + + const int iterations = 10000; + Stopwatch stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + { + stream.Position = 0; + //stream.SetLength(0); + ProtoBuf.Serializer.Serialize(stream, list); + } + TimeSpan elapsed = stopwatch.Elapsed; + Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + { + stream.Position = 0; + //stream.SetLength(0); + ProtoBuf.Serializer.Deserialize>(stream); + } + elapsed = stopwatch.Elapsed; + Assert.AreEqual(10000, list.Count); + for (int i = 0; i < 10000; ++i) + Assert.AreEqual(i, list[i]); + Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); + } + + [Test] + [Category("LongRunning")] + [Ignore("Is used for debugging")] + public void TestPerformanceProtobuf2() + { + var obj = new A {Items = new List()}; + for(int i = 0; i < 10000; ++i) + obj.Items.Add(new Item{X = i}); + + var stream = new MemoryStream(128 * 1024); + ProtoBuf.Serializer.Serialize(stream, obj); + stream.Position = 0; + var a = ProtoBuf.Serializer.Deserialize(stream); + Assert.AreEqual(10000, a.Items.Count); + + const int iterations = 10000; + Stopwatch stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + { + stream.Position = 0; + //stream.SetLength(0); + ProtoBuf.Serializer.Serialize(stream, obj); + } + TimeSpan elapsed = stopwatch.Elapsed; + Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); + stopwatch = Stopwatch.StartNew(); + for(int iter = 0; iter < iterations; ++iter) + { + stream.Position = 0; + //stream.SetLength(0); + a = ProtoBuf.Serializer.Deserialize(stream); + } + elapsed = stopwatch.Elapsed; + Assert.AreEqual(10000, a.Items.Count); + for(int i = 0; i < 10000; ++i) + Assert.AreEqual(i, a.Items[i].X); + Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); + } + + [Test] + public void TestListGetSizeBug() + { + serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.WriteEmptyObjects); + var contract = new BadContract + { + List = new List() + }; + byte[] serialized = serializer.Serialize(contract); + int size = serializer.GetSize(contract); + Assert.AreEqual(serialized.Length, size); + + int index = 0; + var dst = new byte[size]; + serializer.Serialize(contract, dst, ref index); + Assert.AreEqual(index, size); + } + + [Test] + public void TestPrimitivesListGetSizeBug() + { + serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.WriteEmptyObjects); + var contract = new BadContract + { + IntList = new List() + }; + byte[] serialized = serializer.Serialize(contract); + int size = serializer.GetSize(contract); + Assert.AreEqual(serialized.Length, size); + + int index = 0; + var dst = new byte[size]; + serializer.Serialize(contract, dst, ref index); + Assert.AreEqual(index, size); + } + + private Serializer serializer; + + [ProtoContract] + private class A + { + [ProtoMember(1)] + public List Items { get; set; } + } + + [ProtoContract] + private class Item + { + [ProtoMember(1)] + public int X { get; set; } + } + + private class BadContract + { + public List List { get; set; } + public List IntList { get; set; } + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestMerge.cs b/GroBuf.Tests/TestMerge.cs similarity index 97% rename from GroBuf/Tests/TestMerge.cs rename to GroBuf.Tests/TestMerge.cs index c84aced..5c9cc8f 100644 --- a/GroBuf/Tests/TestMerge.cs +++ b/GroBuf.Tests/TestMerge.cs @@ -1,201 +1,201 @@ -using System.Collections.Generic; - -using GroBuf.DataMembersExtracters; -using GroBuf.Tests.TestTools; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestMerge - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.MergeOnRead); - } - - [Test] - public void TestArray1() - { - var first = new int?[] {1, null}; - var second = new int?[] {2, 3, 5}; - serializer.Merge(first, ref second); - second.AssertEqualsTo(new int?[] {1, 3, 5}); - - first = new int?[] {1, null, 3, 4}; - second = new int?[] {5, 6, 7}; - serializer.Merge(first, ref second); - second.AssertEqualsTo(new int?[] {1, 6, 3, 4}); - } - - [Test] - public void TestArray2() - { - var first = new[] {1, 2}; - var second = new[] {2, 3, 5}; - serializer.Merge(first, ref second); - second.AssertEqualsTo(new[] {1, 2, 5}); - - first = new[] {1, 2, 3, 4}; - second = new[] {5, 6, 7}; - serializer.Merge(first, ref second); - second.AssertEqualsTo(new[] {1, 2, 3, 4}); - } - - [Test] - public void TestList1() - { - var first = new List {1, null}; - var second = new List {2, 3, 5}; - serializer.Merge(first, ref second); - Assert.AreEqual(3, second.Count); - Assert.AreEqual(1, second[0]); - Assert.AreEqual(3, second[1]); - Assert.AreEqual(5, second[2]); - - first = new List {1, null, 3, 4}; - second = new List {5, 6, 7}; - serializer.Merge(first, ref second); - Assert.AreEqual(4, second.Count); - Assert.AreEqual(1, second[0]); - Assert.AreEqual(6, second[1]); - Assert.AreEqual(3, second[2]); - Assert.AreEqual(4, second[3]); - } - - [Test] - public void TestList2() - { - var first = new List {1, 2}; - var second = new List {2, 3, 5}; - serializer.Merge(first, ref second); - Assert.AreEqual(3, second.Count); - Assert.AreEqual(1, second[0]); - Assert.AreEqual(2, second[1]); - Assert.AreEqual(5, second[2]); - - first = new List {1, 2, 3, 4}; - second = new List {5, 6, 7}; - serializer.Merge(first, ref second); - Assert.AreEqual(4, second.Count); - Assert.AreEqual(1, second[0]); - Assert.AreEqual(2, second[1]); - Assert.AreEqual(3, second[2]); - Assert.AreEqual(4, second[3]); - } - - [Test] - public void TestClass() - { - var first = new A {Bool = true}; - var second = new A {Bool = false, B = new B {S = "zzz"}}; - serializer.Merge(first, ref second); - second.AssertEqualsTo(new A {Bool = true, B = new B {S = "zzz"}}); - - first = new A {Bool = true, B = new B {S = "qxx"}, Bs = new[] {null, new B {S = "qzz"}}}; - second = new A {B = new B {S = "zzz", Long = 12341234}, Bs = new[] {new B {S = "xxx"}, new B {S = "qqq", Long = 1287346}}}; - serializer.Merge(first, ref second); - second.AssertEqualsTo(new A {Bool = true, B = new B {S = "qxx", Long = 12341234}, Bs = new[] {new B {S = "xxx"}, new B {S = "qzz", Long = 1287346}}}); - } - - [Test] - public void TestStruct() - { - var first = new As {Bool = true}; - var second = new As {Bool = false, B = new Bs {S = "zzz"}}; - serializer.Merge(first, ref second); - second.AssertEqualsTo(new As {Bool = true, B = new Bs {S = "zzz"}}); - - first = new As {Bool = true, B = new Bs {S = "qxx"}, Bs = new[] {new Bs(), new Bs {S = "qzz"}}}; - second = new As {B = new Bs {S = "zzz", Long = 12341234}, Bs = new[] {new Bs {S = "xxx"}, new Bs {S = "qqq", Long = 1287346}}}; - serializer.Merge(first, ref second); - second.AssertEqualsTo(new As {Bool = true, B = new Bs {S = "qxx", Long = 12341234}, Bs = new[] {new Bs {S = "xxx"}, new Bs {S = "qzz", Long = 1287346}}}); - } - - [Test] - public void TestIgnoreDefaultPropPrimitive() - { - var z = new Z{X = 3}; - var z2 = new Z {X = 0}; - serializer.Merge(z2, ref z); - Assert.AreEqual(3, z.X); - } - - [Test] - public void TestIgnoreDefaultPropStruct() - { - var z = new Z{Y = 3m}; - var z2 = new Z {Y = 0m}; - serializer.Merge(z2, ref z); - Assert.AreEqual(3m, z.Y); - } - - [Test] - public void TestIgnoreDefaultFieldPrimitive() - { - var serializer2 = new Serializer(new FieldsExtractor(), null, GroBufOptions.MergeOnRead); - var z = new ZZ{X = 3}; - var z2 = new ZZ {X = 0}; - serializer2.Merge(z2, ref z); - Assert.AreEqual(3, z.X); - } - - [Test] - public void TestIgnoreDefaultFieldStruct() - { - var serializer2 = new Serializer(new FieldsExtractor(), null, GroBufOptions.MergeOnRead); - var z = new ZZ { Y = 3m }; - var z2 = new ZZ {Y = 0m}; - serializer2.Merge(z2, ref z); - Assert.AreEqual(3m, z.Y); - } - - public class Z - { - [IgnoreDefaultOnMerge] - public int X { get; set; } - - [IgnoreDefaultOnMerge] - public decimal Y { get; set; } - } - - public class ZZ - { - [IgnoreDefaultOnMerge] - public int X; - - [IgnoreDefaultOnMerge] - public decimal Y; - } - - public class A - { - public B[] Bs { get; set; } - public bool? Bool { get; set; } - public B B { get; set; } - } - - public class B - { - public string S { get; set; } - public long? Long { get; set; } - } - - public struct As - { - public Bs[] Bs { get; set; } - public bool? Bool { get; set; } - public Bs B { get; set; } - } - - public struct Bs - { - public string S { get; set; } - public long? Long { get; set; } - } - - private Serializer serializer; - } +using System.Collections.Generic; + +using GroBuf.DataMembersExtracters; +using GroBuf.Tests.TestTools; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestMerge + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.MergeOnRead); + } + + [Test] + public void TestArray1() + { + var first = new int?[] {1, null}; + var second = new int?[] {2, 3, 5}; + serializer.Merge(first, ref second); + second.AssertEqualsTo(new int?[] {1, 3, 5}); + + first = new int?[] {1, null, 3, 4}; + second = new int?[] {5, 6, 7}; + serializer.Merge(first, ref second); + second.AssertEqualsTo(new int?[] {1, 6, 3, 4}); + } + + [Test] + public void TestArray2() + { + var first = new[] {1, 2}; + var second = new[] {2, 3, 5}; + serializer.Merge(first, ref second); + second.AssertEqualsTo(new[] {1, 2, 5}); + + first = new[] {1, 2, 3, 4}; + second = new[] {5, 6, 7}; + serializer.Merge(first, ref second); + second.AssertEqualsTo(new[] {1, 2, 3, 4}); + } + + [Test] + public void TestList1() + { + var first = new List {1, null}; + var second = new List {2, 3, 5}; + serializer.Merge(first, ref second); + Assert.AreEqual(3, second.Count); + Assert.AreEqual(1, second[0]); + Assert.AreEqual(3, second[1]); + Assert.AreEqual(5, second[2]); + + first = new List {1, null, 3, 4}; + second = new List {5, 6, 7}; + serializer.Merge(first, ref second); + Assert.AreEqual(4, second.Count); + Assert.AreEqual(1, second[0]); + Assert.AreEqual(6, second[1]); + Assert.AreEqual(3, second[2]); + Assert.AreEqual(4, second[3]); + } + + [Test] + public void TestList2() + { + var first = new List {1, 2}; + var second = new List {2, 3, 5}; + serializer.Merge(first, ref second); + Assert.AreEqual(3, second.Count); + Assert.AreEqual(1, second[0]); + Assert.AreEqual(2, second[1]); + Assert.AreEqual(5, second[2]); + + first = new List {1, 2, 3, 4}; + second = new List {5, 6, 7}; + serializer.Merge(first, ref second); + Assert.AreEqual(4, second.Count); + Assert.AreEqual(1, second[0]); + Assert.AreEqual(2, second[1]); + Assert.AreEqual(3, second[2]); + Assert.AreEqual(4, second[3]); + } + + [Test] + public void TestClass() + { + var first = new A {Bool = true}; + var second = new A {Bool = false, B = new B {S = "zzz"}}; + serializer.Merge(first, ref second); + second.AssertEqualsTo(new A {Bool = true, B = new B {S = "zzz"}}); + + first = new A {Bool = true, B = new B {S = "qxx"}, Bs = new[] {null, new B {S = "qzz"}}}; + second = new A {B = new B {S = "zzz", Long = 12341234}, Bs = new[] {new B {S = "xxx"}, new B {S = "qqq", Long = 1287346}}}; + serializer.Merge(first, ref second); + second.AssertEqualsTo(new A {Bool = true, B = new B {S = "qxx", Long = 12341234}, Bs = new[] {new B {S = "xxx"}, new B {S = "qzz", Long = 1287346}}}); + } + + [Test] + public void TestStruct() + { + var first = new As {Bool = true}; + var second = new As {Bool = false, B = new Bs {S = "zzz"}}; + serializer.Merge(first, ref second); + second.AssertEqualsTo(new As {Bool = true, B = new Bs {S = "zzz"}}); + + first = new As {Bool = true, B = new Bs {S = "qxx"}, Bs = new[] {new Bs(), new Bs {S = "qzz"}}}; + second = new As {B = new Bs {S = "zzz", Long = 12341234}, Bs = new[] {new Bs {S = "xxx"}, new Bs {S = "qqq", Long = 1287346}}}; + serializer.Merge(first, ref second); + second.AssertEqualsTo(new As {Bool = true, B = new Bs {S = "qxx", Long = 12341234}, Bs = new[] {new Bs {S = "xxx"}, new Bs {S = "qzz", Long = 1287346}}}); + } + + [Test] + public void TestIgnoreDefaultPropPrimitive() + { + var z = new Z{X = 3}; + var z2 = new Z {X = 0}; + serializer.Merge(z2, ref z); + Assert.AreEqual(3, z.X); + } + + [Test] + public void TestIgnoreDefaultPropStruct() + { + var z = new Z{Y = 3m}; + var z2 = new Z {Y = 0m}; + serializer.Merge(z2, ref z); + Assert.AreEqual(3m, z.Y); + } + + [Test] + public void TestIgnoreDefaultFieldPrimitive() + { + var serializer2 = new Serializer(new FieldsExtractor(), null, GroBufOptions.MergeOnRead); + var z = new ZZ{X = 3}; + var z2 = new ZZ {X = 0}; + serializer2.Merge(z2, ref z); + Assert.AreEqual(3, z.X); + } + + [Test] + public void TestIgnoreDefaultFieldStruct() + { + var serializer2 = new Serializer(new FieldsExtractor(), null, GroBufOptions.MergeOnRead); + var z = new ZZ { Y = 3m }; + var z2 = new ZZ {Y = 0m}; + serializer2.Merge(z2, ref z); + Assert.AreEqual(3m, z.Y); + } + + public class Z + { + [IgnoreDefaultOnMerge] + public int X { get; set; } + + [IgnoreDefaultOnMerge] + public decimal Y { get; set; } + } + + public class ZZ + { + [IgnoreDefaultOnMerge] + public int X; + + [IgnoreDefaultOnMerge] + public decimal Y; + } + + public class A + { + public B[] Bs { get; set; } + public bool? Bool { get; set; } + public B B { get; set; } + } + + public class B + { + public string S { get; set; } + public long? Long { get; set; } + } + + public struct As + { + public Bs[] Bs { get; set; } + public bool? Bool { get; set; } + public Bs B { get; set; } + } + + public struct Bs + { + public string S { get; set; } + public long? Long { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestMultipleReadWrite.cs b/GroBuf.Tests/TestMultipleReadWrite.cs similarity index 96% rename from GroBuf/Tests/TestMultipleReadWrite.cs rename to GroBuf.Tests/TestMultipleReadWrite.cs index 566e6ba..3c7eff7 100644 --- a/GroBuf/Tests/TestMultipleReadWrite.cs +++ b/GroBuf.Tests/TestMultipleReadWrite.cs @@ -1,67 +1,67 @@ -using GroBuf.DataMembersExtracters; -using GroBuf.Tests.TestTools; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestMultipleReadWrite - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void Test() - { - byte[] data = serializer.Serialize("zzz", 100, new[] {1, 2, 3}); - int index = 0; - Assert.AreEqual("zzz", serializer.Deserialize(data, ref index)); - Assert.AreEqual(100, serializer.Deserialize(data, ref index)); - serializer.Deserialize(data, ref index).AssertEqualsTo(new[] {1, 2, 3}); - Assert.AreEqual(index, data.Length); - } - - [Test] - public void TestBug() - { - byte[] data = serializer.Serialize(new A {Q = 1, Z = 2}, new B {X = 3, Y = 4}); - int index = 0; - var aChanged = serializer.Deserialize(data, ref index); - var bChanged = serializer.Deserialize(data, ref index); - Assert.AreEqual(1, aChanged.Q); - Assert.AreEqual(0, bChanged.Z); - Assert.AreEqual(3, bChanged.X); - Assert.AreEqual(4, bChanged.Y); - } - - public class A - { - public int Q { get; set; } - public int Z { get; set; } - } - - public class B - { - public int X { get; set; } - public int Y { get; set; } - } - - public class AChanged - { - public int Q { get; set; } - } - - public class BChanged - { - public int Z { get; set; } - public int X { get; set; } - public int Y { get; set; } - } - - private ISerializer serializer; - } +using GroBuf.DataMembersExtracters; +using GroBuf.Tests.TestTools; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestMultipleReadWrite + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void Test() + { + byte[] data = serializer.Serialize("zzz", 100, new[] {1, 2, 3}); + int index = 0; + Assert.AreEqual("zzz", serializer.Deserialize(data, ref index)); + Assert.AreEqual(100, serializer.Deserialize(data, ref index)); + serializer.Deserialize(data, ref index).AssertEqualsTo(new[] {1, 2, 3}); + Assert.AreEqual(index, data.Length); + } + + [Test] + public void TestBug() + { + byte[] data = serializer.Serialize(new A {Q = 1, Z = 2}, new B {X = 3, Y = 4}); + int index = 0; + var aChanged = serializer.Deserialize(data, ref index); + var bChanged = serializer.Deserialize(data, ref index); + Assert.AreEqual(1, aChanged.Q); + Assert.AreEqual(0, bChanged.Z); + Assert.AreEqual(3, bChanged.X); + Assert.AreEqual(4, bChanged.Y); + } + + public class A + { + public int Q { get; set; } + public int Z { get; set; } + } + + public class B + { + public int X { get; set; } + public int Y { get; set; } + } + + public class AChanged + { + public int Q { get; set; } + } + + public class BChanged + { + public int Z { get; set; } + public int X { get; set; } + public int Y { get; set; } + } + + private ISerializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestNoConstructor.cs b/GroBuf.Tests/TestNoConstructor.cs similarity index 96% rename from GroBuf/Tests/TestNoConstructor.cs rename to GroBuf.Tests/TestNoConstructor.cs index 4b24d11..e387b09 100644 --- a/GroBuf/Tests/TestNoConstructor.cs +++ b/GroBuf.Tests/TestNoConstructor.cs @@ -1,73 +1,73 @@ -using System; -using System.Diagnostics; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestNoConstructor - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void TestStupid() - { - byte[] serialize = serializer.Serialize(new CNoConstructor(2)); - var cNoConstructor = serializer.Deserialize(serialize); - Assert.AreEqual(2, cNoConstructor.A); - } - - [Test] - [Category("LongRunning")] - public void TestSpeed() - { - byte[] bytes = serializer.Serialize(new CNoConstructorCopy {A = 2}); - var cNoConstructor = serializer.Deserialize(bytes); - Stopwatch w = Stopwatch.StartNew(); - for(int i = 0; i < iterations; i++) - cNoConstructor = serializer.Deserialize(bytes); - Console.WriteLine("total ms: " + w.ElapsedMilliseconds); - Console.WriteLine(cNoConstructor.A); - Assert.AreEqual(2, cNoConstructor.A); - } - - [Test] - [Category("LongRunning")] - public void TestSpeedNoCtor() - { - byte[] bytes = serializer.Serialize(new CNoConstructor(2)); - var cNoConstructor = serializer.Deserialize(bytes); - Stopwatch w = Stopwatch.StartNew(); - for(int i = 0; i < iterations; i++) - cNoConstructor = serializer.Deserialize(bytes); - Console.WriteLine("total ms: " + w.ElapsedMilliseconds); - Console.WriteLine(cNoConstructor.A); - Assert.AreEqual(2, cNoConstructor.A); - } - - public class CNoConstructor - { - public CNoConstructor(int a) - { - A = a; - } - - public int A { get; set; } - } - - public class CNoConstructorCopy - { - public int A { get; set; } - } - - private Serializer serializer; - private const int iterations = 10000000; - } +using System; +using System.Diagnostics; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestNoConstructor + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestStupid() + { + byte[] serialize = serializer.Serialize(new CNoConstructor(2)); + var cNoConstructor = serializer.Deserialize(serialize); + Assert.AreEqual(2, cNoConstructor.A); + } + + [Test] + [Category("LongRunning")] + public void TestSpeed() + { + byte[] bytes = serializer.Serialize(new CNoConstructorCopy {A = 2}); + var cNoConstructor = serializer.Deserialize(bytes); + Stopwatch w = Stopwatch.StartNew(); + for(int i = 0; i < iterations; i++) + cNoConstructor = serializer.Deserialize(bytes); + Console.WriteLine("total ms: " + w.ElapsedMilliseconds); + Console.WriteLine(cNoConstructor.A); + Assert.AreEqual(2, cNoConstructor.A); + } + + [Test] + [Category("LongRunning")] + public void TestSpeedNoCtor() + { + byte[] bytes = serializer.Serialize(new CNoConstructor(2)); + var cNoConstructor = serializer.Deserialize(bytes); + Stopwatch w = Stopwatch.StartNew(); + for(int i = 0; i < iterations; i++) + cNoConstructor = serializer.Deserialize(bytes); + Console.WriteLine("total ms: " + w.ElapsedMilliseconds); + Console.WriteLine(cNoConstructor.A); + Assert.AreEqual(2, cNoConstructor.A); + } + + public class CNoConstructor + { + public CNoConstructor(int a) + { + A = a; + } + + public int A { get; set; } + } + + public class CNoConstructorCopy + { + public int A { get; set; } + } + + private Serializer serializer; + private const int iterations = 10000000; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestNonPublicFields.cs b/GroBuf.Tests/TestNonPublicFields.cs similarity index 95% rename from GroBuf/Tests/TestNonPublicFields.cs rename to GroBuf.Tests/TestNonPublicFields.cs index cfe213f..aa2f7a0 100644 --- a/GroBuf/Tests/TestNonPublicFields.cs +++ b/GroBuf.Tests/TestNonPublicFields.cs @@ -1,48 +1,48 @@ -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestNonPublicFields - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new AllFieldsExtractor()); - } - - [Test] - public void Test() - { - byte[] serialize = serializer.Serialize(new CWithnonPublics(2378, 3434)); - var result = serializer.Deserialize(serialize); - Assert.AreEqual(2378, result.A); - Assert.AreEqual(3434, result.GetB()); - } - - public class CWithnonPublics - { - public CWithnonPublics() - { - } - - public CWithnonPublics(int a, int b) - { - A = a; - B = b; - } - - public int GetB() - { - return B; - } - - public int A { get; private set; } - public int B { private get; set; } - } - - private Serializer serializer; - } +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestNonPublicFields + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new AllFieldsExtractor()); + } + + [Test] + public void Test() + { + byte[] serialize = serializer.Serialize(new CWithnonPublics(2378, 3434)); + var result = serializer.Deserialize(serialize); + Assert.AreEqual(2378, result.A); + Assert.AreEqual(3434, result.GetB()); + } + + public class CWithnonPublics + { + public CWithnonPublics() + { + } + + public CWithnonPublics(int a, int b) + { + A = a; + B = b; + } + + public int GetB() + { + return B; + } + + public int A { get; private set; } + public int B { private get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestNonPublicProperties.cs b/GroBuf.Tests/TestNonPublicProperties.cs similarity index 95% rename from GroBuf/Tests/TestNonPublicProperties.cs rename to GroBuf.Tests/TestNonPublicProperties.cs index 137b193..f134bdb 100644 --- a/GroBuf/Tests/TestNonPublicProperties.cs +++ b/GroBuf.Tests/TestNonPublicProperties.cs @@ -1,51 +1,51 @@ -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestNonPublicProperties - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void Test() - { - byte[] serialize = serializer.Serialize(new CWithnonPublics(2378, 3434, 5656)); - var result = serializer.Deserialize(serialize); - Assert.AreEqual(2378, result.A); - Assert.AreEqual(3434, result.GetB()); - Assert.AreEqual(5656, result.C); - } - - public class CWithnonPublics - { - public CWithnonPublics() - { - } - - public CWithnonPublics(int a, int b, int c) - { - A = a; - B = b; - C = c; - } - - public int GetB() - { - return B; - } - - public int A { get; private set; } - public int B { private get; set; } - public int C { get; } - } - - private Serializer serializer; - } +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestNonPublicProperties + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void Test() + { + byte[] serialize = serializer.Serialize(new CWithnonPublics(2378, 3434, 5656)); + var result = serializer.Deserialize(serialize); + Assert.AreEqual(2378, result.A); + Assert.AreEqual(3434, result.GetB()); + Assert.AreEqual(5656, result.C); + } + + public class CWithnonPublics + { + public CWithnonPublics() + { + } + + public CWithnonPublics(int a, int b, int c) + { + A = a; + B = b; + C = c; + } + + public int GetB() + { + return B; + } + + public int A { get; private set; } + public int B { private get; set; } + public int C { get; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestNull.cs b/GroBuf.Tests/TestNull.cs similarity index 97% rename from GroBuf/Tests/TestNull.cs rename to GroBuf.Tests/TestNull.cs index f5fbadc..a2a3339 100644 --- a/GroBuf/Tests/TestNull.cs +++ b/GroBuf.Tests/TestNull.cs @@ -1,65 +1,65 @@ -using System; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestNull - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void TestClass() - { - var o = (A)null; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.IsNotNull(oo); - Assert.IsNull(oo.S); - Assert.IsNull(oo.B); - } - - [Test] - public void Test() - { - string str1 = @"CcHanVu6d9II"; - string str2 = @"CSPQYxIrDtII"; - string str3 = @"CcVGItItgdII"; - byte[] arr1 = Convert.FromBase64String(str1); - byte[] arr2 = Convert.FromBase64String(str2); - byte[] arr3 = Convert.FromBase64String(str3); - - Console.WriteLine(serializer.Deserialize(typeof(long), arr1)); - Console.WriteLine(serializer.Deserialize(typeof(long), arr2)); - Console.WriteLine(serializer.Deserialize(typeof(long), arr3)); - } - - [Test] - public void Test2() - { - string prev = @"AUABAAD7+4dqyAWRww4aAAAANAA2ADAANwAxADEANwA4ADgANAA1ADQANQCXKqz0ofYgEw4MAAAAMQAyADMANAA1ADYAFI0lnUuxneQOIgAAAC0EQARBBE4EFiEgAFQESwROBEwEQARRBFIERQQWIU4EQgRH7QmXijQ1ZQ4GAAAAUABDAEUAXhnc9MHO7eQNAAAEAAAAAACAiwgAAAAAAArEJGM3c/EEDgQAAAAxADgApgAewED9ehAOAAAAALFSl1huRAAoDhQAAAAwBFMEVwRKBEgEIABCBFEERQRMBMiPwB3tzcafDgAAAABuqp+2NkzVrQ4AAAAARiPpxDURBAcNAAADAAAAAAD4KgAAAAAAAIp4qF30h5M6DgwAAAA0ADQALAAwADAAMAAS37VDXHzi1g4AAAAAtZyIcmn4UY8OAAAAAA=="; - string curr = @"AUABAAD7+4dqyAWRww4aAAAANAA2ADAANwAxADEANwA4ADgANAA1ADQANQCXKqz0ofYgEw4MAAAAMQAyADMANAA1ADYAFI0lnUuxneQOIgAAAC0EQARBBE4EFiEgAFQESwROBEwEQARRBFIERQQWIU4EQgRH7QmXijQ1ZQ4GAAAAUABDAEUAXhnc9MHO7eQNAAACAAAAAADgFQAAAAAAAArEJGM3c/EEDgQAAAAxADgApgAewED9ehAOAAAAALFSl1huRAAoDhQAAAAwBFMEVwRKBEgEIABCBFEERQRMBMiPwB3tzcafDgAAAABuqp+2NkzVrQ4AAAAARiPpxDURBAcNAAADAAAAAAD4KgAAAAAAAIp4qF30h5M6DgwAAAA0ADQALAAwADAAMAAS37VDXHzi1g4AAAAAtZyIcmn4UY8OAAAAAA=="; - Console.WriteLine(DebugViewBuilder.DebugView(Convert.FromBase64String(curr))); - } - - public class A - { - public string S { get; set; } - public B B { get; set; } - } - - public class B - { - public int[] Ints { get; set; } - } - - private Serializer serializer; - } +using System; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestNull + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestClass() + { + var o = (A)null; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.IsNotNull(oo); + Assert.IsNull(oo.S); + Assert.IsNull(oo.B); + } + + [Test] + public void Test() + { + string str1 = @"CcHanVu6d9II"; + string str2 = @"CSPQYxIrDtII"; + string str3 = @"CcVGItItgdII"; + byte[] arr1 = Convert.FromBase64String(str1); + byte[] arr2 = Convert.FromBase64String(str2); + byte[] arr3 = Convert.FromBase64String(str3); + + Console.WriteLine(serializer.Deserialize(typeof(long), arr1)); + Console.WriteLine(serializer.Deserialize(typeof(long), arr2)); + Console.WriteLine(serializer.Deserialize(typeof(long), arr3)); + } + + [Test] + public void Test2() + { + string prev = @"AUABAAD7+4dqyAWRww4aAAAANAA2ADAANwAxADEANwA4ADgANAA1ADQANQCXKqz0ofYgEw4MAAAAMQAyADMANAA1ADYAFI0lnUuxneQOIgAAAC0EQARBBE4EFiEgAFQESwROBEwEQARRBFIERQQWIU4EQgRH7QmXijQ1ZQ4GAAAAUABDAEUAXhnc9MHO7eQNAAAEAAAAAACAiwgAAAAAAArEJGM3c/EEDgQAAAAxADgApgAewED9ehAOAAAAALFSl1huRAAoDhQAAAAwBFMEVwRKBEgEIABCBFEERQRMBMiPwB3tzcafDgAAAABuqp+2NkzVrQ4AAAAARiPpxDURBAcNAAADAAAAAAD4KgAAAAAAAIp4qF30h5M6DgwAAAA0ADQALAAwADAAMAAS37VDXHzi1g4AAAAAtZyIcmn4UY8OAAAAAA=="; + string curr = @"AUABAAD7+4dqyAWRww4aAAAANAA2ADAANwAxADEANwA4ADgANAA1ADQANQCXKqz0ofYgEw4MAAAAMQAyADMANAA1ADYAFI0lnUuxneQOIgAAAC0EQARBBE4EFiEgAFQESwROBEwEQARRBFIERQQWIU4EQgRH7QmXijQ1ZQ4GAAAAUABDAEUAXhnc9MHO7eQNAAACAAAAAADgFQAAAAAAAArEJGM3c/EEDgQAAAAxADgApgAewED9ehAOAAAAALFSl1huRAAoDhQAAAAwBFMEVwRKBEgEIABCBFEERQRMBMiPwB3tzcafDgAAAABuqp+2NkzVrQ4AAAAARiPpxDURBAcNAAADAAAAAAD4KgAAAAAAAIp4qF30h5M6DgwAAAA0ADQALAAwADAAMAAS37VDXHzi1g4AAAAAtZyIcmn4UY8OAAAAAA=="; + Console.WriteLine(DebugViewBuilder.DebugView(Convert.FromBase64String(curr))); + } + + public class A + { + public string S { get; set; } + public B B { get; set; } + } + + public class B + { + public int[] Ints { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestObject.cs b/GroBuf.Tests/TestObject.cs similarity index 96% rename from GroBuf/Tests/TestObject.cs rename to GroBuf.Tests/TestObject.cs index a73b481..6465835 100644 --- a/GroBuf/Tests/TestObject.cs +++ b/GroBuf.Tests/TestObject.cs @@ -1,167 +1,167 @@ -using System; -using System.Collections; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestObject - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void Test1() - { - var o = new A {S = "zzz", B = new B {S = (byte)100}}; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.S); - Assert.AreEqual(100, oo.B.S); - } - - [Test] - public void Test2() - { - var o = new A {S = new Guid("aae41ff9-a337-4a69-b2ee-12ead4669201"), B = new B {S = new DateTime(182374682)}}; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(new Guid("aae41ff9-a337-4a69-b2ee-12ead4669201"), oo.S); - Assert.AreEqual(new DateTime(182374682), oo.B.S); - } - - [Test] - public void TestDecimal() - { - var o = new A {S = 123m}; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(123m, oo.S); - } - - [Test] - public void TestOldDateTimeFormat() - { - var ticks = DateTime.UtcNow.Ticks; - var data = new byte[9]; - data[0] = (byte)GroBufTypeCode.DateTimeOld; - Array.Copy(BitConverter.GetBytes(ticks), 0, data, 1, 8); - var result = serializer.Deserialize(data); - Assert.AreEqual(new DateTime(ticks, DateTimeKind.Utc), result); - } - - [Test] - public void TestArray() - { - var o = new A {S = "zzz", B = new B {S = new object[] {(byte)100, "qxx"}}}; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.S); - var array = oo.B.S as Array; - Assert.NotNull(array); - Assert.AreEqual(2, array.Length); - Assert.AreEqual(100, array.GetValue(0)); - Assert.AreEqual("qxx", array.GetValue(1)); - } - - [Test] - public void TestHashtable() - { - var o = new A {S = new Hashtable {{"1", 1}, {"2", "2"}}}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - var hashtable = oo.S as Hashtable; - Assert.IsNotNull(hashtable); - Assert.AreEqual(2, hashtable.Count); - Assert.AreEqual(1, hashtable["1"]); - Assert.AreEqual("2", hashtable["2"]); - } - - [Test] - public void TestHashtableInArray() - { - var o = new A { S = "zzz", B = new B { S = new object[] { (byte)100, "qxx", new Hashtable { { "1", 1 }, { "2", "2" } } } } }; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.S); - var array = oo.B.S as Array; - Assert.NotNull(array); - Assert.AreEqual(3, array.Length); - Assert.AreEqual(100, array.GetValue(0)); - Assert.AreEqual("qxx", array.GetValue(1)); - var hashtable = array.GetValue(2) as Hashtable; - Assert.IsNotNull(hashtable); - Assert.AreEqual(2, hashtable.Count); - Assert.AreEqual(1, hashtable["1"]); - Assert.AreEqual("2", hashtable["2"]); - } - - [Test] - public void TestStrinArray() - { - var o = new A {S = new[] {"zzz", "qxx"}}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Console.WriteLine(oo); - } - - [Test] - public void TestBad1() - { - var o = new A {S = "zzz", B = new B {S = new A {S = "qxx"}}, Z = "qxx"}; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.S); - Assert.AreEqual(null, oo.B.S); - Assert.AreEqual("qxx", oo.Z); - } - - [Test] - public void TestBad2() - { - var o = new Az {S = "zzz", B = new Bz {S = new Cz {S = 100}}, Z = "qxx"}; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("zzz", oo.S); - Assert.AreEqual(null, oo.B.S); - Assert.AreEqual("qxx", oo.Z); - } - - public class A - { - public object S { get; set; } - public B B { get; set; } - public object Z { get; set; } - } - - public class Az - { - public object S { get; set; } - public Bz B { get; set; } - public string Z { get; set; } - } - - public class Cz - { - public byte S { get; set; } - } - - public struct B - { - public object S { get; set; } - } - - public struct Bz - { - public Cz S { get; set; } - } - - private Serializer serializer; - } +using System; +using System.Collections; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestObject + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void Test1() + { + var o = new A {S = "zzz", B = new B {S = (byte)100}}; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.S); + Assert.AreEqual(100, oo.B.S); + } + + [Test] + public void Test2() + { + var o = new A {S = new Guid("aae41ff9-a337-4a69-b2ee-12ead4669201"), B = new B {S = new DateTime(182374682)}}; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(new Guid("aae41ff9-a337-4a69-b2ee-12ead4669201"), oo.S); + Assert.AreEqual(new DateTime(182374682), oo.B.S); + } + + [Test] + public void TestDecimal() + { + var o = new A {S = 123m}; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(123m, oo.S); + } + + [Test] + public void TestOldDateTimeFormat() + { + var ticks = DateTime.UtcNow.Ticks; + var data = new byte[9]; + data[0] = (byte)GroBufTypeCode.DateTimeOld; + Array.Copy(BitConverter.GetBytes(ticks), 0, data, 1, 8); + var result = serializer.Deserialize(data); + Assert.AreEqual(new DateTime(ticks, DateTimeKind.Utc), result); + } + + [Test] + public void TestArray() + { + var o = new A {S = "zzz", B = new B {S = new object[] {(byte)100, "qxx"}}}; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.S); + var array = oo.B.S as Array; + Assert.NotNull(array); + Assert.AreEqual(2, array.Length); + Assert.AreEqual(100, array.GetValue(0)); + Assert.AreEqual("qxx", array.GetValue(1)); + } + + [Test] + public void TestHashtable() + { + var o = new A {S = new Hashtable {{"1", 1}, {"2", "2"}}}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + var hashtable = oo.S as Hashtable; + Assert.IsNotNull(hashtable); + Assert.AreEqual(2, hashtable.Count); + Assert.AreEqual(1, hashtable["1"]); + Assert.AreEqual("2", hashtable["2"]); + } + + [Test] + public void TestHashtableInArray() + { + var o = new A { S = "zzz", B = new B { S = new object[] { (byte)100, "qxx", new Hashtable { { "1", 1 }, { "2", "2" } } } } }; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.S); + var array = oo.B.S as Array; + Assert.NotNull(array); + Assert.AreEqual(3, array.Length); + Assert.AreEqual(100, array.GetValue(0)); + Assert.AreEqual("qxx", array.GetValue(1)); + var hashtable = array.GetValue(2) as Hashtable; + Assert.IsNotNull(hashtable); + Assert.AreEqual(2, hashtable.Count); + Assert.AreEqual(1, hashtable["1"]); + Assert.AreEqual("2", hashtable["2"]); + } + + [Test] + public void TestStringArray() + { + var o = new A {S = new[] {"zzz", "qxx"}}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Console.WriteLine(oo); + } + + [Test] + public void TestBad1() + { + var o = new A {S = "zzz", B = new B {S = new A {S = "qxx"}}, Z = "qxx"}; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.S); + Assert.AreEqual(null, oo.B.S); + Assert.AreEqual("qxx", oo.Z); + } + + [Test] + public void TestBad2() + { + var o = new Az {S = "zzz", B = new Bz {S = new Cz {S = 100}}, Z = "qxx"}; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("zzz", oo.S); + Assert.AreEqual(null, oo.B.S); + Assert.AreEqual("qxx", oo.Z); + } + + public class A + { + public object S { get; set; } + public B B { get; set; } + public object Z { get; set; } + } + + public class Az + { + public object S { get; set; } + public Bz B { get; set; } + public string Z { get; set; } + } + + public class Cz + { + public byte S { get; set; } + } + + public struct B + { + public object S { get; set; } + } + + public struct Bz + { + public Cz S { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestOnDeserialized.cs b/GroBuf.Tests/TestOnDeserialized.cs similarity index 94% rename from GroBuf/Tests/TestOnDeserialized.cs rename to GroBuf.Tests/TestOnDeserialized.cs index 4f48c66..a8f3b4a 100644 --- a/GroBuf/Tests/TestOnDeserialized.cs +++ b/GroBuf.Tests/TestOnDeserialized.cs @@ -1,64 +1,63 @@ -using System; -using System.Runtime.Remoting; -using System.Runtime.Serialization; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestOnDeserialized - { - private Serializer serializer; - - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void TestOk() - { - var o = new TestData {S = "zzz", DeserializedCalled = false}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.IsTrue(oo.DeserializedCalled); - Assert.That(oo.s, Is.EqualTo("zzz")); - } - - [Test] - public void TestBadMethod() - { - var o = new BadData {S = "zzz"}; - var data = serializer.Serialize(o); - Assert.Throws(() => serializer.Deserialize(data)); - } - - private class TestData - { - public string S { get; set; } - public bool DeserializedCalled { get; set; } - public string s; - - [OnDeserialized] - private void OnDeserialized(StreamingContext context) - { - DeserializedCalled = true; - s = S; - } - } - - private class BadData - { - public string S { get; set; } - - [OnDeserialized] - private void OnDeserialized() - { - } - } - } +using System; +using System.Runtime.Serialization; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestOnDeserialized + { + private Serializer serializer; + + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestOk() + { + var o = new TestData {S = "zzz", DeserializedCalled = false}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.IsTrue(oo.DeserializedCalled); + Assert.That(oo.s, Is.EqualTo("zzz")); + } + + [Test] + public void TestBadMethod() + { + var o = new BadData {S = "zzz"}; + var data = serializer.Serialize(o); + Assert.Throws(() => serializer.Deserialize(data)); + } + + private class TestData + { + public string S { get; set; } + public bool DeserializedCalled { get; set; } + public string s; + + [OnDeserialized] + private void OnDeserialized(StreamingContext context) + { + DeserializedCalled = true; + s = S; + } + } + + private class BadData + { + public string S { get; set; } + + [OnDeserialized] + private void OnDeserialized() + { + } + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestPackReferences.cs b/GroBuf.Tests/TestPackReferences.cs similarity index 97% rename from GroBuf/Tests/TestPackReferences.cs rename to GroBuf.Tests/TestPackReferences.cs index 5b4c173..d33bfac 100644 --- a/GroBuf/Tests/TestPackReferences.cs +++ b/GroBuf.Tests/TestPackReferences.cs @@ -1,126 +1,126 @@ -using System; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestPackReferences - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.PackReferences); - } - - [Test] - public void Test1() - { - Console.WriteLine(serializer.GetSize(new TestClassA { S = "zzz", B = new TestClassB { S = "qxx" } })); - Console.WriteLine(serializer.GetSize(new TestClassA { S = "zzz", B = new TestClassB { S = "zzz" } })); - var data = serializer.Serialize(new TestClassA { S = "zzz", B = new TestClassB { S = "qxx" } }); - Console.WriteLine(data.Length); - var data2 = serializer.Serialize(new TestClassA { S = "zzz", B = new TestClassB { S = "zzz" } }); - Console.WriteLine(data2.Length); - var obj = serializer.Deserialize(data2); - Assert.AreEqual("zzz", obj.S); - Assert.IsNotNull(obj.B); - Assert.AreEqual("zzz", obj.B.S); - } - - [Test] - public void Test2() - { - var o = new TestClassA(); - o.A = o; - var data = serializer.Serialize(o); - Console.WriteLine(data.Length); - var oo = serializer.Deserialize(data); - Assert.AreSame(oo, oo.A); - } - - [Test] - public void Test3() - { - var b = new TestClassB{S = "zzz"}; - var a = new TestClassA{B = b, ArrayB = new[] {b}, S = "zzz"}; - a.A = a; - var data = serializer.Serialize(a); - Console.WriteLine(data.Length); - var aa = serializer.Deserialize(data); - Assert.AreSame(aa, aa.A); - Assert.IsNotNull(aa.ArrayB); - Assert.AreEqual(1, aa.ArrayB.Length); - Assert.IsNotNull(aa.B); - Assert.AreEqual("zzz", aa.B.S); - Assert.AreEqual("zzz", aa.S); - Assert.AreSame(aa.B, aa.ArrayB[0]); - } - - [Test] - public void TestRemovedProperty() - { - var b = new TestClassB { S = "zzz" }; - var a = new TestClassA { B = b, ArrayB = new[] { b }, S = "zzz" }; - a.A = a; - var data = serializer.Serialize(a); - Console.WriteLine(data.Length); - var aa = serializer.Deserialize(data); - Assert.AreSame(aa, aa.A); - Assert.IsNotNull(aa.ArrayB); - Assert.AreEqual(1, aa.ArrayB.Length); - Assert.AreEqual("zzz", aa.S); - Assert.IsNotNull(aa.ArrayB[0]); - Assert.AreEqual("zzz", aa.ArrayB[0].S); - } - - [Test] - public void TestTwoObjects() - { - var b = new TestClassB { S = "zzz" }; - var a = new TestClassA { B = b, ArrayB = new[] { b }, S = "zzz" }; - a.A = a; - var data = serializer.Serialize(a, a); - int index = 0; - var aa = serializer.Deserialize(data, ref index, data.Length); - var aaa = serializer.Deserialize(data, ref index, data.Length); - Assert.AreSame(aa, aa.A); - Assert.IsNotNull(aa.ArrayB); - Assert.AreEqual(1, aa.ArrayB.Length); - Assert.IsNotNull(aa.B); - Assert.AreEqual("zzz", aa.B.S); - Assert.AreEqual("zzz", aa.S); - Assert.AreSame(aa.B, aa.ArrayB[0]); - Assert.AreSame(aaa, aaa.A); - Assert.IsNotNull(aaa.ArrayB); - Assert.AreEqual(1, aaa.ArrayB.Length); - Assert.AreEqual("zzz", aaa.S); - Assert.IsNotNull(aaa.ArrayB[0]); - Assert.AreEqual("zzz", aaa.ArrayB[0].S); - } - - public class TestClassA - { - public TestClassB B { get; set; } - public TestClassA A { get; set; } - public string S { get; set; } - public TestClassB[] ArrayB { get; set; } - } - - public class TestClassAChanged - { - public TestClassAChanged A { get; set; } - public string S { get; set; } - public TestClassB[] ArrayB { get; set; } - } - - public class TestClassB - { - public string S { get; set; } - } - - private Serializer serializer; - } +using System; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestPackReferences + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.PackReferences); + } + + [Test] + public void Test1() + { + Console.WriteLine(serializer.GetSize(new TestClassA { S = "zzz", B = new TestClassB { S = "qxx" } })); + Console.WriteLine(serializer.GetSize(new TestClassA { S = "zzz", B = new TestClassB { S = "zzz" } })); + var data = serializer.Serialize(new TestClassA { S = "zzz", B = new TestClassB { S = "qxx" } }); + Console.WriteLine(data.Length); + var data2 = serializer.Serialize(new TestClassA { S = "zzz", B = new TestClassB { S = "zzz" } }); + Console.WriteLine(data2.Length); + var obj = serializer.Deserialize(data2); + Assert.AreEqual("zzz", obj.S); + Assert.IsNotNull(obj.B); + Assert.AreEqual("zzz", obj.B.S); + } + + [Test] + public void Test2() + { + var o = new TestClassA(); + o.A = o; + var data = serializer.Serialize(o); + Console.WriteLine(data.Length); + var oo = serializer.Deserialize(data); + Assert.AreSame(oo, oo.A); + } + + [Test] + public void Test3() + { + var b = new TestClassB{S = "zzz"}; + var a = new TestClassA{B = b, ArrayB = new[] {b}, S = "zzz"}; + a.A = a; + var data = serializer.Serialize(a); + Console.WriteLine(data.Length); + var aa = serializer.Deserialize(data); + Assert.AreSame(aa, aa.A); + Assert.IsNotNull(aa.ArrayB); + Assert.AreEqual(1, aa.ArrayB.Length); + Assert.IsNotNull(aa.B); + Assert.AreEqual("zzz", aa.B.S); + Assert.AreEqual("zzz", aa.S); + Assert.AreSame(aa.B, aa.ArrayB[0]); + } + + [Test] + public void TestRemovedProperty() + { + var b = new TestClassB { S = "zzz" }; + var a = new TestClassA { B = b, ArrayB = new[] { b }, S = "zzz" }; + a.A = a; + var data = serializer.Serialize(a); + Console.WriteLine(data.Length); + var aa = serializer.Deserialize(data); + Assert.AreSame(aa, aa.A); + Assert.IsNotNull(aa.ArrayB); + Assert.AreEqual(1, aa.ArrayB.Length); + Assert.AreEqual("zzz", aa.S); + Assert.IsNotNull(aa.ArrayB[0]); + Assert.AreEqual("zzz", aa.ArrayB[0].S); + } + + [Test] + public void TestTwoObjects() + { + var b = new TestClassB { S = "zzz" }; + var a = new TestClassA { B = b, ArrayB = new[] { b }, S = "zzz" }; + a.A = a; + var data = serializer.Serialize(a, a); + int index = 0; + var aa = serializer.Deserialize(data, ref index, data.Length); + var aaa = serializer.Deserialize(data, ref index, data.Length); + Assert.AreSame(aa, aa.A); + Assert.IsNotNull(aa.ArrayB); + Assert.AreEqual(1, aa.ArrayB.Length); + Assert.IsNotNull(aa.B); + Assert.AreEqual("zzz", aa.B.S); + Assert.AreEqual("zzz", aa.S); + Assert.AreSame(aa.B, aa.ArrayB[0]); + Assert.AreSame(aaa, aaa.A); + Assert.IsNotNull(aaa.ArrayB); + Assert.AreEqual(1, aaa.ArrayB.Length); + Assert.AreEqual("zzz", aaa.S); + Assert.IsNotNull(aaa.ArrayB[0]); + Assert.AreEqual("zzz", aaa.ArrayB[0].S); + } + + public class TestClassA + { + public TestClassB B { get; set; } + public TestClassA A { get; set; } + public string S { get; set; } + public TestClassB[] ArrayB { get; set; } + } + + public class TestClassAChanged + { + public TestClassAChanged A { get; set; } + public string S { get; set; } + public TestClassB[] ArrayB { get; set; } + } + + public class TestClassB + { + public string S { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestPerformance.cs b/GroBuf.Tests/TestPerformance.cs similarity index 97% rename from GroBuf/Tests/TestPerformance.cs rename to GroBuf.Tests/TestPerformance.cs index f6a6421..666b571 100644 --- a/GroBuf/Tests/TestPerformance.cs +++ b/GroBuf.Tests/TestPerformance.cs @@ -1,399 +1,401 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Runtime.Serialization.Json; -using System.Xml.Serialization; - -using GroBuf.DataMembersExtracters; -using GroBuf.Tests.TestData.Invoic; -using GroBuf.Tests.TestData.Orders; -using GroBuf.Tests.TestTools; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture, Ignore] - public class TestPerformance - { - [SetUp] - public void SetUp() - { - groBuf = new Serializer(new PropertiesExtractor()); - ordersXmlSerializer = new XmlSerializer(typeof(Orders)); - invoicXmlSerializer = new XmlSerializer(typeof(Invoic)); - ordersJsonSerializer = new DataContractJsonSerializer(typeof(Orders)); - invoicJsonSerializer = new DataContractJsonSerializer(typeof(Invoic)); - } - - [Test] - public void TestGroBuf() - { - Console.WriteLine("GroBuf big data: all types"); - DoTestBig(100, data => groBuf.Serialize(data), data => groBuf.Deserialize(data)); - Console.WriteLine(); - Console.WriteLine("GroBuf big data: strings"); - DoTestBig(100, data => groBuf.Serialize(data), data => groBuf.Deserialize(data)); - Console.WriteLine(); - Console.WriteLine("GroBuf small data: all types"); - DoTestSmall(1000, data => groBuf.Serialize(data), data => groBuf.Deserialize(data)); - Console.WriteLine(); - Console.WriteLine("GroBuf small data: strings"); - DoTestSmall(1000, data => groBuf.Serialize(data), data => groBuf.Deserialize(data)); - Console.WriteLine(); - Console.WriteLine("GroBuf tiny data: all types"); - DoTestTiny(10000, data => groBuf.Serialize(data), data => groBuf.Deserialize(data)); - Console.WriteLine(); - Console.WriteLine("GroBuf tiny data: strings"); - DoTestTiny(10000, data => groBuf.Serialize(data), data => groBuf.Deserialize(data)); - } - - [Test] - public void TestProtoBuf() - { - Console.WriteLine("ProtoBuf big data: all types"); - DoTestBig(3, SerializeProtoBuf, DeserializeProtoBuf); - Console.WriteLine(); - Console.WriteLine("ProtoBuf big data: strings:"); - DoTestBig(3, SerializeProtoBuf, DeserializeProtoBuf); - Console.WriteLine(); - Console.WriteLine("ProtoBuf small data: all types"); - DoTestSmall(300, SerializeProtoBuf, DeserializeProtoBuf); - Console.WriteLine(); - Console.WriteLine("ProtoBuf small data: strings"); - DoTestSmall(300, SerializeProtoBuf, DeserializeProtoBuf); - Console.WriteLine(); - Console.WriteLine("ProtoBuf tiny data: all types"); - DoTestTiny(3000, SerializeProtoBuf, DeserializeProtoBuf); - Console.WriteLine(); - Console.WriteLine("ProtoBuf tiny data: strings"); - DoTestTiny(3000, SerializeProtoBuf, DeserializeProtoBuf); - } - - [Test] - public void TestXmlSerializer() - { - Console.WriteLine("XmlSerializer big data: all types"); - DoTestBig(1, SerializeXmlOrders, DeserializeXmlOrders); - Console.WriteLine(); - Console.WriteLine("XmlSerializer big data: strings"); - DoTestBig(1, SerializeXmlInvoic, DeserializeXmlInvoic); - Console.WriteLine(); - Console.WriteLine("XmlSerializer small data: all types"); - DoTestSmall(10, SerializeXmlOrders, DeserializeXmlOrders); - Console.WriteLine(); - Console.WriteLine("XmlSerializer small data: strings"); - DoTestSmall(10, SerializeXmlInvoic, DeserializeXmlInvoic); - Console.WriteLine(); - Console.WriteLine("XmlSerializer tiny data: all types"); - DoTestTiny(100, SerializeXmlOrders, DeserializeXmlOrders); - Console.WriteLine(); - Console.WriteLine("XmlSerializer tiny data: strings"); - DoTestTiny(100, SerializeXmlInvoic, DeserializeXmlInvoic); - } - - [Test] - public void TestJsonSerializer() - { - Console.WriteLine("JsonSerializer big data: all types"); - DoTestBig(1, SerializeJsonOrders, DeserializeJsonOrders); - Console.WriteLine(); - Console.WriteLine("JsonSerializer big data: strings"); - DoTestBig(1, SerializeJsonInvoic, DeserializeJsonInvoic); - Console.WriteLine(); - Console.WriteLine("JsonSerializer small data: all types"); - DoTestSmall(10, SerializeJsonOrders, DeserializeJsonOrders); - Console.WriteLine(); - Console.WriteLine("JsonSerializer small data: strings"); - DoTestSmall(10, SerializeJsonInvoic, DeserializeJsonInvoic); - Console.WriteLine(); - Console.WriteLine("JsonSerializer tiny data: all types"); - DoTestTiny(100, SerializeJsonOrders, DeserializeJsonOrders); - Console.WriteLine(); - Console.WriteLine("JsonSerializer tiny data: strings"); - DoTestTiny(100, SerializeJsonInvoic, DeserializeJsonInvoic); - } - - [Test] - public void TestGroBufGetSize() - { - Console.WriteLine("GroBuf.GetSize big data: all types"); - DoTestGetSizeBig(100, data => groBuf.GetSize(data)); - Console.WriteLine(); - Console.WriteLine("GroBuf.GetSize big data: strings"); - DoTestGetSizeBig(100, data => groBuf.GetSize(data)); - Console.WriteLine(); - Console.WriteLine("GroBuf.GetSize small data: all types"); - DoTestGetSizeSmall(1000, data => groBuf.GetSize(data)); - Console.WriteLine(); - Console.WriteLine("GroBuf.GetSize small data: strings"); - DoTestGetSizeSmall(1000, data => groBuf.GetSize(data)); - Console.WriteLine(); - Console.WriteLine("GroBuf.GetSize tiny data: all types"); - DoTestGetSizeTiny(10000, data => groBuf.GetSize(data)); - Console.WriteLine(); - Console.WriteLine("GroBuf.GetSize tiny data: strings"); - DoTestGetSizeTiny(10000, data => groBuf.GetSize(data)); - } - - [Test] - public void TestGroBufChangeType() - { - Console.WriteLine("GroBuf.ChangeType big data: all types"); - DoTestChangeTypeBig(10, obj => groBuf.ChangeType(obj)); - Console.WriteLine(); - Console.WriteLine("GroBuf.ChangeType big data: strings"); - DoTestChangeTypeBig(10, obj => groBuf.ChangeType(obj)); - Console.WriteLine(); - Console.WriteLine("GroBuf.ChangeType small data: all types"); - DoTestChangeTypeSmall(100, obj => groBuf.ChangeType(obj)); - Console.WriteLine(); - Console.WriteLine("GroBuf.ChangeType small data: strings"); - DoTestChangeTypeSmall(100, obj => groBuf.ChangeType(obj)); - Console.WriteLine(); - Console.WriteLine("GroBuf.ChangeType tiny data: all types"); - DoTestChangeTypeTiny(1000, obj => groBuf.ChangeType(obj)); - Console.WriteLine(); - Console.WriteLine("GroBuf.ChangeType tiny data: strings"); - DoTestChangeTypeTiny(1000, obj => groBuf.ChangeType(obj)); - } - - [Test] - public void TestProtoBufChangeType() - { - Console.WriteLine("ProtoBuf.ChangeType big data: all types"); - DoTestChangeTypeBig(3, ProtoBuf.Serializer.ChangeType); - Console.WriteLine(); - Console.WriteLine("ProtoBuf.ChangeType big data: strings"); - DoTestChangeTypeBig(3, ProtoBuf.Serializer.ChangeType); - Console.WriteLine(); - Console.WriteLine("ProtoBuf.ChangeType small data: all types"); - DoTestChangeTypeSmall(30, ProtoBuf.Serializer.ChangeType); - Console.WriteLine(); - Console.WriteLine("ProtoBuf.ChangeType small data: strings"); - DoTestChangeTypeSmall(30, ProtoBuf.Serializer.ChangeType); - Console.WriteLine(); - Console.WriteLine("ProtoBuf.ChangeType tiny data: all types"); - DoTestChangeTypeTiny(300, ProtoBuf.Serializer.ChangeType); - Console.WriteLine(); - Console.WriteLine("ProtoBuf.ChangeType tiny data: strings"); - DoTestChangeTypeTiny(300, ProtoBuf.Serializer.ChangeType); - } - - private static byte[] SerializeProtoBuf(T obj) - { - stream.Position = 0; - stream.SetLength(0); - ProtoBuf.Serializer.Serialize(stream, obj); - return stream.ToArray(); - } - - private static T DeserializeProtoBuf(byte[] data) - { - return ProtoBuf.Serializer.Deserialize(new MemoryStream(data)); - } - - private byte[] SerializeXmlOrders(Orders obj) - { - stream.Position = 0; - stream.SetLength(0); - ordersXmlSerializer.Serialize(stream, obj); - return stream.ToArray(); - } - - private byte[] SerializeXmlInvoic(Invoic obj) - { - stream.Position = 0; - stream.SetLength(0); - invoicXmlSerializer.Serialize(stream, obj); - return stream.ToArray(); - } - - private Orders DeserializeXmlOrders(byte[] data) - { - return (Orders)ordersXmlSerializer.Deserialize(new MemoryStream(data)); - } - - private Invoic DeserializeXmlInvoic(byte[] data) - { - return (Invoic)invoicXmlSerializer.Deserialize(new MemoryStream(data)); - } - - private byte[] SerializeJsonOrders(Orders obj) - { - stream.Position = 0; - stream.SetLength(0); - ordersJsonSerializer.WriteObject(stream, obj); - return stream.ToArray(); - } - - private byte[] SerializeJsonInvoic(Invoic obj) - { - stream.Position = 0; - stream.SetLength(0); - invoicJsonSerializer.WriteObject(stream, obj); - return stream.ToArray(); - } - - private Orders DeserializeJsonOrders(byte[] data) - { - return (Orders)ordersJsonSerializer.ReadObject(new MemoryStream(data)); - } - - private Invoic DeserializeJsonInvoic(byte[] data) - { - return (Invoic)invoicJsonSerializer.ReadObject(new MemoryStream(data)); - } - - private static void DoTestBig(int iterations, Func serializer, Func deserializer) where TData : class, new() - { - DoTest(iterations, 80, 100, 10, serializer, deserializer); - } - - private static void DoTestSmall(int iterations, Func serializer, Func deserializer) where TData : class, new() - { - DoTest(iterations, 60, 10, 5, serializer, deserializer); - } - - private static void DoTestTiny(int iterations, Func serializer, Func deserializer) where TData : class, new() - { - DoTest(iterations, 30, 5, 2, serializer, deserializer); - } - - private static void DoTest(int iterations, int fillRate, int stringsLength, int arraysSize, Func serializer, Func deserializer) where TData : class, new() - { - const int numberOfObjects = 1000; - var random = new Random(54717651); - var objects = new TData[numberOfObjects]; - objects[0] = TestHelpers.GenerateRandomTrash(random, fillRate, stringsLength, arraysSize); - for(int i = 1; i < objects.Length; ++i) - objects[i] = TestHelpers.GenerateRandomTrash(random, fillRate, stringsLength, arraysSize); - - deserializer(serializer(objects[0])); - - var datas = new byte[numberOfObjects][]; - long size = 0; - var stopwatch = Stopwatch.StartNew(); - for(int i = 0; i < objects.Length; ++i) - { - byte[] cur = null; - for(int j = 0; j < iterations; ++j) - { - cur = serializer(objects[(i + j) % objects.Length]); - size += cur.Length; - } - datas[i] = cur; - } - stopwatch.Stop(); - var elapsed = stopwatch.Elapsed; - Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / numberOfObjects / iterations + " microseconds (" + Math.Round(1000.0 * numberOfObjects * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); - Console.WriteLine("Size: " + ((double)size) / numberOfObjects / iterations + " bytes"); - - var deserializedDatas = new TData[numberOfObjects]; - stopwatch = Stopwatch.StartNew(); - for(int i = 0; i < datas.Length; ++i) - { - TData cur = null; - for(int j = 0; j < iterations; ++j) - cur = deserializer(datas[(i + j) % datas.Length]); - deserializedDatas[i] = cur; - } - stopwatch.Stop(); - elapsed = stopwatch.Elapsed; - Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / numberOfObjects / iterations + " microseconds (" + Math.Round(1000.0 * numberOfObjects * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); - } - - private static void DoTestGetSizeBig(int iterations, Func counter) where TData : class, new() - { - DoTestGetSize(iterations, 80, 1000, 8, counter); - } - - private static void DoTestGetSizeSmall(int iterations, Func counter) where TData : class, new() - { - DoTestGetSize(iterations, 60, 10, 5, counter); - } - - private static void DoTestGetSizeTiny(int iterations, Func counter) where TData : class, new() - { - DoTestGetSize(iterations, 30, 5, 2, counter); - } - - private static void DoTestGetSize(int iterations, int fillRate, int stringsLength, int arraysSize, Func counter) where TData : class, new() - { - const int numberOfObjects = 1000; - var random = new Random(54717651); - var objects = new TData[numberOfObjects]; - objects[0] = TestHelpers.GenerateRandomTrash(random, fillRate, stringsLength, arraysSize); - for(int i = 1; i < objects.Length; ++i) - objects[i] = TestHelpers.GenerateRandomTrash(random, fillRate, stringsLength, arraysSize); - - counter(objects[0]); - - var sizes = new int[numberOfObjects]; - long size = 0; - var stopwatch = Stopwatch.StartNew(); - for(int i = 0; i < objects.Length; ++i) - { - int cur = 0; - for(int j = 0; j < iterations; ++j) - { - cur = counter(objects[(i + j) % objects.Length]); - size += cur; - } - sizes[i] = cur; - } - stopwatch.Stop(); - TimeSpan elapsed = stopwatch.Elapsed; - Console.WriteLine("Size counting: " + elapsed.TotalMilliseconds * 1000 / numberOfObjects / iterations + " microseconds (" + Math.Round(1000.0 * numberOfObjects * iterations / elapsed.TotalMilliseconds) + " size counts per second)"); - Console.WriteLine("Size: " + ((double)size) / numberOfObjects / iterations + " bytes"); - } - - private static void DoTestChangeTypeBig(int iterations, Func typeChanger) where TFrom : class, new() - { - DoTestChangeType(iterations, 80, 1000, 8, typeChanger); - } - - private static void DoTestChangeTypeSmall(int iterations, Func typeChanger) where TFrom : class, new() - { - DoTestChangeType(iterations, 60, 10, 5, typeChanger); - } - - private static void DoTestChangeTypeTiny(int iterations, Func typeChanger) where TFrom : class, new() - { - DoTestChangeType(iterations, 30, 5, 2, typeChanger); - } - - private static void DoTestChangeType(int iterations, int fillRate, int stringsLength, int arraysSize, Func typeChanger) where TFrom : class, new() - { - const int numberOfObjects = 1000; - var random = new Random(54717651); - var from = new TFrom[numberOfObjects]; - from[0] = TestHelpers.GenerateRandomTrash(random, fillRate, stringsLength, arraysSize); - for(int i = 1; i < from.Length; ++i) - from[i] = TestHelpers.GenerateRandomTrash(random, fillRate, stringsLength, arraysSize); - - typeChanger(from[0]); - - var to = new TTo[numberOfObjects]; - var stopwatch = Stopwatch.StartNew(); - for(int i = 0; i < from.Length; ++i) - { - TTo cur = default(TTo); - for(int j = 0; j < iterations; ++j) - cur = typeChanger(from[(i + j) % from.Length]); - to[i] = cur; - } - stopwatch.Stop(); - TimeSpan elapsed = stopwatch.Elapsed; - Console.WriteLine("Type changing: " + elapsed.TotalMilliseconds * 1000 / numberOfObjects / iterations + " microseconds (" + Math.Round(1000.0 * numberOfObjects * iterations / elapsed.TotalMilliseconds) + " type changes per second)"); - } - - private static readonly MemoryStream stream = new MemoryStream(128 * 1024); - - private Serializer groBuf; - private XmlSerializer ordersXmlSerializer; - private XmlSerializer invoicXmlSerializer; - private DataContractJsonSerializer ordersJsonSerializer; - private DataContractJsonSerializer invoicJsonSerializer; - } +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.Serialization.Json; +using System.Xml.Serialization; + +using GroBuf.DataMembersExtracters; +using GroBuf.Tests.TestData.Invoic; +using GroBuf.Tests.TestData.Orders; +using GroBuf.Tests.TestTools; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + [Category("LongRunning")] + [Ignore("Is used for perf comparison")] + public class TestPerformance + { + [SetUp] + public void SetUp() + { + groBuf = new Serializer(new PropertiesExtractor()); + ordersXmlSerializer = new XmlSerializer(typeof(Orders)); + invoicXmlSerializer = new XmlSerializer(typeof(Invoic)); + ordersJsonSerializer = new DataContractJsonSerializer(typeof(Orders)); + invoicJsonSerializer = new DataContractJsonSerializer(typeof(Invoic)); + } + + [Test] + public void TestGroBuf() + { + Console.WriteLine("GroBuf big data: all types"); + DoTestBig(100, data => groBuf.Serialize(data), data => groBuf.Deserialize(data)); + Console.WriteLine(); + Console.WriteLine("GroBuf big data: strings"); + DoTestBig(100, data => groBuf.Serialize(data), data => groBuf.Deserialize(data)); + Console.WriteLine(); + Console.WriteLine("GroBuf small data: all types"); + DoTestSmall(1000, data => groBuf.Serialize(data), data => groBuf.Deserialize(data)); + Console.WriteLine(); + Console.WriteLine("GroBuf small data: strings"); + DoTestSmall(1000, data => groBuf.Serialize(data), data => groBuf.Deserialize(data)); + Console.WriteLine(); + Console.WriteLine("GroBuf tiny data: all types"); + DoTestTiny(10000, data => groBuf.Serialize(data), data => groBuf.Deserialize(data)); + Console.WriteLine(); + Console.WriteLine("GroBuf tiny data: strings"); + DoTestTiny(10000, data => groBuf.Serialize(data), data => groBuf.Deserialize(data)); + } + + [Test] + public void TestProtoBuf() + { + Console.WriteLine("ProtoBuf big data: all types"); + DoTestBig(3, SerializeProtoBuf, DeserializeProtoBuf); + Console.WriteLine(); + Console.WriteLine("ProtoBuf big data: strings:"); + DoTestBig(3, SerializeProtoBuf, DeserializeProtoBuf); + Console.WriteLine(); + Console.WriteLine("ProtoBuf small data: all types"); + DoTestSmall(300, SerializeProtoBuf, DeserializeProtoBuf); + Console.WriteLine(); + Console.WriteLine("ProtoBuf small data: strings"); + DoTestSmall(300, SerializeProtoBuf, DeserializeProtoBuf); + Console.WriteLine(); + Console.WriteLine("ProtoBuf tiny data: all types"); + DoTestTiny(3000, SerializeProtoBuf, DeserializeProtoBuf); + Console.WriteLine(); + Console.WriteLine("ProtoBuf tiny data: strings"); + DoTestTiny(3000, SerializeProtoBuf, DeserializeProtoBuf); + } + + [Test] + public void TestXmlSerializer() + { + Console.WriteLine("XmlSerializer big data: all types"); + DoTestBig(1, SerializeXmlOrders, DeserializeXmlOrders); + Console.WriteLine(); + Console.WriteLine("XmlSerializer big data: strings"); + DoTestBig(1, SerializeXmlInvoic, DeserializeXmlInvoic); + Console.WriteLine(); + Console.WriteLine("XmlSerializer small data: all types"); + DoTestSmall(10, SerializeXmlOrders, DeserializeXmlOrders); + Console.WriteLine(); + Console.WriteLine("XmlSerializer small data: strings"); + DoTestSmall(10, SerializeXmlInvoic, DeserializeXmlInvoic); + Console.WriteLine(); + Console.WriteLine("XmlSerializer tiny data: all types"); + DoTestTiny(100, SerializeXmlOrders, DeserializeXmlOrders); + Console.WriteLine(); + Console.WriteLine("XmlSerializer tiny data: strings"); + DoTestTiny(100, SerializeXmlInvoic, DeserializeXmlInvoic); + } + + [Test] + public void TestJsonSerializer() + { + Console.WriteLine("JsonSerializer big data: all types"); + DoTestBig(1, SerializeJsonOrders, DeserializeJsonOrders); + Console.WriteLine(); + Console.WriteLine("JsonSerializer big data: strings"); + DoTestBig(1, SerializeJsonInvoic, DeserializeJsonInvoic); + Console.WriteLine(); + Console.WriteLine("JsonSerializer small data: all types"); + DoTestSmall(10, SerializeJsonOrders, DeserializeJsonOrders); + Console.WriteLine(); + Console.WriteLine("JsonSerializer small data: strings"); + DoTestSmall(10, SerializeJsonInvoic, DeserializeJsonInvoic); + Console.WriteLine(); + Console.WriteLine("JsonSerializer tiny data: all types"); + DoTestTiny(100, SerializeJsonOrders, DeserializeJsonOrders); + Console.WriteLine(); + Console.WriteLine("JsonSerializer tiny data: strings"); + DoTestTiny(100, SerializeJsonInvoic, DeserializeJsonInvoic); + } + + [Test] + public void TestGroBufGetSize() + { + Console.WriteLine("GroBuf.GetSize big data: all types"); + DoTestGetSizeBig(100, data => groBuf.GetSize(data)); + Console.WriteLine(); + Console.WriteLine("GroBuf.GetSize big data: strings"); + DoTestGetSizeBig(100, data => groBuf.GetSize(data)); + Console.WriteLine(); + Console.WriteLine("GroBuf.GetSize small data: all types"); + DoTestGetSizeSmall(1000, data => groBuf.GetSize(data)); + Console.WriteLine(); + Console.WriteLine("GroBuf.GetSize small data: strings"); + DoTestGetSizeSmall(1000, data => groBuf.GetSize(data)); + Console.WriteLine(); + Console.WriteLine("GroBuf.GetSize tiny data: all types"); + DoTestGetSizeTiny(10000, data => groBuf.GetSize(data)); + Console.WriteLine(); + Console.WriteLine("GroBuf.GetSize tiny data: strings"); + DoTestGetSizeTiny(10000, data => groBuf.GetSize(data)); + } + + [Test] + public void TestGroBufChangeType() + { + Console.WriteLine("GroBuf.ChangeType big data: all types"); + DoTestChangeTypeBig(10, obj => groBuf.ChangeType(obj)); + Console.WriteLine(); + Console.WriteLine("GroBuf.ChangeType big data: strings"); + DoTestChangeTypeBig(10, obj => groBuf.ChangeType(obj)); + Console.WriteLine(); + Console.WriteLine("GroBuf.ChangeType small data: all types"); + DoTestChangeTypeSmall(100, obj => groBuf.ChangeType(obj)); + Console.WriteLine(); + Console.WriteLine("GroBuf.ChangeType small data: strings"); + DoTestChangeTypeSmall(100, obj => groBuf.ChangeType(obj)); + Console.WriteLine(); + Console.WriteLine("GroBuf.ChangeType tiny data: all types"); + DoTestChangeTypeTiny(1000, obj => groBuf.ChangeType(obj)); + Console.WriteLine(); + Console.WriteLine("GroBuf.ChangeType tiny data: strings"); + DoTestChangeTypeTiny(1000, obj => groBuf.ChangeType(obj)); + } + + [Test] + public void TestProtoBufChangeType() + { + Console.WriteLine("ProtoBuf.ChangeType big data: all types"); + DoTestChangeTypeBig(3, ProtoBuf.Serializer.ChangeType); + Console.WriteLine(); + Console.WriteLine("ProtoBuf.ChangeType big data: strings"); + DoTestChangeTypeBig(3, ProtoBuf.Serializer.ChangeType); + Console.WriteLine(); + Console.WriteLine("ProtoBuf.ChangeType small data: all types"); + DoTestChangeTypeSmall(30, ProtoBuf.Serializer.ChangeType); + Console.WriteLine(); + Console.WriteLine("ProtoBuf.ChangeType small data: strings"); + DoTestChangeTypeSmall(30, ProtoBuf.Serializer.ChangeType); + Console.WriteLine(); + Console.WriteLine("ProtoBuf.ChangeType tiny data: all types"); + DoTestChangeTypeTiny(300, ProtoBuf.Serializer.ChangeType); + Console.WriteLine(); + Console.WriteLine("ProtoBuf.ChangeType tiny data: strings"); + DoTestChangeTypeTiny(300, ProtoBuf.Serializer.ChangeType); + } + + private static byte[] SerializeProtoBuf(T obj) + { + stream.Position = 0; + stream.SetLength(0); + ProtoBuf.Serializer.Serialize(stream, obj); + return stream.ToArray(); + } + + private static T DeserializeProtoBuf(byte[] data) + { + return ProtoBuf.Serializer.Deserialize(new MemoryStream(data)); + } + + private byte[] SerializeXmlOrders(Orders obj) + { + stream.Position = 0; + stream.SetLength(0); + ordersXmlSerializer.Serialize(stream, obj); + return stream.ToArray(); + } + + private byte[] SerializeXmlInvoic(Invoic obj) + { + stream.Position = 0; + stream.SetLength(0); + invoicXmlSerializer.Serialize(stream, obj); + return stream.ToArray(); + } + + private Orders DeserializeXmlOrders(byte[] data) + { + return (Orders)ordersXmlSerializer.Deserialize(new MemoryStream(data)); + } + + private Invoic DeserializeXmlInvoic(byte[] data) + { + return (Invoic)invoicXmlSerializer.Deserialize(new MemoryStream(data)); + } + + private byte[] SerializeJsonOrders(Orders obj) + { + stream.Position = 0; + stream.SetLength(0); + ordersJsonSerializer.WriteObject(stream, obj); + return stream.ToArray(); + } + + private byte[] SerializeJsonInvoic(Invoic obj) + { + stream.Position = 0; + stream.SetLength(0); + invoicJsonSerializer.WriteObject(stream, obj); + return stream.ToArray(); + } + + private Orders DeserializeJsonOrders(byte[] data) + { + return (Orders)ordersJsonSerializer.ReadObject(new MemoryStream(data)); + } + + private Invoic DeserializeJsonInvoic(byte[] data) + { + return (Invoic)invoicJsonSerializer.ReadObject(new MemoryStream(data)); + } + + private static void DoTestBig(int iterations, Func serializer, Func deserializer) where TData : class, new() + { + DoTest(iterations, 80, 100, 10, serializer, deserializer); + } + + private static void DoTestSmall(int iterations, Func serializer, Func deserializer) where TData : class, new() + { + DoTest(iterations, 60, 10, 5, serializer, deserializer); + } + + private static void DoTestTiny(int iterations, Func serializer, Func deserializer) where TData : class, new() + { + DoTest(iterations, 30, 5, 2, serializer, deserializer); + } + + private static void DoTest(int iterations, int fillRate, int stringsLength, int arraysSize, Func serializer, Func deserializer) where TData : class, new() + { + const int numberOfObjects = 1000; + var random = new Random(54717651); + var objects = new TData[numberOfObjects]; + objects[0] = TestHelpers.GenerateRandomTrash(random, fillRate, stringsLength, arraysSize); + for(int i = 1; i < objects.Length; ++i) + objects[i] = TestHelpers.GenerateRandomTrash(random, fillRate, stringsLength, arraysSize); + + deserializer(serializer(objects[0])); + + var datas = new byte[numberOfObjects][]; + long size = 0; + var stopwatch = Stopwatch.StartNew(); + for(int i = 0; i < objects.Length; ++i) + { + byte[] cur = null; + for(int j = 0; j < iterations; ++j) + { + cur = serializer(objects[(i + j) % objects.Length]); + size += cur.Length; + } + datas[i] = cur; + } + stopwatch.Stop(); + var elapsed = stopwatch.Elapsed; + Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / numberOfObjects / iterations + " microseconds (" + Math.Round(1000.0 * numberOfObjects * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); + Console.WriteLine("Size: " + ((double)size) / numberOfObjects / iterations + " bytes"); + + var deserializedDatas = new TData[numberOfObjects]; + stopwatch = Stopwatch.StartNew(); + for(int i = 0; i < datas.Length; ++i) + { + TData cur = null; + for(int j = 0; j < iterations; ++j) + cur = deserializer(datas[(i + j) % datas.Length]); + deserializedDatas[i] = cur; + } + stopwatch.Stop(); + elapsed = stopwatch.Elapsed; + Console.WriteLine("Deserializing: " + elapsed.TotalMilliseconds * 1000 / numberOfObjects / iterations + " microseconds (" + Math.Round(1000.0 * numberOfObjects * iterations / elapsed.TotalMilliseconds) + " deserializations per second)"); + } + + private static void DoTestGetSizeBig(int iterations, Func counter) where TData : class, new() + { + DoTestGetSize(iterations, 80, 1000, 8, counter); + } + + private static void DoTestGetSizeSmall(int iterations, Func counter) where TData : class, new() + { + DoTestGetSize(iterations, 60, 10, 5, counter); + } + + private static void DoTestGetSizeTiny(int iterations, Func counter) where TData : class, new() + { + DoTestGetSize(iterations, 30, 5, 2, counter); + } + + private static void DoTestGetSize(int iterations, int fillRate, int stringsLength, int arraysSize, Func counter) where TData : class, new() + { + const int numberOfObjects = 1000; + var random = new Random(54717651); + var objects = new TData[numberOfObjects]; + objects[0] = TestHelpers.GenerateRandomTrash(random, fillRate, stringsLength, arraysSize); + for(int i = 1; i < objects.Length; ++i) + objects[i] = TestHelpers.GenerateRandomTrash(random, fillRate, stringsLength, arraysSize); + + counter(objects[0]); + + var sizes = new int[numberOfObjects]; + long size = 0; + var stopwatch = Stopwatch.StartNew(); + for(int i = 0; i < objects.Length; ++i) + { + int cur = 0; + for(int j = 0; j < iterations; ++j) + { + cur = counter(objects[(i + j) % objects.Length]); + size += cur; + } + sizes[i] = cur; + } + stopwatch.Stop(); + TimeSpan elapsed = stopwatch.Elapsed; + Console.WriteLine("Size counting: " + elapsed.TotalMilliseconds * 1000 / numberOfObjects / iterations + " microseconds (" + Math.Round(1000.0 * numberOfObjects * iterations / elapsed.TotalMilliseconds) + " size counts per second)"); + Console.WriteLine("Size: " + ((double)size) / numberOfObjects / iterations + " bytes"); + } + + private static void DoTestChangeTypeBig(int iterations, Func typeChanger) where TFrom : class, new() + { + DoTestChangeType(iterations, 80, 1000, 8, typeChanger); + } + + private static void DoTestChangeTypeSmall(int iterations, Func typeChanger) where TFrom : class, new() + { + DoTestChangeType(iterations, 60, 10, 5, typeChanger); + } + + private static void DoTestChangeTypeTiny(int iterations, Func typeChanger) where TFrom : class, new() + { + DoTestChangeType(iterations, 30, 5, 2, typeChanger); + } + + private static void DoTestChangeType(int iterations, int fillRate, int stringsLength, int arraysSize, Func typeChanger) where TFrom : class, new() + { + const int numberOfObjects = 1000; + var random = new Random(54717651); + var from = new TFrom[numberOfObjects]; + from[0] = TestHelpers.GenerateRandomTrash(random, fillRate, stringsLength, arraysSize); + for(int i = 1; i < from.Length; ++i) + from[i] = TestHelpers.GenerateRandomTrash(random, fillRate, stringsLength, arraysSize); + + typeChanger(from[0]); + + var to = new TTo[numberOfObjects]; + var stopwatch = Stopwatch.StartNew(); + for(int i = 0; i < from.Length; ++i) + { + TTo cur = default(TTo); + for(int j = 0; j < iterations; ++j) + cur = typeChanger(from[(i + j) % from.Length]); + to[i] = cur; + } + stopwatch.Stop(); + TimeSpan elapsed = stopwatch.Elapsed; + Console.WriteLine("Type changing: " + elapsed.TotalMilliseconds * 1000 / numberOfObjects / iterations + " microseconds (" + Math.Round(1000.0 * numberOfObjects * iterations / elapsed.TotalMilliseconds) + " type changes per second)"); + } + + private static readonly MemoryStream stream = new MemoryStream(128 * 1024); + + private Serializer groBuf; + private XmlSerializer ordersXmlSerializer; + private XmlSerializer invoicXmlSerializer; + private DataContractJsonSerializer ordersJsonSerializer; + private DataContractJsonSerializer invoicJsonSerializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestPrimitives.cs b/GroBuf.Tests/TestPrimitives.cs similarity index 98% rename from GroBuf/Tests/TestPrimitives.cs rename to GroBuf.Tests/TestPrimitives.cs index ba6d397..eeee131 100644 --- a/GroBuf/Tests/TestPrimitives.cs +++ b/GroBuf.Tests/TestPrimitives.cs @@ -1,373 +1,373 @@ -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestPrimitives - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void TestBool() - { - Assert.AreEqual(1, SerializeDeserialize(true)); - Assert.AreEqual(1, SerializeDeserialize(true)); - Assert.AreEqual(1, SerializeDeserialize(true)); - Assert.AreEqual(1, SerializeDeserialize(true)); - Assert.AreEqual(1, SerializeDeserialize(true)); - Assert.AreEqual(1, SerializeDeserialize(true)); - Assert.AreEqual(1, SerializeDeserialize(true)); - Assert.AreEqual(1, SerializeDeserialize(true)); - Assert.AreEqual((float)1, SerializeDeserialize(true)); - Assert.AreEqual((double)1, SerializeDeserialize(true)); - Assert.AreEqual(1.0m, SerializeDeserialize(true)); - - Assert.IsTrue(SerializeDeserialize(int.MaxValue)); - Assert.IsTrue(SerializeDeserialize(1L << 32)); - Assert.IsTrue(SerializeDeserialize(1L << 48)); - Assert.IsFalse(SerializeDeserialize(0)); - Assert.IsFalse(SerializeDeserialize(0)); - Assert.IsFalse(SerializeDeserialize(0)); - Assert.IsFalse(SerializeDeserialize(0)); - Assert.IsFalse(SerializeDeserialize(0)); - Assert.IsTrue(SerializeDeserialize(0.1f)); - Assert.IsTrue(SerializeDeserialize(0.1)); - Assert.IsFalse(SerializeDeserialize(0)); - Assert.IsTrue(SerializeDeserialize(0.1m)); - Assert.IsTrue(SerializeDeserialize(10)); - - Assert.AreEqual(0, SerializeDeserialize(false)); - Assert.AreEqual(0, SerializeDeserialize(false)); - Assert.AreEqual(0, SerializeDeserialize(false)); - Assert.AreEqual(0, SerializeDeserialize(false)); - Assert.AreEqual(0, SerializeDeserialize(false)); - Assert.AreEqual(0, SerializeDeserialize(false)); - Assert.AreEqual(0, SerializeDeserialize(false)); - Assert.AreEqual(0, SerializeDeserialize(false)); - Assert.AreEqual((float)0, SerializeDeserialize(false)); - Assert.AreEqual((double)0, SerializeDeserialize(false)); - Assert.AreEqual(0.0m, SerializeDeserialize(false)); - Assert.IsFalse(SerializeDeserialize(false)); - } - - [Test] - public void TestInt8Negative() - { - const sbyte x = -13; - const byte y = -x - 1; - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(uint.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(byte.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(ushort.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(ulong.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual((float)x, SerializeDeserialize(x)); - Assert.AreEqual((double)x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.IsTrue(SerializeDeserialize(x)); - } - - [Test] - public void TestInt8Positive() - { - const sbyte x = 13; - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual((float)x, SerializeDeserialize(x)); - Assert.AreEqual((double)x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.IsTrue(SerializeDeserialize(x)); - } - - [Test] - public void TestInt16Negative() - { - const short x = -13; - const ushort y = -x - 1; - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(uint.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(byte.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(ushort.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(ulong.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual((float)x, SerializeDeserialize(x)); - Assert.AreEqual((double)x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.IsTrue(SerializeDeserialize(x)); - } - - [Test] - public void TestInt16Positive() - { - const short x = 13; - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual((float)x, SerializeDeserialize(x)); - Assert.AreEqual((double)x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.IsTrue(SerializeDeserialize(x)); - } - - [Test] - public void TestInt32Negative() - { - const int x = -13; - const uint y = -x - 1; - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(uint.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(byte.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(ushort.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(ulong.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual((float)x, SerializeDeserialize(x)); - Assert.AreEqual((double)x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.IsTrue(SerializeDeserialize(x)); - } - - [Test] - public void TestInt32Positive() - { - const int x = 13; - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual((float)x, SerializeDeserialize(x)); - Assert.AreEqual((double)x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.IsTrue(SerializeDeserialize(x)); - } - - [Test] - public void TestUInt8() - { - const byte x = 250; - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(-(byte.MaxValue - x + 1), SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual((float)x, SerializeDeserialize(x)); - Assert.AreEqual((double)x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.IsTrue(SerializeDeserialize(x)); - } - - [Test] - public void TestUInt16() - { - const ushort x = 54321; - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(13, SerializeDeserialize(13)); - Assert.AreEqual(13, SerializeDeserialize(13)); - Assert.AreEqual(-(ushort.MaxValue - x + 1), SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual((float)x, SerializeDeserialize(x)); - Assert.AreEqual((double)x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.IsTrue(SerializeDeserialize(x)); - } - - [Test] - public void TestUInt32() - { - const uint x = 3000000000; - Assert.AreEqual(-(uint.MaxValue - x + 1), SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(13, SerializeDeserialize(13)); - Assert.AreEqual(13, SerializeDeserialize(13)); - Assert.AreEqual(1000, SerializeDeserialize(1000)); - Assert.AreEqual(1000, SerializeDeserialize(1000)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual((float)x, SerializeDeserialize(x)); - Assert.AreEqual((double)x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.IsTrue(SerializeDeserialize(x)); - } - - [Test] - public void TestUInt64() - { - unchecked - { - const ulong x = 10000000000000000000; - Assert.AreEqual(13, SerializeDeserialize(13)); - Assert.AreEqual(13, SerializeDeserialize(13)); - Assert.AreEqual(1000, SerializeDeserialize(1000)); - Assert.AreEqual(1000, SerializeDeserialize(1000)); - Assert.AreEqual(1000000000, SerializeDeserialize(1000000000)); - Assert.AreEqual(1000000000, SerializeDeserialize(1000000000)); - Assert.AreEqual((long)(0L - (ulong.MaxValue - x + 1)), SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual((float)x, SerializeDeserialize(x)); - Assert.AreEqual((double)x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.IsTrue(SerializeDeserialize(x)); - } - } - - [Test] - public void TestInt64Positive() - { - unchecked - { - const long x = 1000000000000000000; - Assert.AreEqual(13, SerializeDeserialize(13)); - Assert.AreEqual(13, SerializeDeserialize(13)); - Assert.AreEqual(1000, SerializeDeserialize(1000)); - Assert.AreEqual(1000, SerializeDeserialize(1000)); - Assert.AreEqual(1000000000, SerializeDeserialize(1000000000)); - Assert.AreEqual(1000000000, SerializeDeserialize(1000000000)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual((float)x, SerializeDeserialize(x)); - Assert.AreEqual((double)x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.IsTrue(SerializeDeserialize(x)); - } - } - - [Test] - public void TestInt64Negative() - { - unchecked - { - const long x = -13; - const ulong y = -x - 1; - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(uint.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(byte.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(ushort.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.AreEqual(ulong.MaxValue - y, SerializeDeserialize(x)); - Assert.AreEqual((float)x, SerializeDeserialize(x)); - Assert.AreEqual((double)x, SerializeDeserialize(x)); - Assert.AreEqual(x, SerializeDeserialize(x)); - Assert.IsTrue(SerializeDeserialize(x)); - } - } - - [Test] - public void TestFloat() - { - unchecked - { - Assert.AreEqual(13, SerializeDeserialize(13.123f)); - Assert.AreEqual(13, SerializeDeserialize(13.123f)); - Assert.AreEqual(1000, SerializeDeserialize(1000.382456f)); - Assert.AreEqual(1000, SerializeDeserialize(1000.382456f)); - Assert.AreEqual(1000000000, SerializeDeserialize(1000000000.73465f)); - Assert.AreEqual(1000000000, SerializeDeserialize(1000000000.73465f)); - Assert.AreEqual(10000000000, SerializeDeserialize(10000000000.73465f)); - Assert.AreEqual(10000000000, SerializeDeserialize(10000000000.73465f)); - Assert.AreEqual(3.1415926f, SerializeDeserialize(3.1415926f)); - Assert.AreEqual((double)3.1415926f, SerializeDeserialize(3.1415926f)); - Assert.AreEqual((decimal)3.1415926f, SerializeDeserialize(3.1415926f)); - Assert.AreEqual(decimal.MaxValue, SerializeDeserialize(1e30f)); - Assert.AreEqual(decimal.MaxValue, SerializeDeserialize(float.MaxValue)); - Assert.AreEqual(decimal.MaxValue, SerializeDeserialize(float.PositiveInfinity)); - Assert.AreEqual(decimal.MaxValue, SerializeDeserialize((float)decimal.MaxValue)); - Assert.AreEqual(decimal.MinValue, SerializeDeserialize(-1e30f)); - Assert.AreEqual(decimal.MinValue, SerializeDeserialize(float.MinValue)); - Assert.AreEqual(decimal.MinValue, SerializeDeserialize(float.NegativeInfinity)); - Assert.AreEqual(decimal.MinValue, SerializeDeserialize((float)decimal.MinValue)); - Assert.AreEqual(0m, SerializeDeserialize(float.NaN)); - Assert.IsTrue(SerializeDeserialize(3.1415926f)); - } - } - - [Test] - public void TestDouble() - { - unchecked - { - Assert.AreEqual(13, SerializeDeserialize(13.123)); - Assert.AreEqual(13, SerializeDeserialize(13.123)); - Assert.AreEqual(1000, SerializeDeserialize(1000.382456)); - Assert.AreEqual(1000, SerializeDeserialize(1000.382456)); - Assert.AreEqual(1000000000, SerializeDeserialize(1000000000.73465)); - Assert.AreEqual(1000000000, SerializeDeserialize(1000000000.73465)); - Assert.AreEqual(12345678912345678, SerializeDeserialize(12345678912345678.73465)); - Assert.AreEqual(12345678912345678, SerializeDeserialize(12345678912345678.73465)); - Assert.AreEqual((float)3.1415926, SerializeDeserialize(3.1415926)); - Assert.AreEqual(3.1415926, SerializeDeserialize(3.1415926)); - Assert.AreEqual((decimal)3.1415926, SerializeDeserialize(3.1415926)); - Assert.AreEqual(decimal.MaxValue, SerializeDeserialize(1e100)); - Assert.AreEqual(decimal.MaxValue, SerializeDeserialize(double.MaxValue)); - Assert.AreEqual(decimal.MaxValue, SerializeDeserialize(double.PositiveInfinity)); - Assert.AreEqual(decimal.MaxValue, SerializeDeserialize((double)decimal.MaxValue)); - Assert.AreEqual(decimal.MinValue, SerializeDeserialize(-1e100)); - Assert.AreEqual(decimal.MinValue, SerializeDeserialize(double.MinValue)); - Assert.AreEqual(decimal.MinValue, SerializeDeserialize(double.NegativeInfinity)); - Assert.AreEqual(decimal.MinValue, SerializeDeserialize((double)decimal.MinValue)); - Assert.AreEqual(0m, SerializeDeserialize(double.NaN)); - Assert.IsTrue(SerializeDeserialize(3.1415926)); - } - } - - [Test] - public void TestDecimal() - { - unchecked - { - Assert.AreEqual(13, SerializeDeserialize(13.123m)); - Assert.AreEqual(13, SerializeDeserialize(13.123m)); - Assert.AreEqual(1000, SerializeDeserialize(1000.382456m)); - Assert.AreEqual(1000, SerializeDeserialize(1000.382456m)); - Assert.AreEqual(1000000000, SerializeDeserialize(1000000000.73465m)); - Assert.AreEqual(1000000000, SerializeDeserialize(1000000000.73465m)); - Assert.AreEqual(12345678912345678, SerializeDeserialize(12345678912345678.73465m)); - Assert.AreEqual(12345678912345678, SerializeDeserialize(12345678912345678.73465m)); - Assert.AreEqual((float)3.1415926, SerializeDeserialize(3.1415926m)); - Assert.AreEqual(3.1415926, SerializeDeserialize(3.1415926m)); - Assert.AreEqual(3.1415926m, SerializeDeserialize(3.1415926m)); - Assert.IsTrue(SerializeDeserialize(3.1415926m)); - } - } - - private TOut SerializeDeserialize(TIn value) - { - return serializer.Deserialize(serializer.Serialize(value)); - } - - private Serializer serializer; - } +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestPrimitives + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestBool() + { + Assert.AreEqual(1, SerializeDeserialize(true)); + Assert.AreEqual(1, SerializeDeserialize(true)); + Assert.AreEqual(1, SerializeDeserialize(true)); + Assert.AreEqual(1, SerializeDeserialize(true)); + Assert.AreEqual(1, SerializeDeserialize(true)); + Assert.AreEqual(1, SerializeDeserialize(true)); + Assert.AreEqual(1, SerializeDeserialize(true)); + Assert.AreEqual(1, SerializeDeserialize(true)); + Assert.AreEqual((float)1, SerializeDeserialize(true)); + Assert.AreEqual((double)1, SerializeDeserialize(true)); + Assert.AreEqual(1.0m, SerializeDeserialize(true)); + + Assert.IsTrue(SerializeDeserialize(int.MaxValue)); + Assert.IsTrue(SerializeDeserialize(1L << 32)); + Assert.IsTrue(SerializeDeserialize(1L << 48)); + Assert.IsFalse(SerializeDeserialize(0)); + Assert.IsFalse(SerializeDeserialize(0)); + Assert.IsFalse(SerializeDeserialize(0)); + Assert.IsFalse(SerializeDeserialize(0)); + Assert.IsFalse(SerializeDeserialize(0)); + Assert.IsTrue(SerializeDeserialize(0.1f)); + Assert.IsTrue(SerializeDeserialize(0.1)); + Assert.IsFalse(SerializeDeserialize(0)); + Assert.IsTrue(SerializeDeserialize(0.1m)); + Assert.IsTrue(SerializeDeserialize(10)); + + Assert.AreEqual(0, SerializeDeserialize(false)); + Assert.AreEqual(0, SerializeDeserialize(false)); + Assert.AreEqual(0, SerializeDeserialize(false)); + Assert.AreEqual(0, SerializeDeserialize(false)); + Assert.AreEqual(0, SerializeDeserialize(false)); + Assert.AreEqual(0, SerializeDeserialize(false)); + Assert.AreEqual(0, SerializeDeserialize(false)); + Assert.AreEqual(0, SerializeDeserialize(false)); + Assert.AreEqual((float)0, SerializeDeserialize(false)); + Assert.AreEqual((double)0, SerializeDeserialize(false)); + Assert.AreEqual(0.0m, SerializeDeserialize(false)); + Assert.IsFalse(SerializeDeserialize(false)); + } + + [Test] + public void TestInt8Negative() + { + const sbyte x = -13; + const byte y = -x - 1; + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(uint.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(byte.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(ushort.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(ulong.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual((float)x, SerializeDeserialize(x)); + Assert.AreEqual((double)x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.IsTrue(SerializeDeserialize(x)); + } + + [Test] + public void TestInt8Positive() + { + const sbyte x = 13; + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual((float)x, SerializeDeserialize(x)); + Assert.AreEqual((double)x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.IsTrue(SerializeDeserialize(x)); + } + + [Test] + public void TestInt16Negative() + { + const short x = -13; + const ushort y = -x - 1; + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(uint.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(byte.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(ushort.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(ulong.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual((float)x, SerializeDeserialize(x)); + Assert.AreEqual((double)x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.IsTrue(SerializeDeserialize(x)); + } + + [Test] + public void TestInt16Positive() + { + const short x = 13; + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual((float)x, SerializeDeserialize(x)); + Assert.AreEqual((double)x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.IsTrue(SerializeDeserialize(x)); + } + + [Test] + public void TestInt32Negative() + { + const int x = -13; + const uint y = -x - 1; + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(uint.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(byte.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(ushort.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(ulong.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual((float)x, SerializeDeserialize(x)); + Assert.AreEqual((double)x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.IsTrue(SerializeDeserialize(x)); + } + + [Test] + public void TestInt32Positive() + { + const int x = 13; + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual((float)x, SerializeDeserialize(x)); + Assert.AreEqual((double)x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.IsTrue(SerializeDeserialize(x)); + } + + [Test] + public void TestUInt8() + { + const byte x = 250; + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(-(byte.MaxValue - x + 1), SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual((float)x, SerializeDeserialize(x)); + Assert.AreEqual((double)x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.IsTrue(SerializeDeserialize(x)); + } + + [Test] + public void TestUInt16() + { + const ushort x = 54321; + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(13, SerializeDeserialize(13)); + Assert.AreEqual(13, SerializeDeserialize(13)); + Assert.AreEqual(-(ushort.MaxValue - x + 1), SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual((float)x, SerializeDeserialize(x)); + Assert.AreEqual((double)x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.IsTrue(SerializeDeserialize(x)); + } + + [Test] + public void TestUInt32() + { + const uint x = 3000000000; + Assert.AreEqual(-(uint.MaxValue - x + 1), SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(13, SerializeDeserialize(13)); + Assert.AreEqual(13, SerializeDeserialize(13)); + Assert.AreEqual(1000, SerializeDeserialize(1000)); + Assert.AreEqual(1000, SerializeDeserialize(1000)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual((float)x, SerializeDeserialize(x)); + Assert.AreEqual((double)x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.IsTrue(SerializeDeserialize(x)); + } + + [Test] + public void TestUInt64() + { + unchecked + { + const ulong x = 10000000000000000000; + Assert.AreEqual(13, SerializeDeserialize(13)); + Assert.AreEqual(13, SerializeDeserialize(13)); + Assert.AreEqual(1000, SerializeDeserialize(1000)); + Assert.AreEqual(1000, SerializeDeserialize(1000)); + Assert.AreEqual(1000000000, SerializeDeserialize(1000000000)); + Assert.AreEqual(1000000000, SerializeDeserialize(1000000000)); + Assert.AreEqual((long)(0L - (ulong.MaxValue - x + 1)), SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual((float)x, SerializeDeserialize(x)); + Assert.AreEqual((double)x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.IsTrue(SerializeDeserialize(x)); + } + } + + [Test] + public void TestInt64Positive() + { + unchecked + { + const long x = 1000000000000000000; + Assert.AreEqual(13, SerializeDeserialize(13)); + Assert.AreEqual(13, SerializeDeserialize(13)); + Assert.AreEqual(1000, SerializeDeserialize(1000)); + Assert.AreEqual(1000, SerializeDeserialize(1000)); + Assert.AreEqual(1000000000, SerializeDeserialize(1000000000)); + Assert.AreEqual(1000000000, SerializeDeserialize(1000000000)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual((float)x, SerializeDeserialize(x)); + Assert.AreEqual((double)x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.IsTrue(SerializeDeserialize(x)); + } + } + + [Test] + public void TestInt64Negative() + { + unchecked + { + const long x = -13; + const ulong y = -x - 1; + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(uint.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(byte.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(ushort.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.AreEqual(ulong.MaxValue - y, SerializeDeserialize(x)); + Assert.AreEqual((float)x, SerializeDeserialize(x)); + Assert.AreEqual((double)x, SerializeDeserialize(x)); + Assert.AreEqual(x, SerializeDeserialize(x)); + Assert.IsTrue(SerializeDeserialize(x)); + } + } + + [Test] + public void TestFloat() + { + unchecked + { + Assert.AreEqual(13, SerializeDeserialize(13.123f)); + Assert.AreEqual(13, SerializeDeserialize(13.123f)); + Assert.AreEqual(1000, SerializeDeserialize(1000.382456f)); + Assert.AreEqual(1000, SerializeDeserialize(1000.382456f)); + Assert.AreEqual(1000000000, SerializeDeserialize(1000000000.73465f)); + Assert.AreEqual(1000000000, SerializeDeserialize(1000000000.73465f)); + Assert.AreEqual(10000000000, SerializeDeserialize(10000000000.73465f)); + Assert.AreEqual(10000000000, SerializeDeserialize(10000000000.73465f)); + Assert.AreEqual(3.1415926f, SerializeDeserialize(3.1415926f)); + Assert.AreEqual((double)3.1415926f, SerializeDeserialize(3.1415926f)); + Assert.AreEqual((decimal)3.1415926f, SerializeDeserialize(3.1415926f)); + Assert.AreEqual(decimal.MaxValue, SerializeDeserialize(1e30f)); + Assert.AreEqual(decimal.MaxValue, SerializeDeserialize(float.MaxValue)); + Assert.AreEqual(decimal.MaxValue, SerializeDeserialize(float.PositiveInfinity)); + Assert.AreEqual(decimal.MaxValue, SerializeDeserialize((float)decimal.MaxValue)); + Assert.AreEqual(decimal.MinValue, SerializeDeserialize(-1e30f)); + Assert.AreEqual(decimal.MinValue, SerializeDeserialize(float.MinValue)); + Assert.AreEqual(decimal.MinValue, SerializeDeserialize(float.NegativeInfinity)); + Assert.AreEqual(decimal.MinValue, SerializeDeserialize((float)decimal.MinValue)); + Assert.AreEqual(0m, SerializeDeserialize(float.NaN)); + Assert.IsTrue(SerializeDeserialize(3.1415926f)); + } + } + + [Test] + public void TestDouble() + { + unchecked + { + Assert.AreEqual(13, SerializeDeserialize(13.123)); + Assert.AreEqual(13, SerializeDeserialize(13.123)); + Assert.AreEqual(1000, SerializeDeserialize(1000.382456)); + Assert.AreEqual(1000, SerializeDeserialize(1000.382456)); + Assert.AreEqual(1000000000, SerializeDeserialize(1000000000.73465)); + Assert.AreEqual(1000000000, SerializeDeserialize(1000000000.73465)); + Assert.AreEqual(12345678912345678, SerializeDeserialize(12345678912345678.73465)); + Assert.AreEqual(12345678912345678, SerializeDeserialize(12345678912345678.73465)); + Assert.AreEqual((float)3.1415926, SerializeDeserialize(3.1415926)); + Assert.AreEqual(3.1415926, SerializeDeserialize(3.1415926)); + Assert.AreEqual((decimal)3.1415926, SerializeDeserialize(3.1415926)); + Assert.AreEqual(decimal.MaxValue, SerializeDeserialize(1e100)); + Assert.AreEqual(decimal.MaxValue, SerializeDeserialize(double.MaxValue)); + Assert.AreEqual(decimal.MaxValue, SerializeDeserialize(double.PositiveInfinity)); + Assert.AreEqual(decimal.MaxValue, SerializeDeserialize((double)decimal.MaxValue)); + Assert.AreEqual(decimal.MinValue, SerializeDeserialize(-1e100)); + Assert.AreEqual(decimal.MinValue, SerializeDeserialize(double.MinValue)); + Assert.AreEqual(decimal.MinValue, SerializeDeserialize(double.NegativeInfinity)); + Assert.AreEqual(decimal.MinValue, SerializeDeserialize((double)decimal.MinValue)); + Assert.AreEqual(0m, SerializeDeserialize(double.NaN)); + Assert.IsTrue(SerializeDeserialize(3.1415926)); + } + } + + [Test] + public void TestDecimal() + { + unchecked + { + Assert.AreEqual(13, SerializeDeserialize(13.123m)); + Assert.AreEqual(13, SerializeDeserialize(13.123m)); + Assert.AreEqual(1000, SerializeDeserialize(1000.382456m)); + Assert.AreEqual(1000, SerializeDeserialize(1000.382456m)); + Assert.AreEqual(1000000000, SerializeDeserialize(1000000000.73465m)); + Assert.AreEqual(1000000000, SerializeDeserialize(1000000000.73465m)); + Assert.AreEqual(12345678912345678, SerializeDeserialize(12345678912345678.73465m)); + Assert.AreEqual(12345678912345678, SerializeDeserialize(12345678912345678.73465m)); + Assert.AreEqual((float)3.1415926, SerializeDeserialize(3.1415926m)); + Assert.AreEqual(3.1415926, SerializeDeserialize(3.1415926m)); + Assert.AreEqual(3.1415926m, SerializeDeserialize(3.1415926m)); + Assert.IsTrue(SerializeDeserialize(3.1415926m)); + } + } + + private TOut SerializeDeserialize(TIn value) + { + return serializer.Deserialize(serializer.Serialize(value)); + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestProperties.cs b/GroBuf.Tests/TestProperties.cs similarity index 96% rename from GroBuf/Tests/TestProperties.cs rename to GroBuf.Tests/TestProperties.cs index 8342c4f..b1bfea4 100644 --- a/GroBuf/Tests/TestProperties.cs +++ b/GroBuf.Tests/TestProperties.cs @@ -1,71 +1,71 @@ -using System; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestProperties - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void Test() - { - var o = new A {Bool = true, Ints = new[] {10, 2, 4}, B = new B {S = "zzz", Long = 123456789123456789, DateTime = new DateTime(1234567890123, DateTimeKind.Local)}}; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(true, oo.Bool); - Assert.IsNotNull(oo.Ints); - Assert.AreEqual(3, oo.Ints.Length); - Assert.AreEqual(10, oo.Ints[0]); - Assert.AreEqual(2, oo.Ints[1]); - Assert.AreEqual(4, oo.Ints[2]); - Assert.IsNotNull(oo.B); - Assert.AreEqual("zzz", oo.B.S); - Assert.AreEqual(123456789123456789, oo.B.Long); - Assert.AreEqual(1234567890123, oo.B.DateTime.Ticks); - } - - [Test] - public void TestEmpty() - { - var o = new B {S = "zzz"}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.IsNotNull(oo); - data = serializer.Serialize(oo); - o = serializer.Deserialize(data); - Assert.IsNotNull(o); - Assert.IsNull(o.S); - Assert.IsNull(o.Long); - Assert.AreEqual(default(DateTime), o.DateTime); - } - - public class A - { - public int[] Ints { get; set; } - public bool? Bool { get; set; } - public B B { get; set; } - } - - public class B - { - public string S { get; set; } - public long? Long { get; set; } - public DateTime DateTime { get; set; } - } - - public class C - { - } - - private Serializer serializer; - } +using System; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestProperties + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void Test() + { + var o = new A {Bool = true, Ints = new[] {10, 2, 4}, B = new B {S = "zzz", Long = 123456789123456789, DateTime = new DateTime(1234567890123, DateTimeKind.Local)}}; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(true, oo.Bool); + Assert.IsNotNull(oo.Ints); + Assert.AreEqual(3, oo.Ints.Length); + Assert.AreEqual(10, oo.Ints[0]); + Assert.AreEqual(2, oo.Ints[1]); + Assert.AreEqual(4, oo.Ints[2]); + Assert.IsNotNull(oo.B); + Assert.AreEqual("zzz", oo.B.S); + Assert.AreEqual(123456789123456789, oo.B.Long); + Assert.AreEqual(1234567890123, oo.B.DateTime.Ticks); + } + + [Test] + public void TestEmpty() + { + var o = new B {S = "zzz"}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.IsNotNull(oo); + data = serializer.Serialize(oo); + o = serializer.Deserialize(data); + Assert.IsNotNull(o); + Assert.IsNull(o.S); + Assert.IsNull(o.Long); + Assert.AreEqual(default(DateTime), o.DateTime); + } + + public class A + { + public int[] Ints { get; set; } + public bool? Bool { get; set; } + public B B { get; set; } + } + + public class B + { + public string S { get; set; } + public long? Long { get; set; } + public DateTime DateTime { get; set; } + } + + public class C + { + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestPropertiesExtractor.cs b/GroBuf.Tests/TestPropertiesExtractor.cs similarity index 95% rename from GroBuf/Tests/TestPropertiesExtractor.cs rename to GroBuf.Tests/TestPropertiesExtractor.cs index 7952315..d0faf94 100644 --- a/GroBuf/Tests/TestPropertiesExtractor.cs +++ b/GroBuf.Tests/TestPropertiesExtractor.cs @@ -1,28 +1,28 @@ -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -using System.Linq; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestPropertiesExtractor - { - [Test] - public void TestPrivatePropertyInBaseClass() - { - CollectionAssert.AreEquivalent(new[] {"S", "X"}, new AllPropertiesExtractor().GetMembers(typeof(B)).Select(member => member.Name)); - } - - public class A - { - private string S { get; set; } - } - - public class B: A - { - public int X { get; set; } - } - } +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +using System.Linq; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestPropertiesExtractor + { + [Test] + public void TestPrivatePropertyInBaseClass() + { + CollectionAssert.AreEquivalent(new[] {"S", "X"}, new AllPropertiesExtractor().GetMembers(typeof(B)).Select(member => member.Name)); + } + + public class A + { + private string S { get; set; } + } + + public class B: A + { + public int X { get; set; } + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestStrings.cs b/GroBuf.Tests/TestStrings.cs similarity index 97% rename from GroBuf/Tests/TestStrings.cs rename to GroBuf.Tests/TestStrings.cs index d537eff..a313c44 100644 --- a/GroBuf/Tests/TestStrings.cs +++ b/GroBuf.Tests/TestStrings.cs @@ -1,110 +1,110 @@ -using System; -using System.Diagnostics; -using System.Text; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestStrings - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void TestPerformance() - { - const int length = 32; - var arr = new char[length]; - for (int i = 0; i < length; ++i) - arr[i] = (char)('a' + i % 26); - var s = new string(arr); - byte[] data = serializer.Serialize(s); - var buf = Encoding.UTF8.GetBytes(s); - const int iterations = 100000; - long size = 0; - var stopwatch = Stopwatch.StartNew(); - for(int i = 0; i < iterations; ++i) - { - //data = Encoding.UTF8.GetBytes(s);//serializer.Serialize(s); - s = Encoding.UTF8.GetString(buf); - size += s.Length; - } - var elapsed = stopwatch.Elapsed; - Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); - Console.WriteLine("Size: " + ((double)size) / iterations + " bytes"); - } - - [Test] - public void TestString() - { - const string s = "zzz \u2376 \uDEAD"; - byte[] bytes = serializer.Serialize(s); - var deserialize = serializer.Deserialize(bytes); - Assert.AreEqual("zzz \u2376 \uDEAD", deserialize); - } - - [Test] - public void TestString1() - { - const string s = "zzz \u2376 \uDEAD"; - byte[] bytes = serializer.Serialize(typeof(string), s); - var deserialize = serializer.Deserialize(typeof(string), bytes); - Assert.AreEqual("zzz \u2376 \uDEAD", deserialize); - } - - [Test] - public void TestStringInProp() - { - const string s = "zzz \u2376 \uDEAD"; - byte[] bytes = serializer.Serialize(new WithS {S = s}); - var deserialize = serializer.Deserialize(bytes); - Assert.AreEqual("zzz \u2376 \uDEAD", deserialize.S); - } - - [Test] - public void TestStringNull() - { - byte[] bytes = serializer.Serialize(null); - var deserialize = serializer.Deserialize(bytes); - Assert.AreEqual(null, deserialize); - } - - [Test] - public void TestStringNullInProp() - { - byte[] bytes = serializer.Serialize(new WithS()); - var deserialize = serializer.Deserialize(bytes); - Assert.AreEqual(null, deserialize.S); - } - - [Test] - public void TestStringEmpty() - { - byte[] bytes = serializer.Serialize(""); - var deserialize = serializer.Deserialize(bytes); - Assert.AreEqual("", deserialize); - } - - [Test] - public void TestStringEmptyInProp() - { - byte[] bytes = serializer.Serialize(new WithS {S = ""}); - var deserialize = serializer.Deserialize(bytes); - Assert.AreEqual("", deserialize.S); - } - - public class WithS - { - public string S { get; set; } - } - - private Serializer serializer; - } +using System; +using System.Diagnostics; +using System.Text; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestStrings + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void TestPerformance() + { + const int length = 32; + var arr = new char[length]; + for (int i = 0; i < length; ++i) + arr[i] = (char)('a' + i % 26); + var s = new string(arr); + byte[] data = serializer.Serialize(s); + var buf = Encoding.UTF8.GetBytes(s); + const int iterations = 100000; + long size = 0; + var stopwatch = Stopwatch.StartNew(); + for(int i = 0; i < iterations; ++i) + { + //data = Encoding.UTF8.GetBytes(s);//serializer.Serialize(s); + s = Encoding.UTF8.GetString(buf); + size += s.Length; + } + var elapsed = stopwatch.Elapsed; + Console.WriteLine("Serializing: " + elapsed.TotalMilliseconds * 1000 / iterations + " microseconds (" + Math.Round(1000.0 * iterations / elapsed.TotalMilliseconds) + " serializations per second)"); + Console.WriteLine("Size: " + ((double)size) / iterations + " bytes"); + } + + [Test] + public void TestString() + { + const string s = "zzz \u2376 \uDEAD"; + byte[] bytes = serializer.Serialize(s); + var deserialize = serializer.Deserialize(bytes); + Assert.AreEqual("zzz \u2376 \uDEAD", deserialize); + } + + [Test] + public void TestString1() + { + const string s = "zzz \u2376 \uDEAD"; + byte[] bytes = serializer.Serialize(typeof(string), s); + var deserialize = serializer.Deserialize(typeof(string), bytes); + Assert.AreEqual("zzz \u2376 \uDEAD", deserialize); + } + + [Test] + public void TestStringInProp() + { + const string s = "zzz \u2376 \uDEAD"; + byte[] bytes = serializer.Serialize(new WithS {S = s}); + var deserialize = serializer.Deserialize(bytes); + Assert.AreEqual("zzz \u2376 \uDEAD", deserialize.S); + } + + [Test] + public void TestStringNull() + { + byte[] bytes = serializer.Serialize(null); + var deserialize = serializer.Deserialize(bytes); + Assert.AreEqual(null, deserialize); + } + + [Test] + public void TestStringNullInProp() + { + byte[] bytes = serializer.Serialize(new WithS()); + var deserialize = serializer.Deserialize(bytes); + Assert.AreEqual(null, deserialize.S); + } + + [Test] + public void TestStringEmpty() + { + byte[] bytes = serializer.Serialize(""); + var deserialize = serializer.Deserialize(bytes); + Assert.AreEqual("", deserialize); + } + + [Test] + public void TestStringEmptyInProp() + { + byte[] bytes = serializer.Serialize(new WithS {S = ""}); + var deserialize = serializer.Deserialize(bytes); + Assert.AreEqual("", deserialize.S); + } + + public class WithS + { + public string S { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestStruct.cs b/GroBuf.Tests/TestStruct.cs similarity index 96% rename from GroBuf/Tests/TestStruct.cs rename to GroBuf.Tests/TestStruct.cs index e767e81..25d0d06 100644 --- a/GroBuf/Tests/TestStruct.cs +++ b/GroBuf.Tests/TestStruct.cs @@ -1,48 +1,48 @@ -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestStruct - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void Test() - { - var o = new A {Bool = true, Ints = new[] {10, 2, 4}, B = new B {S = "zzz", Long = 123456789123456789}}; - byte[] data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual(true, oo.Bool); - Assert.IsNotNull(oo.Ints); - Assert.AreEqual(3, oo.Ints.Length); - Assert.AreEqual(10, oo.Ints[0]); - Assert.AreEqual(2, oo.Ints[1]); - Assert.AreEqual(4, oo.Ints[2]); - Assert.IsNotNull(oo.B); - Assert.AreEqual("zzz", oo.B.S); - Assert.AreEqual(123456789123456789, oo.B.Long); - } - - public struct A - { - public int[] Ints { get; set; } - public bool? Bool { get; set; } - public B B { get; set; } - } - - public struct B - { - public string S { get; set; } - public long? Long { get; set; } - } - - private Serializer serializer; - } +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestStruct + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void Test() + { + var o = new A {Bool = true, Ints = new[] {10, 2, 4}, B = new B {S = "zzz", Long = 123456789123456789}}; + byte[] data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual(true, oo.Bool); + Assert.IsNotNull(oo.Ints); + Assert.AreEqual(3, oo.Ints.Length); + Assert.AreEqual(10, oo.Ints[0]); + Assert.AreEqual(2, oo.Ints[1]); + Assert.AreEqual(4, oo.Ints[2]); + Assert.IsNotNull(oo.B); + Assert.AreEqual("zzz", oo.B.S); + Assert.AreEqual(123456789123456789, oo.B.Long); + } + + public struct A + { + public int[] Ints { get; set; } + public bool? Bool { get; set; } + public B B { get; set; } + } + + public struct B + { + public string S { get; set; } + public long? Long { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestTimeSpan.cs b/GroBuf.Tests/TestTimeSpan.cs similarity index 96% rename from GroBuf/Tests/TestTimeSpan.cs rename to GroBuf.Tests/TestTimeSpan.cs index 73603df..7d5118c 100644 --- a/GroBuf/Tests/TestTimeSpan.cs +++ b/GroBuf.Tests/TestTimeSpan.cs @@ -1,51 +1,51 @@ -using System; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestTimeSpan - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new AllPropertiesExtractor()); - } - - [Test] - public void TestSize() - { - var timeSpan = new TimeSpan(12938746); - var size = serializer.GetSize(timeSpan); - Assert.AreEqual(9, size); - } - - [Test] - public void TestReadWrite() - { - var timeSpan = new TimeSpan(239856851); - var data = serializer.Serialize(timeSpan); - var timeSpan2 = serializer.Deserialize(data); - Assert.AreEqual(timeSpan, timeSpan2); - } - - [Test] - public void TestReadWrite2() - { - var zzz = new Zzz {TimeSpan = new TimeSpan(82354222765175)}; - var data = serializer.Serialize(zzz); - var zzz2 = serializer.Deserialize(data); - Assert.AreEqual(zzz.TimeSpan, zzz2.TimeSpan); - } - - public class Zzz - { - public TimeSpan TimeSpan { get; set; } - } - - private Serializer serializer; - } +using System; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestTimeSpan + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new AllPropertiesExtractor()); + } + + [Test] + public void TestSize() + { + var timeSpan = new TimeSpan(12938746); + var size = serializer.GetSize(timeSpan); + Assert.AreEqual(9, size); + } + + [Test] + public void TestReadWrite() + { + var timeSpan = new TimeSpan(239856851); + var data = serializer.Serialize(timeSpan); + var timeSpan2 = serializer.Deserialize(data); + Assert.AreEqual(timeSpan, timeSpan2); + } + + [Test] + public void TestReadWrite2() + { + var zzz = new Zzz {TimeSpan = new TimeSpan(82354222765175)}; + var data = serializer.Serialize(zzz); + var zzz2 = serializer.Deserialize(data); + Assert.AreEqual(zzz.TimeSpan, zzz2.TimeSpan); + } + + public class Zzz + { + public TimeSpan TimeSpan { get; set; } + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestTools/ConcurrentCache.cs b/GroBuf.Tests/TestTools/ConcurrentCache.cs similarity index 96% rename from GroBuf/Tests/TestTools/ConcurrentCache.cs rename to GroBuf.Tests/TestTools/ConcurrentCache.cs index 2173fdd..3f66ed4 100644 --- a/GroBuf/Tests/TestTools/ConcurrentCache.cs +++ b/GroBuf.Tests/TestTools/ConcurrentCache.cs @@ -1,44 +1,44 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; - -namespace GroBuf.Tests.TestTools -{ - public class ConcurrentCache - { - public ConcurrentCache(Dictionary dictionary, Func extractData) - { - this.dictionary = new ConcurrentDictionary(dictionary); - this.extractData = extractData; - } - - public ConcurrentCache(Func extractData) - : this(new Dictionary(), extractData) - { - } - - public TValue Get(TKey obj) - { - return dictionary.GetOrAdd(obj, extractData); - } - - public bool Contains(TKey key) - { - return dictionary.ContainsKey(key); - } - - public void Remove(TKey key) - { - TValue value; - dictionary.TryRemove(key, out value); - } - - public void Clear() - { - dictionary.Clear(); - } - - private readonly Func extractData; - private readonly ConcurrentDictionary dictionary; - } +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; + +namespace GroBuf.Tests.TestTools +{ + public class ConcurrentCache + { + public ConcurrentCache(Dictionary dictionary, Func extractData) + { + this.dictionary = new ConcurrentDictionary(dictionary); + this.extractData = extractData; + } + + public ConcurrentCache(Func extractData) + : this(new Dictionary(), extractData) + { + } + + public TValue Get(TKey obj) + { + return dictionary.GetOrAdd(obj, extractData); + } + + public bool Contains(TKey key) + { + return dictionary.ContainsKey(key); + } + + public void Remove(TKey key) + { + TValue value; + dictionary.TryRemove(key, out value); + } + + public void Clear() + { + dictionary.Clear(); + } + + private readonly Func extractData; + private readonly ConcurrentDictionary dictionary; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestTools/ExtenderImpl.cs b/GroBuf.Tests/TestTools/ExtenderImpl.cs similarity index 97% rename from GroBuf/Tests/TestTools/ExtenderImpl.cs rename to GroBuf.Tests/TestTools/ExtenderImpl.cs index d0e9600..40ae4dd 100644 --- a/GroBuf/Tests/TestTools/ExtenderImpl.cs +++ b/GroBuf.Tests/TestTools/ExtenderImpl.cs @@ -1,233 +1,233 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using System.Reflection.Emit; - -namespace GroBuf.Tests.TestTools -{ - public class ExtenderImpl - { - public ExtenderImpl(Func> scanProperties) - { - this.scanProperties = scanProperties; - } - - public ExtenderImpl() - : this(ScanProperties.AllPublic) - { - } - - public void Extend(Type type, object source) - { - if(source == null) - throw new ArgumentNullException("source"); - Action extender = GetExtender(type); - extender(source); - } - - private Action GetExtender(Type type) - { - var result = (Action)typeExtenders[type]; - if(result == null) - { - lock(typeExtendersLock) - { - result = (Action)typeExtenders[type]; - if(result == null) - { - result = BuildExtender(type); - typeExtenders[type] = result; - } - } - } - return result; - } - - private Action BuildExtender(Type type) - { - IEnumerable propertyInfos = scanProperties(type); - var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), - new[] {GetType(), typeof(object)}, GetType(), true); - ILGenerator il = dynamicMethod.GetILGenerator(); - foreach(var propertyInfo in propertyInfos) - { - if(propertyInfo.PropertyType.IsArray) - EmitFillOfArrayProperty(il, type, propertyInfo); - else if(propertyInfo.PropertyType.IsClass) - EmitFillOfClassProperty(il, type, propertyInfo); - } - il.Emit(OpCodes.Ret); - - var action = - (Action)dynamicMethod.CreateDelegate(typeof(Action)); - return o => action(this, o); - } - - private static readonly MethodInfo extendMethodInfo = - typeof(ExtenderImpl).GetMethod("Extend", - BindingFlags.Public | BindingFlags.Instance, null, - new[] {typeof(Type), typeof(object)}, - null); - - private static readonly MethodInfo getTypeFromHandle = - typeof(Type).GetMethod("GetTypeFromHandle", - BindingFlags.Public | - BindingFlags.Static, null, - new[] {typeof(RuntimeTypeHandle)}, - null); - - private readonly Func> scanProperties; - - private readonly Hashtable typeExtenders = new Hashtable(); - private readonly object typeExtendersLock = new object(); - - #region Emit - - private static void EmitFillOfArrayProperty(ILGenerator il, Type type, PropertyInfo propertyInfo) - { - MethodInfo getter = propertyInfo.GetGetMethod(); - if(getter == null) - return; - - MethodInfo setter = propertyInfo.GetSetMethod(); - Type elementType = propertyInfo.PropertyType.GetElementType(); - ConstructorInfo constructorInfo = elementType.GetConstructor( - BindingFlags.Instance | BindingFlags.Public, - null, new Type[0], null); - - LocalBuilder array = il.DeclareLocal(propertyInfo.PropertyType); - LocalBuilder index = il.DeclareLocal(typeof(int)); - - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Castclass, type); - il.Emit(OpCodes.Callvirt, getter); // stack: [o.Prop] - il.Emit(OpCodes.Dup); // stack: [o.Prop, o.Prop] - il.Emit(OpCodes.Stloc, array); // var array = o.Prop; stack = [array] - - Label arrayNotNull = il.DefineLabel(); - Label allDone = il.DefineLabel(); - - if(setter != null) - { - il.Emit(OpCodes.Brtrue, arrayNotNull); // if (array != null) goto arrayNotNull - - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Castclass, type); // stack: [o] - il.Emit(OpCodes.Ldc_I4_0); // stack: [o, 0] - il.Emit(OpCodes.Newarr, elementType); // stack: [o, new elementType[0]] - il.Emit(OpCodes.Callvirt, setter); // o.Prop = new elementType[0] - - il.Emit(OpCodes.Br, allDone); // goto allDone - } - else - il.Emit(OpCodes.Brfalse, allDone); // if (array == null) goto allDone - - il.MarkLabel(arrayNotNull); - - if(elementType.IsClass) - { - il.Emit(OpCodes.Ldloc, array); - il.Emit(OpCodes.Ldlen); - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Stloc, index); // index = array.Length; stack = [array.Length] - il.Emit(OpCodes.Brfalse, allDone); // if (array.Length == 0) goto allDone - - Label cycleStart = il.DefineLabel(); - Label cycleEnd = il.DefineLabel(); - - il.MarkLabel(cycleStart); - - il.Emit(OpCodes.Ldloc, array); - il.Emit(OpCodes.Ldloc, index); - il.Emit(OpCodes.Ldc_I4_1); - il.Emit(OpCodes.Sub); // stack: [array, index-1] - il.Emit(OpCodes.Dup); // stack: [array, index-1, index-1] - il.Emit(OpCodes.Stloc, index); // index--; stack: [array, index] - il.Emit(OpCodes.Ldelem, elementType); // stack = [array[index]] - - Label itemNotNull = il.DefineLabel(); - - if(constructorInfo == null) - il.Emit(OpCodes.Brfalse, cycleEnd); // if (item == null) goto cycleEnd - else - { - il.Emit(OpCodes.Brtrue, itemNotNull); // if (item != null) goto itemNotNull - il.Emit(OpCodes.Ldloc, array); - il.Emit(OpCodes.Ldloc, index); - il.Emit(OpCodes.Newobj, constructorInfo); - il.Emit(OpCodes.Stelem, elementType); // array[index] = new elementType() - } - - il.MarkLabel(itemNotNull); - - il.Emit(OpCodes.Ldarg_0); // stack = [this] - il.Emit(OpCodes.Ldtoken, elementType); - il.Emit(OpCodes.Call, getTypeFromHandle); // stack = [this, elementType] - il.Emit(OpCodes.Ldloc, array); - il.Emit(OpCodes.Ldloc, index); - il.Emit(OpCodes.Ldelem, elementType); // stack = [this, elementType, array[index]] - il.Emit(OpCodes.Call, extendMethodInfo); // this.Extend(elementType, array[index]) - - il.MarkLabel(cycleEnd); - - il.Emit(OpCodes.Ldloc, index); - il.Emit(OpCodes.Brtrue, cycleStart); // if (index != 0) goto cycleStart; - } - il.MarkLabel(allDone); - } - - private static void EmitFillOfClassProperty(ILGenerator il, Type type, PropertyInfo propertyInfo) - { - MethodInfo getter = propertyInfo.GetGetMethod(); - if(getter == null) - return; - - MethodInfo setter = propertyInfo.GetSetMethod(); - ConstructorInfo constructorInfo = propertyInfo.PropertyType.GetConstructor( - BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null); - - il.Emit(OpCodes.Ldarg_1); // stack: [(object) o] - il.Emit(OpCodes.Castclass, type); // stack: [(Type) o] - il.Emit(OpCodes.Callvirt, getter); // stack: [o.Prop] - - Label propDone = il.DefineLabel(); - Label propNotNull = il.DefineLabel(); - - if(constructorInfo == null || setter == null || type == propertyInfo.PropertyType) - il.Emit(OpCodes.Brfalse, propDone); // if (o.Prop == null) goto propDone //stack: [] - else - { - il.Emit(OpCodes.Brtrue, propNotNull); // if (o.Prop != null) goto propNotNull - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Castclass, type); // stack: [o] - il.Emit(OpCodes.Newobj, constructorInfo); // stack: [o, new Prop()] - il.Emit(OpCodes.Callvirt, setter); // o.Prop = new Prop() - } - - il.MarkLabel(propNotNull); - - il.Emit(OpCodes.Ldarg_0); // stack: [extender] - il.Emit(OpCodes.Ldtoken, propertyInfo.PropertyType); - il.Emit(OpCodes.Call, getTypeFromHandle); // stack: [extender, PropertyType] - il.Emit(OpCodes.Ldarg_1); // stack: [extender, PropertyType, o] - il.Emit(OpCodes.Castclass, type); - il.Emit(OpCodes.Callvirt, getter); // stack: [extender, PropertyType, o.Prop] - il.Emit(OpCodes.Call, extendMethodInfo); // extender.Extend(PropertyType, o.Prop) - - il.MarkLabel(propDone); - } - - #endregion - - #region Nested type: ScanProperties - - public static class ScanProperties - { - public static readonly Func> AllPublic = - type => type.GetProperties(BindingFlags.Instance | BindingFlags.Public); - } - - #endregion - } +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; + +namespace GroBuf.Tests.TestTools +{ + public class ExtenderImpl + { + public ExtenderImpl(Func> scanProperties) + { + this.scanProperties = scanProperties; + } + + public ExtenderImpl() + : this(ScanProperties.AllPublic) + { + } + + public void Extend(Type type, object source) + { + if(source == null) + throw new ArgumentNullException("source"); + Action extender = GetExtender(type); + extender(source); + } + + private Action GetExtender(Type type) + { + var result = (Action)typeExtenders[type]; + if(result == null) + { + lock(typeExtendersLock) + { + result = (Action)typeExtenders[type]; + if(result == null) + { + result = BuildExtender(type); + typeExtenders[type] = result; + } + } + } + return result; + } + + private Action BuildExtender(Type type) + { + IEnumerable propertyInfos = scanProperties(type); + var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), + new[] {GetType(), typeof(object)}, GetType(), true); + ILGenerator il = dynamicMethod.GetILGenerator(); + foreach(var propertyInfo in propertyInfos) + { + if(propertyInfo.PropertyType.IsArray) + EmitFillOfArrayProperty(il, type, propertyInfo); + else if(propertyInfo.PropertyType.IsClass) + EmitFillOfClassProperty(il, type, propertyInfo); + } + il.Emit(OpCodes.Ret); + + var action = + (Action)dynamicMethod.CreateDelegate(typeof(Action)); + return o => action(this, o); + } + + private static readonly MethodInfo extendMethodInfo = + typeof(ExtenderImpl).GetMethod("Extend", + BindingFlags.Public | BindingFlags.Instance, null, + new[] {typeof(Type), typeof(object)}, + null); + + private static readonly MethodInfo getTypeFromHandle = + typeof(Type).GetMethod("GetTypeFromHandle", + BindingFlags.Public | + BindingFlags.Static, null, + new[] {typeof(RuntimeTypeHandle)}, + null); + + private readonly Func> scanProperties; + + private readonly Hashtable typeExtenders = new Hashtable(); + private readonly object typeExtendersLock = new object(); + + #region Emit + + private static void EmitFillOfArrayProperty(ILGenerator il, Type type, PropertyInfo propertyInfo) + { + MethodInfo getter = propertyInfo.GetGetMethod(); + if(getter == null) + return; + + MethodInfo setter = propertyInfo.GetSetMethod(); + Type elementType = propertyInfo.PropertyType.GetElementType(); + ConstructorInfo constructorInfo = elementType.GetConstructor( + BindingFlags.Instance | BindingFlags.Public, + null, new Type[0], null); + + LocalBuilder array = il.DeclareLocal(propertyInfo.PropertyType); + LocalBuilder index = il.DeclareLocal(typeof(int)); + + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Castclass, type); + il.Emit(OpCodes.Callvirt, getter); // stack: [o.Prop] + il.Emit(OpCodes.Dup); // stack: [o.Prop, o.Prop] + il.Emit(OpCodes.Stloc, array); // var array = o.Prop; stack = [array] + + Label arrayNotNull = il.DefineLabel(); + Label allDone = il.DefineLabel(); + + if(setter != null) + { + il.Emit(OpCodes.Brtrue, arrayNotNull); // if (array != null) goto arrayNotNull + + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Castclass, type); // stack: [o] + il.Emit(OpCodes.Ldc_I4_0); // stack: [o, 0] + il.Emit(OpCodes.Newarr, elementType); // stack: [o, new elementType[0]] + il.Emit(OpCodes.Callvirt, setter); // o.Prop = new elementType[0] + + il.Emit(OpCodes.Br, allDone); // goto allDone + } + else + il.Emit(OpCodes.Brfalse, allDone); // if (array == null) goto allDone + + il.MarkLabel(arrayNotNull); + + if(elementType.IsClass) + { + il.Emit(OpCodes.Ldloc, array); + il.Emit(OpCodes.Ldlen); + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Stloc, index); // index = array.Length; stack = [array.Length] + il.Emit(OpCodes.Brfalse, allDone); // if (array.Length == 0) goto allDone + + Label cycleStart = il.DefineLabel(); + Label cycleEnd = il.DefineLabel(); + + il.MarkLabel(cycleStart); + + il.Emit(OpCodes.Ldloc, array); + il.Emit(OpCodes.Ldloc, index); + il.Emit(OpCodes.Ldc_I4_1); + il.Emit(OpCodes.Sub); // stack: [array, index-1] + il.Emit(OpCodes.Dup); // stack: [array, index-1, index-1] + il.Emit(OpCodes.Stloc, index); // index--; stack: [array, index] + il.Emit(OpCodes.Ldelem, elementType); // stack = [array[index]] + + Label itemNotNull = il.DefineLabel(); + + if(constructorInfo == null) + il.Emit(OpCodes.Brfalse, cycleEnd); // if (item == null) goto cycleEnd + else + { + il.Emit(OpCodes.Brtrue, itemNotNull); // if (item != null) goto itemNotNull + il.Emit(OpCodes.Ldloc, array); + il.Emit(OpCodes.Ldloc, index); + il.Emit(OpCodes.Newobj, constructorInfo); + il.Emit(OpCodes.Stelem, elementType); // array[index] = new elementType() + } + + il.MarkLabel(itemNotNull); + + il.Emit(OpCodes.Ldarg_0); // stack = [this] + il.Emit(OpCodes.Ldtoken, elementType); + il.Emit(OpCodes.Call, getTypeFromHandle); // stack = [this, elementType] + il.Emit(OpCodes.Ldloc, array); + il.Emit(OpCodes.Ldloc, index); + il.Emit(OpCodes.Ldelem, elementType); // stack = [this, elementType, array[index]] + il.Emit(OpCodes.Call, extendMethodInfo); // this.Extend(elementType, array[index]) + + il.MarkLabel(cycleEnd); + + il.Emit(OpCodes.Ldloc, index); + il.Emit(OpCodes.Brtrue, cycleStart); // if (index != 0) goto cycleStart; + } + il.MarkLabel(allDone); + } + + private static void EmitFillOfClassProperty(ILGenerator il, Type type, PropertyInfo propertyInfo) + { + MethodInfo getter = propertyInfo.GetGetMethod(); + if(getter == null) + return; + + MethodInfo setter = propertyInfo.GetSetMethod(); + ConstructorInfo constructorInfo = propertyInfo.PropertyType.GetConstructor( + BindingFlags.Instance | BindingFlags.Public, null, new Type[0], null); + + il.Emit(OpCodes.Ldarg_1); // stack: [(object) o] + il.Emit(OpCodes.Castclass, type); // stack: [(Type) o] + il.Emit(OpCodes.Callvirt, getter); // stack: [o.Prop] + + Label propDone = il.DefineLabel(); + Label propNotNull = il.DefineLabel(); + + if(constructorInfo == null || setter == null || type == propertyInfo.PropertyType) + il.Emit(OpCodes.Brfalse, propDone); // if (o.Prop == null) goto propDone //stack: [] + else + { + il.Emit(OpCodes.Brtrue, propNotNull); // if (o.Prop != null) goto propNotNull + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Castclass, type); // stack: [o] + il.Emit(OpCodes.Newobj, constructorInfo); // stack: [o, new Prop()] + il.Emit(OpCodes.Callvirt, setter); // o.Prop = new Prop() + } + + il.MarkLabel(propNotNull); + + il.Emit(OpCodes.Ldarg_0); // stack: [extender] + il.Emit(OpCodes.Ldtoken, propertyInfo.PropertyType); + il.Emit(OpCodes.Call, getTypeFromHandle); // stack: [extender, PropertyType] + il.Emit(OpCodes.Ldarg_1); // stack: [extender, PropertyType, o] + il.Emit(OpCodes.Castclass, type); + il.Emit(OpCodes.Callvirt, getter); // stack: [extender, PropertyType, o.Prop] + il.Emit(OpCodes.Call, extendMethodInfo); // extender.Extend(PropertyType, o.Prop) + + il.MarkLabel(propDone); + } + + #endregion + + #region Nested type: ScanProperties + + public static class ScanProperties + { + public static readonly Func> AllPublic = + type => type.GetProperties(BindingFlags.Instance | BindingFlags.Public); + } + + #endregion + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestTools/ObjectComparer.cs b/GroBuf.Tests/TestTools/ObjectComparer.cs similarity index 97% rename from GroBuf/Tests/TestTools/ObjectComparer.cs rename to GroBuf.Tests/TestTools/ObjectComparer.cs index 5d766a9..c42c5e2 100644 --- a/GroBuf/Tests/TestTools/ObjectComparer.cs +++ b/GroBuf.Tests/TestTools/ObjectComparer.cs @@ -1,17 +1,17 @@ -using NUnit.Framework; - -namespace GroBuf.Tests.TestTools -{ - public static class ObjectComparer - { - public static void AssertEqualsTo(this T actual, T expected) - { - string badXml = "".ReformatXml(); - string expectedStr = expected.ObjectToString(); - Assert.AreNotEqual(expectedStr.ReformatXml(), badXml, "bug(expected)"); - string actualStr = actual.ObjectToString(); - Assert.AreNotEqual(actualStr.ReformatXml(), badXml, "bug(actual)"); - Assert.AreEqual(expectedStr, actualStr); - } - } +using NUnit.Framework; + +namespace GroBuf.Tests.TestTools +{ + public static class ObjectComparer + { + public static void AssertEqualsTo(this T actual, T expected) + { + string badXml = "".ReformatXml(); + string expectedStr = expected.ObjectToString(); + Assert.AreNotEqual(expectedStr.ReformatXml(), badXml, "bug(expected)"); + string actualStr = actual.ObjectToString(); + Assert.AreNotEqual(actualStr.ReformatXml(), badXml, "bug(actual)"); + Assert.AreEqual(expectedStr, actualStr); + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestTools/ObjectSerializer.cs b/GroBuf.Tests/TestTools/ObjectSerializer.cs similarity index 97% rename from GroBuf/Tests/TestTools/ObjectSerializer.cs rename to GroBuf.Tests/TestTools/ObjectSerializer.cs index f55c956..fb8b5fd 100644 --- a/GroBuf/Tests/TestTools/ObjectSerializer.cs +++ b/GroBuf.Tests/TestTools/ObjectSerializer.cs @@ -1,139 +1,139 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Reflection; -using System.Text; -using System.Xml; - -namespace GroBuf.Tests.TestTools -{ - public static class ObjectSerializer - { - public static string ObjectToString(this T instance) - { - Type type = typeof(T); - if(type.IsInterface) - type = instance.GetType(); - var builder = new StringBuilder(); - using(XmlWriter writer = XmlWriter.Create(builder, new XmlWriterSettings {Indent = true, OmitXmlDeclaration = true})) - new ObjectWriter(writer).Write(type, instance, "root"); - return builder.ToString(); - } - - private class ObjectWriter - { - public ObjectWriter(XmlWriter writer) - { - this.writer = writer; - } - - public void Write(Type type, object value, string name) - { - writer.WriteStartElement(name); - DoWrite(type, value); - writer.WriteEndElement(); - } - - private void DoWrite(Type type, object value) - { - if(TryWriteNullValue(value)) return; - if(TryWriteNullableTypeValue(type, value)) return; - if(TryWriteSimpleTypeValue(type, value)) return; - if(TryWriteArrayTypeValue(type, value)) return; - WriteComplexTypeValue(type, value); - } - - private void WriteComplexTypeValue(Type type, object value) - { - foreach(var fieldInfo in GetFields(type)) - Write(fieldInfo.FieldType, fieldInfo.GetValue(value), FieldNameToTagName(fieldInfo.Name)); - } - - private static IEnumerable GetFields(Type type) - { - var result = new List(); - while(type != null) - { - FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetField | BindingFlags.Instance); - result.AddRange(fields.Where(fieldInfo => !fieldInfo.IsLiteral && !fieldInfo.FieldType.IsInterface)); - type = type.BaseType; - } - return result; - } - - private static string FieldNameToTagName(string name) - { - if(name.EndsWith(">k__BackingField")) - return name.Substring(1, name.IndexOf('>') - 1); - return name; - } - - private bool TryWriteArrayTypeValue(Type type, object value) - { - if(!type.IsArray) - return false; - writer.WriteAttributeString("type", "array"); - var array = (Array)value; - if(array.Rank > 1) - throw new NotSupportedException("array with rank > 1"); - Type elementType = type.GetElementType(); - for(int i = 0; i < array.Length; ++i) - Write(elementType, array.GetValue(i), "item"); - return true; - } - - private bool TryWriteSimpleTypeValue(Type type, object value) - { - string result = FindSimpleValue(type, value); - if(result == null) - return false; - writer.WriteValue(result); - return true; - } - - private static string FindSimpleValue(Type type, object value) - { - if(type == typeof(char) && (char)value == (char)0) - return "0x0000"; - if(type.IsEnum || type.IsPrimitive || value is string || value is Guid || value is IPEndPoint || value is decimal) - return value.ToString(); - if(value is DateTime) - return ((DateTime)value).Ticks.ToString(); - return null; - } - - private bool TryWriteNullableTypeValue(Type type, object value) - { - if(!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(Nullable<>)) - return false; - MethodInfo getMethodHasValue = type.GetProperty("HasValue").GetGetMethod(); - var hasValue = (bool)getMethodHasValue.Invoke(value, new object[0]); - if(!hasValue) - WriteNull(); - else - { - MethodInfo getMethodValue = type.GetProperty("Value").GetGetMethod(); - object nullableValue = getMethodValue.Invoke(value, new object[0]); - DoWrite(type.GetGenericArguments()[0], nullableValue); - } - return true; - } - - private bool TryWriteNullValue(object value) - { - if(value != null) - return false; - WriteNull(); - return true; - } - - private void WriteNull() - { - writer.WriteAttributeString("type", "null"); - } - - private readonly XmlWriter writer; - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Text; +using System.Xml; + +namespace GroBuf.Tests.TestTools +{ + public static class ObjectSerializer + { + public static string ObjectToString(this T instance) + { + Type type = typeof(T); + if(type.IsInterface) + type = instance.GetType(); + var builder = new StringBuilder(); + using(XmlWriter writer = XmlWriter.Create(builder, new XmlWriterSettings {Indent = true, OmitXmlDeclaration = true})) + new ObjectWriter(writer).Write(type, instance, "root"); + return builder.ToString(); + } + + private class ObjectWriter + { + public ObjectWriter(XmlWriter writer) + { + this.writer = writer; + } + + public void Write(Type type, object value, string name) + { + writer.WriteStartElement(name); + DoWrite(type, value); + writer.WriteEndElement(); + } + + private void DoWrite(Type type, object value) + { + if(TryWriteNullValue(value)) return; + if(TryWriteNullableTypeValue(type, value)) return; + if(TryWriteSimpleTypeValue(type, value)) return; + if(TryWriteArrayTypeValue(type, value)) return; + WriteComplexTypeValue(type, value); + } + + private void WriteComplexTypeValue(Type type, object value) + { + foreach(var fieldInfo in GetFields(type)) + Write(fieldInfo.FieldType, fieldInfo.GetValue(value), FieldNameToTagName(fieldInfo.Name)); + } + + private static IEnumerable GetFields(Type type) + { + var result = new List(); + while(type != null) + { + FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetField | BindingFlags.Instance); + result.AddRange(fields.Where(fieldInfo => !fieldInfo.IsLiteral && !fieldInfo.FieldType.IsInterface)); + type = type.BaseType; + } + return result; + } + + private static string FieldNameToTagName(string name) + { + if(name.EndsWith(">k__BackingField")) + return name.Substring(1, name.IndexOf('>') - 1); + return name; + } + + private bool TryWriteArrayTypeValue(Type type, object value) + { + if(!type.IsArray) + return false; + writer.WriteAttributeString("type", "array"); + var array = (Array)value; + if(array.Rank > 1) + throw new NotSupportedException("array with rank > 1"); + Type elementType = type.GetElementType(); + for(int i = 0; i < array.Length; ++i) + Write(elementType, array.GetValue(i), "item"); + return true; + } + + private bool TryWriteSimpleTypeValue(Type type, object value) + { + string result = FindSimpleValue(type, value); + if(result == null) + return false; + writer.WriteValue(result); + return true; + } + + private static string FindSimpleValue(Type type, object value) + { + if(type == typeof(char) && (char)value == (char)0) + return "0x0000"; + if(type.IsEnum || type.IsPrimitive || value is string || value is Guid || value is IPEndPoint || value is decimal) + return value.ToString(); + if(value is DateTime) + return ((DateTime)value).Ticks.ToString(); + return null; + } + + private bool TryWriteNullableTypeValue(Type type, object value) + { + if(!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(Nullable<>)) + return false; + MethodInfo getMethodHasValue = type.GetProperty("HasValue").GetGetMethod(); + var hasValue = (bool)getMethodHasValue.Invoke(value, new object[0]); + if(!hasValue) + WriteNull(); + else + { + MethodInfo getMethodValue = type.GetProperty("Value").GetGetMethod(); + object nullableValue = getMethodValue.Invoke(value, new object[0]); + DoWrite(type.GetGenericArguments()[0], nullableValue); + } + return true; + } + + private bool TryWriteNullValue(object value) + { + if(value != null) + return false; + WriteNull(); + return true; + } + + private void WriteNull() + { + writer.WriteAttributeString("type", "null"); + } + + private readonly XmlWriter writer; + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestTools/TestHelpers.cs b/GroBuf.Tests/TestTools/TestHelpers.cs similarity index 97% rename from GroBuf/Tests/TestTools/TestHelpers.cs rename to GroBuf.Tests/TestTools/TestHelpers.cs index 803485f..fd46b4d 100644 --- a/GroBuf/Tests/TestTools/TestHelpers.cs +++ b/GroBuf.Tests/TestTools/TestHelpers.cs @@ -1,137 +1,137 @@ -using System; -using System.Reflection; - -namespace GroBuf.Tests.TestTools -{ - public static class TestHelpers - { - public static void Extend(T obj) - { - extender.Extend(typeof(T), obj); - } - - public static T GenerateRandomTrash(Random random, int fillRate, int stringsLength, int arraysSize) where T : new() - { - var result = new T(); - FillWithRandomTrash(result, random, fillRate, stringsLength, arraysSize); - return result; - } - - private static string RandomString(Random random, int length, char first, char last) - { - var arr = new char[length]; - for(int i = 0; i < length; ++i) - arr[i] = (char)random.Next(first, last + 1); - return new string(arr); - } - - private static bool CanBeNull(Type type) - { - return type.IsClass || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); - } - - public static void FillWithRandomTrash(object obj, Random random, int fillRate, int stringsLength, int arraysSize) - { - Type type = obj.GetType(); - PropertyInfo[] properties = typePropertiesCache.Get(type); - var isNull = new bool[properties.Length]; - for(int i = 0; i < isNull.Length; ++i) - isNull[i] = CanBeNull(properties[i].PropertyType) && random.Next(101) > fillRate; - for(int index = 0; index < properties.Length; index++) - { - if(isNull[index]) continue; - PropertyInfo property = properties[index]; - Type propertyType = property.PropertyType; - MethodInfo setter = property.GetSetMethod(); - if(!propertyType.IsArray) - { - if(IsALeaf(propertyType)) - setter.Invoke(obj, new[] {GetRandomValue(propertyType, random, stringsLength)}); - else - { - ConstructorInfo constructorInfo = typeConstructorCache.Get(propertyType); - object child = constructorInfo.Invoke(new object[0]); - setter.Invoke(obj, new[] {child}); - FillWithRandomTrash(child, random, fillRate, stringsLength, arraysSize); - } - } - else - { - Type elementType = propertyType.GetElementType(); - int length = random.Next(arraysSize, arraysSize * 2); - Array array = Array.CreateInstance(elementType, length); - setter.Invoke(obj, new[] {array}); - if(IsALeaf(elementType)) - { - for(int i = 0; i < length; ++i) - array.SetValue(GetRandomValue(elementType, random, stringsLength), i); - } - else - { - ConstructorInfo constructorInfo = typeConstructorCache.Get(elementType); - for(int i = 0; i < length; ++i) - array.SetValue(constructorInfo.Invoke(new object[0]), i); - for(int i = 0; i < length; ++i) - FillWithRandomTrash(array.GetValue(i), random, fillRate, stringsLength, arraysSize); - } - } - } - } - - private static object GetRandomValue(Type type, Random random, int stringsLength) - { - if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) - return GetRandomValue(type.GetGenericArguments()[0], random, stringsLength); - if(type == typeof(Guid)) - return Guid.NewGuid(); - switch(Type.GetTypeCode(type)) - { - case TypeCode.Boolean: - return random.Next(2) == 0; - case TypeCode.Byte: - return (byte)(random.Next(256)); - case TypeCode.SByte: - return (sbyte)(random.Next(256) - 128); - case TypeCode.UInt16: - return (ushort)(random.Next(65536)); - case TypeCode.Int16: - return (short)(random.Next(65536) - 32768); - case TypeCode.Char: - return (char)random.Next('a', 'z' + 1); - case TypeCode.UInt32: - return (uint)(random.Next(65536)) | (((uint)(random.Next(65536))) << 16); - case TypeCode.Int32: - return (int)(((uint)(random.Next(65536)) | (((uint)(random.Next(65536))) << 16)) - (1U << 31)); - case TypeCode.UInt64: - return RandomUInt64(random); - case TypeCode.Int64: - return (long)(RandomUInt64(random) - (1UL << 63)); - case TypeCode.DateTime: - return new DateTime(DateTime.MinValue.Ticks + (long)(RandomUInt64(random) % ((ulong)(DateTime.MaxValue.Ticks - DateTime.MinValue.Ticks + 1)))); - case TypeCode.Single: - return (float)random.NextDouble(); - case TypeCode.Double: - return random.NextDouble(); - case TypeCode.String: - return RandomString(random, random.Next(stringsLength, stringsLength * 3), 'a', 'z'); - default: - throw new NotSupportedException(); - } - } - - private static ulong RandomUInt64(Random random) - { - return (ulong)(random.Next(65536)) | (((ulong)(random.Next(65536))) << 16) | (((ulong)(random.Next(65536))) << 32) | (((ulong)(random.Next(65536))) << 48); - } - - private static bool IsALeaf(Type type) - { - return type.IsPrimitive || type == typeof(string) || type == typeof(Guid) || type == typeof(DateTime) || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && IsALeaf(type.GetGenericArguments()[0])); - } - - private static readonly ExtenderImpl extender = new ExtenderImpl(); - - private static readonly ConcurrentCache typePropertiesCache = new ConcurrentCache(type => type.GetProperties(BindingFlags.Instance | BindingFlags.Public)); - private static readonly ConcurrentCache typeConstructorCache = new ConcurrentCache(type => type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null)); - } +using System; +using System.Reflection; + +namespace GroBuf.Tests.TestTools +{ + public static class TestHelpers + { + public static void Extend(T obj) + { + extender.Extend(typeof(T), obj); + } + + public static T GenerateRandomTrash(Random random, int fillRate, int stringsLength, int arraysSize) where T : new() + { + var result = new T(); + FillWithRandomTrash(result, random, fillRate, stringsLength, arraysSize); + return result; + } + + private static string RandomString(Random random, int length, char first, char last) + { + var arr = new char[length]; + for(int i = 0; i < length; ++i) + arr[i] = (char)random.Next(first, last + 1); + return new string(arr); + } + + private static bool CanBeNull(Type type) + { + return type.IsClass || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); + } + + public static void FillWithRandomTrash(object obj, Random random, int fillRate, int stringsLength, int arraysSize) + { + Type type = obj.GetType(); + PropertyInfo[] properties = typePropertiesCache.Get(type); + var isNull = new bool[properties.Length]; + for(int i = 0; i < isNull.Length; ++i) + isNull[i] = CanBeNull(properties[i].PropertyType) && random.Next(101) > fillRate; + for(int index = 0; index < properties.Length; index++) + { + if(isNull[index]) continue; + PropertyInfo property = properties[index]; + Type propertyType = property.PropertyType; + MethodInfo setter = property.GetSetMethod(); + if(!propertyType.IsArray) + { + if(IsALeaf(propertyType)) + setter.Invoke(obj, new[] {GetRandomValue(propertyType, random, stringsLength)}); + else + { + ConstructorInfo constructorInfo = typeConstructorCache.Get(propertyType); + object child = constructorInfo.Invoke(new object[0]); + setter.Invoke(obj, new[] {child}); + FillWithRandomTrash(child, random, fillRate, stringsLength, arraysSize); + } + } + else + { + Type elementType = propertyType.GetElementType(); + int length = random.Next(arraysSize, arraysSize * 2); + Array array = Array.CreateInstance(elementType, length); + setter.Invoke(obj, new[] {array}); + if(IsALeaf(elementType)) + { + for(int i = 0; i < length; ++i) + array.SetValue(GetRandomValue(elementType, random, stringsLength), i); + } + else + { + ConstructorInfo constructorInfo = typeConstructorCache.Get(elementType); + for(int i = 0; i < length; ++i) + array.SetValue(constructorInfo.Invoke(new object[0]), i); + for(int i = 0; i < length; ++i) + FillWithRandomTrash(array.GetValue(i), random, fillRate, stringsLength, arraysSize); + } + } + } + } + + private static object GetRandomValue(Type type, Random random, int stringsLength) + { + if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + return GetRandomValue(type.GetGenericArguments()[0], random, stringsLength); + if(type == typeof(Guid)) + return Guid.NewGuid(); + switch(Type.GetTypeCode(type)) + { + case TypeCode.Boolean: + return random.Next(2) == 0; + case TypeCode.Byte: + return (byte)(random.Next(256)); + case TypeCode.SByte: + return (sbyte)(random.Next(256) - 128); + case TypeCode.UInt16: + return (ushort)(random.Next(65536)); + case TypeCode.Int16: + return (short)(random.Next(65536) - 32768); + case TypeCode.Char: + return (char)random.Next('a', 'z' + 1); + case TypeCode.UInt32: + return (uint)(random.Next(65536)) | (((uint)(random.Next(65536))) << 16); + case TypeCode.Int32: + return (int)(((uint)(random.Next(65536)) | (((uint)(random.Next(65536))) << 16)) - (1U << 31)); + case TypeCode.UInt64: + return RandomUInt64(random); + case TypeCode.Int64: + return (long)(RandomUInt64(random) - (1UL << 63)); + case TypeCode.DateTime: + return new DateTime(DateTime.MinValue.Ticks + (long)(RandomUInt64(random) % ((ulong)(DateTime.MaxValue.Ticks - DateTime.MinValue.Ticks + 1)))); + case TypeCode.Single: + return (float)random.NextDouble(); + case TypeCode.Double: + return random.NextDouble(); + case TypeCode.String: + return RandomString(random, random.Next(stringsLength, stringsLength * 3), 'a', 'z'); + default: + throw new NotSupportedException(); + } + } + + private static ulong RandomUInt64(Random random) + { + return (ulong)(random.Next(65536)) | (((ulong)(random.Next(65536))) << 16) | (((ulong)(random.Next(65536))) << 32) | (((ulong)(random.Next(65536))) << 48); + } + + private static bool IsALeaf(Type type) + { + return type.IsPrimitive || type == typeof(string) || type == typeof(Guid) || type == typeof(DateTime) || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && IsALeaf(type.GetGenericArguments()[0])); + } + + private static readonly ExtenderImpl extender = new ExtenderImpl(); + + private static readonly ConcurrentCache typePropertiesCache = new ConcurrentCache(type => type.GetProperties(BindingFlags.Instance | BindingFlags.Public)); + private static readonly ConcurrentCache typeConstructorCache = new ConcurrentCache(type => type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null)); + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestTools/XmlHelpers.cs b/GroBuf.Tests/TestTools/XmlHelpers.cs similarity index 97% rename from GroBuf/Tests/TestTools/XmlHelpers.cs rename to GroBuf.Tests/TestTools/XmlHelpers.cs index c02b091..7a41294 100644 --- a/GroBuf/Tests/TestTools/XmlHelpers.cs +++ b/GroBuf.Tests/TestTools/XmlHelpers.cs @@ -1,80 +1,80 @@ -using System; -using System.Linq; -using System.Text; -using System.Xml; - -namespace GroBuf.Tests.TestTools -{ - public static class XmlHelpers - { - public static XmlNode GoToChild(this XmlNode node, string name) - { - var xmlNode = TryGoToChild(node, name); - if(xmlNode != null) return xmlNode; - throw new FormatException(string.Format(" '{0}' '{1}'", node.Name, name)); - } - - public static XmlNode TryGoToChild(this XmlNode node, string name) - { - for(int i = 0; i < node.ChildNodes.Count; i++) - { - var nodeName = node.ChildNodes[i].Name.Split(':').Last(); - if(string.Compare(nodeName, name, StringComparison.OrdinalIgnoreCase) == 0) - return node.ChildNodes[i]; - } - return null; - } - - public static T TryGetChildNode(this XmlNode parent, string localName) where T : XmlNode - { - return TryGetChildNode(parent, localName, null); - } - - public static T TryGetChildNode(this XmlNode parent, string localName, string namespaceUri) where T : XmlNode - { - foreach(XmlNode node in parent.ChildNodes) - { - if(localName.Equals(node.LocalName, StringComparison.OrdinalIgnoreCase) - && typeof(T).IsAssignableFrom(node.GetType()) - && (namespaceUri == null || node.NamespaceURI == namespaceUri)) - return (T)node; - } - return null; - } - - public static string FormattedOuterXml(this XmlNode node) - { - var result = new StringBuilder(); - XmlWriter writer = XmlWriter.Create(result, new XmlWriterSettings - { - Indent = true, - OmitXmlDeclaration = !node.HasXmlDeclaration() - }); - node.WriteTo(writer); - writer.Flush(); - return result.ToString(); - } - - public static string ReformatXml(this string xml) - { - return FormattedOuterXml(CreateXml(xml)); - } - - public static XmlDocument CreateXml(string xml) - { - return CreateXml(x => x.LoadXml(xml)); - } - - private static bool HasXmlDeclaration(this XmlNode node) - { - return node.TryGetChildNode("xml") != null; - } - - private static XmlDocument CreateXml(Action loadAction) - { - var result = new XmlDocument(); - loadAction(result); - return result; - } - } +using System; +using System.Linq; +using System.Text; +using System.Xml; + +namespace GroBuf.Tests.TestTools +{ + public static class XmlHelpers + { + public static XmlNode GoToChild(this XmlNode node, string name) + { + var xmlNode = TryGoToChild(node, name); + if(xmlNode != null) return xmlNode; + throw new FormatException(string.Format(" '{0}' '{1}'", node.Name, name)); + } + + public static XmlNode TryGoToChild(this XmlNode node, string name) + { + for(int i = 0; i < node.ChildNodes.Count; i++) + { + var nodeName = node.ChildNodes[i].Name.Split(':').Last(); + if(string.Compare(nodeName, name, StringComparison.OrdinalIgnoreCase) == 0) + return node.ChildNodes[i]; + } + return null; + } + + public static T TryGetChildNode(this XmlNode parent, string localName) where T : XmlNode + { + return TryGetChildNode(parent, localName, null); + } + + public static T TryGetChildNode(this XmlNode parent, string localName, string namespaceUri) where T : XmlNode + { + foreach(XmlNode node in parent.ChildNodes) + { + if(localName.Equals(node.LocalName, StringComparison.OrdinalIgnoreCase) + && typeof(T).IsAssignableFrom(node.GetType()) + && (namespaceUri == null || node.NamespaceURI == namespaceUri)) + return (T)node; + } + return null; + } + + public static string FormattedOuterXml(this XmlNode node) + { + var result = new StringBuilder(); + XmlWriter writer = XmlWriter.Create(result, new XmlWriterSettings + { + Indent = true, + OmitXmlDeclaration = !node.HasXmlDeclaration() + }); + node.WriteTo(writer); + writer.Flush(); + return result.ToString(); + } + + public static string ReformatXml(this string xml) + { + return FormattedOuterXml(CreateXml(xml)); + } + + public static XmlDocument CreateXml(string xml) + { + return CreateXml(x => x.LoadXml(xml)); + } + + private static bool HasXmlDeclaration(this XmlNode node) + { + return node.TryGetChildNode("xml") != null; + } + + private static XmlDocument CreateXml(Action loadAction) + { + var result = new XmlDocument(); + loadAction(result); + return result; + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestTuple.cs b/GroBuf.Tests/TestTuple.cs similarity index 100% rename from GroBuf/Tests/TestTuple.cs rename to GroBuf.Tests/TestTuple.cs diff --git a/GroBuf/Tests/TestUnknownTypeCode.cs b/GroBuf.Tests/TestUnknownTypeCode.cs similarity index 95% rename from GroBuf/Tests/TestUnknownTypeCode.cs rename to GroBuf.Tests/TestUnknownTypeCode.cs index 4d716e4..0a401d4 100644 --- a/GroBuf/Tests/TestUnknownTypeCode.cs +++ b/GroBuf.Tests/TestUnknownTypeCode.cs @@ -1,24 +1,24 @@ -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestUnknownTypeCode - { - private Serializer serializer; - - [SetUp] - public void SetUp() - { - serializer = new Serializer(new SerializeInterfaceTest.AllPropertiesExtractor()); - } - - [Test] - public void Test() - { - var data = serializer.Serialize(0); - data[0] = 127; - Assert.Throws(() => serializer.Deserialize(data)); - } - } +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestUnknownTypeCode + { + private Serializer serializer; + + [SetUp] + public void SetUp() + { + serializer = new Serializer(new SerializeInterfaceTest.AllPropertiesExtractor()); + } + + [Test] + public void Test() + { + var data = serializer.Serialize(0); + data[0] = 127; + Assert.Throws(() => serializer.Deserialize(data)); + } + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestWithDerivedTypes.cs b/GroBuf.Tests/TestWithDerivedTypes.cs similarity index 96% rename from GroBuf/Tests/TestWithDerivedTypes.cs rename to GroBuf.Tests/TestWithDerivedTypes.cs index 2de66a2..d77c4c3 100644 --- a/GroBuf/Tests/TestWithDerivedTypes.cs +++ b/GroBuf.Tests/TestWithDerivedTypes.cs @@ -1,57 +1,57 @@ -using System; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestWithDerivedTypes - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor()); - } - - [Test] - public void Test1() - { - var o = new Derived {Z = "zzz", S = "qxx"}; - var e = Assert.Throws(() => serializer.Serialize(o)); - Assert.AreEqual("Hash code collision: members 'Base.V' and 'Derived.V' have the same hash code = 1558541029501997959", e.Message); - } - - [Test] - public void Test2() - { - var o = new A {B = new Derived {Z = "zzz", S = "qxx"}}; - var data = serializer.Serialize(o); - var oo = serializer.Deserialize(data); - Assert.AreEqual("qxx", oo.B.S); - Assert.AreEqual("DerivedV", oo.B.VF); - } - - public class A - { - public Base B { get; set; } - } - - public class Base - { - public string S { get; set; } - public virtual string V { get { return "BaseV"; } set { VF = value; } } - public string VF; - } - - public class Derived : Base - { - public string Z { get; set; } - public override string V { get { return "DerivedV"; } set { VFF = value; } } - public string VFF; - } - - private Serializer serializer; - } +using System; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestWithDerivedTypes + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor()); + } + + [Test] + public void Test1() + { + var o = new Derived {Z = "zzz", S = "qxx"}; + var e = Assert.Throws(() => serializer.Serialize(o)); + Assert.AreEqual("Hash code collision: members 'Base.V' and 'Derived.V' have the same hash code = 1558541029501997959", e.Message); + } + + [Test] + public void Test2() + { + var o = new A {B = new Derived {Z = "zzz", S = "qxx"}}; + var data = serializer.Serialize(o); + var oo = serializer.Deserialize(data); + Assert.AreEqual("qxx", oo.B.S); + Assert.AreEqual("DerivedV", oo.B.VF); + } + + public class A + { + public Base B { get; set; } + } + + public class Base + { + public string S { get; set; } + public virtual string V { get { return "BaseV"; } set { VF = value; } } + public string VF; + } + + public class Derived : Base + { + public string Z { get; set; } + public override string V { get { return "DerivedV"; } set { VFF = value; } } + public string VFF; + } + + private Serializer serializer; + } } \ No newline at end of file diff --git a/GroBuf/Tests/TestWriteEmptyObjects.cs b/GroBuf.Tests/TestWriteEmptyObjects.cs similarity index 96% rename from GroBuf/Tests/TestWriteEmptyObjects.cs rename to GroBuf.Tests/TestWriteEmptyObjects.cs index d2d20a7..bdd439e 100644 --- a/GroBuf/Tests/TestWriteEmptyObjects.cs +++ b/GroBuf.Tests/TestWriteEmptyObjects.cs @@ -1,142 +1,142 @@ -using System.Collections.Generic; - -using GroBuf.DataMembersExtracters; - -using NUnit.Framework; - -namespace GroBuf.Tests -{ - [TestFixture] - public class TestWriteEmptyObjects - { - [SetUp] - public void SetUp() - { - serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.WriteEmptyObjects); - } - - [Test] - public void TestEmptyArray() - { - var a = new A {Strings = new string[0]}; - var data = serializer.Serialize(a); - var aa = serializer.Deserialize(data); - Assert.IsNotNull(aa); - Assert.IsNotNull(aa.Strings); - Assert.AreEqual(0, aa.Strings.Length); - } - - [Test] - public void TestEmptyPrimitivesArray() - { - var a = new A {Ints = new int[0]}; - var data = serializer.Serialize(a); - var aa = serializer.Deserialize(data); - Assert.IsNotNull(aa); - Assert.IsNotNull(aa.Ints); - Assert.AreEqual(0, aa.Ints.Length); - } - - [Test] - public void TestEmptyList() - { - var a = new A {StringList = new List()}; - var data = serializer.Serialize(a); - var aa = serializer.Deserialize(data); - Assert.IsNotNull(aa); - Assert.IsNotNull(aa.StringList); - Assert.AreEqual(0, aa.StringList.Count); - } - - [Test] - public void TestEmptyPrimitivesList() - { - var a = new A {IntList = new List()}; - var data = serializer.Serialize(a); - var aa = serializer.Deserialize(data); - Assert.IsNotNull(aa); - Assert.IsNotNull(aa.IntList); - Assert.AreEqual(0, aa.IntList.Count); - } - - [Test] - public void TestEmptyHashSet() - { - var a = new A {StringHashSet = new HashSet()}; - var data = serializer.Serialize(a); - var aa = serializer.Deserialize(data); - Assert.IsNotNull(aa); - Assert.IsNotNull(aa.StringHashSet); - Assert.AreEqual(0, aa.StringHashSet.Count); - } - - [Test] - public void TestEmptyPrimitivesHashSet() - { - var a = new A { IntHashSet = new HashSet() }; - var data = serializer.Serialize(a); - var aa = serializer.Deserialize(data); - Assert.IsNotNull(aa); - Assert.IsNotNull(aa.IntHashSet); - Assert.AreEqual(0, aa.IntHashSet.Count); - } - - [Test] - public void TestEmptyDictionary() - { - var a = new A {Dict = new Dictionary()}; - var data = serializer.Serialize(a); - var aa = serializer.Deserialize(data); - Assert.IsNotNull(aa); - Assert.IsNotNull(aa.Dict); - Assert.AreEqual(0, aa.Dict.Count); - } - - [Test] - public void TestEmptyClass() - { - var b = new B {A = new A()}; - var data = serializer.Serialize(b); - var bb = serializer.Deserialize(data); - Assert.IsNotNull(bb); - Assert.IsNotNull(bb.A); - } - - [Test] - public void TestComplex() - { - var b = new B {A = new A {Strings = new string[0], Ints = new int[0]}, ArrayA = new[] {null, new A()}}; - var data = serializer.Serialize(b); - var bb = serializer.Deserialize(data); - Assert.IsNotNull(bb); - Assert.IsNotNull(bb.A); - Assert.IsNotNull(bb.A.Strings); - Assert.AreEqual(0, bb.A.Strings.Length); - Assert.IsNotNull(bb.A.Ints); - Assert.AreEqual(0, bb.A.Ints.Length); - Assert.IsNotNull(bb.ArrayA); - Assert.AreEqual(2, bb.ArrayA.Length); - Assert.IsNull(bb.ArrayA[0]); - Assert.IsNotNull(bb.ArrayA[1]); - } - - private Serializer serializer; - - private class A - { - public string[] Strings { get; set; } - public int[] Ints { get; set; } - public List StringList { get; set; } - public List IntList { get; set; } - public HashSet StringHashSet { get; set; } - public HashSet IntHashSet { get; set; } - public Dictionary Dict { get; set; } - } - - private class B - { - public A A { get; set; } - public A[] ArrayA { get; set; } - } - } +using System.Collections.Generic; + +using GroBuf.DataMembersExtracters; + +using NUnit.Framework; + +namespace GroBuf.Tests +{ + [TestFixture] + public class TestWriteEmptyObjects + { + [SetUp] + public void SetUp() + { + serializer = new Serializer(new PropertiesExtractor(), null, GroBufOptions.WriteEmptyObjects); + } + + [Test] + public void TestEmptyArray() + { + var a = new A {Strings = new string[0]}; + var data = serializer.Serialize(a); + var aa = serializer.Deserialize(data); + Assert.IsNotNull(aa); + Assert.IsNotNull(aa.Strings); + Assert.AreEqual(0, aa.Strings.Length); + } + + [Test] + public void TestEmptyPrimitivesArray() + { + var a = new A {Ints = new int[0]}; + var data = serializer.Serialize(a); + var aa = serializer.Deserialize(data); + Assert.IsNotNull(aa); + Assert.IsNotNull(aa.Ints); + Assert.AreEqual(0, aa.Ints.Length); + } + + [Test] + public void TestEmptyList() + { + var a = new A {StringList = new List()}; + var data = serializer.Serialize(a); + var aa = serializer.Deserialize(data); + Assert.IsNotNull(aa); + Assert.IsNotNull(aa.StringList); + Assert.AreEqual(0, aa.StringList.Count); + } + + [Test] + public void TestEmptyPrimitivesList() + { + var a = new A {IntList = new List()}; + var data = serializer.Serialize(a); + var aa = serializer.Deserialize(data); + Assert.IsNotNull(aa); + Assert.IsNotNull(aa.IntList); + Assert.AreEqual(0, aa.IntList.Count); + } + + [Test] + public void TestEmptyHashSet() + { + var a = new A {StringHashSet = new HashSet()}; + var data = serializer.Serialize(a); + var aa = serializer.Deserialize(data); + Assert.IsNotNull(aa); + Assert.IsNotNull(aa.StringHashSet); + Assert.AreEqual(0, aa.StringHashSet.Count); + } + + [Test] + public void TestEmptyPrimitivesHashSet() + { + var a = new A { IntHashSet = new HashSet() }; + var data = serializer.Serialize(a); + var aa = serializer.Deserialize(data); + Assert.IsNotNull(aa); + Assert.IsNotNull(aa.IntHashSet); + Assert.AreEqual(0, aa.IntHashSet.Count); + } + + [Test] + public void TestEmptyDictionary() + { + var a = new A {Dict = new Dictionary()}; + var data = serializer.Serialize(a); + var aa = serializer.Deserialize(data); + Assert.IsNotNull(aa); + Assert.IsNotNull(aa.Dict); + Assert.AreEqual(0, aa.Dict.Count); + } + + [Test] + public void TestEmptyClass() + { + var b = new B {A = new A()}; + var data = serializer.Serialize(b); + var bb = serializer.Deserialize(data); + Assert.IsNotNull(bb); + Assert.IsNotNull(bb.A); + } + + [Test] + public void TestComplex() + { + var b = new B {A = new A {Strings = new string[0], Ints = new int[0]}, ArrayA = new[] {null, new A()}}; + var data = serializer.Serialize(b); + var bb = serializer.Deserialize(data); + Assert.IsNotNull(bb); + Assert.IsNotNull(bb.A); + Assert.IsNotNull(bb.A.Strings); + Assert.AreEqual(0, bb.A.Strings.Length); + Assert.IsNotNull(bb.A.Ints); + Assert.AreEqual(0, bb.A.Ints.Length); + Assert.IsNotNull(bb.ArrayA); + Assert.AreEqual(2, bb.ArrayA.Length); + Assert.IsNull(bb.ArrayA[0]); + Assert.IsNotNull(bb.ArrayA[1]); + } + + private Serializer serializer; + + private class A + { + public string[] Strings { get; set; } + public int[] Ints { get; set; } + public List StringList { get; set; } + public List IntList { get; set; } + public HashSet StringHashSet { get; set; } + public HashSet IntHashSet { get; set; } + public Dictionary Dict { get; set; } + } + + private class B + { + public A A { get; set; } + public A[] ArrayA { get; set; } + } + } } \ No newline at end of file diff --git a/GroBuf.nuspec b/GroBuf.nuspec deleted file mode 100644 index be2fb7a..0000000 --- a/GroBuf.nuspec +++ /dev/null @@ -1,17 +0,0 @@ - - - - GroBuf - 1.2.0 - GroBuf - https://github.com/homuroll/GroBuf - false - Igor Chevdar - Fast binary serializer - Copyright 2011-2016 - - - - - - \ No newline at end of file diff --git a/GroBuf.sln b/GroBuf.sln new file mode 100644 index 0000000..aa3d9c2 --- /dev/null +++ b/GroBuf.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2010 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GroBuf", "GroBuf\GroBuf.csproj", "{FB981757-D4F2-4DD7-AB98-62BD8CA5F01D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GroBuf.Tests", "GroBuf.Tests\GroBuf.Tests.csproj", "{7AC4F6AF-43D0-497A-90A5-515BF9B1313B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FB981757-D4F2-4DD7-AB98-62BD8CA5F01D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB981757-D4F2-4DD7-AB98-62BD8CA5F01D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB981757-D4F2-4DD7-AB98-62BD8CA5F01D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB981757-D4F2-4DD7-AB98-62BD8CA5F01D}.Release|Any CPU.Build.0 = Release|Any CPU + {7AC4F6AF-43D0-497A-90A5-515BF9B1313B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AC4F6AF-43D0-497A-90A5-515BF9B1313B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AC4F6AF-43D0-497A-90A5-515BF9B1313B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AC4F6AF-43D0-497A-90A5-515BF9B1313B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {68B676D4-A7FF-4FF9-9EC8-0EC2788FB28A} + EndGlobalSection +EndGlobal diff --git a/GroBuf.sln.DotSettings b/GroBuf.sln.DotSettings new file mode 100644 index 0000000..52478a4 --- /dev/null +++ b/GroBuf.sln.DotSettings @@ -0,0 +1,7 @@ + + C:\projects\open-source\skbkontur\GroBuf\Common.DotSettings + ..\Common.DotSettings + True + True + 1 + LongRunning \ No newline at end of file diff --git a/GroBuf/GroBuf/CompiledDynamicMethod.cs b/GroBuf/CompiledDynamicMethod.cs similarity index 96% rename from GroBuf/GroBuf/CompiledDynamicMethod.cs rename to GroBuf/CompiledDynamicMethod.cs index 3e695bf..a7736cd 100644 --- a/GroBuf/GroBuf/CompiledDynamicMethod.cs +++ b/GroBuf/CompiledDynamicMethod.cs @@ -1,13 +1,13 @@ -using System; -using System.Reflection.Emit; - -namespace GroBuf -{ - internal class CompiledDynamicMethod - { - public DynamicMethod Method { get; set; } - public int Index { get; set; } - public IntPtr Pointer { get; set; } - public Delegate Delegate { get; set; } - } +using System; +using System.Reflection.Emit; + +namespace GroBuf +{ + internal class CompiledDynamicMethod + { + public DynamicMethod Method { get; set; } + public int Index { get; set; } + public IntPtr Pointer { get; set; } + public Delegate Delegate { get; set; } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/DataCorruptedException.cs b/GroBuf/DataCorruptedException.cs similarity index 94% rename from GroBuf/GroBuf/DataCorruptedException.cs rename to GroBuf/DataCorruptedException.cs index e50233f..e3fc72d 100644 --- a/GroBuf/GroBuf/DataCorruptedException.cs +++ b/GroBuf/DataCorruptedException.cs @@ -1,12 +1,12 @@ -using System; - -namespace GroBuf -{ - public class DataCorruptedException : Exception - { - public DataCorruptedException(string message) - : base(message) - { - } - } +using System; + +namespace GroBuf +{ + public class DataCorruptedException : Exception + { + public DataCorruptedException(string message) + : base(message) + { + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/DataLengthAttribute.cs b/GroBuf/DataLengthAttribute.cs similarity index 94% rename from GroBuf/GroBuf/DataLengthAttribute.cs rename to GroBuf/DataLengthAttribute.cs index faace95..0034432 100644 --- a/GroBuf/GroBuf/DataLengthAttribute.cs +++ b/GroBuf/DataLengthAttribute.cs @@ -1,14 +1,14 @@ -using System; - -namespace GroBuf -{ - internal class DataLengthAttribute : Attribute - { - public DataLengthAttribute(int length) - { - Length = length; - } - - public int Length { get; private set; } - } +using System; + +namespace GroBuf +{ + internal class DataLengthAttribute : Attribute + { + public DataLengthAttribute(int length) + { + Length = length; + } + + public int Length { get; private set; } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/DataMembersExtracters/AllFieldsExtractor.cs b/GroBuf/DataMembersExtracters/AllFieldsExtractor.cs similarity index 97% rename from GroBuf/GroBuf/DataMembersExtracters/AllFieldsExtractor.cs rename to GroBuf/DataMembersExtracters/AllFieldsExtractor.cs index 229f794..7e4f8e6 100644 --- a/GroBuf/GroBuf/DataMembersExtracters/AllFieldsExtractor.cs +++ b/GroBuf/DataMembersExtracters/AllFieldsExtractor.cs @@ -1,25 +1,25 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace GroBuf.DataMembersExtracters -{ - public class AllFieldsExtractor : IDataMembersExtractor - { - public IDataMember[] GetMembers(Type type) - { - var result = new List(); - GetMembers(type, result); - return result.ToArray(); - } - - private static void GetMembers(Type type, List members) - { - if(type == null || type == typeof(object)) - return; - members.AddRange(type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly).Select(DataMember.Create)); - GetMembers(type.BaseType, members); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace GroBuf.DataMembersExtracters +{ + public class AllFieldsExtractor : IDataMembersExtractor + { + public IDataMember[] GetMembers(Type type) + { + var result = new List(); + GetMembers(type, result); + return result.ToArray(); + } + + private static void GetMembers(Type type, List members) + { + if(type == null || type == typeof(object)) + return; + members.AddRange(type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly).Select(DataMember.Create)); + GetMembers(type.BaseType, members); + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/DataMembersExtracters/AllPropertiesExtractor.cs b/GroBuf/DataMembersExtracters/AllPropertiesExtractor.cs similarity index 97% rename from GroBuf/GroBuf/DataMembersExtracters/AllPropertiesExtractor.cs rename to GroBuf/DataMembersExtracters/AllPropertiesExtractor.cs index cf206d6..0a88aa2 100644 --- a/GroBuf/GroBuf/DataMembersExtracters/AllPropertiesExtractor.cs +++ b/GroBuf/DataMembersExtracters/AllPropertiesExtractor.cs @@ -1,26 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace GroBuf.DataMembersExtracters -{ - public class AllPropertiesExtractor : IDataMembersExtractor - { - public IDataMember[] GetMembers(Type type) - { - var result = new List(); - GetMembers(type, result); - return result.ToArray(); - } - - private static void GetMembers(Type type, List members) - { - if(type == null || type == typeof(object)) - return; - var properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); - members.AddRange(properties.Where(property => property.CanRead && property.GetGetMethod(true).GetParameters().Length == 0 && property.TryGetWritableMemberInfo() != null).Select(DataMember.Create)); - GetMembers(type.BaseType, members); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace GroBuf.DataMembersExtracters +{ + public class AllPropertiesExtractor : IDataMembersExtractor + { + public IDataMember[] GetMembers(Type type) + { + var result = new List(); + GetMembers(type, result); + return result.ToArray(); + } + + private static void GetMembers(Type type, List members) + { + if(type == null || type == typeof(object)) + return; + var properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); + members.AddRange(properties.Where(property => property.CanRead && property.GetGetMethod(true).GetParameters().Length == 0 && property.TryGetWritableMemberInfo() != null).Select(DataMember.Create)); + GetMembers(type.BaseType, members); + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/DataMembersExtracters/DataMember.cs b/GroBuf/DataMembersExtracters/DataMember.cs similarity index 97% rename from GroBuf/GroBuf/DataMembersExtracters/DataMember.cs rename to GroBuf/DataMembersExtracters/DataMember.cs index 50312b9..a44719d 100644 --- a/GroBuf/GroBuf/DataMembersExtracters/DataMember.cs +++ b/GroBuf/DataMembersExtracters/DataMember.cs @@ -1,64 +1,64 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Runtime.Serialization; - -namespace GroBuf.DataMembersExtracters -{ - public class DataMember : IDataMember - { - private DataMember(ulong? id, MemberInfo member) - { - Id = id; - Member = member; - } - - private DataMember(string name, MemberInfo member) - { - Name = name; - Member = member; - } - - public ulong? Id { get; private set; } - - public string Name { get; private set; } - - public MemberInfo Member { get; private set; } - - public override string ToString() - { - return string.Format("Id: {0}, Name: {1}, Member.Name: {2}", Id, Name, Member.Name); - } - - public static DataMember Create(MemberInfo member) - { - return TryCreateByGroboAttribute(member) ?? TryCreateByDataMemberAttribute(member) ?? CreateByName(member); - } - - public static DataMember CreateByName(MemberInfo member) - { - return new DataMember(member.Name, member); - } - - public static DataMember TryCreateByDataMemberAttribute(MemberInfo member) - { - var dataMemberAttribute = (DataMemberAttribute)member.GetCustomAttributes(typeof(DataMemberAttribute), false).SingleOrDefault(); - if(dataMemberAttribute == null) - return null; - var name = string.IsNullOrWhiteSpace(dataMemberAttribute.Name) ? member.Name : dataMemberAttribute.Name; - return new DataMember(name, member); - } - - private static DataMember TryCreateByGroboAttribute(MemberInfo member) - { - var groboAttribute = (GroboMemberAttribute)member.GetCustomAttributes(typeof(GroboMemberAttribute), false).SingleOrDefault(); - if(groboAttribute == null) - return null; - if(groboAttribute.Id.HasValue) - return new DataMember(groboAttribute.Id.Value, member); - if(!string.IsNullOrWhiteSpace(groboAttribute.Name)) - return new DataMember(groboAttribute.Name, member); - throw new InvalidOperationException("Empty grobo name of member '" + member.DeclaringType.Name + "." + member.Name + "'"); - } - } +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; + +namespace GroBuf.DataMembersExtracters +{ + public class DataMember : IDataMember + { + private DataMember(ulong? id, MemberInfo member) + { + Id = id; + Member = member; + } + + private DataMember(string name, MemberInfo member) + { + Name = name; + Member = member; + } + + public ulong? Id { get; private set; } + + public string Name { get; private set; } + + public MemberInfo Member { get; private set; } + + public override string ToString() + { + return string.Format("Id: {0}, Name: {1}, Member.Name: {2}", Id, Name, Member.Name); + } + + public static DataMember Create(MemberInfo member) + { + return TryCreateByGroboAttribute(member) ?? TryCreateByDataMemberAttribute(member) ?? CreateByName(member); + } + + public static DataMember CreateByName(MemberInfo member) + { + return new DataMember(member.Name, member); + } + + public static DataMember TryCreateByDataMemberAttribute(MemberInfo member) + { + var dataMemberAttribute = (DataMemberAttribute)member.GetCustomAttributes(typeof(DataMemberAttribute), false).SingleOrDefault(); + if(dataMemberAttribute == null) + return null; + var name = string.IsNullOrWhiteSpace(dataMemberAttribute.Name) ? member.Name : dataMemberAttribute.Name; + return new DataMember(name, member); + } + + private static DataMember TryCreateByGroboAttribute(MemberInfo member) + { + var groboAttribute = (GroboMemberAttribute)member.GetCustomAttributes(typeof(GroboMemberAttribute), false).SingleOrDefault(); + if(groboAttribute == null) + return null; + if(groboAttribute.Id.HasValue) + return new DataMember(groboAttribute.Id.Value, member); + if(!string.IsNullOrWhiteSpace(groboAttribute.Name)) + return new DataMember(groboAttribute.Name, member); + throw new InvalidOperationException("Empty grobo name of member '" + member.DeclaringType.Name + "." + member.Name + "'"); + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/DataMembersExtracters/DataMembersByAttributeExtractor.cs b/GroBuf/DataMembersExtracters/DataMembersByAttributeExtractor.cs similarity index 97% rename from GroBuf/GroBuf/DataMembersExtracters/DataMembersByAttributeExtractor.cs rename to GroBuf/DataMembersExtracters/DataMembersByAttributeExtractor.cs index 78872f7..3835656 100644 --- a/GroBuf/GroBuf/DataMembersExtracters/DataMembersByAttributeExtractor.cs +++ b/GroBuf/DataMembersExtracters/DataMembersByAttributeExtractor.cs @@ -1,27 +1,27 @@ -using System; -using System.Linq; -using System.Reflection; - -namespace GroBuf.DataMembersExtracters -{ - public class DataMembersByAttributeExtractor : IDataMembersExtractor - { - public DataMembersByAttributeExtractor(bool extractOnlyWithAttribute) - { - this.extractOnlyWithAttribute = extractOnlyWithAttribute; - } - - public IDataMember[] GetMembers(Type type) - { - return type.GetProperties(BindingFlags.Public | BindingFlags.Instance) - .Where(property => property.CanRead && property.GetGetMethod(true).GetParameters().Length == 0 && property.TryGetWritableMemberInfo().TryGetWritableMemberInfo() != null) - .Select(x => - { - var result = DataMember.TryCreateByDataMemberAttribute(x); - return extractOnlyWithAttribute ? result : (result ?? DataMember.CreateByName(x)); - }).Where(x => x != null).ToArray(); - } - - private readonly bool extractOnlyWithAttribute; - } +using System; +using System.Linq; +using System.Reflection; + +namespace GroBuf.DataMembersExtracters +{ + public class DataMembersByAttributeExtractor : IDataMembersExtractor + { + public DataMembersByAttributeExtractor(bool extractOnlyWithAttribute) + { + this.extractOnlyWithAttribute = extractOnlyWithAttribute; + } + + public IDataMember[] GetMembers(Type type) + { + return type.GetProperties(BindingFlags.Public | BindingFlags.Instance) + .Where(property => property.CanRead && property.GetGetMethod(true).GetParameters().Length == 0 && property.TryGetWritableMemberInfo().TryGetWritableMemberInfo() != null) + .Select(x => + { + var result = DataMember.TryCreateByDataMemberAttribute(x); + return extractOnlyWithAttribute ? result : (result ?? DataMember.CreateByName(x)); + }).Where(x => x != null).ToArray(); + } + + private readonly bool extractOnlyWithAttribute; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/DataMembersExtracters/FieldsExtractor.cs b/GroBuf/DataMembersExtracters/FieldsExtractor.cs similarity index 96% rename from GroBuf/GroBuf/DataMembersExtracters/FieldsExtractor.cs rename to GroBuf/DataMembersExtracters/FieldsExtractor.cs index 3d25114..5fb1a04 100644 --- a/GroBuf/GroBuf/DataMembersExtracters/FieldsExtractor.cs +++ b/GroBuf/DataMembersExtracters/FieldsExtractor.cs @@ -1,25 +1,25 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace GroBuf.DataMembersExtracters -{ - public class FieldsExtractor : IDataMembersExtractor - { - public IDataMember[] GetMembers(Type type) - { - var result = new List(); - GetMembers(type, result); - return result.ToArray(); - } - - private static void GetMembers(Type type, List members) - { - if (type == null || type == typeof(object)) - return; - members.AddRange(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly).Select(DataMember.Create)); - GetMembers(type.BaseType, members); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace GroBuf.DataMembersExtracters +{ + public class FieldsExtractor : IDataMembersExtractor + { + public IDataMember[] GetMembers(Type type) + { + var result = new List(); + GetMembers(type, result); + return result.ToArray(); + } + + private static void GetMembers(Type type, List members) + { + if (type == null || type == typeof(object)) + return; + members.AddRange(type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly).Select(DataMember.Create)); + GetMembers(type.BaseType, members); + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/DataMembersExtracters/GroboMemberAttribute.cs b/GroBuf/DataMembersExtracters/GroboMemberAttribute.cs similarity index 95% rename from GroBuf/GroBuf/DataMembersExtracters/GroboMemberAttribute.cs rename to GroBuf/DataMembersExtracters/GroboMemberAttribute.cs index c4d2aae..976a410 100644 --- a/GroBuf/GroBuf/DataMembersExtracters/GroboMemberAttribute.cs +++ b/GroBuf/DataMembersExtracters/GroboMemberAttribute.cs @@ -1,21 +1,21 @@ -using System; - -namespace GroBuf.DataMembersExtracters -{ - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] - public class GroboMemberAttribute: Attribute - { - public GroboMemberAttribute(string name) - { - Name = name; - } - - public GroboMemberAttribute(ulong id) - { - Id = id; - } - - public ulong? Id { get; private set; } - public string Name { get; private set; } - } +using System; + +namespace GroBuf.DataMembersExtracters +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class GroboMemberAttribute: Attribute + { + public GroboMemberAttribute(string name) + { + Name = name; + } + + public GroboMemberAttribute(ulong id) + { + Id = id; + } + + public ulong? Id { get; private set; } + public string Name { get; private set; } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/DataMembersExtracters/IDataMember.cs b/GroBuf/DataMembersExtracters/IDataMember.cs similarity index 95% rename from GroBuf/GroBuf/DataMembersExtracters/IDataMember.cs rename to GroBuf/DataMembersExtracters/IDataMember.cs index 5a2cf54..ec64b5d 100644 --- a/GroBuf/GroBuf/DataMembersExtracters/IDataMember.cs +++ b/GroBuf/DataMembersExtracters/IDataMember.cs @@ -1,11 +1,11 @@ -using System.Reflection; - -namespace GroBuf.DataMembersExtracters -{ - public interface IDataMember - { - ulong? Id { get; } - string Name { get; } - MemberInfo Member { get; } - } +using System.Reflection; + +namespace GroBuf.DataMembersExtracters +{ + public interface IDataMember + { + ulong? Id { get; } + string Name { get; } + MemberInfo Member { get; } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/DataMembersExtracters/IDataMembersExtractor.cs b/GroBuf/DataMembersExtracters/IDataMembersExtractor.cs similarity index 95% rename from GroBuf/GroBuf/DataMembersExtracters/IDataMembersExtractor.cs rename to GroBuf/DataMembersExtracters/IDataMembersExtractor.cs index f755ae6..9ffca30 100644 --- a/GroBuf/GroBuf/DataMembersExtracters/IDataMembersExtractor.cs +++ b/GroBuf/DataMembersExtracters/IDataMembersExtractor.cs @@ -1,9 +1,9 @@ -using System; - -namespace GroBuf.DataMembersExtracters -{ - public interface IDataMembersExtractor - { - IDataMember[] GetMembers(Type type); - } +using System; + +namespace GroBuf.DataMembersExtracters +{ + public interface IDataMembersExtractor + { + IDataMember[] GetMembers(Type type); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/DataMembersExtracters/PropertiesExtractor.cs b/GroBuf/DataMembersExtracters/PropertiesExtractor.cs similarity index 97% rename from GroBuf/GroBuf/DataMembersExtracters/PropertiesExtractor.cs rename to GroBuf/DataMembersExtracters/PropertiesExtractor.cs index d2296c7..0f69857 100644 --- a/GroBuf/GroBuf/DataMembersExtracters/PropertiesExtractor.cs +++ b/GroBuf/DataMembersExtracters/PropertiesExtractor.cs @@ -1,26 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace GroBuf.DataMembersExtracters -{ - public class PropertiesExtractor : IDataMembersExtractor - { - public IDataMember[] GetMembers(Type type) - { - var result = new List(); - GetMembers(type, result); - return result.ToArray(); - } - - private static void GetMembers(Type type, List members) - { - if(type == null || type == typeof(object)) - return; - var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); - members.AddRange(properties.Where(property => property.CanRead && property.GetGetMethod(true).GetParameters().Length == 0 && property.TryGetWritableMemberInfo() != null).Select(DataMember.Create)); - GetMembers(type.BaseType, members); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace GroBuf.DataMembersExtracters +{ + public class PropertiesExtractor : IDataMembersExtractor + { + public IDataMember[] GetMembers(Type type) + { + var result = new List(); + GetMembers(type, result); + return result.ToArray(); + } + + private static void GetMembers(Type type, List members) + { + if(type == null || type == typeof(object)) + return; + var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + members.AddRange(properties.Where(property => property.CanRead && property.GetGetMethod(true).GetParameters().Length == 0 && property.TryGetWritableMemberInfo() != null).Select(DataMember.Create)); + GetMembers(type.BaseType, members); + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/DebugViewBuilder.cs b/GroBuf/DebugViewBuilder.cs similarity index 97% rename from GroBuf/GroBuf/DebugViewBuilder.cs rename to GroBuf/DebugViewBuilder.cs index e4ccb56..b3a0c70 100644 --- a/GroBuf/GroBuf/DebugViewBuilder.cs +++ b/GroBuf/DebugViewBuilder.cs @@ -1,518 +1,518 @@ -using System; -using System.Reflection.Emit; -using System.Text; - -namespace GroBuf -{ - public class DebugViewBuilder - { - public static unsafe string DebugView(byte[] data) - { - if(data == null || data.Length == 0) - throw new ArgumentNullException("data"); - var result = new StringBuilder(); - var debugViewBuilder = new DebugViewBuilder(); - fixed(byte* ptr = &data[0]) - { - var index = 0; - while(index < data.Length) - { - debugViewBuilder.Print(ptr, ref index, data.Length, result); - result.AppendLine(); - } - } - return result.ToString(); - } - - private static string[] BuildMargins() - { - var result = new string[1024]; - result[0] = ""; - for(var i = 1; i < 1024; ++i) - result[i] = new string(' ', i); - return result; - } - - private unsafe void Print(byte* data, ref int index, int length, StringBuilder result) - { - if(index >= length) - throw new InvalidOperationException("Unexpected end of data"); - var typeCode = (GroBufTypeCode)data[index++]; - switch(typeCode) - { - case GroBufTypeCode.Empty: - result.Append(margins[margin]); - result.Append(""); - break; - case GroBufTypeCode.Object: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - margin += 2; - var start = index; - while(index < start + dataLength) - { - result.Append(margins[margin]); - result.Append(""); - result.Append(margins[margin]); - result.AppendLine(""); - margin += 2; - index += 8; - Print(data, ref index, length, result); - margin -= 2; - result.Append(margins[margin]); - result.AppendLine(""); - } - margin -= 2; - result.Append(margins[margin]); - result.Append(""); - } - break; - case GroBufTypeCode.Array: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - var arrayLength = *(int*)(data + index); - index += 4; - result.Append(margins[margin]); - result.Append(""); - margin += 2; - for(var i = 0; i < arrayLength; ++i) - { - result.Append(margins[margin]); - result.Append(""); - result.Append(margins[margin]); - result.AppendLine(""); - margin += 2; - Print(data, ref index, length, result); - margin -= 2; - result.Append(margins[margin]); - result.AppendLine(""); - } - margin -= 2; - result.Append(margins[margin]); - result.Append(""); - } - break; - case GroBufTypeCode.Dictionary: - { - if (index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if (index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - var dictLength = *(int*)(data + index); - index += 4; - result.Append(margins[margin]); - result.Append(""); - margin += 2; - for (var i = 0; i < dictLength; ++i) - { - result.Append(margins[margin]); - result.Append(""); - result.Append(margins[margin]); - result.AppendLine(""); - margin += 2; - Print(data, ref index, length, result); - margin -= 2; - result.Append(margins[margin]); - result.AppendLine(""); - result.Append(margins[margin]); - result.AppendLine(""); - margin += 2; - Print(data, ref index, length, result); - margin -= 2; - result.Append(margins[margin]); - result.AppendLine(""); - } - margin -= 2; - result.Append(margins[margin]); - result.Append(""); - } - break; - case GroBufTypeCode.Boolean: - if(index >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(" 0); - result.Append(">"); - ++index; - break; - case GroBufTypeCode.Int8: - if(index >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - ++index; - break; - case GroBufTypeCode.UInt8: - if(index >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - ++index; - break; - case GroBufTypeCode.Int16: - if(index + 1 >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += 2; - break; - case GroBufTypeCode.UInt16: - if(index + 1 >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += 2; - break; - case GroBufTypeCode.Int32: - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += 4; - break; - case GroBufTypeCode.UInt32: - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += 4; - break; - case GroBufTypeCode.Int64: - if(index + 7 >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += 8; - break; - case GroBufTypeCode.UInt64: - if(index + 7 >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += 8; - break; - case GroBufTypeCode.Single: - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += 4; - break; - case GroBufTypeCode.Double: - if(index + 7 >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += 8; - break; - case GroBufTypeCode.Decimal: - if(index + 15 >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += 16; - break; - case GroBufTypeCode.Guid: - if(index + 15 >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += 16; - break; - case GroBufTypeCode.Enum: - if(index + 7 >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += 8; - break; - case GroBufTypeCode.String: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - var arr = new char[dataLength / 2]; - if(dataLength > 0) - { - fixed(char* dest = &arr[0]) - memoryCopier((IntPtr)dest, (IntPtr)(data + index), dataLength); - } - result.Append(margins[margin]); - result.Append(""); - index += dataLength; - } - break; - case GroBufTypeCode.DateTimeOld: - throw new NotSupportedException("Old DateTime format is not supported"); - case GroBufTypeCode.DateTimeNew: - if(index + 7 >= length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += 8; - break; - case GroBufTypeCode.BooleanArray: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += dataLength; - } - break; - case GroBufTypeCode.Int8Array: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += dataLength; - } - break; - case GroBufTypeCode.UInt8Array: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += dataLength; - } - break; - case GroBufTypeCode.Int16Array: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += dataLength; - } - break; - case GroBufTypeCode.UInt16Array: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += dataLength; - } - break; - case GroBufTypeCode.Int32Array: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += dataLength; - } - break; - case GroBufTypeCode.UInt32Array: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += dataLength; - } - break; - case GroBufTypeCode.Int64Array: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += dataLength; - } - break; - case GroBufTypeCode.UInt64Array: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += dataLength; - } - break; - case GroBufTypeCode.SingleArray: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += dataLength; - } - break; - case GroBufTypeCode.DoubleArray: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += dataLength; - } - break; - case GroBufTypeCode.CustomData: - { - if(index + 3 >= length) - throw new InvalidOperationException("Unexpected end of data"); - var dataLength = *(int*)(data + index); - index += 4; - if(index + dataLength > length) - throw new InvalidOperationException("Unexpected end of data"); - result.Append(margins[margin]); - result.Append(""); - index += dataLength; - } - break; - default: - throw new NotSupportedException(string.Format("Type code '{0}' is not supported", typeCode)); - } - result.AppendLine(); - } - - private static Action BuildMemoryCopier() - { - var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] {typeof(IntPtr), typeof(IntPtr), typeof(int)}, typeof(string), true); - var il = method.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Ldarg_2); - il.Emit(OpCodes.Cpblk); // dest, source, number of bytes - il.Emit(OpCodes.Ret); - return (Action)method.CreateDelegate(typeof(Action)); - } - - private int margin; - - private static readonly string[] margins = BuildMargins(); - - private static readonly Action memoryCopier = BuildMemoryCopier(); - } +using System; +using System.Reflection.Emit; +using System.Text; + +namespace GroBuf +{ + public class DebugViewBuilder + { + public static unsafe string DebugView(byte[] data) + { + if(data == null || data.Length == 0) + throw new ArgumentNullException("data"); + var result = new StringBuilder(); + var debugViewBuilder = new DebugViewBuilder(); + fixed(byte* ptr = &data[0]) + { + var index = 0; + while(index < data.Length) + { + debugViewBuilder.Print(ptr, ref index, data.Length, result); + result.AppendLine(); + } + } + return result.ToString(); + } + + private static string[] BuildMargins() + { + var result = new string[1024]; + result[0] = ""; + for(var i = 1; i < 1024; ++i) + result[i] = new string(' ', i); + return result; + } + + private unsafe void Print(byte* data, ref int index, int length, StringBuilder result) + { + if(index >= length) + throw new InvalidOperationException("Unexpected end of data"); + var typeCode = (GroBufTypeCode)data[index++]; + switch(typeCode) + { + case GroBufTypeCode.Empty: + result.Append(margins[margin]); + result.Append(""); + break; + case GroBufTypeCode.Object: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + margin += 2; + var start = index; + while(index < start + dataLength) + { + result.Append(margins[margin]); + result.Append(""); + result.Append(margins[margin]); + result.AppendLine(""); + margin += 2; + index += 8; + Print(data, ref index, length, result); + margin -= 2; + result.Append(margins[margin]); + result.AppendLine(""); + } + margin -= 2; + result.Append(margins[margin]); + result.Append(""); + } + break; + case GroBufTypeCode.Array: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + var arrayLength = *(int*)(data + index); + index += 4; + result.Append(margins[margin]); + result.Append(""); + margin += 2; + for(var i = 0; i < arrayLength; ++i) + { + result.Append(margins[margin]); + result.Append(""); + result.Append(margins[margin]); + result.AppendLine(""); + margin += 2; + Print(data, ref index, length, result); + margin -= 2; + result.Append(margins[margin]); + result.AppendLine(""); + } + margin -= 2; + result.Append(margins[margin]); + result.Append(""); + } + break; + case GroBufTypeCode.Dictionary: + { + if (index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if (index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + var dictLength = *(int*)(data + index); + index += 4; + result.Append(margins[margin]); + result.Append(""); + margin += 2; + for (var i = 0; i < dictLength; ++i) + { + result.Append(margins[margin]); + result.Append(""); + result.Append(margins[margin]); + result.AppendLine(""); + margin += 2; + Print(data, ref index, length, result); + margin -= 2; + result.Append(margins[margin]); + result.AppendLine(""); + result.Append(margins[margin]); + result.AppendLine(""); + margin += 2; + Print(data, ref index, length, result); + margin -= 2; + result.Append(margins[margin]); + result.AppendLine(""); + } + margin -= 2; + result.Append(margins[margin]); + result.Append(""); + } + break; + case GroBufTypeCode.Boolean: + if(index >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(" 0); + result.Append(">"); + ++index; + break; + case GroBufTypeCode.Int8: + if(index >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + ++index; + break; + case GroBufTypeCode.UInt8: + if(index >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + ++index; + break; + case GroBufTypeCode.Int16: + if(index + 1 >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += 2; + break; + case GroBufTypeCode.UInt16: + if(index + 1 >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += 2; + break; + case GroBufTypeCode.Int32: + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += 4; + break; + case GroBufTypeCode.UInt32: + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += 4; + break; + case GroBufTypeCode.Int64: + if(index + 7 >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += 8; + break; + case GroBufTypeCode.UInt64: + if(index + 7 >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += 8; + break; + case GroBufTypeCode.Single: + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += 4; + break; + case GroBufTypeCode.Double: + if(index + 7 >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += 8; + break; + case GroBufTypeCode.Decimal: + if(index + 15 >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += 16; + break; + case GroBufTypeCode.Guid: + if(index + 15 >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += 16; + break; + case GroBufTypeCode.Enum: + if(index + 7 >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += 8; + break; + case GroBufTypeCode.String: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + var arr = new char[dataLength / 2]; + if(dataLength > 0) + { + fixed(char* dest = &arr[0]) + memoryCopier((IntPtr)dest, (IntPtr)(data + index), dataLength); + } + result.Append(margins[margin]); + result.Append(""); + index += dataLength; + } + break; + case GroBufTypeCode.DateTimeOld: + throw new NotSupportedException("Old DateTime format is not supported"); + case GroBufTypeCode.DateTimeNew: + if(index + 7 >= length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += 8; + break; + case GroBufTypeCode.BooleanArray: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += dataLength; + } + break; + case GroBufTypeCode.Int8Array: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += dataLength; + } + break; + case GroBufTypeCode.UInt8Array: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += dataLength; + } + break; + case GroBufTypeCode.Int16Array: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += dataLength; + } + break; + case GroBufTypeCode.UInt16Array: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += dataLength; + } + break; + case GroBufTypeCode.Int32Array: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += dataLength; + } + break; + case GroBufTypeCode.UInt32Array: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += dataLength; + } + break; + case GroBufTypeCode.Int64Array: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += dataLength; + } + break; + case GroBufTypeCode.UInt64Array: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += dataLength; + } + break; + case GroBufTypeCode.SingleArray: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += dataLength; + } + break; + case GroBufTypeCode.DoubleArray: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += dataLength; + } + break; + case GroBufTypeCode.CustomData: + { + if(index + 3 >= length) + throw new InvalidOperationException("Unexpected end of data"); + var dataLength = *(int*)(data + index); + index += 4; + if(index + dataLength > length) + throw new InvalidOperationException("Unexpected end of data"); + result.Append(margins[margin]); + result.Append(""); + index += dataLength; + } + break; + default: + throw new NotSupportedException(string.Format("Type code '{0}' is not supported", typeCode)); + } + result.AppendLine(); + } + + private static Action BuildMemoryCopier() + { + var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] {typeof(IntPtr), typeof(IntPtr), typeof(int)}, typeof(string), true); + var il = method.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Cpblk); // dest, source, number of bytes + il.Emit(OpCodes.Ret); + return (Action)method.CreateDelegate(typeof(Action)); + } + + private int margin; + + private static readonly string[] margins = BuildMargins(); + + private static readonly Action memoryCopier = BuildMemoryCopier(); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/DefaultGroBufCustomSerializerCollection.cs b/GroBuf/DefaultGroBufCustomSerializerCollection.cs similarity index 98% rename from GroBuf/GroBuf/DefaultGroBufCustomSerializerCollection.cs rename to GroBuf/DefaultGroBufCustomSerializerCollection.cs index b94385e..fa4206c 100644 --- a/GroBuf/GroBuf/DefaultGroBufCustomSerializerCollection.cs +++ b/GroBuf/DefaultGroBufCustomSerializerCollection.cs @@ -1,35 +1,35 @@ -using System; -using System.Linq; -using System.Reflection; - -namespace GroBuf -{ - public class DefaultGroBufCustomSerializerCollection : IGroBufCustomSerializerCollection - { - public IGroBufCustomSerializer Get(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer) - { - var attribute = declaredType.GetCustomAttributes(typeof(GroBufCustomSerializationAttribute), false).FirstOrDefault() as GroBufCustomSerializationAttribute; - if(attribute == null) return null; - Type customSerializerType = attribute.CustomSerializerType ?? declaredType; - MethodInfo customSizeCounter = GroBufHelpers.GetMethod(customSerializerType); - if(customSizeCounter == null) - throw new MissingMethodException("Missing grobuf custom size counter for type '" + customSerializerType + "'"); - MethodInfo writer = GroBufHelpers.GetMethod(customSerializerType); - if(writer == null) - throw new MissingMethodException("Missing grobuf custom writer for type '" + customSerializerType + "'"); - MethodInfo reader = GroBufHelpers.GetMethod(customSerializerType); - if(reader == null) - throw new MissingMethodException("Missing grobuf custom reader for type '" + customSerializerType + "'"); - var sizeCounterDelegate = (SizeCounterDelegate)customSizeCounter.Invoke( - null, - new object[] {(Func)(type => ((o, empty, context) => factory(type).CountSize(o, empty, context))), (SizeCounterDelegate)(baseSerializer.CountSize)}); - var writerDelegate = (WriterDelegate)writer.Invoke( - null, - new object[] {(Func)(type => ((object o, bool empty, IntPtr result, ref int index, WriterContext context) => factory(type).Write(o, empty, result, ref index, context))), (WriterDelegate)(baseSerializer.Write)}); - var readerDelegate = (ReaderDelegate)reader.Invoke( - null, - new object[] {(Func)(type => ((IntPtr data, ref int index, ref object result, ReaderContext context) => factory(type).Read(data, ref index, ref result, context))), (ReaderDelegate)(baseSerializer.Read)}); - return new GroBufCustomSerializerByAttribute(sizeCounterDelegate, writerDelegate, readerDelegate); - } - } +using System; +using System.Linq; +using System.Reflection; + +namespace GroBuf +{ + public class DefaultGroBufCustomSerializerCollection : IGroBufCustomSerializerCollection + { + public IGroBufCustomSerializer Get(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer) + { + var attribute = declaredType.GetCustomAttributes(typeof(GroBufCustomSerializationAttribute), false).FirstOrDefault() as GroBufCustomSerializationAttribute; + if(attribute == null) return null; + Type customSerializerType = attribute.CustomSerializerType ?? declaredType; + MethodInfo customSizeCounter = GroBufHelpers.GetMethod(customSerializerType); + if(customSizeCounter == null) + throw new MissingMethodException("Missing grobuf custom size counter for type '" + customSerializerType + "'"); + MethodInfo writer = GroBufHelpers.GetMethod(customSerializerType); + if(writer == null) + throw new MissingMethodException("Missing grobuf custom writer for type '" + customSerializerType + "'"); + MethodInfo reader = GroBufHelpers.GetMethod(customSerializerType); + if(reader == null) + throw new MissingMethodException("Missing grobuf custom reader for type '" + customSerializerType + "'"); + var sizeCounterDelegate = (SizeCounterDelegate)customSizeCounter.Invoke( + null, + new object[] {(Func)(type => ((o, empty, context) => factory(type).CountSize(o, empty, context))), (SizeCounterDelegate)(baseSerializer.CountSize)}); + var writerDelegate = (WriterDelegate)writer.Invoke( + null, + new object[] {(Func)(type => ((object o, bool empty, IntPtr result, ref int index, WriterContext context) => factory(type).Write(o, empty, result, ref index, context))), (WriterDelegate)(baseSerializer.Write)}); + var readerDelegate = (ReaderDelegate)reader.Invoke( + null, + new object[] {(Func)(type => ((IntPtr data, ref int index, ref object result, ReaderContext context) => factory(type).Read(data, ref index, ref result, context))), (ReaderDelegate)(baseSerializer.Read)}); + return new GroBufCustomSerializerByAttribute(sizeCounterDelegate, writerDelegate, readerDelegate); + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/EmptyGroBufCustomSerializerCollection.cs b/GroBuf/EmptyGroBufCustomSerializerCollection.cs similarity index 96% rename from GroBuf/GroBuf/EmptyGroBufCustomSerializerCollection.cs rename to GroBuf/EmptyGroBufCustomSerializerCollection.cs index eb4c1e2..3111ee0 100644 --- a/GroBuf/GroBuf/EmptyGroBufCustomSerializerCollection.cs +++ b/GroBuf/EmptyGroBufCustomSerializerCollection.cs @@ -1,12 +1,12 @@ -using System; - -namespace GroBuf -{ - public class EmptyGroBufCustomSerializerCollection : IGroBufCustomSerializerCollection - { - public IGroBufCustomSerializer Get(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer) - { - return null; - } - } +using System; + +namespace GroBuf +{ + public class EmptyGroBufCustomSerializerCollection : IGroBufCustomSerializerCollection + { + public IGroBufCustomSerializer Get(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer) + { + return null; + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/EnumHelpers.cs b/GroBuf/EnumHelpers.cs similarity index 97% rename from GroBuf/GroBuf/EnumHelpers.cs rename to GroBuf/EnumHelpers.cs index e82796e..a8beb5e 100644 --- a/GroBuf/GroBuf/EnumHelpers.cs +++ b/GroBuf/EnumHelpers.cs @@ -1,104 +1,104 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -using GroBuf.DataMembersExtracters; - -namespace GroBuf -{ - public static class EnumHelpers - { - public static void BuildHashCodesTable(Type type, out int[] values, out ulong[] hashCodes) - { - var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static); - var enumValues = fields.Select(field => ConvertToInt(Enum.Parse(type, field.Name), type.GetEnumUnderlyingType())).ToArray(); - var uniqueValues = new HashSet(enumValues).ToArray(); - var nameHashes = GroBufHelpers.CalcHashesAndCheck(fields.Select(DataMember.Create)); - var hashSet = new HashSet(); - for(var x = (uint)enumValues.Length;; ++x) - { - hashSet.Clear(); - var ok = true; - foreach(var value in uniqueValues) - { - var item = ((uint)value) % x; - if(hashSet.Contains(item)) - { - ok = false; - break; - } - hashSet.Add(item); - } - if(!ok) continue; - hashCodes = new ulong[x]; - values = new int[x]; - for(var i = 0; i < x; ++i) - values[i] = -1; - for(var i = 0; i < enumValues.Length; i++) - { - var value = enumValues[i]; - var index = ((uint)value) % x; - hashCodes[index] = nameHashes[i]; - values[index] = value; - } - break; - } - } - - public static void BuildValuesTable(Type type, out int[] values, out ulong[] hashCodes) - { - var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static); - var arr = fields.Select(field => ConvertToInt(Enum.Parse(type, field.Name), type.GetEnumUnderlyingType())).ToArray(); - var hashes = GroBufHelpers.CalcHashesAndCheck(fields.Select(DataMember.Create)); - var hashSet = new HashSet(); - for(var x = (uint)hashes.Length;; ++x) - { - hashSet.Clear(); - var ok = true; - foreach(var hash in hashes) - { - var item = (uint)(hash % x); - if(hashSet.Contains(item)) - { - ok = false; - break; - } - hashSet.Add(item); - } - if(!ok) continue; - hashCodes = new ulong[x]; - values = new int[x]; - for(var i = 0; i < hashes.Length; i++) - { - var hash = hashes[i]; - var index = (int)(hash % x); - hashCodes[index] = hash; - values[index] = (int)arr.GetValue(i); - } - return; - } - } - - private static int ConvertToInt(object enumValue, Type underlyingType) - { - switch(Type.GetTypeCode(underlyingType)) - { - case TypeCode.SByte: - return (sbyte)enumValue; - case TypeCode.Byte: - return (byte)enumValue; - case TypeCode.Int16: - return (short)enumValue; - case TypeCode.UInt16: - return (ushort)enumValue; - case TypeCode.Int32: - return (int)enumValue; - case TypeCode.UInt32: - return unchecked((int)(uint)enumValue); - default: - throw new NotSupportedException(string.Format("Enum with underlying type '{0}' is not supported", underlyingType)); - } - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +using GroBuf.DataMembersExtracters; + +namespace GroBuf +{ + public static class EnumHelpers + { + public static void BuildHashCodesTable(Type type, out int[] values, out ulong[] hashCodes) + { + var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static); + var enumValues = fields.Select(field => ConvertToInt(Enum.Parse(type, field.Name), type.GetEnumUnderlyingType())).ToArray(); + var uniqueValues = new HashSet(enumValues).ToArray(); + var nameHashes = GroBufHelpers.CalcHashesAndCheck(fields.Select(DataMember.Create)); + var hashSet = new HashSet(); + for(var x = (uint)enumValues.Length;; ++x) + { + hashSet.Clear(); + var ok = true; + foreach(var value in uniqueValues) + { + var item = ((uint)value) % x; + if(hashSet.Contains(item)) + { + ok = false; + break; + } + hashSet.Add(item); + } + if(!ok) continue; + hashCodes = new ulong[x]; + values = new int[x]; + for(var i = 0; i < x; ++i) + values[i] = -1; + for(var i = 0; i < enumValues.Length; i++) + { + var value = enumValues[i]; + var index = ((uint)value) % x; + hashCodes[index] = nameHashes[i]; + values[index] = value; + } + break; + } + } + + public static void BuildValuesTable(Type type, out int[] values, out ulong[] hashCodes) + { + var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static); + var arr = fields.Select(field => ConvertToInt(Enum.Parse(type, field.Name), type.GetEnumUnderlyingType())).ToArray(); + var hashes = GroBufHelpers.CalcHashesAndCheck(fields.Select(DataMember.Create)); + var hashSet = new HashSet(); + for(var x = (uint)hashes.Length;; ++x) + { + hashSet.Clear(); + var ok = true; + foreach(var hash in hashes) + { + var item = (uint)(hash % x); + if(hashSet.Contains(item)) + { + ok = false; + break; + } + hashSet.Add(item); + } + if(!ok) continue; + hashCodes = new ulong[x]; + values = new int[x]; + for(var i = 0; i < hashes.Length; i++) + { + var hash = hashes[i]; + var index = (int)(hash % x); + hashCodes[index] = hash; + values[index] = (int)arr.GetValue(i); + } + return; + } + } + + private static int ConvertToInt(object enumValue, Type underlyingType) + { + switch(Type.GetTypeCode(underlyingType)) + { + case TypeCode.SByte: + return (sbyte)enumValue; + case TypeCode.Byte: + return (byte)enumValue; + case TypeCode.Int16: + return (short)enumValue; + case TypeCode.UInt16: + return (ushort)enumValue; + case TypeCode.Int32: + return (int)enumValue; + case TypeCode.UInt32: + return unchecked((int)(uint)enumValue); + default: + throw new NotSupportedException(string.Format("Enum with underlying type '{0}' is not supported", underlyingType)); + } + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf.5.1.ReSharper b/GroBuf/GroBuf.5.1.ReSharper deleted file mode 100644 index 138bf65..0000000 --- a/GroBuf/GroBuf.5.1.ReSharper +++ /dev/null @@ -1,179 +0,0 @@ - - - - - SOLUTION - - - 1 - ONLY_FOR_MULTILINE - ONLY_FOR_MULTILINE - ONLY_FOR_MULTILINE - ONLY_FOR_MULTILINE - ONLY_FOR_MULTILINE - ONLY_FOR_MULTILINE - False - False - 1 - 1 - - public - protected - internal - private - new - abstract - virtual - override - sealed - static - readonly - extern - unsafe - volatile - - False - False - True - False - True - True - False - False - False - False - False - False - False - False - False - False - False - False - - - - $object$_On$event$ - $event$Handler - - - True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -]]> - - - - - - $object$_On$event$ - $event$Handler - - - - - - - - - - - - - - $object$_On$event$ - $event$Handler - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/GroBuf/GroBuf.6.0.ReSharper b/GroBuf/GroBuf.6.0.ReSharper deleted file mode 100644 index 4bbae19..0000000 --- a/GroBuf/GroBuf.6.0.ReSharper +++ /dev/null @@ -1,200 +0,0 @@ - - - - - SOLUTION - - - - - - - 1 - ONLY_FOR_MULTILINE - ONLY_FOR_MULTILINE - ONLY_FOR_MULTILINE - ONLY_FOR_MULTILINE - ONLY_FOR_MULTILINE - ONLY_FOR_MULTILINE - False - False - 1 - 1 - - public - protected - internal - private - new - abstract - virtual - override - sealed - static - readonly - extern - unsafe - volatile - - False - False - True - False - True - True - False - False - False - False - False - False - False - False - False - False - False - False - - - - $object$_On$event$ - $event$Handler - - - True - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -]]> - - - - - - - - - - - - - - - - - - - - - $object$_On$event$ - $event$Handler - - - - - - - - - - - - - ReturnDefaultValue - - - $object$_On$event$ - $event$Handler - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/GroBuf/GroBuf.csproj b/GroBuf/GroBuf.csproj new file mode 100644 index 0000000..3914477 --- /dev/null +++ b/GroBuf/GroBuf.csproj @@ -0,0 +1,22 @@ + + + netstandard2.0;net45 + true + GroBuf + 1.3.0 + 1.3.0.0 + Igor Chevdar + SKB Kontur + SKB Kontur 2011-2018 + false + GroBuf is a fast binary serializer for .NET + .NET Binary Serialization + https://github.com/skbkontur/GroBuf + https://github.com/skbkontur/GroBuf + git + + + + + + diff --git a/GroBuf/GroBuf.sln b/GroBuf/GroBuf.sln deleted file mode 100644 index 34e00ba..0000000 --- a/GroBuf/GroBuf.sln +++ /dev/null @@ -1,36 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GroBuf", "GroBuf\GroBuf.csproj", "{80D1D3A4-A424-43C3-B46B-3A87941A68B4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{60E8EA76-2CBB-4A14-B9AA-F639E1D131BC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {80D1D3A4-A424-43C3-B46B-3A87941A68B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {80D1D3A4-A424-43C3-B46B-3A87941A68B4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {80D1D3A4-A424-43C3-B46B-3A87941A68B4}.Debug|x86.ActiveCfg = Debug|x86 - {80D1D3A4-A424-43C3-B46B-3A87941A68B4}.Debug|x86.Build.0 = Debug|x86 - {80D1D3A4-A424-43C3-B46B-3A87941A68B4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {80D1D3A4-A424-43C3-B46B-3A87941A68B4}.Release|Any CPU.Build.0 = Release|Any CPU - {80D1D3A4-A424-43C3-B46B-3A87941A68B4}.Release|x86.ActiveCfg = Release|x86 - {80D1D3A4-A424-43C3-B46B-3A87941A68B4}.Release|x86.Build.0 = Release|x86 - {60E8EA76-2CBB-4A14-B9AA-F639E1D131BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {60E8EA76-2CBB-4A14-B9AA-F639E1D131BC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {60E8EA76-2CBB-4A14-B9AA-F639E1D131BC}.Debug|x86.ActiveCfg = Debug|x86 - {60E8EA76-2CBB-4A14-B9AA-F639E1D131BC}.Debug|x86.Build.0 = Debug|x86 - {60E8EA76-2CBB-4A14-B9AA-F639E1D131BC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {60E8EA76-2CBB-4A14-B9AA-F639E1D131BC}.Release|Any CPU.Build.0 = Release|Any CPU - {60E8EA76-2CBB-4A14-B9AA-F639E1D131BC}.Release|x86.ActiveCfg = Release|x86 - {60E8EA76-2CBB-4A14-B9AA-F639E1D131BC}.Release|x86.Build.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/GroBuf/GroBuf/GroBuf.csproj b/GroBuf/GroBuf/GroBuf.csproj deleted file mode 100644 index 9ec38a6..0000000 --- a/GroBuf/GroBuf/GroBuf.csproj +++ /dev/null @@ -1,247 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {80D1D3A4-A424-43C3-B46B-3A87941A68B4} - Library - Properties - GroBuf - GroBuf - v4.5 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - true - false - - - true - bin\x86\Debug\ - DEBUG;TRACE - true - full - x86 - bin\Debug\GroBuf.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - MinimumRecommendedRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - false - - - bin\x86\Release\ - TRACE - true - true - pdbonly - x86 - bin\Release\GroBuf.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - MinimumRecommendedRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - - - - ..\packages\GrEmit.2.1.9\lib\net40\GrEmit.dll - - - ..\packages\Mono.Reflection.1.1.0.0\lib\Mono.Reflection.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/GroBuf/GroBuf/Properties/AssemblyInfo.cs b/GroBuf/GroBuf/Properties/AssemblyInfo.cs deleted file mode 100644 index 46e8093..0000000 --- a/GroBuf/GroBuf/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. - -[assembly : AssemblyTitle("GroBuf")] -[assembly : AssemblyDescription("")] -[assembly : AssemblyConfiguration("")] -[assembly : AssemblyCompany("SKB Kontur")] -[assembly : AssemblyProduct("GroBuf")] -[assembly : AssemblyCopyright("Copyright © 2011-2016")] -[assembly : AssemblyTrademark("")] -[assembly : AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. - -[assembly : ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM - -[assembly : Guid("38b137c1-f64c-4b03-82d9-37e4d6bdcffc")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] - -[assembly : AssemblyVersion("1.2.0")] -[assembly : AssemblyFileVersion("1.2.0")] \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/IPAddressSizeCounterBuilder.cs b/GroBuf/GroBuf/SizeCounters/IPAddressSizeCounterBuilder.cs deleted file mode 100644 index 3c41e44..0000000 --- a/GroBuf/GroBuf/SizeCounters/IPAddressSizeCounterBuilder.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Net; -using System.Net.Sockets; -using System.Reflection; - -namespace GroBuf.SizeCounters -{ - internal class IPAddressSizeCounterBuilder : SizeCounterBuilderBase - { - public IPAddressSizeCounterBuilder() - : base(typeof(IPAddress)) - { - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - - il.Ldc_I4(4); // stack: [4] - context.LoadObj(); // stack: [4, obj] - il.Ldfld(Type.GetField("m_Family", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [4, obj.m_Family] - il.Ldc_I4((int)AddressFamily.InterNetworkV6); // stack: [4, obj.m_Family, AddressFamily.InterNetworkV6] - il.Ceq(); // stack: [4, obj.m_Family == AddressFamily.InterNetworkV6] - il.Ldc_I4(1); // stack: [4, obj.m_Family == AddressFamily.InterNetworkV6, 1] - il.Shl(); // stack: [4, (obj.m_Family == AddressFamily.InterNetworkV6) << 1] - il.Shl(); // stack: [4 << ((obj.m_Family == AddressFamily.InterNetworkV6) << 1)] - il.Ldc_I4(5); // stack: [4 << ((obj.m_Family == AddressFamily.InterNetworkV6) << 1), 5] - il.Add(); // stack: [4 << ((obj.m_Family == AddressFamily.InterNetworkV6) << 1) + 5] - } - - protected override bool IsReference { get { return false; } } - } -} \ No newline at end of file diff --git a/GroBuf/GroBuf/packages.config b/GroBuf/GroBuf/packages.config deleted file mode 100644 index c751ecd..0000000 --- a/GroBuf/GroBuf/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/GroBuf/GroBuf/GroBufCustomSerializationAttribute.cs b/GroBuf/GroBufCustomSerializationAttribute.cs similarity index 96% rename from GroBuf/GroBuf/GroBufCustomSerializationAttribute.cs rename to GroBuf/GroBufCustomSerializationAttribute.cs index 1fef7e8..220592d 100644 --- a/GroBuf/GroBuf/GroBufCustomSerializationAttribute.cs +++ b/GroBuf/GroBufCustomSerializationAttribute.cs @@ -1,19 +1,19 @@ -using System; - -namespace GroBuf -{ - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] - public class GroBufCustomSerializationAttribute : Attribute - { - public GroBufCustomSerializationAttribute() - { - } - - public GroBufCustomSerializationAttribute(Type customSerializerType) - { - CustomSerializerType = customSerializerType; - } - - public Type CustomSerializerType { get; private set; } - } +using System; + +namespace GroBuf +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] + public class GroBufCustomSerializationAttribute : Attribute + { + public GroBufCustomSerializationAttribute() + { + } + + public GroBufCustomSerializationAttribute(Type customSerializerType) + { + CustomSerializerType = customSerializerType; + } + + public Type CustomSerializerType { get; private set; } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/GroBufCustomSerializerByAttribute.cs b/GroBuf/GroBufCustomSerializerByAttribute.cs similarity index 97% rename from GroBuf/GroBuf/GroBufCustomSerializerByAttribute.cs rename to GroBuf/GroBufCustomSerializerByAttribute.cs index 584508d..ea26f78 100644 --- a/GroBuf/GroBuf/GroBufCustomSerializerByAttribute.cs +++ b/GroBuf/GroBufCustomSerializerByAttribute.cs @@ -1,33 +1,33 @@ -using System; - -namespace GroBuf -{ - internal class GroBufCustomSerializerByAttribute : IGroBufCustomSerializer - { - public GroBufCustomSerializerByAttribute(SizeCounterDelegate sizeCounter, WriterDelegate writerDelegate, ReaderDelegate readerDelegate) - { - this.sizeCounter = sizeCounter; - this.writerDelegate = writerDelegate; - this.readerDelegate = readerDelegate; - } - - public int CountSize(object obj, bool writeEmpty, WriterContext context) - { - return sizeCounter(obj, writeEmpty, context); - } - - public void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) - { - writerDelegate(obj, writeEmpty, result, ref index, context); - } - - public void Read(IntPtr data, ref int index, ref object result, ReaderContext context) - { - readerDelegate(data, ref index, ref result, context); - } - - private readonly SizeCounterDelegate sizeCounter; - private readonly WriterDelegate writerDelegate; - private readonly ReaderDelegate readerDelegate; - } +using System; + +namespace GroBuf +{ + internal class GroBufCustomSerializerByAttribute : IGroBufCustomSerializer + { + public GroBufCustomSerializerByAttribute(SizeCounterDelegate sizeCounter, WriterDelegate writerDelegate, ReaderDelegate readerDelegate) + { + this.sizeCounter = sizeCounter; + this.writerDelegate = writerDelegate; + this.readerDelegate = readerDelegate; + } + + public int CountSize(object obj, bool writeEmpty, WriterContext context) + { + return sizeCounter(obj, writeEmpty, context); + } + + public void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) + { + writerDelegate(obj, writeEmpty, result, ref index, context); + } + + public void Read(IntPtr data, ref int index, ref object result, ReaderContext context) + { + readerDelegate(data, ref index, ref result, context); + } + + private readonly SizeCounterDelegate sizeCounter; + private readonly WriterDelegate writerDelegate; + private readonly ReaderDelegate readerDelegate; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/GroBufHelpers.cs b/GroBuf/GroBufHelpers.cs similarity index 95% rename from GroBuf/GroBuf/GroBufHelpers.cs rename to GroBuf/GroBufHelpers.cs index c33dea9..44ff0e2 100644 --- a/GroBuf/GroBuf/GroBufHelpers.cs +++ b/GroBuf/GroBufHelpers.cs @@ -1,201 +1,197 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; -using System.Runtime.CompilerServices; - -using GrEmit; - -using GroBuf.DataMembersExtracters; - -using Mono.Reflection; - -namespace GroBuf -{ - public static class GroBufHelpers - { - static GroBufHelpers() - { - isMono = Type.GetType("Mono.Runtime") != null; - ExtractDynamicMethodPointer = EmitDynamicMethodPointerExtractor(); - LeafTypes = BuildLeafTypes(); - LeafTypeHandles = LeafTypes.Select(type => type == null ? IntPtr.Zero : type.TypeHandle.Value).ToArray(); - } - - public static bool IsMono { get { return isMono; } } - - public static Type GetMemberType(this MemberInfo member) - { - switch(member.MemberType) - { - case MemberTypes.Property: - return ((PropertyInfo)member).PropertyType; - case MemberTypes.Field: - return ((FieldInfo)member).FieldType; - default: - throw new NotSupportedException("Data member of type " + member.MemberType + " is not supported"); - } - } - - public static MethodInfo GetMethod(Type type) - { - MethodInfo result = type.GetMethods(BindingFlags.Public | BindingFlags.Static).FirstOrDefault(method => method.GetCustomAttributes(typeof(TAttribute), true).Any()); - if(result != null) - return result; - return type.BaseType == typeof(object) ? null : GetMethod(type.BaseType); - } - - public static bool IsTuple(this Type type) - { - if(!type.IsGenericType) - return false; - type = type.GetGenericTypeDefinition(); - return type == typeof(Tuple<>) || type == typeof(Tuple<,>) || type == typeof(Tuple<,,>) || type == typeof(Tuple<,,,>) - || type == typeof(Tuple<,,,,>) || type == typeof(Tuple<,,,,,>) || type == typeof(Tuple<,,,,,,>) - || type == typeof(Tuple<,,,,,,>) || type == typeof(Tuple<,,,,,,,>); - } - - public static ulong[] CalcHashesAndCheck(IEnumerable dataMembers) - { - var dict = new Dictionary(); - foreach(var dataMember in dataMembers) - { - var hash = dataMember.Id ?? CalcHash(dataMember.Name); - if(hash == 0) - throw new InvalidOperationException(string.Format("Hash code of '{0}.{1}' equals to zero", dataMember.Member.DeclaringType.Name, dataMember.Member.Name)); - if(dict.ContainsKey(hash)) - { - if(dict[hash] == dataMember.Member) - throw new InvalidOperationException(string.Format("Duplicated member '{0}.{1}'", dataMember.Member.DeclaringType.Name, dataMember.Member.Name)); - throw new InvalidOperationException(string.Format("Hash code collision: members '{0}.{1}' and '{2}.{3}' have the same hash code = {4}", dataMember.Member.DeclaringType.Name, dataMember.Member.Name, dict[hash].DeclaringType.Name, dict[hash].Name, hash)); - } - dict.Add(hash, dataMember.Member); - } - return dict.Keys.ToArray(); - } - - public static ulong CalcHash(string str) - { - return HashCalculator.CalcHash(str); - } - - public static uint CalcSize(ulong[] values) - { - var hashSet = new HashSet(); - for(var n = Math.Max((uint)values.Length, 1);; ++n) - { - hashSet.Clear(); - bool ok = true; - foreach(var x in values) - { - var item = (uint)(x % n); - if(hashSet.Contains(item)) - { - ok = false; - break; - } - hashSet.Add(item); - } - if(ok) return n; - } - } - - public static readonly IntPtr[] LeafTypeHandles; - public static readonly Type[] LeafTypes; - - public static readonly int[] Lengths = BuildLengths(); - - public static readonly Func ExtractDynamicMethodPointer; - public static readonly HashCalculator HashCalculator = new HashCalculator(Seed, 1000); - public const int Seed = 314159265; //NOTE не менять !!! - - private static Func EmitDynamicMethodPointerExtractor() - { - if (isMono) - { - return dynMethod => - { - var handle = dynMethod.MethodHandle; - RuntimeHelpers.PrepareMethod(handle); - return handle.GetFunctionPointer(); - }; - } - var method = new DynamicMethod("DynamicMethodPointerExtractor", typeof(IntPtr), new[] {typeof(DynamicMethod)}, typeof(GroBufHelpers).Module, true); - using (var il = new GroboIL(method)) - { - il.Ldarg(0); // stack: [dynamicMethod] - MethodInfo getMethodDescriptorMethod = typeof(DynamicMethod).GetMethod("GetMethodDescriptor", BindingFlags.Instance | BindingFlags.NonPublic); - if(getMethodDescriptorMethod == null) - throw new MissingMethodException(typeof(DynamicMethod).Name, "GetMethodDescriptor"); - il.Call(getMethodDescriptorMethod); // stack: [dynamicMethod.GetMethodDescriptor()] - var runtimeMethodHandle = il.DeclareLocal(typeof(RuntimeMethodHandle)); - il.Stloc(runtimeMethodHandle); // runtimeMethodHandle = dynamicMethod.GetMethodDescriptor(); stack: [] - il.Ldloc(runtimeMethodHandle); // stack: [runtimeMethodHandle] - MethodInfo prepareMethodMethod = typeof(RuntimeHelpers).GetMethod("PrepareMethod", new[] {typeof(RuntimeMethodHandle)}); - if(prepareMethodMethod == null) - throw new MissingMethodException(typeof(RuntimeHelpers).Name, "PrepareMethod"); - il.Call(prepareMethodMethod); // RuntimeHelpers.PrepareMethod(runtimeMethodHandle) - MethodInfo getFunctionPointerMethod = typeof(RuntimeMethodHandle).GetMethod("GetFunctionPointer", BindingFlags.Instance | BindingFlags.Public); - if(getFunctionPointerMethod == null) - throw new MissingMethodException(typeof(RuntimeMethodHandle).Name, "GetFunctionPointer"); - il.Ldloca(runtimeMethodHandle); // stack: [&runtimeMethodHandle] - il.Call(getFunctionPointerMethod); // stack: [runtimeMethodHandle.GetFunctionPointer()] - il.Ret(); // return runtimeMethodHandle.GetFunctionPointer() - } - return (Func)method.CreateDelegate(typeof(Func)); - } - - private static int[] BuildLengths() - { - var lengths = new int[256]; - Type type = typeof(GroBufTypeCode); - FieldInfo[] fields = type.GetFields(); - foreach(var field in fields) - { - if(field.FieldType != type) continue; - var attribute = (DataLengthAttribute)field.GetCustomAttributes(typeof(DataLengthAttribute), false).SingleOrDefault(); - if(attribute == null) throw new InvalidOperationException(string.Format("Data length of '{0}.{1}' must be specified", type, field)); - lengths[(int)field.GetValue(dummy)] = attribute.Length; - } - return lengths; - } - - private static Type[] BuildLeafTypes() - { - Type type = typeof(GroBufTypeCode); - FieldInfo[] fields = type.GetFields(); - var types = (from field in fields - where field.FieldType == type - select (LeafTypeAttribute)field.GetCustomAttributes(typeof(LeafTypeAttribute), false).SingleOrDefault() - into attribute - where attribute != null - select attribute.Type).ToList(); - var n = CalcSize(types.Select(x => (ulong)x.TypeHandle.Value.ToInt64()).ToArray()); - var result = new Type[n]; - foreach(var x in types) - result[x.TypeHandle.Value.ToInt64() % n] = x; - return result; - } - - public static MemberInfo TryGetWritableMemberInfo(this MemberInfo memberInfo) - { - var propertyInfo = memberInfo as PropertyInfo; - if(propertyInfo == null) - return memberInfo; - if(propertyInfo.CanWrite && propertyInfo.GetSetMethod(true).GetParameters().Length == 1) - return memberInfo; - try - { - return propertyInfo.GetBackingField(); - } - catch - { - } - return null; - } - - private static readonly object dummy = new object(); - private static readonly bool isMono; - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.CompilerServices; + +using GrEmit; + +using GroBuf.DataMembersExtracters; + +using Mono.Reflection; + +namespace GroBuf +{ + public static class GroBufHelpers + { + static GroBufHelpers() + { + ExtractDynamicMethodPointer = EmitDynamicMethodPointerExtractor(); + LeafTypes = BuildLeafTypes(); + LeafTypeHandles = LeafTypes.Select(type => type == null ? IntPtr.Zero : type.TypeHandle.Value).ToArray(); + } + + public static Type GetMemberType(this MemberInfo member) + { + switch(member.MemberType) + { + case MemberTypes.Property: + return ((PropertyInfo)member).PropertyType; + case MemberTypes.Field: + return ((FieldInfo)member).FieldType; + default: + throw new NotSupportedException("Data member of type " + member.MemberType + " is not supported"); + } + } + + public static MethodInfo GetMethod(Type type) + { + MethodInfo result = type.GetMethods(BindingFlags.Public | BindingFlags.Static).FirstOrDefault(method => method.GetCustomAttributes(typeof(TAttribute), true).Any()); + if(result != null) + return result; + return type.BaseType == typeof(object) ? null : GetMethod(type.BaseType); + } + + public static bool IsTuple(this Type type) + { + if(!type.IsGenericType) + return false; + type = type.GetGenericTypeDefinition(); + return type == typeof(Tuple<>) || type == typeof(Tuple<,>) || type == typeof(Tuple<,,>) || type == typeof(Tuple<,,,>) + || type == typeof(Tuple<,,,,>) || type == typeof(Tuple<,,,,,>) || type == typeof(Tuple<,,,,,,>) + || type == typeof(Tuple<,,,,,,>) || type == typeof(Tuple<,,,,,,,>); + } + + public static ulong[] CalcHashesAndCheck(IEnumerable dataMembers) + { + var dict = new Dictionary(); + foreach(var dataMember in dataMembers) + { + var hash = dataMember.Id ?? CalcHash(dataMember.Name); + if(hash == 0) + throw new InvalidOperationException(string.Format("Hash code of '{0}.{1}' equals to zero", dataMember.Member.DeclaringType.Name, dataMember.Member.Name)); + if(dict.ContainsKey(hash)) + { + if(dict[hash] == dataMember.Member) + throw new InvalidOperationException(string.Format("Duplicated member '{0}.{1}'", dataMember.Member.DeclaringType.Name, dataMember.Member.Name)); + throw new InvalidOperationException(string.Format("Hash code collision: members '{0}.{1}' and '{2}.{3}' have the same hash code = {4}", dataMember.Member.DeclaringType.Name, dataMember.Member.Name, dict[hash].DeclaringType.Name, dict[hash].Name, hash)); + } + dict.Add(hash, dataMember.Member); + } + return dict.Keys.ToArray(); + } + + public static ulong CalcHash(string str) + { + return HashCalculator.CalcHash(str); + } + + public static uint CalcSize(ulong[] values) + { + var hashSet = new HashSet(); + for(var n = Math.Max((uint)values.Length, 1);; ++n) + { + hashSet.Clear(); + bool ok = true; + foreach(var x in values) + { + var item = (uint)(x % n); + if(hashSet.Contains(item)) + { + ok = false; + break; + } + hashSet.Add(item); + } + if(ok) return n; + } + } + + public static readonly IntPtr[] LeafTypeHandles; + public static readonly Type[] LeafTypes; + + public static readonly int[] Lengths = BuildLengths(); + + public static readonly Func ExtractDynamicMethodPointer; + public static readonly HashCalculator HashCalculator = new HashCalculator(Seed, 1000); + public const int Seed = 314159265; //NOTE не менять !!! + + private static Func EmitDynamicMethodPointerExtractor() + { + if (PlatformHelpers.IsMono) + { + return dynMethod => + { + var handle = dynMethod.MethodHandle; + RuntimeHelpers.PrepareMethod(handle); + return handle.GetFunctionPointer(); + }; + } + var method = new DynamicMethod("DynamicMethodPointerExtractor", typeof(IntPtr), new[] {typeof(DynamicMethod)}, typeof(GroBufHelpers).Module, true); + using (var il = new GroboIL(method)) + { + il.Ldarg(0); // stack: [dynamicMethod] + MethodInfo getMethodDescriptorMethod = typeof(DynamicMethod).GetMethod("GetMethodDescriptor", BindingFlags.Instance | BindingFlags.NonPublic); + if(getMethodDescriptorMethod == null) + throw new MissingMethodException(typeof(DynamicMethod).Name, "GetMethodDescriptor"); + il.Call(getMethodDescriptorMethod); // stack: [dynamicMethod.GetMethodDescriptor()] + var runtimeMethodHandle = il.DeclareLocal(typeof(RuntimeMethodHandle)); + il.Stloc(runtimeMethodHandle); // runtimeMethodHandle = dynamicMethod.GetMethodDescriptor(); stack: [] + il.Ldloc(runtimeMethodHandle); // stack: [runtimeMethodHandle] + MethodInfo prepareMethodMethod = typeof(RuntimeHelpers).GetMethod("PrepareMethod", new[] {typeof(RuntimeMethodHandle)}); + if(prepareMethodMethod == null) + throw new MissingMethodException(typeof(RuntimeHelpers).Name, "PrepareMethod"); + il.Call(prepareMethodMethod); // RuntimeHelpers.PrepareMethod(runtimeMethodHandle) + MethodInfo getFunctionPointerMethod = typeof(RuntimeMethodHandle).GetMethod("GetFunctionPointer", BindingFlags.Instance | BindingFlags.Public); + if(getFunctionPointerMethod == null) + throw new MissingMethodException(typeof(RuntimeMethodHandle).Name, "GetFunctionPointer"); + il.Ldloca(runtimeMethodHandle); // stack: [&runtimeMethodHandle] + il.Call(getFunctionPointerMethod); // stack: [runtimeMethodHandle.GetFunctionPointer()] + il.Ret(); // return runtimeMethodHandle.GetFunctionPointer() + } + return (Func)method.CreateDelegate(typeof(Func)); + } + + private static int[] BuildLengths() + { + var lengths = new int[256]; + Type type = typeof(GroBufTypeCode); + FieldInfo[] fields = type.GetFields(); + foreach(var field in fields) + { + if(field.FieldType != type) continue; + var attribute = (DataLengthAttribute)field.GetCustomAttributes(typeof(DataLengthAttribute), false).SingleOrDefault(); + if(attribute == null) throw new InvalidOperationException(string.Format("Data length of '{0}.{1}' must be specified", type, field)); + lengths[(int)field.GetValue(dummy)] = attribute.Length; + } + return lengths; + } + + private static Type[] BuildLeafTypes() + { + Type type = typeof(GroBufTypeCode); + FieldInfo[] fields = type.GetFields(); + var types = (from field in fields + where field.FieldType == type + select (LeafTypeAttribute)field.GetCustomAttributes(typeof(LeafTypeAttribute), false).SingleOrDefault() + into attribute + where attribute != null + select attribute.Type).ToList(); + var n = CalcSize(types.Select(x => (ulong)x.TypeHandle.Value.ToInt64()).ToArray()); + var result = new Type[n]; + foreach(var x in types) + result[x.TypeHandle.Value.ToInt64() % n] = x; + return result; + } + + public static MemberInfo TryGetWritableMemberInfo(this MemberInfo memberInfo) + { + var propertyInfo = memberInfo as PropertyInfo; + if(propertyInfo == null) + return memberInfo; + if(propertyInfo.CanWrite && propertyInfo.GetSetMethod(true).GetParameters().Length == 1) + return memberInfo; + try + { + return propertyInfo.GetBackingField(); + } + catch + { + } + return null; + } + + private static readonly object dummy = new object(); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/GroBufOptions.cs b/GroBuf/GroBufOptions.cs similarity index 94% rename from GroBuf/GroBuf/GroBufOptions.cs rename to GroBuf/GroBufOptions.cs index 7a5c09a..0f68257 100644 --- a/GroBuf/GroBuf/GroBufOptions.cs +++ b/GroBuf/GroBufOptions.cs @@ -1,13 +1,13 @@ -using System; - -namespace GroBuf -{ - [Flags] - public enum GroBufOptions - { - None = 0, - WriteEmptyObjects = 1, - MergeOnRead = 2, - PackReferences = 4, - } +using System; + +namespace GroBuf +{ + [Flags] + public enum GroBufOptions + { + None = 0, + WriteEmptyObjects = 1, + MergeOnRead = 2, + PackReferences = 4, + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/GroBufRandom.cs b/GroBuf/GroBufRandom.cs similarity index 96% rename from GroBuf/GroBuf/GroBufRandom.cs rename to GroBuf/GroBufRandom.cs index 82610c9..0b743c8 100644 --- a/GroBuf/GroBuf/GroBufRandom.cs +++ b/GroBuf/GroBufRandom.cs @@ -1,64 +1,64 @@ -using System; - -namespace GroBuf -{ - internal class GroBufRandom - { - public GroBufRandom() - : this(Environment.TickCount) - { - } - - public GroBufRandom(int seed) - { - m_seedArray = new int[56]; - int num4 = (seed == -0x80000000) ? 0x7fffffff : Math.Abs(seed); - int num2 = 0x9a4ec86 - num4; - m_seedArray[55] = num2; - int num3 = 1; - for(int i = 1; i < 55; i++) - { - int index = (21 * i) % 55; - m_seedArray[index] = num3; - num3 = num2 - num3; - if(num3 < 0) - num3 += 0x7fffffff; - num2 = m_seedArray[index]; - } - for(int j = 1; j < 5; j++) - { - for(int k = 1; k < 56; k++) - { - m_seedArray[k] -= m_seedArray[1 + ((k + 30) % 55)]; - if(m_seedArray[k] < 0) - m_seedArray[k] += 0x7fffffff; - } - } - m_inext = 0; - m_inextp = 21; - } - - public int Next() - { - int inext = m_inext; - int inextp = m_inextp; - if(++inext >= 56) - inext = 1; - if(++inextp >= 56) - inextp = 1; - int num = m_seedArray[inext] - m_seedArray[inextp]; - if(num == 0x7fffffff) - num--; - if(num < 0) - num += 0x7fffffff; - m_seedArray[inext] = num; - m_inext = inext; - m_inextp = inextp; - return num; - } - - private int m_inext; - private int m_inextp; - private readonly int[] m_seedArray; - } +using System; + +namespace GroBuf +{ + internal class GroBufRandom + { + public GroBufRandom() + : this(Environment.TickCount) + { + } + + public GroBufRandom(int seed) + { + m_seedArray = new int[56]; + int num4 = (seed == -0x80000000) ? 0x7fffffff : Math.Abs(seed); + int num2 = 0x9a4ec86 - num4; + m_seedArray[55] = num2; + int num3 = 1; + for(int i = 1; i < 55; i++) + { + int index = (21 * i) % 55; + m_seedArray[index] = num3; + num3 = num2 - num3; + if(num3 < 0) + num3 += 0x7fffffff; + num2 = m_seedArray[index]; + } + for(int j = 1; j < 5; j++) + { + for(int k = 1; k < 56; k++) + { + m_seedArray[k] -= m_seedArray[1 + ((k + 30) % 55)]; + if(m_seedArray[k] < 0) + m_seedArray[k] += 0x7fffffff; + } + } + m_inext = 0; + m_inextp = 21; + } + + public int Next() + { + int inext = m_inext; + int inextp = m_inextp; + if(++inext >= 56) + inext = 1; + if(++inextp >= 56) + inextp = 1; + int num = m_seedArray[inext] - m_seedArray[inextp]; + if(num == 0x7fffffff) + num--; + if(num < 0) + num += 0x7fffffff; + m_seedArray[inext] = num; + m_inext = inext; + m_inextp = inextp; + return num; + } + + private int m_inext; + private int m_inextp; + private readonly int[] m_seedArray; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/GroBufReader.cs b/GroBuf/GroBufReader.cs similarity index 97% rename from GroBuf/GroBuf/GroBufReader.cs rename to GroBuf/GroBufReader.cs index c305486..5ed7dd6 100644 --- a/GroBuf/GroBuf/GroBufReader.cs +++ b/GroBuf/GroBufReader.cs @@ -1,371 +1,371 @@ -using System; -using System.Collections; -using System.Reflection; -using System.Reflection.Emit; - -using GrEmit; - -using GroBuf.DataMembersExtracters; -using GroBuf.Readers; - -namespace GroBuf -{ - internal class GroBufReader - { - public GroBufReader(long serializerId, IDataMembersExtractor dataMembersExtractor, IGroBufCustomSerializerCollection customSerializerCollection, GroBufOptions options, Func factory, Func baseFactory) - { - this.serializerId = serializerId; - this.dataMembersExtractor = dataMembersExtractor; - this.customSerializerCollection = customSerializerCollection; - this.options = options; - this.factory = factory; - this.baseFactory = baseFactory; - var assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run); - module = assembly.DefineDynamicModule(Guid.NewGuid().ToString()); - readerCollection = new ReaderCollection(customSerializerCollection, factory, baseFactory, module); - } - - public void Read(IntPtr data, ref T result, int length) - { - if (data == IntPtr.Zero) - throw new ArgumentNullException("data"); - int index = 0; - Read(data, ref index, length, ref result); - } - - public unsafe void Read(byte[] data, ref T result) - { - if(data == null) - throw new ArgumentNullException("data"); - if(data.Length == 0) - throw new ArgumentException("Cannot read data from empty array"); - fixed(byte* d = &data[0]) - { - int index = 0; - Read((IntPtr)d, ref index, data.Length, ref result); - if(index < data.Length) - throw new DataCorruptedException("Encountered extra data"); - } - } - - public T Read(byte[] data, ref int index) - { - if(data == null) - throw new ArgumentNullException("data"); - return Read(data, ref index, data.Length); - } - - public unsafe T Read(byte[] data, ref int index, int length) - { - if(data == null) - throw new ArgumentNullException("data"); - if(data.Length == 0) - throw new ArgumentException("Cannot read data from empty array"); - if(length > data.Length) - throw new ArgumentOutOfRangeException("length"); - T result = default(T); - fixed(byte* d = &data[0]) - Read((IntPtr)d, ref index, length, ref result); - return result; - } - - public T Read(byte[] data) - { - T result = default(T); - Read(data, ref result); - return result; - } - - public T Read(byte[] data, int length) - { - int index = 0; - return Read(data, ref index, length); - } - - public unsafe void Read(IntPtr data, ref int index, int length, ref T result) - { - int references = 0; - if(index >= length) - throw new DataCorruptedException("Unexpected end of data"); - var start = (byte*)(data + index); - if(*start == (byte)GroBufTypeCode.Reference) - { - if(index + 5 >= length) - throw new DataCorruptedException("Unexpected end of data"); - references = *(int*)(start + 1); - index += 5; - } - GetReader(false)(data, ref index, ref result, new ReaderContext(serializerId, length, index, references)); - } - - public T Read(IntPtr data, ref int index, int length) - { - T result = default(T); - Read(data, ref index, length, ref result); - return result; - } - - public unsafe void Read(Type type, byte[] data, ref object result) - { - if(data == null) - throw new ArgumentNullException("data"); - if(data.Length == 0) - throw new ArgumentException("Cannot read data from empty array"); - fixed(byte* d = &data[0]) - { - int index = 0; - Read(type, (IntPtr)d, ref index, data.Length, ref result); - if(index < data.Length) - throw new DataCorruptedException("Encountered extra data"); - } - } - - public object Read(Type type, byte[] data, ref int index) - { - if(data == null) - throw new ArgumentNullException("data"); - return Read(type, data, ref index, data.Length); - } - - public unsafe object Read(Type type, byte[] data, ref int index, int length) - { - if(data == null) - throw new ArgumentNullException("data"); - if(data.Length == 0) - throw new ArgumentException("Cannot read data from empty array"); - if(length > data.Length) - throw new ArgumentOutOfRangeException("length"); - object result = null; - fixed(byte* d = &data[0]) - Read(type, (IntPtr)d, ref index, length, ref result); - return result; - } - - public object Read(Type type, IntPtr data, ref int index, int length) - { - if (data == IntPtr.Zero) - throw new ArgumentNullException("data"); - object result = null; - Read(type, data, ref index, length, ref result); - return result; - } - - public object Read(Type type, byte[] data) - { - object result = null; - Read(type, data, ref result); - return result; - } - - public object Read(Type type, byte[] data, int length) - { - int index = 0; - return Read(type, data, ref index, length); - } - - public unsafe void Read(Type type, IntPtr data, ref int index, int length, ref object result) - { - int references = 0; - if (index >= length) - throw new DataCorruptedException("Unexpected end of data"); - var start = (byte*)(data + index); - if (*start == (byte)GroBufTypeCode.Reference) - { - if (index + 5 >= length) - throw new DataCorruptedException("Unexpected end of data"); - references = *(int*)(start + 1); - index += 5; - } - GetReader(type, false)(data, ref index, ref result, new ReaderContext(serializerId, length, index, references)); - } - - public void Read(Type type, bool ignoreCustomSerialization, IntPtr data, ref int index, ref object result, ReaderContext context) - { - GetReader(type, ignoreCustomSerialization)(data, ref index, ref result, context); - } - - public GroBufOptions Options { get { return options; } } - - private ReaderDelegate GetReader(bool ignoreCustomSerialization) - { - var hashtable = ignoreCustomSerialization ? readers4 : readers; - var type = typeof(T); - var reader = (ReaderDelegate)hashtable[type]; - if(reader == null) - { - lock(readersLock) - { - reader = (ReaderDelegate)hashtable[type]; - if(reader == null) - { - reader = BuildReader(ignoreCustomSerialization); - hashtable[type] = reader; - } - } - } - return reader; - } - - private ReaderDelegate GetReader(Type type, bool ignoreCustomSerialization) - { - var hashtable = ignoreCustomSerialization ? readers3 : readers2; - var reader = (ReaderDelegate)hashtable[type]; - if(reader == null) - { - lock(readersLock) - { - reader = (ReaderDelegate)hashtable[type]; - if(reader == null) - { - reader = BuildReader(type, ignoreCustomSerialization); - hashtable[type] = reader; - } - } - } - return reader; - } - - private IntPtr GetReadMethod(Type type, bool ignoreCustomSerialization) - { - var hashtable = ignoreCustomSerialization ? readMethodsWithoutCustomSerialization : readMethodsWithCustomSerialization; - var readMethod = (IntPtr?)hashtable[type]; - if(readMethod == null) - { - lock(readMethodsLock) - { - readMethod = (IntPtr?)hashtable[type]; - if(readMethod == null) - { - readMethod = new ReaderTypeBuilder(this, module, readerCollection, dataMembersExtractor).BuildReader(type, ignoreCustomSerialization); - hashtable[type] = readMethod; - } - } - } - return readMethod.Value; - } - - private ReaderDelegate BuildReader(bool ignoreCustomSerialization) - { - var type = typeof(T); - var reader = GetReadMethod(type, ignoreCustomSerialization); - var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] {typeof(IntPtr), typeof(int).MakeByRefType(), type.MakeByRefType(), typeof(ReaderContext)}, GetType(), true); - using (var il = new GroboIL(dynamicMethod)) - { - il.Ldarg(0); // stack: [data] - il.Ldarg(1); // stack: [data, ref index] - il.Ldarg(2); // stack: [data, ref index, ref result] - - if(!type.IsValueType && type != typeof(string) && (ignoreCustomSerialization || customSerializerCollection.Get(type, factory, baseFactory(type)) == null)) - { - il.Dup(); // stack: [data, ref index, ref result, ref result] - il.Ldind(type); // stack: [data, ref index, ref result, result] - var notNullLabel = il.DefineLabel("notNull"); - il.Brtrue(notNullLabel); // if(result != null) goto notNull; stack: [data, ref index, ref result] - il.Dup(); // stack: [data, ref index, ref result, ref result] - if(!type.IsArray) - ObjectConstructionHelper.EmitConstructionOfType(type, il); // stack: [data, ref index, ref result, ref result, new type()] - else - { - il.Ldc_I4(0); // stack: [data, ref index, ref result, ref result, 0] - il.Newarr(type.GetElementType()); // stack: [data, ref index, ref result, ref result, new elementType[0]] - } - il.Stind(type); // result = new type(); stack: [data, ref index, ref result] - il.MarkLabel(notNullLabel); - } - - il.Ldarg(3); // stack: [data, ref index, ref result, context] - il.Ldc_IntPtr(reader); - il.Calli(CallingConventions.Standard, typeof(void), new[] {typeof(IntPtr), typeof(int).MakeByRefType(), type.MakeByRefType(), typeof(ReaderContext)}); // reader(data, ref index, ref result, context); stack: [] - il.Ret(); - } - - return (ReaderDelegate)dynamicMethod.CreateDelegate(typeof(ReaderDelegate)); - } - - private ReaderDelegate BuildReader(Type type, bool ignoreCustomSerialization) - { - var reader = GetReadMethod(type, ignoreCustomSerialization); - var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] {typeof(IntPtr), typeof(int).MakeByRefType(), typeof(object).MakeByRefType(), typeof(ReaderContext)}, GetType(), true); - using (var il = new GroboIL(dynamicMethod)) - { - il.Ldarg(0); // stack: [data] - il.Ldarg(1); // stack: [data, ref index] - il.Ldarg(2); // stack: [data, ref index, ref result] - - var local = il.DeclareLocal(type); - if(!type.IsValueType) - { - if(type != typeof(string) && (ignoreCustomSerialization || customSerializerCollection.Get(type, factory, baseFactory(type)) == null)) - { - il.Dup(); // stack: [data, ref index, ref result, ref result] - il.Ldind(typeof(object)); // stack: [data, ref index, ref result, result] - var notNullLabel = il.DefineLabel("notNull"); - il.Brtrue(notNullLabel); // if(result != null) goto notNull; stack: [data, ref index, ref result] - il.Dup(); // stack: [data, ref index, ref result, ref result] - if(!type.IsArray) - ObjectConstructionHelper.EmitConstructionOfType(type, il); // stack: [data, ref index, ref result, ref result, new type()] - else - { - il.Ldc_I4(0); // stack: [data, ref index, ref result, ref result, 0] - il.Newarr(type.GetElementType()); // stack: [data, ref index, ref result, ref result, new elementType[0]] - } - il.Stind(typeof(object)); // result = new type(); stack: [data, ref index, ref result] - il.MarkLabel(notNullLabel); - } - il.Ldind(typeof(object)); // stack: [data, ref index, result] - il.Castclass(type); // stack: [data, ref index, (type)result] - il.Stloc(local); // local = (type)result; stack: [data, ref index] - } - else - { - il.Ldind(typeof(object)); // stack: [data, ref index, result] - var nullLabel = il.DefineLabel("null"); - il.Dup(); // stack: [data, ref index, length, result] - il.Brfalse(nullLabel); // if(result == null) goto null; stack: [data, ref index, result] - il.Unbox_Any(type); // stack: [data, ref result, (type)result] - il.Stloc(local); // local = (type)result, stack: [data, ref result] - var notNullLabel = il.DefineLabel("notNull"); - il.Br(notNullLabel); - il.MarkLabel(nullLabel); - il.Pop(); // stack: [data, ref index] - il.Ldloca(local); // stack: [data, ref index, ref local] - il.Initobj(type); // local = default(type); stack: [data, ref index] - il.MarkLabel(notNullLabel); - } - - il.Ldloca(local); // stack: [data, ref index, ref local] - il.Ldarg(3); // stack: [data, ref index, ref result, context] - il.Ldc_IntPtr(reader); - il.Calli(CallingConventions.Standard, typeof(void), new[] {typeof(IntPtr), typeof(int).MakeByRefType(), type.MakeByRefType(), typeof(ReaderContext)}); // reader(data, ref index, ref result, context); stack: [] - - il.Ldarg(2); // stack: [ref result] - il.Ldloc(local); // stack: [ref result, local] - if(type.IsValueType) - il.Box(type); // stack: [ref result, (object)local] - il.Stind(typeof(object)); // result = (object)local - - il.Ret(); - } - - return (ReaderDelegate)dynamicMethod.CreateDelegate(typeof(ReaderDelegate)); - } - - private readonly long serializerId; - private readonly IDataMembersExtractor dataMembersExtractor; - private readonly IGroBufCustomSerializerCollection customSerializerCollection; - private readonly GroBufOptions options; - private readonly Func factory; - private readonly Func baseFactory; - - private readonly Hashtable readers = new Hashtable(); - private readonly Hashtable readers2 = new Hashtable(); - private readonly Hashtable readers3 = new Hashtable(); - private readonly Hashtable readers4 = new Hashtable(); - internal readonly Hashtable readMethodsWithCustomSerialization = new Hashtable(); - private readonly Hashtable readMethodsWithoutCustomSerialization = new Hashtable(); - private readonly object readersLock = new object(); - private readonly object readMethodsLock = new object(); - private readonly ModuleBuilder module; - private readonly IReaderCollection readerCollection; - } +using System; +using System.Collections; +using System.Reflection; +using System.Reflection.Emit; + +using GrEmit; + +using GroBuf.DataMembersExtracters; +using GroBuf.Readers; + +namespace GroBuf +{ + internal class GroBufReader + { + public GroBufReader(long serializerId, IDataMembersExtractor dataMembersExtractor, IGroBufCustomSerializerCollection customSerializerCollection, GroBufOptions options, Func factory, Func baseFactory) + { + this.serializerId = serializerId; + this.dataMembersExtractor = dataMembersExtractor; + this.customSerializerCollection = customSerializerCollection; + this.options = options; + this.factory = factory; + this.baseFactory = baseFactory; + var assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run); + module = assembly.DefineDynamicModule(Guid.NewGuid().ToString()); + readerCollection = new ReaderCollection(customSerializerCollection, factory, baseFactory, module); + } + + public void Read(IntPtr data, ref T result, int length) + { + if (data == IntPtr.Zero) + throw new ArgumentNullException("data"); + int index = 0; + Read(data, ref index, length, ref result); + } + + public unsafe void Read(byte[] data, ref T result) + { + if(data == null) + throw new ArgumentNullException("data"); + if(data.Length == 0) + throw new ArgumentException("Cannot read data from empty array"); + fixed(byte* d = &data[0]) + { + int index = 0; + Read((IntPtr)d, ref index, data.Length, ref result); + if(index < data.Length) + throw new DataCorruptedException("Encountered extra data"); + } + } + + public T Read(byte[] data, ref int index) + { + if(data == null) + throw new ArgumentNullException("data"); + return Read(data, ref index, data.Length); + } + + public unsafe T Read(byte[] data, ref int index, int length) + { + if(data == null) + throw new ArgumentNullException("data"); + if(data.Length == 0) + throw new ArgumentException("Cannot read data from empty array"); + if(length > data.Length) + throw new ArgumentOutOfRangeException("length"); + T result = default(T); + fixed(byte* d = &data[0]) + Read((IntPtr)d, ref index, length, ref result); + return result; + } + + public T Read(byte[] data) + { + T result = default(T); + Read(data, ref result); + return result; + } + + public T Read(byte[] data, int length) + { + int index = 0; + return Read(data, ref index, length); + } + + public unsafe void Read(IntPtr data, ref int index, int length, ref T result) + { + int references = 0; + if(index >= length) + throw new DataCorruptedException("Unexpected end of data"); + var start = (byte*)(data + index); + if(*start == (byte)GroBufTypeCode.Reference) + { + if(index + 5 >= length) + throw new DataCorruptedException("Unexpected end of data"); + references = *(int*)(start + 1); + index += 5; + } + GetReader(false)(data, ref index, ref result, new ReaderContext(serializerId, length, index, references)); + } + + public T Read(IntPtr data, ref int index, int length) + { + T result = default(T); + Read(data, ref index, length, ref result); + return result; + } + + public unsafe void Read(Type type, byte[] data, ref object result) + { + if(data == null) + throw new ArgumentNullException("data"); + if(data.Length == 0) + throw new ArgumentException("Cannot read data from empty array"); + fixed(byte* d = &data[0]) + { + int index = 0; + Read(type, (IntPtr)d, ref index, data.Length, ref result); + if(index < data.Length) + throw new DataCorruptedException("Encountered extra data"); + } + } + + public object Read(Type type, byte[] data, ref int index) + { + if(data == null) + throw new ArgumentNullException("data"); + return Read(type, data, ref index, data.Length); + } + + public unsafe object Read(Type type, byte[] data, ref int index, int length) + { + if(data == null) + throw new ArgumentNullException("data"); + if(data.Length == 0) + throw new ArgumentException("Cannot read data from empty array"); + if(length > data.Length) + throw new ArgumentOutOfRangeException("length"); + object result = null; + fixed(byte* d = &data[0]) + Read(type, (IntPtr)d, ref index, length, ref result); + return result; + } + + public object Read(Type type, IntPtr data, ref int index, int length) + { + if (data == IntPtr.Zero) + throw new ArgumentNullException("data"); + object result = null; + Read(type, data, ref index, length, ref result); + return result; + } + + public object Read(Type type, byte[] data) + { + object result = null; + Read(type, data, ref result); + return result; + } + + public object Read(Type type, byte[] data, int length) + { + int index = 0; + return Read(type, data, ref index, length); + } + + public unsafe void Read(Type type, IntPtr data, ref int index, int length, ref object result) + { + int references = 0; + if (index >= length) + throw new DataCorruptedException("Unexpected end of data"); + var start = (byte*)(data + index); + if (*start == (byte)GroBufTypeCode.Reference) + { + if (index + 5 >= length) + throw new DataCorruptedException("Unexpected end of data"); + references = *(int*)(start + 1); + index += 5; + } + GetReader(type, false)(data, ref index, ref result, new ReaderContext(serializerId, length, index, references)); + } + + public void Read(Type type, bool ignoreCustomSerialization, IntPtr data, ref int index, ref object result, ReaderContext context) + { + GetReader(type, ignoreCustomSerialization)(data, ref index, ref result, context); + } + + public GroBufOptions Options { get { return options; } } + + private ReaderDelegate GetReader(bool ignoreCustomSerialization) + { + var hashtable = ignoreCustomSerialization ? readers4 : readers; + var type = typeof(T); + var reader = (ReaderDelegate)hashtable[type]; + if(reader == null) + { + lock(readersLock) + { + reader = (ReaderDelegate)hashtable[type]; + if(reader == null) + { + reader = BuildReader(ignoreCustomSerialization); + hashtable[type] = reader; + } + } + } + return reader; + } + + private ReaderDelegate GetReader(Type type, bool ignoreCustomSerialization) + { + var hashtable = ignoreCustomSerialization ? readers3 : readers2; + var reader = (ReaderDelegate)hashtable[type]; + if(reader == null) + { + lock(readersLock) + { + reader = (ReaderDelegate)hashtable[type]; + if(reader == null) + { + reader = BuildReader(type, ignoreCustomSerialization); + hashtable[type] = reader; + } + } + } + return reader; + } + + private IntPtr GetReadMethod(Type type, bool ignoreCustomSerialization) + { + var hashtable = ignoreCustomSerialization ? readMethodsWithoutCustomSerialization : readMethodsWithCustomSerialization; + var readMethod = (IntPtr?)hashtable[type]; + if(readMethod == null) + { + lock(readMethodsLock) + { + readMethod = (IntPtr?)hashtable[type]; + if(readMethod == null) + { + readMethod = new ReaderTypeBuilder(this, module, readerCollection, dataMembersExtractor).BuildReader(type, ignoreCustomSerialization); + hashtable[type] = readMethod; + } + } + } + return readMethod.Value; + } + + private ReaderDelegate BuildReader(bool ignoreCustomSerialization) + { + var type = typeof(T); + var reader = GetReadMethod(type, ignoreCustomSerialization); + var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] {typeof(IntPtr), typeof(int).MakeByRefType(), type.MakeByRefType(), typeof(ReaderContext)}, GetType(), true); + using (var il = new GroboIL(dynamicMethod)) + { + il.Ldarg(0); // stack: [data] + il.Ldarg(1); // stack: [data, ref index] + il.Ldarg(2); // stack: [data, ref index, ref result] + + if(!type.IsValueType && type != typeof(string) && (ignoreCustomSerialization || customSerializerCollection.Get(type, factory, baseFactory(type)) == null)) + { + il.Dup(); // stack: [data, ref index, ref result, ref result] + il.Ldind(type); // stack: [data, ref index, ref result, result] + var notNullLabel = il.DefineLabel("notNull"); + il.Brtrue(notNullLabel); // if(result != null) goto notNull; stack: [data, ref index, ref result] + il.Dup(); // stack: [data, ref index, ref result, ref result] + if(!type.IsArray) + ObjectConstructionHelper.EmitConstructionOfType(type, il); // stack: [data, ref index, ref result, ref result, new type()] + else + { + il.Ldc_I4(0); // stack: [data, ref index, ref result, ref result, 0] + il.Newarr(type.GetElementType()); // stack: [data, ref index, ref result, ref result, new elementType[0]] + } + il.Stind(type); // result = new type(); stack: [data, ref index, ref result] + il.MarkLabel(notNullLabel); + } + + il.Ldarg(3); // stack: [data, ref index, ref result, context] + il.Ldc_IntPtr(reader); + il.Calli(CallingConventions.Standard, typeof(void), new[] {typeof(IntPtr), typeof(int).MakeByRefType(), type.MakeByRefType(), typeof(ReaderContext)}); // reader(data, ref index, ref result, context); stack: [] + il.Ret(); + } + + return (ReaderDelegate)dynamicMethod.CreateDelegate(typeof(ReaderDelegate)); + } + + private ReaderDelegate BuildReader(Type type, bool ignoreCustomSerialization) + { + var reader = GetReadMethod(type, ignoreCustomSerialization); + var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] {typeof(IntPtr), typeof(int).MakeByRefType(), typeof(object).MakeByRefType(), typeof(ReaderContext)}, GetType(), true); + using (var il = new GroboIL(dynamicMethod)) + { + il.Ldarg(0); // stack: [data] + il.Ldarg(1); // stack: [data, ref index] + il.Ldarg(2); // stack: [data, ref index, ref result] + + var local = il.DeclareLocal(type); + if(!type.IsValueType) + { + if(type != typeof(string) && (ignoreCustomSerialization || customSerializerCollection.Get(type, factory, baseFactory(type)) == null)) + { + il.Dup(); // stack: [data, ref index, ref result, ref result] + il.Ldind(typeof(object)); // stack: [data, ref index, ref result, result] + var notNullLabel = il.DefineLabel("notNull"); + il.Brtrue(notNullLabel); // if(result != null) goto notNull; stack: [data, ref index, ref result] + il.Dup(); // stack: [data, ref index, ref result, ref result] + if(!type.IsArray) + ObjectConstructionHelper.EmitConstructionOfType(type, il); // stack: [data, ref index, ref result, ref result, new type()] + else + { + il.Ldc_I4(0); // stack: [data, ref index, ref result, ref result, 0] + il.Newarr(type.GetElementType()); // stack: [data, ref index, ref result, ref result, new elementType[0]] + } + il.Stind(typeof(object)); // result = new type(); stack: [data, ref index, ref result] + il.MarkLabel(notNullLabel); + } + il.Ldind(typeof(object)); // stack: [data, ref index, result] + il.Castclass(type); // stack: [data, ref index, (type)result] + il.Stloc(local); // local = (type)result; stack: [data, ref index] + } + else + { + il.Ldind(typeof(object)); // stack: [data, ref index, result] + var nullLabel = il.DefineLabel("null"); + il.Dup(); // stack: [data, ref index, length, result] + il.Brfalse(nullLabel); // if(result == null) goto null; stack: [data, ref index, result] + il.Unbox_Any(type); // stack: [data, ref result, (type)result] + il.Stloc(local); // local = (type)result, stack: [data, ref result] + var notNullLabel = il.DefineLabel("notNull"); + il.Br(notNullLabel); + il.MarkLabel(nullLabel); + il.Pop(); // stack: [data, ref index] + il.Ldloca(local); // stack: [data, ref index, ref local] + il.Initobj(type); // local = default(type); stack: [data, ref index] + il.MarkLabel(notNullLabel); + } + + il.Ldloca(local); // stack: [data, ref index, ref local] + il.Ldarg(3); // stack: [data, ref index, ref result, context] + il.Ldc_IntPtr(reader); + il.Calli(CallingConventions.Standard, typeof(void), new[] {typeof(IntPtr), typeof(int).MakeByRefType(), type.MakeByRefType(), typeof(ReaderContext)}); // reader(data, ref index, ref result, context); stack: [] + + il.Ldarg(2); // stack: [ref result] + il.Ldloc(local); // stack: [ref result, local] + if(type.IsValueType) + il.Box(type); // stack: [ref result, (object)local] + il.Stind(typeof(object)); // result = (object)local + + il.Ret(); + } + + return (ReaderDelegate)dynamicMethod.CreateDelegate(typeof(ReaderDelegate)); + } + + private readonly long serializerId; + private readonly IDataMembersExtractor dataMembersExtractor; + private readonly IGroBufCustomSerializerCollection customSerializerCollection; + private readonly GroBufOptions options; + private readonly Func factory; + private readonly Func baseFactory; + + private readonly Hashtable readers = new Hashtable(); + private readonly Hashtable readers2 = new Hashtable(); + private readonly Hashtable readers3 = new Hashtable(); + private readonly Hashtable readers4 = new Hashtable(); + internal readonly Hashtable readMethodsWithCustomSerialization = new Hashtable(); + private readonly Hashtable readMethodsWithoutCustomSerialization = new Hashtable(); + private readonly object readersLock = new object(); + private readonly object readMethodsLock = new object(); + private readonly ModuleBuilder module; + private readonly IReaderCollection readerCollection; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/GroBufReaderAttribute.cs b/GroBuf/GroBufReaderAttribute.cs similarity index 94% rename from GroBuf/GroBuf/GroBufReaderAttribute.cs rename to GroBuf/GroBufReaderAttribute.cs index b329717..00bc0ed 100644 --- a/GroBuf/GroBuf/GroBufReaderAttribute.cs +++ b/GroBuf/GroBufReaderAttribute.cs @@ -1,9 +1,9 @@ -using System; - -namespace GroBuf -{ - [AttributeUsage(AttributeTargets.Method)] - public class GroBufReaderAttribute : Attribute - { - } +using System; + +namespace GroBuf +{ + [AttributeUsage(AttributeTargets.Method)] + public class GroBufReaderAttribute : Attribute + { + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/GroBufSizeCounterAttribute.cs b/GroBuf/GroBufSizeCounterAttribute.cs similarity index 94% rename from GroBuf/GroBuf/GroBufSizeCounterAttribute.cs rename to GroBuf/GroBufSizeCounterAttribute.cs index 4ec6911..abd6df4 100644 --- a/GroBuf/GroBuf/GroBufSizeCounterAttribute.cs +++ b/GroBuf/GroBufSizeCounterAttribute.cs @@ -1,9 +1,9 @@ -using System; - -namespace GroBuf -{ - [AttributeUsage(AttributeTargets.Method)] - public class GroBufSizeCounterAttribute : Attribute - { - } +using System; + +namespace GroBuf +{ + [AttributeUsage(AttributeTargets.Method)] + public class GroBufSizeCounterAttribute : Attribute + { + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/GroBufTypeCode.cs b/GroBuf/GroBufTypeCode.cs similarity index 95% rename from GroBuf/GroBuf/GroBufTypeCode.cs rename to GroBuf/GroBufTypeCode.cs index b214407..f0085e2 100644 --- a/GroBuf/GroBuf/GroBufTypeCode.cs +++ b/GroBuf/GroBufTypeCode.cs @@ -1,119 +1,119 @@ -using System; -using System.Collections; - -namespace GroBuf -{ - public enum GroBufTypeCode - { - [DataLength(1)] - Empty = 0, - - [DataLength(-1)] - Object = 1, - - [DataLength(-1), LeafType(typeof(object[]))] - Array = 2, - - [DataLength(1), LeafType(typeof(sbyte))] - Int8 = 3, - - [DataLength(1), LeafType(typeof(byte))] - UInt8 = 4, - - [DataLength(2), LeafType(typeof(short))] - Int16 = 5, - - [DataLength(2), LeafType(typeof(ushort))] - UInt16 = 6, - - [DataLength(4), LeafType(typeof(int))] - Int32 = 7, - - [DataLength(4), LeafType(typeof(uint))] - UInt32 = 8, - - [DataLength(8), LeafType(typeof(long))] - Int64 = 9, - - [DataLength(8), LeafType(typeof(ulong))] - UInt64 = 10, - - [DataLength(4), LeafType(typeof(float))] - Single = 11, - - [DataLength(8), LeafType(typeof(double))] - Double = 12, - - [DataLength(16), LeafType(typeof(decimal))] - Decimal = 13, - - [DataLength(-1), LeafType(typeof(string))] - String = 14, - - [DataLength(16), LeafType(typeof(Guid))] - Guid = 15, - - [DataLength(8)] - Enum = 16, - - [DataLength(1), LeafType(typeof(bool))] - Boolean = 17, - - [DataLength(-2)] - DateTimeOld = 18, - - [DataLength(-1), LeafType(typeof(sbyte[]))] - Int8Array = 19, - - [DataLength(-1), LeafType(typeof(byte[]))] - UInt8Array = 20, - - [DataLength(-1), LeafType(typeof(short[]))] - Int16Array = 21, - - [DataLength(-1), LeafType(typeof(ushort[]))] - UInt16Array = 22, - - [DataLength(-1), LeafType(typeof(int[]))] - Int32Array = 23, - - [DataLength(-1), LeafType(typeof(uint[]))] - UInt32Array = 24, - - [DataLength(-1), LeafType(typeof(long[]))] - Int64Array = 25, - - [DataLength(-1), LeafType(typeof(ulong[]))] - UInt64Array = 26, - - [DataLength(-1), LeafType(typeof(float[]))] - SingleArray = 27, - - [DataLength(-1), LeafType(typeof(double[]))] - DoubleArray = 28, - - [DataLength(-1), LeafType(typeof(bool[]))] - BooleanArray = 29, - - [DataLength(-1), LeafType(typeof(Hashtable))] - Dictionary = 30, - - [DataLength(8), LeafType(typeof(DateTime))] - DateTimeNew = 31, - - [DataLength(4)] - Reference = 32, - - [DataLength(10)] - DateTimeOffset = 33, - - [DataLength(-1)] - Tuple = 34, - - [DataLength(-1)] - Reserved = 254, - - [DataLength(-1)] - CustomData = 255 - } +using System; +using System.Collections; + +namespace GroBuf +{ + public enum GroBufTypeCode + { + [DataLength(1)] + Empty = 0, + + [DataLength(-1)] + Object = 1, + + [DataLength(-1), LeafType(typeof(object[]))] + Array = 2, + + [DataLength(1), LeafType(typeof(sbyte))] + Int8 = 3, + + [DataLength(1), LeafType(typeof(byte))] + UInt8 = 4, + + [DataLength(2), LeafType(typeof(short))] + Int16 = 5, + + [DataLength(2), LeafType(typeof(ushort))] + UInt16 = 6, + + [DataLength(4), LeafType(typeof(int))] + Int32 = 7, + + [DataLength(4), LeafType(typeof(uint))] + UInt32 = 8, + + [DataLength(8), LeafType(typeof(long))] + Int64 = 9, + + [DataLength(8), LeafType(typeof(ulong))] + UInt64 = 10, + + [DataLength(4), LeafType(typeof(float))] + Single = 11, + + [DataLength(8), LeafType(typeof(double))] + Double = 12, + + [DataLength(16), LeafType(typeof(decimal))] + Decimal = 13, + + [DataLength(-1), LeafType(typeof(string))] + String = 14, + + [DataLength(16), LeafType(typeof(Guid))] + Guid = 15, + + [DataLength(8)] + Enum = 16, + + [DataLength(1), LeafType(typeof(bool))] + Boolean = 17, + + [DataLength(-2)] + DateTimeOld = 18, + + [DataLength(-1), LeafType(typeof(sbyte[]))] + Int8Array = 19, + + [DataLength(-1), LeafType(typeof(byte[]))] + UInt8Array = 20, + + [DataLength(-1), LeafType(typeof(short[]))] + Int16Array = 21, + + [DataLength(-1), LeafType(typeof(ushort[]))] + UInt16Array = 22, + + [DataLength(-1), LeafType(typeof(int[]))] + Int32Array = 23, + + [DataLength(-1), LeafType(typeof(uint[]))] + UInt32Array = 24, + + [DataLength(-1), LeafType(typeof(long[]))] + Int64Array = 25, + + [DataLength(-1), LeafType(typeof(ulong[]))] + UInt64Array = 26, + + [DataLength(-1), LeafType(typeof(float[]))] + SingleArray = 27, + + [DataLength(-1), LeafType(typeof(double[]))] + DoubleArray = 28, + + [DataLength(-1), LeafType(typeof(bool[]))] + BooleanArray = 29, + + [DataLength(-1), LeafType(typeof(Hashtable))] + Dictionary = 30, + + [DataLength(8), LeafType(typeof(DateTime))] + DateTimeNew = 31, + + [DataLength(4)] + Reference = 32, + + [DataLength(10)] + DateTimeOffset = 33, + + [DataLength(-1)] + Tuple = 34, + + [DataLength(-1)] + Reserved = 254, + + [DataLength(-1)] + CustomData = 255 + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/GroBufTypeCodeMap.cs b/GroBuf/GroBufTypeCodeMap.cs similarity index 97% rename from GroBuf/GroBuf/GroBufTypeCodeMap.cs rename to GroBuf/GroBufTypeCodeMap.cs index 05c0a74..1886e93 100644 --- a/GroBuf/GroBuf/GroBufTypeCodeMap.cs +++ b/GroBuf/GroBufTypeCodeMap.cs @@ -1,68 +1,68 @@ -using System; -using System.Collections; - -namespace GroBuf -{ - public static class GroBufTypeCodeMap - { - private static readonly GroBufTypeCode[] map = new[] - { - GroBufTypeCode.Empty, - GroBufTypeCode.Object, - GroBufTypeCode.Empty, - GroBufTypeCode.Boolean, - GroBufTypeCode.UInt16, - GroBufTypeCode.Int8, - GroBufTypeCode.UInt8, - GroBufTypeCode.Int16, - GroBufTypeCode.UInt16, - GroBufTypeCode.Int32, - GroBufTypeCode.UInt32, - GroBufTypeCode.Int64, - GroBufTypeCode.UInt64, - GroBufTypeCode.Single, - GroBufTypeCode.Double, - GroBufTypeCode.Decimal, - GroBufTypeCode.DateTimeNew, - GroBufTypeCode.Empty, - GroBufTypeCode.String, - }; - - private static readonly GroBufTypeCode[] mapItemToArray = BuildItemToArrayMap(); - - private static GroBufTypeCode[] BuildItemToArrayMap() - { - var result = new GroBufTypeCode[256]; - for(int i = 0; i < 256; ++i) - result[i] = GroBufTypeCode.Array; - result[(int)GroBufTypeCode.Int8] = GroBufTypeCode.Int8Array; - result[(int)GroBufTypeCode.UInt8] = GroBufTypeCode.UInt8Array; - result[(int)GroBufTypeCode.Int16] = GroBufTypeCode.Int16Array; - result[(int)GroBufTypeCode.UInt16] = GroBufTypeCode.UInt16Array; - result[(int)GroBufTypeCode.Int32] = GroBufTypeCode.Int32Array; - result[(int)GroBufTypeCode.UInt32] = GroBufTypeCode.UInt32Array; - result[(int)GroBufTypeCode.Int64] = GroBufTypeCode.Int64Array; - result[(int)GroBufTypeCode.UInt64] = GroBufTypeCode.UInt64Array; - result[(int)GroBufTypeCode.Single] = GroBufTypeCode.SingleArray; - result[(int)GroBufTypeCode.Double] = GroBufTypeCode.DoubleArray; - result[(int)GroBufTypeCode.Boolean] = GroBufTypeCode.BooleanArray; - return result; - } - - public static GroBufTypeCode GetTypeCode(Type type) - { - var result = map[(int)Type.GetTypeCode(type)]; - if(result != GroBufTypeCode.Object) - return result; - if (type.IsEnum) - return GroBufTypeCode.Enum; - if (type.IsArray && type.GetArrayRank() == 1) - return mapItemToArray[(int)GetTypeCode(type.GetElementType())]; - if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ArraySegment<>)) - return mapItemToArray[(int)GetTypeCode(type.GetGenericArguments()[0])]; - if(type == typeof(Guid)) return GroBufTypeCode.Guid; - if(type == typeof(Hashtable)) return GroBufTypeCode.Dictionary; - return GroBufTypeCode.Object; - } - } +using System; +using System.Collections; + +namespace GroBuf +{ + public static class GroBufTypeCodeMap + { + private static readonly GroBufTypeCode[] map = new[] + { + GroBufTypeCode.Empty, + GroBufTypeCode.Object, + GroBufTypeCode.Empty, + GroBufTypeCode.Boolean, + GroBufTypeCode.UInt16, + GroBufTypeCode.Int8, + GroBufTypeCode.UInt8, + GroBufTypeCode.Int16, + GroBufTypeCode.UInt16, + GroBufTypeCode.Int32, + GroBufTypeCode.UInt32, + GroBufTypeCode.Int64, + GroBufTypeCode.UInt64, + GroBufTypeCode.Single, + GroBufTypeCode.Double, + GroBufTypeCode.Decimal, + GroBufTypeCode.DateTimeNew, + GroBufTypeCode.Empty, + GroBufTypeCode.String, + }; + + private static readonly GroBufTypeCode[] mapItemToArray = BuildItemToArrayMap(); + + private static GroBufTypeCode[] BuildItemToArrayMap() + { + var result = new GroBufTypeCode[256]; + for(int i = 0; i < 256; ++i) + result[i] = GroBufTypeCode.Array; + result[(int)GroBufTypeCode.Int8] = GroBufTypeCode.Int8Array; + result[(int)GroBufTypeCode.UInt8] = GroBufTypeCode.UInt8Array; + result[(int)GroBufTypeCode.Int16] = GroBufTypeCode.Int16Array; + result[(int)GroBufTypeCode.UInt16] = GroBufTypeCode.UInt16Array; + result[(int)GroBufTypeCode.Int32] = GroBufTypeCode.Int32Array; + result[(int)GroBufTypeCode.UInt32] = GroBufTypeCode.UInt32Array; + result[(int)GroBufTypeCode.Int64] = GroBufTypeCode.Int64Array; + result[(int)GroBufTypeCode.UInt64] = GroBufTypeCode.UInt64Array; + result[(int)GroBufTypeCode.Single] = GroBufTypeCode.SingleArray; + result[(int)GroBufTypeCode.Double] = GroBufTypeCode.DoubleArray; + result[(int)GroBufTypeCode.Boolean] = GroBufTypeCode.BooleanArray; + return result; + } + + public static GroBufTypeCode GetTypeCode(Type type) + { + var result = map[(int)Type.GetTypeCode(type)]; + if(result != GroBufTypeCode.Object) + return result; + if (type.IsEnum) + return GroBufTypeCode.Enum; + if (type.IsArray && type.GetArrayRank() == 1) + return mapItemToArray[(int)GetTypeCode(type.GetElementType())]; + if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ArraySegment<>)) + return mapItemToArray[(int)GetTypeCode(type.GetGenericArguments()[0])]; + if(type == typeof(Guid)) return GroBufTypeCode.Guid; + if(type == typeof(Hashtable)) return GroBufTypeCode.Dictionary; + return GroBufTypeCode.Object; + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/GroBufWriter.cs b/GroBuf/GroBufWriter.cs similarity index 97% rename from GroBuf/GroBuf/GroBufWriter.cs rename to GroBuf/GroBufWriter.cs index f9016ab..9125956 100644 --- a/GroBuf/GroBuf/GroBufWriter.cs +++ b/GroBuf/GroBufWriter.cs @@ -1,379 +1,379 @@ -using System; -using System.Collections; -using System.Reflection; -using System.Reflection.Emit; - -using GrEmit; - -using GroBuf.DataMembersExtracters; -using GroBuf.SizeCounters; -using GroBuf.Writers; - -namespace GroBuf -{ - internal class GroBufWriter - { - public GroBufWriter(long serializerId, IDataMembersExtractor dataMembersExtractor, IGroBufCustomSerializerCollection customSerializerCollection, GroBufOptions options, Func factory, Func baseFactory) - { - this.serializerId = serializerId; - this.dataMembersExtractor = dataMembersExtractor; - this.options = options; - sizeCounterCollection = new SizeCounterCollection(customSerializerCollection, factory, baseFactory); - writerCollection = new WriterCollection(customSerializerCollection, factory, baseFactory); - assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run); - module = assembly.DefineDynamicModule(Guid.NewGuid().ToString()); - trackReferences = options.HasFlag(GroBufOptions.PackReferences); - } - - public int GetSize(T obj) - { - return GetSize(false, obj, true); - } - - public void Write(T obj, IntPtr result, int length) - { - int index = 0; - Write(false, obj, result, ref index, length); - if (index != length) - throw new Exception("Bug: at the end of serialization index must point at the end of array"); - } - - private void Write(bool ignoreCustomSerialization, T obj, IntPtr result, ref int index, int length) - { - var writerAndSizeCounter = GetWriterAndSizeCounter(ignoreCustomSerialization); - if(!trackReferences) - writerAndSizeCounter.Item1(obj, true, result, ref index, new WriterContext(serializerId, length, index, trackReferences)); - else - { - var context = new WriterContext(serializerId, length, index, trackReferences); - writerAndSizeCounter.Item2(obj, true, context); - Write(obj, result, ref index, writerAndSizeCounter.Item1, context); - } - } - - public unsafe void Write(T obj, byte[] result, ref int index) - { - fixed (byte* r = &result[0]) - Write(false, obj, (IntPtr)r, ref index, result.Length); - } - - public void Write(T obj, IntPtr result, ref int index, int length) - { - Write(false, obj, result, ref index, length); - } - - public byte[] Write(T obj) - { - return Write(false, obj); - } - - public unsafe byte[] Write(bool ignoreCustomSerialization, T obj) - { - var writerAndCounter = GetWriterAndSizeCounter(ignoreCustomSerialization); - var context = new WriterContext(serializerId, 0, 0, trackReferences); - var size = writerAndCounter.Item2(obj, true, context); - size = context.references > 0 ? size + 5 : size; - var result = new byte[size]; - context.length = size; - int index = 0; - fixed(byte* r = &result[0]) - Write(obj, (IntPtr)r, ref index, writerAndCounter.Item1, context); - if (index != size) - throw new Exception("Bug: at the end of serialization index must point at the end of array"); - return result; - } - - private unsafe void Write(T obj, IntPtr data, ref int index, WriterDelegate writer, WriterContext context) - { - if (context.references > 0) - { - var r = (byte*)(data + index); - *r = (byte)GroBufTypeCode.Reference; - *(int*)(r + 1) = context.references; - index += 5; - } - context.start = index; - writer(obj, true, data, ref index, new WriterContext(serializerId, context.length, context.start, trackReferences)); - } - - private unsafe void Write(object obj, IntPtr data, ref int index, WriterDelegate writer, WriterContext context) - { - if (context.references > 0) - { - var r = (byte*)(data + index); - *r = (byte)GroBufTypeCode.Reference; - *(int*)(r + 1) = context.references; - index += 5; - } - context.start = index; - writer(obj, true, data, ref index, new WriterContext(serializerId, context.length, context.start, trackReferences)); - } - - public int GetSize(Type type, object obj) - { - var context = new WriterContext(serializerId, 0, 0, trackReferences); - var result = GetSize(type, false, obj, true, context); - return context.references > 0 ? result + 5 : result; - } - - public void Write(Type type, object obj, IntPtr result, int length) - { - int index = 0; - Write(type, false, obj, result, ref index, length); - if (index != length) - throw new Exception("Bug: at the end of serialization index must point at the end of array"); - } - - private void Write(Type type, bool ignoreCustomSerialization, object obj, IntPtr result, ref int index, int length) - { - var writerAndSizeCounter = GetWriterAndSizeCounter(type, ignoreCustomSerialization); - if (!trackReferences) - writerAndSizeCounter.Item1(obj, true, result, ref index, new WriterContext(serializerId, length, index, trackReferences)); - else - { - var context = new WriterContext(serializerId, length, index, trackReferences); - writerAndSizeCounter.Item2(obj, true, context); - Write(obj, result, ref index, writerAndSizeCounter.Item1, context); - } - } - - public void Write(Type type, object obj, IntPtr result, ref int index, int length) - { - Write(type, false, obj, result, ref index, length); - } - - public void Write(Type type, object obj, byte[] result, ref int index) - { - Write(type, false, obj, result, ref index); - } - - public unsafe void Write(Type type, bool ignoreCustomSerialization, object obj, byte[] result, ref int index) - { - fixed (byte* r = &result[0]) - Write(type, ignoreCustomSerialization, obj, (IntPtr)r, ref index, result.Length); - } - - public void Write(Type type, bool ignoreCustomSerialization, object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) - { - GetWriterAndSizeCounter(type, ignoreCustomSerialization).Item1(obj, writeEmpty, result, ref index, context); - } - - public byte[] Write(Type type, object obj) - { - return Write(type, false, obj); - } - - private unsafe byte[] Write(Type type, bool ignoreCustomSerialization, object obj) - { - var writerAndCounter = GetWriterAndSizeCounter(type, ignoreCustomSerialization); - var context = new WriterContext(serializerId, 0, 0, trackReferences); - var size = writerAndCounter.Item2(obj, true, context); - size = context.references > 0 ? size + 5 : size; - var result = new byte[size]; - context.length = size; - int index = 0; - fixed(byte* r = &result[0]) - Write(obj, (IntPtr)r, ref index, writerAndCounter.Item1, context); - if(index != size) - throw new Exception("At the end of serialization index must point at the end of array"); - return result; - } - - public int GetSize(Type type, bool ignoreCustomSerialization, object obj, bool writeEmpty, WriterContext context) - { - return GetWriterAndSizeCounter(type, ignoreCustomSerialization).Item2(obj, writeEmpty, context); - } - - public GroBufOptions Options { get { return options; } } - - private int GetSize(bool ignoreCustomSerialization, T obj, bool writeEmpty) - { - var context = new WriterContext(serializerId, 0, 0, trackReferences); - var result = GetWriterAndSizeCounter(ignoreCustomSerialization).Item2(obj, writeEmpty, context); - return context.references > 0 ? result + 5 : result; - } - - private Tuple GetWriterAndSizeCounter(Type type, bool ignoreCustomSerialization) - { - var hashtable = ignoreCustomSerialization ? writersAndSizeCounters3 : writersAndSizeCounters2; - var writerAndSizeCounter = (Tuple)hashtable[type]; - if(writerAndSizeCounter == null) - { - lock(writersAndSizeCountersLock) - { - writerAndSizeCounter = (Tuple)hashtable[type]; - if(writerAndSizeCounter == null) - { - writerAndSizeCounter = new Tuple(BuildWriter(type, ignoreCustomSerialization), BuildCounter(type, ignoreCustomSerialization)); - hashtable[type] = writerAndSizeCounter; - } - } - } - return writerAndSizeCounter; - } - - private Tuple, SizeCounterDelegate> GetWriterAndSizeCounter(bool ignoreCustomSerialization) - { - var hashtable = ignoreCustomSerialization ? writersAndSizeCounters4 : writersAndSizeCounters; - var type = typeof(T); - var writerAndSizeCounter = (Tuple, SizeCounterDelegate>)hashtable[type]; - if(writerAndSizeCounter == null) - { - lock(writersAndSizeCountersLock) - { - writerAndSizeCounter = (Tuple, SizeCounterDelegate>)hashtable[type]; - if(writerAndSizeCounter == null) - { - writerAndSizeCounter = new Tuple, SizeCounterDelegate>(BuildWriter(ignoreCustomSerialization), BuildCounter(ignoreCustomSerialization)); - hashtable[type] = writerAndSizeCounter; - } - } - } - return writerAndSizeCounter; - } - - private IntPtr GetWriter(Type type, bool ignoreCustomSerialization) - { - var hashtable = ignoreCustomSerialization ? writersWithoutCustomSerialization : writersWithCustomSerialization; - var writer = (IntPtr?)hashtable[type]; - if(writer == null) - { - lock(writersLock) - { - writer = (IntPtr?)hashtable[type]; - if(writer == null) - { - writer = new WriterTypeBuilder(this, module, writerCollection, dataMembersExtractor).BuildWriter(type, ignoreCustomSerialization); - hashtable[type] = writer; - } - } - } - return writer.Value; - } - - private WriterDelegate BuildWriter(bool ignoreCustomSerialization) - { - var type = typeof(T); - IntPtr writer = GetWriter(type, ignoreCustomSerialization); - - var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] {type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext)}, module, true); - using (var il = new GroboIL(dynamicMethod)) - { - il.Ldarg(0); // stack: [obj] - il.Ldarg(1); // stack: [obj, writeEmpty] - il.Ldarg(2); // stack: [obj, writeEmpty, result] - il.Ldarg(3); // stack: [obj, writeEmpty, result, ref index] - il.Ldarg(4); // stack: [obj, writeEmpty, result, ref index, context] - il.Ldc_IntPtr(writer); - il.Calli(CallingConventions.Standard, typeof(void), new[] {type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext)}); // writer.write(obj, writeEmpty, result, ref index, context); stack: [] - il.Ret(); - } - - return (WriterDelegate)dynamicMethod.CreateDelegate(typeof(WriterDelegate)); - } - - private WriterDelegate BuildWriter(Type type, bool ignoreCustomSerialization) - { - IntPtr writer = GetWriter(type, ignoreCustomSerialization); - - var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] {typeof(object), typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext)}, module, true); - using (var il = new GroboIL(dynamicMethod)) - { - il.Ldarg(0); // stack: [obj] - if(type.IsValueType) - il.Unbox_Any(type); // stack: [(type)obj] - else - il.Castclass(type); // stack: [(type)obj] - il.Ldarg(1); // stack: [(type)obj, writeEmpty] - il.Ldarg(2); // stack: [(type)obj, writeEmpty, result] - il.Ldarg(3); // stack: [(type)obj, writeEmpty, result, ref index] - il.Ldarg(4); // stack: [(type)obj, writeEmpty, result, ref index, context] - il.Ldc_IntPtr(writer); - il.Calli(CallingConventions.Standard, typeof(void), new[] {type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext)}); // writer.write((type)obj, writeEmpty, result, ref index, context); stack: [] - il.Ret(); - } - - return (WriterDelegate)dynamicMethod.CreateDelegate(typeof(WriterDelegate)); - } - - private IntPtr GetCounter(Type type, bool ignoreCustomSerialization) - { - var hashtable = ignoreCustomSerialization ? countersWithoutCustomSerialization : countersWithCustomSerialization; - var counter = (IntPtr?)hashtable[type]; - if(counter == null) - { - lock(countersLock) - { - counter = (IntPtr?)hashtable[type]; - if(counter == null) - { - counter = new SizeCounterTypeBuilder(this, module, sizeCounterCollection, dataMembersExtractor).BuildSizeCounter(type, ignoreCustomSerialization); - hashtable[type] = counter; - } - } - } - return counter.Value; - } - - private SizeCounterDelegate BuildCounter(bool ignoreCustomSerialization) - { - var type = typeof(T); - IntPtr counter = GetCounter(type, ignoreCustomSerialization); - - var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] {type, typeof(bool), typeof(WriterContext)}, GetType(), true); - using (var il = new GroboIL(dynamicMethod)) - { - il.Ldarg(0); // stack: [obj] - il.Ldarg(1); // stack: [obj, writeEmpty] - il.Ldarg(2); // stack: [obj, writeEmpty, context] - il.Ldc_IntPtr(counter); // stack: [obj, writeEmpty, context, counter] - il.Calli(CallingConventions.Standard, typeof(int), new[] {type, typeof(bool), typeof(WriterContext)}); // counter(obj, writeEmpty, context); stack: [] - il.Ret(); - } - return (SizeCounterDelegate)dynamicMethod.CreateDelegate(typeof(SizeCounterDelegate)); - } - - private SizeCounterDelegate BuildCounter(Type type, bool ignoreCustomSerialization) - { - IntPtr counter = GetCounter(type, ignoreCustomSerialization); - - var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] {typeof(object), typeof(bool), typeof(WriterContext)}, GetType(), true); - using (var il = new GroboIL(dynamicMethod)) - { - il.Ldarg(0); // stack: [obj] - if(type.IsValueType) - il.Unbox_Any(type); // stack: [(type)obj] - else - il.Castclass(type); // stack: [(type)obj] - il.Ldarg(1); // stack: [(type)obj, writeEmpty] - il.Ldarg(2); // stack: [(type)obj, writeEmpty, context] - il.Ldc_IntPtr(counter); // stack: [(type)obj, writeEmpty, context, counter] - il.Calli(CallingConventions.Standard, typeof(int), new[] {type, typeof(bool), typeof(WriterContext)}); // counter((type)obj, writeEmpty, context); stack: [] - il.Ret(); - } - - return (SizeCounterDelegate)dynamicMethod.CreateDelegate(typeof(SizeCounterDelegate)); - } - - private readonly long serializerId; - private readonly IDataMembersExtractor dataMembersExtractor; - private readonly GroBufOptions options; - - private readonly Hashtable writersAndSizeCounters = new Hashtable(); - private readonly Hashtable writersAndSizeCounters2 = new Hashtable(); - private readonly Hashtable writersAndSizeCounters3 = new Hashtable(); - private readonly Hashtable writersAndSizeCounters4 = new Hashtable(); - internal readonly Hashtable writersWithCustomSerialization = new Hashtable(); - private readonly Hashtable writersWithoutCustomSerialization = new Hashtable(); - internal readonly Hashtable countersWithCustomSerialization = new Hashtable(); - private readonly Hashtable countersWithoutCustomSerialization = new Hashtable(); - private readonly object writersAndSizeCountersLock = new object(); - private readonly object writersLock = new object(); - private readonly object countersLock = new object(); - private readonly IWriterCollection writerCollection; - private readonly ISizeCounterCollection sizeCounterCollection; - private readonly AssemblyBuilder assembly; - private readonly ModuleBuilder module; - private bool trackReferences; - } +using System; +using System.Collections; +using System.Reflection; +using System.Reflection.Emit; + +using GrEmit; + +using GroBuf.DataMembersExtracters; +using GroBuf.SizeCounters; +using GroBuf.Writers; + +namespace GroBuf +{ + internal class GroBufWriter + { + public GroBufWriter(long serializerId, IDataMembersExtractor dataMembersExtractor, IGroBufCustomSerializerCollection customSerializerCollection, GroBufOptions options, Func factory, Func baseFactory) + { + this.serializerId = serializerId; + this.dataMembersExtractor = dataMembersExtractor; + this.options = options; + sizeCounterCollection = new SizeCounterCollection(customSerializerCollection, factory, baseFactory); + writerCollection = new WriterCollection(customSerializerCollection, factory, baseFactory); + assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run); + module = assembly.DefineDynamicModule(Guid.NewGuid().ToString()); + trackReferences = options.HasFlag(GroBufOptions.PackReferences); + } + + public int GetSize(T obj) + { + return GetSize(false, obj, true); + } + + public void Write(T obj, IntPtr result, int length) + { + int index = 0; + Write(false, obj, result, ref index, length); + if (index != length) + throw new Exception("Bug: at the end of serialization index must point at the end of array"); + } + + private void Write(bool ignoreCustomSerialization, T obj, IntPtr result, ref int index, int length) + { + var writerAndSizeCounter = GetWriterAndSizeCounter(ignoreCustomSerialization); + if(!trackReferences) + writerAndSizeCounter.Item1(obj, true, result, ref index, new WriterContext(serializerId, length, index, trackReferences)); + else + { + var context = new WriterContext(serializerId, length, index, trackReferences); + writerAndSizeCounter.Item2(obj, true, context); + Write(obj, result, ref index, writerAndSizeCounter.Item1, context); + } + } + + public unsafe void Write(T obj, byte[] result, ref int index) + { + fixed (byte* r = &result[0]) + Write(false, obj, (IntPtr)r, ref index, result.Length); + } + + public void Write(T obj, IntPtr result, ref int index, int length) + { + Write(false, obj, result, ref index, length); + } + + public byte[] Write(T obj) + { + return Write(false, obj); + } + + public unsafe byte[] Write(bool ignoreCustomSerialization, T obj) + { + var writerAndCounter = GetWriterAndSizeCounter(ignoreCustomSerialization); + var context = new WriterContext(serializerId, 0, 0, trackReferences); + var size = writerAndCounter.Item2(obj, true, context); + size = context.references > 0 ? size + 5 : size; + var result = new byte[size]; + context.length = size; + int index = 0; + fixed(byte* r = &result[0]) + Write(obj, (IntPtr)r, ref index, writerAndCounter.Item1, context); + if (index != size) + throw new Exception("Bug: at the end of serialization index must point at the end of array"); + return result; + } + + private unsafe void Write(T obj, IntPtr data, ref int index, WriterDelegate writer, WriterContext context) + { + if (context.references > 0) + { + var r = (byte*)(data + index); + *r = (byte)GroBufTypeCode.Reference; + *(int*)(r + 1) = context.references; + index += 5; + } + context.start = index; + writer(obj, true, data, ref index, new WriterContext(serializerId, context.length, context.start, trackReferences)); + } + + private unsafe void Write(object obj, IntPtr data, ref int index, WriterDelegate writer, WriterContext context) + { + if (context.references > 0) + { + var r = (byte*)(data + index); + *r = (byte)GroBufTypeCode.Reference; + *(int*)(r + 1) = context.references; + index += 5; + } + context.start = index; + writer(obj, true, data, ref index, new WriterContext(serializerId, context.length, context.start, trackReferences)); + } + + public int GetSize(Type type, object obj) + { + var context = new WriterContext(serializerId, 0, 0, trackReferences); + var result = GetSize(type, false, obj, true, context); + return context.references > 0 ? result + 5 : result; + } + + public void Write(Type type, object obj, IntPtr result, int length) + { + int index = 0; + Write(type, false, obj, result, ref index, length); + if (index != length) + throw new Exception("Bug: at the end of serialization index must point at the end of array"); + } + + private void Write(Type type, bool ignoreCustomSerialization, object obj, IntPtr result, ref int index, int length) + { + var writerAndSizeCounter = GetWriterAndSizeCounter(type, ignoreCustomSerialization); + if (!trackReferences) + writerAndSizeCounter.Item1(obj, true, result, ref index, new WriterContext(serializerId, length, index, trackReferences)); + else + { + var context = new WriterContext(serializerId, length, index, trackReferences); + writerAndSizeCounter.Item2(obj, true, context); + Write(obj, result, ref index, writerAndSizeCounter.Item1, context); + } + } + + public void Write(Type type, object obj, IntPtr result, ref int index, int length) + { + Write(type, false, obj, result, ref index, length); + } + + public void Write(Type type, object obj, byte[] result, ref int index) + { + Write(type, false, obj, result, ref index); + } + + public unsafe void Write(Type type, bool ignoreCustomSerialization, object obj, byte[] result, ref int index) + { + fixed (byte* r = &result[0]) + Write(type, ignoreCustomSerialization, obj, (IntPtr)r, ref index, result.Length); + } + + public void Write(Type type, bool ignoreCustomSerialization, object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) + { + GetWriterAndSizeCounter(type, ignoreCustomSerialization).Item1(obj, writeEmpty, result, ref index, context); + } + + public byte[] Write(Type type, object obj) + { + return Write(type, false, obj); + } + + private unsafe byte[] Write(Type type, bool ignoreCustomSerialization, object obj) + { + var writerAndCounter = GetWriterAndSizeCounter(type, ignoreCustomSerialization); + var context = new WriterContext(serializerId, 0, 0, trackReferences); + var size = writerAndCounter.Item2(obj, true, context); + size = context.references > 0 ? size + 5 : size; + var result = new byte[size]; + context.length = size; + int index = 0; + fixed(byte* r = &result[0]) + Write(obj, (IntPtr)r, ref index, writerAndCounter.Item1, context); + if(index != size) + throw new Exception("At the end of serialization index must point at the end of array"); + return result; + } + + public int GetSize(Type type, bool ignoreCustomSerialization, object obj, bool writeEmpty, WriterContext context) + { + return GetWriterAndSizeCounter(type, ignoreCustomSerialization).Item2(obj, writeEmpty, context); + } + + public GroBufOptions Options { get { return options; } } + + private int GetSize(bool ignoreCustomSerialization, T obj, bool writeEmpty) + { + var context = new WriterContext(serializerId, 0, 0, trackReferences); + var result = GetWriterAndSizeCounter(ignoreCustomSerialization).Item2(obj, writeEmpty, context); + return context.references > 0 ? result + 5 : result; + } + + private Tuple GetWriterAndSizeCounter(Type type, bool ignoreCustomSerialization) + { + var hashtable = ignoreCustomSerialization ? writersAndSizeCounters3 : writersAndSizeCounters2; + var writerAndSizeCounter = (Tuple)hashtable[type]; + if(writerAndSizeCounter == null) + { + lock(writersAndSizeCountersLock) + { + writerAndSizeCounter = (Tuple)hashtable[type]; + if(writerAndSizeCounter == null) + { + writerAndSizeCounter = new Tuple(BuildWriter(type, ignoreCustomSerialization), BuildCounter(type, ignoreCustomSerialization)); + hashtable[type] = writerAndSizeCounter; + } + } + } + return writerAndSizeCounter; + } + + private Tuple, SizeCounterDelegate> GetWriterAndSizeCounter(bool ignoreCustomSerialization) + { + var hashtable = ignoreCustomSerialization ? writersAndSizeCounters4 : writersAndSizeCounters; + var type = typeof(T); + var writerAndSizeCounter = (Tuple, SizeCounterDelegate>)hashtable[type]; + if(writerAndSizeCounter == null) + { + lock(writersAndSizeCountersLock) + { + writerAndSizeCounter = (Tuple, SizeCounterDelegate>)hashtable[type]; + if(writerAndSizeCounter == null) + { + writerAndSizeCounter = new Tuple, SizeCounterDelegate>(BuildWriter(ignoreCustomSerialization), BuildCounter(ignoreCustomSerialization)); + hashtable[type] = writerAndSizeCounter; + } + } + } + return writerAndSizeCounter; + } + + private IntPtr GetWriter(Type type, bool ignoreCustomSerialization) + { + var hashtable = ignoreCustomSerialization ? writersWithoutCustomSerialization : writersWithCustomSerialization; + var writer = (IntPtr?)hashtable[type]; + if(writer == null) + { + lock(writersLock) + { + writer = (IntPtr?)hashtable[type]; + if(writer == null) + { + writer = new WriterTypeBuilder(this, module, writerCollection, dataMembersExtractor).BuildWriter(type, ignoreCustomSerialization); + hashtable[type] = writer; + } + } + } + return writer.Value; + } + + private WriterDelegate BuildWriter(bool ignoreCustomSerialization) + { + var type = typeof(T); + IntPtr writer = GetWriter(type, ignoreCustomSerialization); + + var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] {type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext)}, module, true); + using (var il = new GroboIL(dynamicMethod)) + { + il.Ldarg(0); // stack: [obj] + il.Ldarg(1); // stack: [obj, writeEmpty] + il.Ldarg(2); // stack: [obj, writeEmpty, result] + il.Ldarg(3); // stack: [obj, writeEmpty, result, ref index] + il.Ldarg(4); // stack: [obj, writeEmpty, result, ref index, context] + il.Ldc_IntPtr(writer); + il.Calli(CallingConventions.Standard, typeof(void), new[] {type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext)}); // writer.write(obj, writeEmpty, result, ref index, context); stack: [] + il.Ret(); + } + + return (WriterDelegate)dynamicMethod.CreateDelegate(typeof(WriterDelegate)); + } + + private WriterDelegate BuildWriter(Type type, bool ignoreCustomSerialization) + { + IntPtr writer = GetWriter(type, ignoreCustomSerialization); + + var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(void), new[] {typeof(object), typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext)}, module, true); + using (var il = new GroboIL(dynamicMethod)) + { + il.Ldarg(0); // stack: [obj] + if(type.IsValueType) + il.Unbox_Any(type); // stack: [(type)obj] + else + il.Castclass(type); // stack: [(type)obj] + il.Ldarg(1); // stack: [(type)obj, writeEmpty] + il.Ldarg(2); // stack: [(type)obj, writeEmpty, result] + il.Ldarg(3); // stack: [(type)obj, writeEmpty, result, ref index] + il.Ldarg(4); // stack: [(type)obj, writeEmpty, result, ref index, context] + il.Ldc_IntPtr(writer); + il.Calli(CallingConventions.Standard, typeof(void), new[] {type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext)}); // writer.write((type)obj, writeEmpty, result, ref index, context); stack: [] + il.Ret(); + } + + return (WriterDelegate)dynamicMethod.CreateDelegate(typeof(WriterDelegate)); + } + + private IntPtr GetCounter(Type type, bool ignoreCustomSerialization) + { + var hashtable = ignoreCustomSerialization ? countersWithoutCustomSerialization : countersWithCustomSerialization; + var counter = (IntPtr?)hashtable[type]; + if(counter == null) + { + lock(countersLock) + { + counter = (IntPtr?)hashtable[type]; + if(counter == null) + { + counter = new SizeCounterTypeBuilder(this, module, sizeCounterCollection, dataMembersExtractor).BuildSizeCounter(type, ignoreCustomSerialization); + hashtable[type] = counter; + } + } + } + return counter.Value; + } + + private SizeCounterDelegate BuildCounter(bool ignoreCustomSerialization) + { + var type = typeof(T); + IntPtr counter = GetCounter(type, ignoreCustomSerialization); + + var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] {type, typeof(bool), typeof(WriterContext)}, GetType(), true); + using (var il = new GroboIL(dynamicMethod)) + { + il.Ldarg(0); // stack: [obj] + il.Ldarg(1); // stack: [obj, writeEmpty] + il.Ldarg(2); // stack: [obj, writeEmpty, context] + il.Ldc_IntPtr(counter); // stack: [obj, writeEmpty, context, counter] + il.Calli(CallingConventions.Standard, typeof(int), new[] {type, typeof(bool), typeof(WriterContext)}); // counter(obj, writeEmpty, context); stack: [] + il.Ret(); + } + return (SizeCounterDelegate)dynamicMethod.CreateDelegate(typeof(SizeCounterDelegate)); + } + + private SizeCounterDelegate BuildCounter(Type type, bool ignoreCustomSerialization) + { + IntPtr counter = GetCounter(type, ignoreCustomSerialization); + + var dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] {typeof(object), typeof(bool), typeof(WriterContext)}, GetType(), true); + using (var il = new GroboIL(dynamicMethod)) + { + il.Ldarg(0); // stack: [obj] + if(type.IsValueType) + il.Unbox_Any(type); // stack: [(type)obj] + else + il.Castclass(type); // stack: [(type)obj] + il.Ldarg(1); // stack: [(type)obj, writeEmpty] + il.Ldarg(2); // stack: [(type)obj, writeEmpty, context] + il.Ldc_IntPtr(counter); // stack: [(type)obj, writeEmpty, context, counter] + il.Calli(CallingConventions.Standard, typeof(int), new[] {type, typeof(bool), typeof(WriterContext)}); // counter((type)obj, writeEmpty, context); stack: [] + il.Ret(); + } + + return (SizeCounterDelegate)dynamicMethod.CreateDelegate(typeof(SizeCounterDelegate)); + } + + private readonly long serializerId; + private readonly IDataMembersExtractor dataMembersExtractor; + private readonly GroBufOptions options; + + private readonly Hashtable writersAndSizeCounters = new Hashtable(); + private readonly Hashtable writersAndSizeCounters2 = new Hashtable(); + private readonly Hashtable writersAndSizeCounters3 = new Hashtable(); + private readonly Hashtable writersAndSizeCounters4 = new Hashtable(); + internal readonly Hashtable writersWithCustomSerialization = new Hashtable(); + private readonly Hashtable writersWithoutCustomSerialization = new Hashtable(); + internal readonly Hashtable countersWithCustomSerialization = new Hashtable(); + private readonly Hashtable countersWithoutCustomSerialization = new Hashtable(); + private readonly object writersAndSizeCountersLock = new object(); + private readonly object writersLock = new object(); + private readonly object countersLock = new object(); + private readonly IWriterCollection writerCollection; + private readonly ISizeCounterCollection sizeCounterCollection; + private readonly AssemblyBuilder assembly; + private readonly ModuleBuilder module; + private bool trackReferences; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/GroBufWriterAttribute.cs b/GroBuf/GroBufWriterAttribute.cs similarity index 94% rename from GroBuf/GroBuf/GroBufWriterAttribute.cs rename to GroBuf/GroBufWriterAttribute.cs index 1337a2d..a16c686 100644 --- a/GroBuf/GroBuf/GroBufWriterAttribute.cs +++ b/GroBuf/GroBufWriterAttribute.cs @@ -1,9 +1,9 @@ -using System; - -namespace GroBuf -{ - [AttributeUsage(AttributeTargets.Method)] - public class GroBufWriterAttribute : Attribute - { - } +using System; + +namespace GroBuf +{ + [AttributeUsage(AttributeTargets.Method)] + public class GroBufWriterAttribute : Attribute + { + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/HashCalculator.cs b/GroBuf/HashCalculator.cs similarity index 97% rename from GroBuf/GroBuf/HashCalculator.cs rename to GroBuf/HashCalculator.cs index 24f8106..7d6f0c8 100644 --- a/GroBuf/GroBuf/HashCalculator.cs +++ b/GroBuf/HashCalculator.cs @@ -1,45 +1,45 @@ -using System; - -namespace GroBuf -{ - public class HashCalculator - { - public HashCalculator(int seed, int maxLength) - { - this.seed = seed; - this.maxLength = maxLength; - randTable = InitRandTable(maxLength * 2); - } - - public ulong CalcHash(string str) - { - if(str.Length > maxLength) - throw new NotSupportedException(string.Format("Names with length greater than {0}", maxLength)); - ulong result = 0; - for(int i = 0; i < str.Length; ++i) - { - result ^= randTable[2 * i][str[i] & 0xFF]; - result ^= randTable[2 * i + 1][(str[i] >> 8) & 0xFF]; - } - return result; - } - - private ulong[][] InitRandTable(int count) - { - var random = new GroBufRandom(seed); - var table = new ulong[count][]; - for(int len = 0; len < count; ++len) - { - var arr = new ulong[256]; - for(int i = 0; i < arr.Length; ++i) - arr[i] = ((ulong)(random.Next() & 0xFFFFFF)) | (((ulong)(random.Next() & 0xFFFFFF)) << 24) | (((ulong)(random.Next() & 0xFFFFFF)) << 48); - table[len] = arr; - } - return table; - } - - private readonly int seed; - private readonly int maxLength; - private readonly ulong[][] randTable; - } +using System; + +namespace GroBuf +{ + public class HashCalculator + { + public HashCalculator(int seed, int maxLength) + { + this.seed = seed; + this.maxLength = maxLength; + randTable = InitRandTable(maxLength * 2); + } + + public ulong CalcHash(string str) + { + if(str.Length > maxLength) + throw new NotSupportedException(string.Format("Names with length greater than {0}", maxLength)); + ulong result = 0; + for(int i = 0; i < str.Length; ++i) + { + result ^= randTable[2 * i][str[i] & 0xFF]; + result ^= randTable[2 * i + 1][(str[i] >> 8) & 0xFF]; + } + return result; + } + + private ulong[][] InitRandTable(int count) + { + var random = new GroBufRandom(seed); + var table = new ulong[count][]; + for(int len = 0; len < count; ++len) + { + var arr = new ulong[256]; + for(int i = 0; i < arr.Length; ++i) + arr[i] = ((ulong)(random.Next() & 0xFFFFFF)) | (((ulong)(random.Next() & 0xFFFFFF)) << 24) | (((ulong)(random.Next() & 0xFFFFFF)) << 48); + table[len] = arr; + } + return table; + } + + private readonly int seed; + private readonly int maxLength; + private readonly ulong[][] randTable; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/IGroBufCustomSerializer.cs b/GroBuf/IGroBufCustomSerializer.cs similarity index 97% rename from GroBuf/GroBuf/IGroBufCustomSerializer.cs rename to GroBuf/IGroBufCustomSerializer.cs index ac17780..27ef157 100644 --- a/GroBuf/GroBuf/IGroBufCustomSerializer.cs +++ b/GroBuf/IGroBufCustomSerializer.cs @@ -1,11 +1,11 @@ -using System; - -namespace GroBuf -{ - public interface IGroBufCustomSerializer - { - int CountSize(object obj, bool writeEmpty, WriterContext context); - void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context); - void Read(IntPtr data, ref int index, ref object result, ReaderContext context); - } +using System; + +namespace GroBuf +{ + public interface IGroBufCustomSerializer + { + int CountSize(object obj, bool writeEmpty, WriterContext context); + void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context); + void Read(IntPtr data, ref int index, ref object result, ReaderContext context); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/IGroBufCustomSerializerCollection.cs b/GroBuf/IGroBufCustomSerializerCollection.cs similarity index 96% rename from GroBuf/GroBuf/IGroBufCustomSerializerCollection.cs rename to GroBuf/IGroBufCustomSerializerCollection.cs index bf92b68..daf5d3a 100644 --- a/GroBuf/GroBuf/IGroBufCustomSerializerCollection.cs +++ b/GroBuf/IGroBufCustomSerializerCollection.cs @@ -1,9 +1,9 @@ -using System; - -namespace GroBuf -{ - public interface IGroBufCustomSerializerCollection - { - IGroBufCustomSerializer Get(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer); - } +using System; + +namespace GroBuf +{ + public interface IGroBufCustomSerializerCollection + { + IGroBufCustomSerializer Get(Type declaredType, Func factory, IGroBufCustomSerializer baseSerializer); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/ISerializer.cs b/GroBuf/ISerializer.cs similarity index 97% rename from GroBuf/GroBuf/ISerializer.cs rename to GroBuf/ISerializer.cs index b6b1ea7..2dcc7da 100644 --- a/GroBuf/GroBuf/ISerializer.cs +++ b/GroBuf/ISerializer.cs @@ -1,31 +1,31 @@ -using System; - -namespace GroBuf -{ - public interface ISerializer - { - int GetSize(T obj); - void Serialize(T obj, byte[] result, ref int index); - byte[] Serialize(T obj); - T Deserialize(byte[] data); - T Deserialize(byte[] data, ref int index); - T Deserialize(byte[] data, int length); - T Deserialize(byte[] data, ref int index, int length); - T Deserialize(IntPtr data, ref int index, int length); - void Merge(T from, ref T to); - TTo ChangeType(TFrom obj); - T Copy(T obj); - - int GetSize(Type type, object obj); - void Serialize(Type type, object obj, byte[] result, ref int index); - void Serialize(Type type, object obj, IntPtr result, ref int index, int length); - byte[] Serialize(Type type, object obj); - object Deserialize(Type type, byte[] data); - object Deserialize(Type type, byte[] data, ref int index); - object Deserialize(Type type, byte[] data, int length); - object Deserialize(Type type, byte[] data, ref int index, int length); - object Deserialize(Type type, IntPtr result, ref int index, int length); - object ChangeType(Type from, Type to, object obj); - object Copy(Type type, object obj); - } +using System; + +namespace GroBuf +{ + public interface ISerializer + { + int GetSize(T obj); + void Serialize(T obj, byte[] result, ref int index); + byte[] Serialize(T obj); + T Deserialize(byte[] data); + T Deserialize(byte[] data, ref int index); + T Deserialize(byte[] data, int length); + T Deserialize(byte[] data, ref int index, int length); + T Deserialize(IntPtr data, ref int index, int length); + void Merge(T from, ref T to); + TTo ChangeType(TFrom obj); + T Copy(T obj); + + int GetSize(Type type, object obj); + void Serialize(Type type, object obj, byte[] result, ref int index); + void Serialize(Type type, object obj, IntPtr result, ref int index, int length); + byte[] Serialize(Type type, object obj); + object Deserialize(Type type, byte[] data); + object Deserialize(Type type, byte[] data, ref int index); + object Deserialize(Type type, byte[] data, int length); + object Deserialize(Type type, byte[] data, ref int index, int length); + object Deserialize(Type type, IntPtr result, ref int index, int length); + object ChangeType(Type from, Type to, object obj); + object Copy(Type type, object obj); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/IgnoreDefaultOnMergeAttribute.cs b/GroBuf/IgnoreDefaultOnMergeAttribute.cs similarity index 100% rename from GroBuf/GroBuf/IgnoreDefaultOnMergeAttribute.cs rename to GroBuf/IgnoreDefaultOnMergeAttribute.cs diff --git a/GroBuf/GroBuf/InternalSerializer.cs b/GroBuf/InternalSerializer.cs similarity index 97% rename from GroBuf/GroBuf/InternalSerializer.cs rename to GroBuf/InternalSerializer.cs index 3e54407..9be14dd 100644 --- a/GroBuf/GroBuf/InternalSerializer.cs +++ b/GroBuf/InternalSerializer.cs @@ -1,35 +1,35 @@ -using System; - -namespace GroBuf -{ - internal class InternalSerializer : IGroBufCustomSerializer - { - public InternalSerializer(GroBufWriter groBufWriter, GroBufReader groBufReader, Type type, bool ignoreCustomSerializer) - { - this.groBufWriter = groBufWriter; - this.groBufReader = groBufReader; - this.type = type; - this.ignoreCustomSerializer = ignoreCustomSerializer; - } - - public int CountSize(object obj, bool writeEmpty, WriterContext context) - { - return groBufWriter.GetSize(type, ignoreCustomSerializer, obj, writeEmpty, context); - } - - public void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) - { - groBufWriter.Write(type, ignoreCustomSerializer, obj, writeEmpty, result, ref index, context); - } - - public void Read(IntPtr data, ref int index, ref object result, ReaderContext context) - { - groBufReader.Read(type, ignoreCustomSerializer, data, ref index, ref result, context); - } - - private readonly GroBufWriter groBufWriter; - private readonly GroBufReader groBufReader; - private readonly Type type; - private readonly bool ignoreCustomSerializer; - } +using System; + +namespace GroBuf +{ + internal class InternalSerializer : IGroBufCustomSerializer + { + public InternalSerializer(GroBufWriter groBufWriter, GroBufReader groBufReader, Type type, bool ignoreCustomSerializer) + { + this.groBufWriter = groBufWriter; + this.groBufReader = groBufReader; + this.type = type; + this.ignoreCustomSerializer = ignoreCustomSerializer; + } + + public int CountSize(object obj, bool writeEmpty, WriterContext context) + { + return groBufWriter.GetSize(type, ignoreCustomSerializer, obj, writeEmpty, context); + } + + public void Write(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context) + { + groBufWriter.Write(type, ignoreCustomSerializer, obj, writeEmpty, result, ref index, context); + } + + public void Read(IntPtr data, ref int index, ref object result, ReaderContext context) + { + groBufReader.Read(type, ignoreCustomSerializer, data, ref index, ref result, context); + } + + private readonly GroBufWriter groBufWriter; + private readonly GroBufReader groBufReader; + private readonly Type type; + private readonly bool ignoreCustomSerializer; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/LeafTypeAttribute.cs b/GroBuf/LeafTypeAttribute.cs similarity index 94% rename from GroBuf/GroBuf/LeafTypeAttribute.cs rename to GroBuf/LeafTypeAttribute.cs index 1c3b05d..5f536da 100644 --- a/GroBuf/GroBuf/LeafTypeAttribute.cs +++ b/GroBuf/LeafTypeAttribute.cs @@ -1,14 +1,14 @@ -using System; - -namespace GroBuf -{ - internal class LeafTypeAttribute: Attribute - { - public LeafTypeAttribute(Type type) - { - Type = type; - } - - public Type Type { get; private set; } - } +using System; + +namespace GroBuf +{ + internal class LeafTypeAttribute: Attribute + { + public LeafTypeAttribute(Type type) + { + Type = type; + } + + public Type Type { get; private set; } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/MissingConstructorException.cs b/GroBuf/MissingConstructorException.cs similarity index 96% rename from GroBuf/GroBuf/MissingConstructorException.cs rename to GroBuf/MissingConstructorException.cs index 7bfaf3f..e94b74c 100644 --- a/GroBuf/GroBuf/MissingConstructorException.cs +++ b/GroBuf/MissingConstructorException.cs @@ -1,18 +1,18 @@ -using System; -using System.Linq; - -namespace GroBuf -{ - public class MissingConstructorException : Exception - { - public MissingConstructorException(Type type) - : base("Type '" + type + "' has no parameterless constructor") - { - } - - public MissingConstructorException(Type type, params Type[] parameters) - : base(string.Format("Type '{0}' has no constructor with arguments ({1})", type, string.Join(", ", parameters.Select(t => "'" + t + "'")))) - { - } - } +using System; +using System.Linq; + +namespace GroBuf +{ + public class MissingConstructorException : Exception + { + public MissingConstructorException(Type type) + : base("Type '" + type + "' has no parameterless constructor") + { + } + + public MissingConstructorException(Type type, params Type[] parameters) + : base(string.Format("Type '{0}' has no constructor with arguments ({1})", type, string.Join(", ", parameters.Select(t => "'" + t + "'")))) + { + } + } } \ No newline at end of file diff --git a/GroBuf/PlatformHelpers.cs b/GroBuf/PlatformHelpers.cs new file mode 100644 index 0000000..beb41e6 --- /dev/null +++ b/GroBuf/PlatformHelpers.cs @@ -0,0 +1,32 @@ +using System; + +namespace GroBuf +{ + public static class PlatformHelpers + { + static PlatformHelpers() + { + IsMono = Type.GetType("Mono.Runtime") != null; + } + + public static bool IsMono { get; } + + public static string DelegateTargetFieldName => IsMono ? "m_target" : "_target"; + public static string LazyValueFactoryFieldName => SelectName("_factory", "m_valueFactory"); + public static string DateTimeOffsetDateTimeFieldName => SelectName("_dateTime", "m_dateTime"); + public static string DateTimeOffsetOffsetMinutesFieldName => SelectName("_offsetMinutes", "m_offsetMinutes"); + public static string HashtableCountFieldName => SelectName("_count", "count"); + public static string HashtableBucketsFieldName => SelectName("_buckets", "buckets"); + public static string HashSetSlotsFieldName => SelectName("_slots", "m_slots"); + public static string HashSetLastIndexFieldName => SelectName("_lastIndex", "m_lastIndex"); + + private static string SelectName(string netcoreName, string net45Name) + { +#if NETSTANDARD2_0 + return netcoreName; +#else + return net45Name; +#endif + } + } +} \ No newline at end of file diff --git a/GroBuf/GroBuf/RawData.cs b/GroBuf/RawData.cs similarity index 95% rename from GroBuf/GroBuf/RawData.cs rename to GroBuf/RawData.cs index 124eb8f..7bc1c1d 100644 --- a/GroBuf/GroBuf/RawData.cs +++ b/GroBuf/RawData.cs @@ -1,23 +1,23 @@ -using System; - -namespace GroBuf -{ - internal class RawData - { - private readonly long serializerId; - private readonly byte[] data; - private readonly Func reader; - - public RawData(long serializerId, byte[] data, Func reader) - { - this.serializerId = serializerId; - this.data = data; - this.reader = reader; - } - - public T GetValue() - { - return reader(data); - } - } +using System; + +namespace GroBuf +{ + internal class RawData + { + private readonly long serializerId; + private readonly byte[] data; + private readonly Func reader; + + public RawData(long serializerId, byte[] data, Func reader) + { + this.serializerId = serializerId; + this.data = data; + this.reader = reader; + } + + public T GetValue() + { + return reader(data); + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/ReaderContext.cs b/GroBuf/ReaderContext.cs similarity index 98% rename from GroBuf/GroBuf/ReaderContext.cs rename to GroBuf/ReaderContext.cs index 7eef0d1..9e2ee7c 100644 --- a/GroBuf/GroBuf/ReaderContext.cs +++ b/GroBuf/ReaderContext.cs @@ -1,28 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Reflection; - -namespace GroBuf -{ - public class ReaderContext - { - public ReaderContext(long serializerId, int length, int start, int references) - { - this.serializerId = serializerId; - this.length = length; - this.start = start; - objects = references == 0 ? null : new Dictionary(); - } - - public readonly long serializerId; - public readonly int length; - public readonly int start; - public readonly Dictionary objects; - - public static readonly FieldInfo LengthField = (FieldInfo)((MemberExpression)((Expression>)(context => context.length)).Body).Member; - public static readonly FieldInfo StartField = (FieldInfo)((MemberExpression)((Expression>)(context => context.start)).Body).Member; - public static readonly FieldInfo ObjectsField = (FieldInfo)((MemberExpression)((Expression>>)(context => context.objects)).Body).Member; - public static readonly FieldInfo SerializerIdField = (FieldInfo)((MemberExpression)((Expression>)(context => context.serializerId)).Body).Member; - } +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; + +namespace GroBuf +{ + public class ReaderContext + { + public ReaderContext(long serializerId, int length, int start, int references) + { + this.serializerId = serializerId; + this.length = length; + this.start = start; + objects = references == 0 ? null : new Dictionary(); + } + + public readonly long serializerId; + public readonly int length; + public readonly int start; + public readonly Dictionary objects; + + public static readonly FieldInfo LengthField = (FieldInfo)((MemberExpression)((Expression>)(context => context.length)).Body).Member; + public static readonly FieldInfo StartField = (FieldInfo)((MemberExpression)((Expression>)(context => context.start)).Body).Member; + public static readonly FieldInfo ObjectsField = (FieldInfo)((MemberExpression)((Expression>>)(context => context.objects)).Body).Member; + public static readonly FieldInfo SerializerIdField = (FieldInfo)((MemberExpression)((Expression>)(context => context.serializerId)).Body).Member; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/ReaderDelegate.cs b/GroBuf/ReaderDelegate.cs similarity index 97% rename from GroBuf/GroBuf/ReaderDelegate.cs rename to GroBuf/ReaderDelegate.cs index 7d22592..55ee3fc 100644 --- a/GroBuf/GroBuf/ReaderDelegate.cs +++ b/GroBuf/ReaderDelegate.cs @@ -1,8 +1,8 @@ -using System; - -namespace GroBuf -{ - public delegate void ReaderDelegate(IntPtr data, ref int index, ref T result, ReaderContext context); - - public delegate void ReaderDelegate(IntPtr data, ref int index, ref object result, ReaderContext context); +using System; + +namespace GroBuf +{ + public delegate void ReaderDelegate(IntPtr data, ref int index, ref T result, ReaderContext context); + + public delegate void ReaderDelegate(IntPtr data, ref int index, ref object result, ReaderContext context); } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/ArrayReaderBuilder.cs b/GroBuf/Readers/ArrayReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/ArrayReaderBuilder.cs rename to GroBuf/Readers/ArrayReaderBuilder.cs index 349aff4..1afdccc 100644 --- a/GroBuf/GroBuf/Readers/ArrayReaderBuilder.cs +++ b/GroBuf/Readers/ArrayReaderBuilder.cs @@ -1,165 +1,165 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; - -namespace GroBuf.Readers -{ - internal class ArrayReaderBuilder : ReaderBuilderBase - { - public ArrayReaderBuilder(Type type) - : base(type) - { - if(!Type.IsArray) throw new InvalidOperationException("An array expected but was '" + Type + "'"); - if(Type.GetArrayRank() != 1) throw new NotSupportedException("Arrays with rank greater than 1 are not supported"); - elementType = Type.GetElementType(); - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - var il = context.Il; - - il.Ldloc(context.TypeCode); // stack: [type code] - il.Ldc_I4((int)GroBufTypeCode.Array); // stack: [type code, GroBufTypeCode.Array] - var tryReadArrayElementLabel = il.DefineLabel("tryReadArrayElement"); - il.Bne_Un(tryReadArrayElementLabel); // if(type code != GroBufTypeCode.Array) goto tryReadArrayElement; stack: [] - - context.IncreaseIndexBy1(); - var length = context.Length; - - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [data length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] - - context.AssertLength(); - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [array length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] - il.Stloc(length); // length = array length; stack: [] - - if(context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) - { - var createArrayLabel = il.DefineLabel("createArray"); - context.LoadResult(Type); // stack: [result] - il.Brfalse(createArrayLabel); // if(result == null) goto createArray; - context.LoadResult(Type); // stack: [result] - il.Ldlen(); // stack: [result.Length] - il.Ldloc(length); // stack: [result.Length, length] - var arrayCreatedLabel = il.DefineLabel("arrayCreated"); - il.Bge(arrayCreatedLabel, false); // if(result.Length >= length) goto arrayCreated; - - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(length); // stack: [ref result, length] - il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, length) - il.Br(arrayCreatedLabel); // goto arrayCreated - - il.MarkLabel(createArrayLabel); - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(length); // stack: [ref result, length] - il.Newarr(elementType); // stack: [ref result, new type[length]] - il.Stind(Type); // result = new type[length]; stack: [] - - il.MarkLabel(arrayCreatedLabel); - } - else - { - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(length); // stack: [ref result, length] - il.Newarr(elementType); // stack: [ref result, new type[length]] - il.Stind(Type); // result = new type[length]; stack: [] - } - - context.StoreObject(Type); - - il.Ldloc(length); // stack: [length] - var doneLabel = il.DefineLabel("done"); - il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] - var i = il.DeclareLocal(typeof(uint)); - il.Ldc_I4(0); // stack: [0] - il.Stloc(i); // i = 0; stack: [] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - - context.LoadData(); // stack: [pinnedData] - context.LoadIndexByRef(); // stack: [pinnedData, ref index] - context.LoadResult(Type); // stack: [pinnedData, ref index, result] - il.Ldloc(i); // stack: [pinnedData, ref index, result, i] - - il.Ldelema(elementType); // stack: [pinnedData, ref index, ref result[i]] - context.LoadContext(); // stack: [pinnedData, ref index, ref result[i], context] - - context.CallReader(elementType); // reader(pinnedData, ref index, ref result[i], context); stack: [] - il.Ldloc(i); // stack: [i] - il.Ldc_I4(1); // stack: [i, 1] - il.Add(); // stack: [i + 1] - il.Dup(); // stack: [i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [i] - il.Ldloc(length); // stack: [i, length] - il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart - il.Br(doneLabel); - - il.MarkLabel(tryReadArrayElementLabel); - - if(context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) - { - var createArrayLabel = il.DefineLabel("createArray"); - context.LoadResult(Type); // stack: [result] - il.Brfalse(createArrayLabel); // if(result == null) goto createArray; - context.LoadResult(Type); // stack: [result] - il.Ldlen(); // stack: [result.Length] - il.Ldc_I4(1); // stack: [result.Length, 1] - var arrayCreatedLabel = il.DefineLabel("arrayCreated"); - il.Bge(arrayCreatedLabel, false); // if(result.Length >= 1) goto arrayCreated; - - context.LoadResultByRef(); // stack: [ref result] - il.Ldc_I4(1); // stack: [ref result, 1] - il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, length) - il.Br(arrayCreatedLabel); // goto arrayCreated - - il.MarkLabel(createArrayLabel); - context.LoadResultByRef(); // stack: [ref result] - il.Ldc_I4(1); // stack: [ref result, 1] - il.Newarr(elementType); // stack: [ref result, new type[1]] - il.Stind(Type); // result = new type[1]; stack: [] - - il.MarkLabel(arrayCreatedLabel); - } - else - { - context.LoadResultByRef(); // stack: [ref result] - il.Ldc_I4(1); // stack: [ref result, 1] - il.Newarr(elementType); // stack: [ref result, new type[1]] - il.Stind(Type); // result = new type[1]; stack: [] - } - - context.StoreObject(Type); - - context.LoadData(); // stack: [pinnedData] - context.LoadIndexByRef(); // stack: [pinnedData, ref index] - context.LoadResult(Type); // stack: [pinnedData, ref index, result] - il.Ldc_I4(0); // stack: [pinnedData, ref index, result, 0] - - il.Ldelema(elementType); // stack: [pinnedData, ref index, ref result[0]] - context.LoadContext(); // stack: [pinnedData, ref index, ref result[0], context] - - context.CallReader(elementType); // reader(pinnedData, ref index, ref result[0], context); stack: [] - - il.MarkLabel(doneLabel); // stack: [] - } - - protected override bool IsReference { get { return true; } } - - private static readonly MethodInfo resizeMethod = ((MethodCallExpression)((Expression>)(arr => Array.Resize(ref arr, 0))).Body).Method.GetGenericMethodDefinition(); - private readonly Type elementType; - } +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace GroBuf.Readers +{ + internal class ArrayReaderBuilder : ReaderBuilderBase + { + public ArrayReaderBuilder(Type type) + : base(type) + { + if(!Type.IsArray) throw new InvalidOperationException("An array expected but was '" + Type + "'"); + if(Type.GetArrayRank() != 1) throw new NotSupportedException("Arrays with rank greater than 1 are not supported"); + elementType = Type.GetElementType(); + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + var il = context.Il; + + il.Ldloc(context.TypeCode); // stack: [type code] + il.Ldc_I4((int)GroBufTypeCode.Array); // stack: [type code, GroBufTypeCode.Array] + var tryReadArrayElementLabel = il.DefineLabel("tryReadArrayElement"); + il.Bne_Un(tryReadArrayElementLabel); // if(type code != GroBufTypeCode.Array) goto tryReadArrayElement; stack: [] + + context.IncreaseIndexBy1(); + var length = context.Length; + + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [data length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] + + context.AssertLength(); + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [array length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] + il.Stloc(length); // length = array length; stack: [] + + if(context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) + { + var createArrayLabel = il.DefineLabel("createArray"); + context.LoadResult(Type); // stack: [result] + il.Brfalse(createArrayLabel); // if(result == null) goto createArray; + context.LoadResult(Type); // stack: [result] + il.Ldlen(); // stack: [result.Length] + il.Ldloc(length); // stack: [result.Length, length] + var arrayCreatedLabel = il.DefineLabel("arrayCreated"); + il.Bge(arrayCreatedLabel, false); // if(result.Length >= length) goto arrayCreated; + + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(length); // stack: [ref result, length] + il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, length) + il.Br(arrayCreatedLabel); // goto arrayCreated + + il.MarkLabel(createArrayLabel); + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(length); // stack: [ref result, length] + il.Newarr(elementType); // stack: [ref result, new type[length]] + il.Stind(Type); // result = new type[length]; stack: [] + + il.MarkLabel(arrayCreatedLabel); + } + else + { + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(length); // stack: [ref result, length] + il.Newarr(elementType); // stack: [ref result, new type[length]] + il.Stind(Type); // result = new type[length]; stack: [] + } + + context.StoreObject(Type); + + il.Ldloc(length); // stack: [length] + var doneLabel = il.DefineLabel("done"); + il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] + var i = il.DeclareLocal(typeof(uint)); + il.Ldc_I4(0); // stack: [0] + il.Stloc(i); // i = 0; stack: [] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + + context.LoadData(); // stack: [pinnedData] + context.LoadIndexByRef(); // stack: [pinnedData, ref index] + context.LoadResult(Type); // stack: [pinnedData, ref index, result] + il.Ldloc(i); // stack: [pinnedData, ref index, result, i] + + il.Ldelema(elementType); // stack: [pinnedData, ref index, ref result[i]] + context.LoadContext(); // stack: [pinnedData, ref index, ref result[i], context] + + context.CallReader(elementType); // reader(pinnedData, ref index, ref result[i], context); stack: [] + il.Ldloc(i); // stack: [i] + il.Ldc_I4(1); // stack: [i, 1] + il.Add(); // stack: [i + 1] + il.Dup(); // stack: [i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [i] + il.Ldloc(length); // stack: [i, length] + il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart + il.Br(doneLabel); + + il.MarkLabel(tryReadArrayElementLabel); + + if(context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) + { + var createArrayLabel = il.DefineLabel("createArray"); + context.LoadResult(Type); // stack: [result] + il.Brfalse(createArrayLabel); // if(result == null) goto createArray; + context.LoadResult(Type); // stack: [result] + il.Ldlen(); // stack: [result.Length] + il.Ldc_I4(1); // stack: [result.Length, 1] + var arrayCreatedLabel = il.DefineLabel("arrayCreated"); + il.Bge(arrayCreatedLabel, false); // if(result.Length >= 1) goto arrayCreated; + + context.LoadResultByRef(); // stack: [ref result] + il.Ldc_I4(1); // stack: [ref result, 1] + il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, length) + il.Br(arrayCreatedLabel); // goto arrayCreated + + il.MarkLabel(createArrayLabel); + context.LoadResultByRef(); // stack: [ref result] + il.Ldc_I4(1); // stack: [ref result, 1] + il.Newarr(elementType); // stack: [ref result, new type[1]] + il.Stind(Type); // result = new type[1]; stack: [] + + il.MarkLabel(arrayCreatedLabel); + } + else + { + context.LoadResultByRef(); // stack: [ref result] + il.Ldc_I4(1); // stack: [ref result, 1] + il.Newarr(elementType); // stack: [ref result, new type[1]] + il.Stind(Type); // result = new type[1]; stack: [] + } + + context.StoreObject(Type); + + context.LoadData(); // stack: [pinnedData] + context.LoadIndexByRef(); // stack: [pinnedData, ref index] + context.LoadResult(Type); // stack: [pinnedData, ref index, result] + il.Ldc_I4(0); // stack: [pinnedData, ref index, result, 0] + + il.Ldelema(elementType); // stack: [pinnedData, ref index, ref result[0]] + context.LoadContext(); // stack: [pinnedData, ref index, ref result[0], context] + + context.CallReader(elementType); // reader(pinnedData, ref index, ref result[0], context); stack: [] + + il.MarkLabel(doneLabel); // stack: [] + } + + protected override bool IsReference { get { return true; } } + + private static readonly MethodInfo resizeMethod = ((MethodCallExpression)((Expression>)(arr => Array.Resize(ref arr, 0))).Body).Method.GetGenericMethodDefinition(); + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/ArraySegmentReaderBuilder.cs b/GroBuf/Readers/ArraySegmentReaderBuilder.cs similarity index 100% rename from GroBuf/GroBuf/Readers/ArraySegmentReaderBuilder.cs rename to GroBuf/Readers/ArraySegmentReaderBuilder.cs diff --git a/GroBuf/GroBuf/Readers/ClassReaderBuilder.cs b/GroBuf/Readers/ClassReaderBuilder.cs similarity index 98% rename from GroBuf/GroBuf/Readers/ClassReaderBuilder.cs rename to GroBuf/Readers/ClassReaderBuilder.cs index ea86420..13e91f2 100644 --- a/GroBuf/GroBuf/Readers/ClassReaderBuilder.cs +++ b/GroBuf/Readers/ClassReaderBuilder.cs @@ -1,304 +1,304 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; -using System.Runtime.Serialization; - -using GrEmit; - -namespace GroBuf.Readers -{ - internal class ClassReaderBuilder : ReaderBuilderBase - { - public ClassReaderBuilder(Type type) - : base(type) - { - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.SetFields(Type, new[] - { - new KeyValuePair("setters_" + Type.Name + "_" + Guid.NewGuid(), typeof(IntPtr[])), - new KeyValuePair("delegates_" + Type.Name + "_" + Guid.NewGuid(), typeof(Delegate[])), - new KeyValuePair("hashCodes_" + Type.Name + "_" + Guid.NewGuid(), typeof(ulong[])), - }); - foreach(var member in context.GetDataMembers(Type)) - { - Type memberType; - switch(member.Member.MemberType) - { - case MemberTypes.Property: - memberType = ((PropertyInfo)member.Member).PropertyType; - break; - case MemberTypes.Field: - memberType = ((FieldInfo)member.Member).FieldType; - break; - default: - throw new NotSupportedException("Data member of type " + member.Member.MemberType + " is not supported"); - } - context.BuildConstants(memberType); - } - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - MemberInfo[] dataMembers; - ulong[] hashCodes; - BuildMembersTable(context.Context, out hashCodes, out dataMembers); - - var il = context.Il; - var end = context.Length; - var typeCode = context.TypeCode; - - var setters = dataMembers.Select(member => member == null ? default(KeyValuePair) : GetMemberSetter(context.Context, member)).ToArray(); - - var settersField = context.Context.InitConstField(Type, 0, setters.Select(pair => pair.Value).ToArray()); - context.Context.InitConstField(Type, 1, setters.Select(pair => pair.Key).ToArray()); - var hashCodesField = context.Context.InitConstField(Type, 2, hashCodes); - - context.IncreaseIndexBy1(); // index = index + 1 - context.AssertTypeCode(GroBufTypeCode.Object); - - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [(uint)data[index] = data length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] - - il.Dup(); // stack: [data length, data length] - il.Stloc(end); // end = data length; stack: [data length] - - if(!Type.IsValueType) - { - context.LoadResultByRef(); // stack: [data length, ref result] - il.Ldind(Type); // stack: [data length, result] - var notNullLabel = il.DefineLabel("notNull"); - il.Brtrue(notNullLabel); // if(result != null) goto notNull; stack: [data length] - context.LoadResultByRef(); // stack: [data length, ref result] - ObjectConstructionHelper.EmitConstructionOfType(Type, il); - il.Stind(Type); // result = new type(); stack: [data length] - il.MarkLabel(notNullLabel); - } - - context.StoreObject(Type); - - var doneLabel = il.DefineLabel("done"); - il.Brfalse(doneLabel); // if(data length == 0) goto done; stack: [] - il.Ldloc(end); // stack: [data length] - - context.AssertLength(); // stack: [] - - il.Ldloc(end); // stack: [data length] - context.LoadIndex(); // stack: [data length, index] - il.Add(); // stack: [data length + index] - il.Stloc(end); // end = data length + index - - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - - il.Ldc_I4(9); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(long)); // stack: [*(int64*)&data[index] = hashCode] - context.IncreaseIndexBy8(); // index = index + 8; stack: [*(int64*)&data[index] = hashCode] - - il.Dup(); // stack: [hashCode, hashCode] - il.Ldc_I8(dataMembers.Length); // stack: [hashCode, hashCode, (int64)hashCodes.Length] - il.Rem(true); // stack: [hashCode, hashCode % hashCodes.Length] - il.Conv(); // stack: [hashCode, (int)(hashCode % hashCodes.Length)] - var idx = il.DeclareLocal(typeof(int)); - il.Stloc(idx); // idx = (int)(hashCode % hashCodes.Length); stack: [hashCode] - - context.LoadField(hashCodesField); // stack: [hashCode, hashCodes] - il.Ldloc(idx); // stack: [hashCode, hashCodes, idx] - il.Ldelem(typeof(long)); // stack: [hashCode, hashCodes[idx]] - - var skipDataLabel = il.DefineLabel("skipData"); - il.Bne_Un(skipDataLabel); // if(hashCode != hashCodes[idx]) goto skipData; stack: [] - - // Read data - context.LoadData(); // stack: [pinnedData] - context.LoadIndexByRef(); // stack: [pinnedData, ref index] - context.LoadResultByRef(); // stack: [pinnedData, ref index, ref result] - context.LoadContext(); // stack: [pinnedData, ref index, ref result, context] - - context.LoadField(settersField); // stack: [pinnedData, ref index, ref result, context, setters] - il.Ldloc(idx); // stack: [pinnedData, ref index, ref result, context, setters, idx] - il.Ldelem(typeof(IntPtr)); // stack: [pinnedData, ref index, ref result, context, setters[idx]] - var parameterTypes = new[] {typeof(byte*), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext)}; - il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // setters[idx](pinnedData, ref index, ref result, context); stack: [] - - var checkIndexLabel = il.DefineLabel("checkIndex"); - il.Br(checkIndexLabel); // goto checkIndex - - il.MarkLabel(skipDataLabel); - // Skip data - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(byte)); // stack: [data[index]] - il.Stloc(typeCode); // typeCode = data[index]; stack: [] - context.IncreaseIndexBy1(); // index = index + 1 - context.CheckTypeCode(); - context.SkipValue(); - - il.MarkLabel(checkIndexLabel); - - context.LoadIndex(); // stack: [index] - il.Ldloc(end); // stack: [index, end] - il.Blt(cycleStartLabel, true); // if(index < end) goto cycleStart; stack: [] - - var onDeserializedMethod = Type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) - .SingleOrDefault(method => method.GetCustomAttribute() != null); - if(onDeserializedMethod != null) - { - var parameters = onDeserializedMethod.GetParameters(); - if(parameters.Length != 1 || parameters[0].ParameterType != typeof(StreamingContext)) - throw new InvalidOperationException(string.Format("The method '{0}' marked with 'OnDeserialized' attribute must accept exactly one parameter of type '{1}'", onDeserializedMethod, typeof(StreamingContext).FullName)); - context.LoadResult(Type); - il.Ldc_I4((int)StreamingContextStates.Other); - il.Newobj(typeof(StreamingContext).GetConstructor(new[] {typeof(StreamingContextStates)})); - il.Call(onDeserializedMethod); - } - - il.MarkLabel(doneLabel); - } - - protected override bool IsReference { get { return true; } } - - private void BuildMembersTable(ReaderTypeBuilderContext context, out ulong[] hashCodes, out MemberInfo[] dataMembers) - { - var members = context.GetDataMembers(Type); - var hashes = GroBufHelpers.CalcHashesAndCheck(members); - var n = GroBufHelpers.CalcSize(hashes); - hashCodes = new ulong[n]; - dataMembers = new MemberInfo[n]; - for(var i = 0; i < members.Length; i++) - { - var index = (int)(hashes[i] % n); - hashCodes[index] = hashes[i]; - dataMembers[index] = members[i].Member; - } - } - - private KeyValuePair GetMemberSetter(ReaderTypeBuilderContext context, MemberInfo member) - { - var method = new DynamicMethod("Set_" + Type.Name + "_" + member.Name + "_" + Guid.NewGuid(), typeof(void), - new[] - { - typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext) - }, context.Module, true); - var writableMember = member.TryGetWritableMemberInfo(); - using(var il = new GroboIL(method)) - { - il.Ldarg(0); // stack: [data] - il.Ldarg(1); // stack: [data, ref index] - switch(writableMember.MemberType) - { - case MemberTypes.Field: - var field = (FieldInfo)writableMember; - var done = false; - if(member.GetCustomAttributes(typeof(IgnoreDefaultOnMergeAttribute), false).Length > 0 && field.FieldType.IsValueType) - { - var equalityOperator = field.FieldType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); - if(field.FieldType.IsPrimitive || equalityOperator != null) - { - var fieldValue = il.DeclareLocal(field.FieldType); - il.Ldarg(2); // stack: [data, ref index, ref result] - if(!Type.IsValueType) - il.Ldind(Type); // stack: [data, ref index, result] - il.Ldfld(field); - il.Stloc(fieldValue); - il.Ldloca(fieldValue); - il.Ldarg(3); // stack: [data, ref index, ref result.field, context] - ReaderMethodBuilderContext.CallReader(il, field.FieldType, context); // reader(data, ref index, ref result.field, context); stack: [] - - var temp = il.DeclareLocal(field.FieldType); - il.Ldloca(temp); - il.Initobj(field.FieldType); - il.Ldloc(temp); - il.Ldloc(fieldValue); - if(field.FieldType.IsPrimitive) - il.Ceq(); - else - il.Call(equalityOperator); - var notDefaultLabel = il.DefineLabel("notDefault"); - il.Brfalse(notDefaultLabel); - il.Ret(); - il.MarkLabel(notDefaultLabel); - il.Ldarg(2); - if(!Type.IsValueType) - il.Ldind(Type); // stack: [data, ref index, result] - il.Ldloc(fieldValue); - il.Stfld(field); - done = true; - } - } - if(!done) - { - il.Ldarg(2); // stack: [data, ref index, ref result] - if(!Type.IsValueType) - il.Ldind(Type); // stack: [data, ref index, result] - il.Ldflda(field); // stack: [data, ref index, ref result.field] - il.Ldarg(3); // stack: [data, ref index, ref result.field, context] - ReaderMethodBuilderContext.CallReader(il, field.FieldType, context); // reader(data, ref index, ref result.field, context); stack: [] - } - break; - case MemberTypes.Property: - var property = (PropertyInfo)writableMember; - var propertyValue = il.DeclareLocal(property.PropertyType); - if(context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) - { - var getter = property.GetGetMethod(true); - if(getter == null) - throw new MissingMethodException(Type.Name, property.Name + "_get"); - il.Ldarg(2); // stack: [data, ref index, ref result] - if(!Type.IsValueType) - il.Ldind(Type); // stack: [data, ref index, result] - il.Call(getter, Type); // stack: [ data, ref index, result.property] - il.Stloc(propertyValue); // propertyValue = result.property; stack: [data, ref index] - } - il.Ldloca(propertyValue); // stack: [data, ref index, ref propertyValue] - il.Ldarg(3); // stack: [data, ref index, ref propertyValue, context] - ReaderMethodBuilderContext.CallReader(il, property.PropertyType, context); // reader(data, ref index, ref propertyValue, context); stack: [] - if(member.GetCustomAttributes(typeof(IgnoreDefaultOnMergeAttribute), false).Length > 0 && property.PropertyType.IsValueType) - { - var equalityOperator = property.PropertyType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); - if(property.PropertyType.IsPrimitive || equalityOperator != null) - { - var temp = il.DeclareLocal(property.PropertyType); - il.Ldloca(temp); - il.Initobj(property.PropertyType); - il.Ldloc(temp); - il.Ldloc(propertyValue); - if(property.PropertyType.IsPrimitive) - il.Ceq(); - else - il.Call(equalityOperator); - var notDefaultLabel = il.DefineLabel("notDefault"); - il.Brfalse(notDefaultLabel); - il.Ret(); - il.MarkLabel(notDefaultLabel); - } - } - il.Ldarg(2); // stack: [ref result] - if(!Type.IsValueType) - il.Ldind(Type); // stack: [result] - il.Ldloc(propertyValue); // stack: [result, propertyValue] - var setter = property.GetSetMethod(true); - if(setter == null) - throw new MissingMethodException(Type.Name, property.Name + "_set"); - il.Call(setter, Type); // result.property = propertyValue - break; - default: - throw new NotSupportedException("Data member of type '" + member.MemberType + "' is not supported"); - } - il.Ret(); - } - var @delegate = method.CreateDelegate(typeof(ReaderDelegate<>).MakeGenericType(Type)); - return new KeyValuePair(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.Serialization; + +using GrEmit; + +namespace GroBuf.Readers +{ + internal class ClassReaderBuilder : ReaderBuilderBase + { + public ClassReaderBuilder(Type type) + : base(type) + { + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.SetFields(Type, new[] + { + new KeyValuePair("setters_" + Type.Name + "_" + Guid.NewGuid(), typeof(IntPtr[])), + new KeyValuePair("delegates_" + Type.Name + "_" + Guid.NewGuid(), typeof(Delegate[])), + new KeyValuePair("hashCodes_" + Type.Name + "_" + Guid.NewGuid(), typeof(ulong[])), + }); + foreach(var member in context.GetDataMembers(Type)) + { + Type memberType; + switch(member.Member.MemberType) + { + case MemberTypes.Property: + memberType = ((PropertyInfo)member.Member).PropertyType; + break; + case MemberTypes.Field: + memberType = ((FieldInfo)member.Member).FieldType; + break; + default: + throw new NotSupportedException("Data member of type " + member.Member.MemberType + " is not supported"); + } + context.BuildConstants(memberType); + } + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + MemberInfo[] dataMembers; + ulong[] hashCodes; + BuildMembersTable(context.Context, out hashCodes, out dataMembers); + + var il = context.Il; + var end = context.Length; + var typeCode = context.TypeCode; + + var setters = dataMembers.Select(member => member == null ? default(KeyValuePair) : GetMemberSetter(context.Context, member)).ToArray(); + + var settersField = context.Context.InitConstField(Type, 0, setters.Select(pair => pair.Value).ToArray()); + context.Context.InitConstField(Type, 1, setters.Select(pair => pair.Key).ToArray()); + var hashCodesField = context.Context.InitConstField(Type, 2, hashCodes); + + context.IncreaseIndexBy1(); // index = index + 1 + context.AssertTypeCode(GroBufTypeCode.Object); + + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [(uint)data[index] = data length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] + + il.Dup(); // stack: [data length, data length] + il.Stloc(end); // end = data length; stack: [data length] + + if(!Type.IsValueType) + { + context.LoadResultByRef(); // stack: [data length, ref result] + il.Ldind(Type); // stack: [data length, result] + var notNullLabel = il.DefineLabel("notNull"); + il.Brtrue(notNullLabel); // if(result != null) goto notNull; stack: [data length] + context.LoadResultByRef(); // stack: [data length, ref result] + ObjectConstructionHelper.EmitConstructionOfType(Type, il); + il.Stind(Type); // result = new type(); stack: [data length] + il.MarkLabel(notNullLabel); + } + + context.StoreObject(Type); + + var doneLabel = il.DefineLabel("done"); + il.Brfalse(doneLabel); // if(data length == 0) goto done; stack: [] + il.Ldloc(end); // stack: [data length] + + context.AssertLength(); // stack: [] + + il.Ldloc(end); // stack: [data length] + context.LoadIndex(); // stack: [data length, index] + il.Add(); // stack: [data length + index] + il.Stloc(end); // end = data length + index + + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + + il.Ldc_I4(9); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(long)); // stack: [*(int64*)&data[index] = hashCode] + context.IncreaseIndexBy8(); // index = index + 8; stack: [*(int64*)&data[index] = hashCode] + + il.Dup(); // stack: [hashCode, hashCode] + il.Ldc_I8(dataMembers.Length); // stack: [hashCode, hashCode, (int64)hashCodes.Length] + il.Rem(true); // stack: [hashCode, hashCode % hashCodes.Length] + il.Conv(); // stack: [hashCode, (int)(hashCode % hashCodes.Length)] + var idx = il.DeclareLocal(typeof(int)); + il.Stloc(idx); // idx = (int)(hashCode % hashCodes.Length); stack: [hashCode] + + context.LoadField(hashCodesField); // stack: [hashCode, hashCodes] + il.Ldloc(idx); // stack: [hashCode, hashCodes, idx] + il.Ldelem(typeof(long)); // stack: [hashCode, hashCodes[idx]] + + var skipDataLabel = il.DefineLabel("skipData"); + il.Bne_Un(skipDataLabel); // if(hashCode != hashCodes[idx]) goto skipData; stack: [] + + // Read data + context.LoadData(); // stack: [pinnedData] + context.LoadIndexByRef(); // stack: [pinnedData, ref index] + context.LoadResultByRef(); // stack: [pinnedData, ref index, ref result] + context.LoadContext(); // stack: [pinnedData, ref index, ref result, context] + + context.LoadField(settersField); // stack: [pinnedData, ref index, ref result, context, setters] + il.Ldloc(idx); // stack: [pinnedData, ref index, ref result, context, setters, idx] + il.Ldelem(typeof(IntPtr)); // stack: [pinnedData, ref index, ref result, context, setters[idx]] + var parameterTypes = new[] {typeof(byte*), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext)}; + il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // setters[idx](pinnedData, ref index, ref result, context); stack: [] + + var checkIndexLabel = il.DefineLabel("checkIndex"); + il.Br(checkIndexLabel); // goto checkIndex + + il.MarkLabel(skipDataLabel); + // Skip data + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(byte)); // stack: [data[index]] + il.Stloc(typeCode); // typeCode = data[index]; stack: [] + context.IncreaseIndexBy1(); // index = index + 1 + context.CheckTypeCode(); + context.SkipValue(); + + il.MarkLabel(checkIndexLabel); + + context.LoadIndex(); // stack: [index] + il.Ldloc(end); // stack: [index, end] + il.Blt(cycleStartLabel, true); // if(index < end) goto cycleStart; stack: [] + + var onDeserializedMethod = Type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + .SingleOrDefault(method => method.GetCustomAttribute() != null); + if(onDeserializedMethod != null) + { + var parameters = onDeserializedMethod.GetParameters(); + if(parameters.Length != 1 || parameters[0].ParameterType != typeof(StreamingContext)) + throw new InvalidOperationException(string.Format("The method '{0}' marked with 'OnDeserialized' attribute must accept exactly one parameter of type '{1}'", onDeserializedMethod, typeof(StreamingContext).FullName)); + context.LoadResult(Type); + il.Ldc_I4((int)StreamingContextStates.Other); + il.Newobj(typeof(StreamingContext).GetConstructor(new[] {typeof(StreamingContextStates)})); + il.Call(onDeserializedMethod); + } + + il.MarkLabel(doneLabel); + } + + protected override bool IsReference { get { return true; } } + + private void BuildMembersTable(ReaderTypeBuilderContext context, out ulong[] hashCodes, out MemberInfo[] dataMembers) + { + var members = context.GetDataMembers(Type); + var hashes = GroBufHelpers.CalcHashesAndCheck(members); + var n = GroBufHelpers.CalcSize(hashes); + hashCodes = new ulong[n]; + dataMembers = new MemberInfo[n]; + for(var i = 0; i < members.Length; i++) + { + var index = (int)(hashes[i] % n); + hashCodes[index] = hashes[i]; + dataMembers[index] = members[i].Member; + } + } + + private KeyValuePair GetMemberSetter(ReaderTypeBuilderContext context, MemberInfo member) + { + var method = new DynamicMethod("Set_" + Type.Name + "_" + member.Name + "_" + Guid.NewGuid(), typeof(void), + new[] + { + typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext) + }, context.Module, true); + var writableMember = member.TryGetWritableMemberInfo(); + using(var il = new GroboIL(method)) + { + il.Ldarg(0); // stack: [data] + il.Ldarg(1); // stack: [data, ref index] + switch(writableMember.MemberType) + { + case MemberTypes.Field: + var field = (FieldInfo)writableMember; + var done = false; + if(member.GetCustomAttributes(typeof(IgnoreDefaultOnMergeAttribute), false).Length > 0 && field.FieldType.IsValueType) + { + var equalityOperator = field.FieldType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + if(field.FieldType.IsPrimitive || equalityOperator != null) + { + var fieldValue = il.DeclareLocal(field.FieldType); + il.Ldarg(2); // stack: [data, ref index, ref result] + if(!Type.IsValueType) + il.Ldind(Type); // stack: [data, ref index, result] + il.Ldfld(field); + il.Stloc(fieldValue); + il.Ldloca(fieldValue); + il.Ldarg(3); // stack: [data, ref index, ref result.field, context] + ReaderMethodBuilderContext.CallReader(il, field.FieldType, context); // reader(data, ref index, ref result.field, context); stack: [] + + var temp = il.DeclareLocal(field.FieldType); + il.Ldloca(temp); + il.Initobj(field.FieldType); + il.Ldloc(temp); + il.Ldloc(fieldValue); + if(field.FieldType.IsPrimitive) + il.Ceq(); + else + il.Call(equalityOperator); + var notDefaultLabel = il.DefineLabel("notDefault"); + il.Brfalse(notDefaultLabel); + il.Ret(); + il.MarkLabel(notDefaultLabel); + il.Ldarg(2); + if(!Type.IsValueType) + il.Ldind(Type); // stack: [data, ref index, result] + il.Ldloc(fieldValue); + il.Stfld(field); + done = true; + } + } + if(!done) + { + il.Ldarg(2); // stack: [data, ref index, ref result] + if(!Type.IsValueType) + il.Ldind(Type); // stack: [data, ref index, result] + il.Ldflda(field); // stack: [data, ref index, ref result.field] + il.Ldarg(3); // stack: [data, ref index, ref result.field, context] + ReaderMethodBuilderContext.CallReader(il, field.FieldType, context); // reader(data, ref index, ref result.field, context); stack: [] + } + break; + case MemberTypes.Property: + var property = (PropertyInfo)writableMember; + var propertyValue = il.DeclareLocal(property.PropertyType); + if(context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) + { + var getter = property.GetGetMethod(true); + if(getter == null) + throw new MissingMethodException(Type.Name, property.Name + "_get"); + il.Ldarg(2); // stack: [data, ref index, ref result] + if(!Type.IsValueType) + il.Ldind(Type); // stack: [data, ref index, result] + il.Call(getter, Type); // stack: [ data, ref index, result.property] + il.Stloc(propertyValue); // propertyValue = result.property; stack: [data, ref index] + } + il.Ldloca(propertyValue); // stack: [data, ref index, ref propertyValue] + il.Ldarg(3); // stack: [data, ref index, ref propertyValue, context] + ReaderMethodBuilderContext.CallReader(il, property.PropertyType, context); // reader(data, ref index, ref propertyValue, context); stack: [] + if(member.GetCustomAttributes(typeof(IgnoreDefaultOnMergeAttribute), false).Length > 0 && property.PropertyType.IsValueType) + { + var equalityOperator = property.PropertyType.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + if(property.PropertyType.IsPrimitive || equalityOperator != null) + { + var temp = il.DeclareLocal(property.PropertyType); + il.Ldloca(temp); + il.Initobj(property.PropertyType); + il.Ldloc(temp); + il.Ldloc(propertyValue); + if(property.PropertyType.IsPrimitive) + il.Ceq(); + else + il.Call(equalityOperator); + var notDefaultLabel = il.DefineLabel("notDefault"); + il.Brfalse(notDefaultLabel); + il.Ret(); + il.MarkLabel(notDefaultLabel); + } + } + il.Ldarg(2); // stack: [ref result] + if(!Type.IsValueType) + il.Ldind(Type); // stack: [result] + il.Ldloc(propertyValue); // stack: [result, propertyValue] + var setter = property.GetSetMethod(true); + if(setter == null) + throw new MissingMethodException(Type.Name, property.Name + "_set"); + il.Call(setter, Type); // result.property = propertyValue + break; + default: + throw new NotSupportedException("Data member of type '" + member.MemberType + "' is not supported"); + } + il.Ret(); + } + var @delegate = method.CreateDelegate(typeof(ReaderDelegate<>).MakeGenericType(Type)); + return new KeyValuePair(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)); + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/CustomReaderBuilder.cs b/GroBuf/Readers/CustomReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/CustomReaderBuilder.cs rename to GroBuf/Readers/CustomReaderBuilder.cs index a9b7836..3076213 100644 --- a/GroBuf/GroBuf/Readers/CustomReaderBuilder.cs +++ b/GroBuf/Readers/CustomReaderBuilder.cs @@ -1,69 +1,69 @@ -using System; -using System.Collections.Generic; - -using GrEmit.Utils; - -namespace GroBuf.Readers -{ - internal class CustomReaderBuilder : ReaderBuilderBase - { - public CustomReaderBuilder(Type type, IGroBufCustomSerializer customSerializer) - : base(type) - { - this.customSerializer = customSerializer; - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.SetFields(Type, new[] {new KeyValuePair("customSerializer_" + Type.Name + "_" + Guid.NewGuid(), typeof(IGroBufCustomSerializer))}); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - var customSerializerField = context.Context.InitConstField(Type, 0, customSerializer); - var il = context.Il; - - context.IncreaseIndexBy1(); // index = index + 1 - context.AssertTypeCode(GroBufTypeCode.CustomData); - - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [(uint)data[index]] - context.IncreaseIndexBy4(); // index = index + 4; stack: [(uint)data[index]] - - context.AssertLength(); // stack: [] - - var local = il.DeclareLocal(typeof(object)); - context.LoadField(customSerializerField); // stack: [customSerializer] - context.LoadData(); // stack: [customSerializer, data] - context.LoadIndexByRef(); // stack: [customSerializer, data, ref index] - il.Ldloca(local); // stack: [customSerializer, data, ref index, ref local] - context.LoadContext(); // stack: [customSerializer, data, ref index, ref local, context] - int dummy = 0; - object dummyObj = null; - var readMethod = HackHelpers.GetMethodDefinition(serializer => serializer.Read(IntPtr.Zero, ref dummy, ref dummyObj, null)); - il.Call(readMethod); // customSerializer.Read(data, ref index, length, ref local); stack: [] - - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(local); // stack: [ref result, ref local] - if(!Type.IsValueType) - { - il.Castclass(Type); - il.Stind(Type); - } - else - { - il.Unbox_Any(Type); // stack: [ref result, (Type)local] - il.Stobj(Type); // result = (Type)local - } - - context.StoreObject(Type); - } - - protected override bool IsReference { get { return false; } } - - private readonly IGroBufCustomSerializer customSerializer; - } +using System; +using System.Collections.Generic; + +using GrEmit.Utils; + +namespace GroBuf.Readers +{ + internal class CustomReaderBuilder : ReaderBuilderBase + { + public CustomReaderBuilder(Type type, IGroBufCustomSerializer customSerializer) + : base(type) + { + this.customSerializer = customSerializer; + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.SetFields(Type, new[] {new KeyValuePair("customSerializer_" + Type.Name + "_" + Guid.NewGuid(), typeof(IGroBufCustomSerializer))}); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + var customSerializerField = context.Context.InitConstField(Type, 0, customSerializer); + var il = context.Il; + + context.IncreaseIndexBy1(); // index = index + 1 + context.AssertTypeCode(GroBufTypeCode.CustomData); + + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [(uint)data[index]] + context.IncreaseIndexBy4(); // index = index + 4; stack: [(uint)data[index]] + + context.AssertLength(); // stack: [] + + var local = il.DeclareLocal(typeof(object)); + context.LoadField(customSerializerField); // stack: [customSerializer] + context.LoadData(); // stack: [customSerializer, data] + context.LoadIndexByRef(); // stack: [customSerializer, data, ref index] + il.Ldloca(local); // stack: [customSerializer, data, ref index, ref local] + context.LoadContext(); // stack: [customSerializer, data, ref index, ref local, context] + int dummy = 0; + object dummyObj = null; + var readMethod = HackHelpers.GetMethodDefinition(serializer => serializer.Read(IntPtr.Zero, ref dummy, ref dummyObj, null)); + il.Call(readMethod); // customSerializer.Read(data, ref index, length, ref local); stack: [] + + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(local); // stack: [ref result, ref local] + if(!Type.IsValueType) + { + il.Castclass(Type); + il.Stind(Type); + } + else + { + il.Unbox_Any(Type); // stack: [ref result, (Type)local] + il.Stobj(Type); // result = (Type)local + } + + context.StoreObject(Type); + } + + protected override bool IsReference { get { return false; } } + + private readonly IGroBufCustomSerializer customSerializer; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/DateTimeOffsetReaderBuilder.cs b/GroBuf/Readers/DateTimeOffsetReaderBuilder.cs similarity index 85% rename from GroBuf/GroBuf/Readers/DateTimeOffsetReaderBuilder.cs rename to GroBuf/Readers/DateTimeOffsetReaderBuilder.cs index dafa33c..5cecbc7 100644 --- a/GroBuf/GroBuf/Readers/DateTimeOffsetReaderBuilder.cs +++ b/GroBuf/Readers/DateTimeOffsetReaderBuilder.cs @@ -1,50 +1,50 @@ -using System; -using System.Reflection; - -namespace GroBuf.Readers -{ - internal class DateTimeOffsetReaderBuilder : ReaderBuilderBase - { - public DateTimeOffsetReaderBuilder() - : base(typeof(DateTimeOffset)) - { - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.BuildConstants(typeof(DateTime)); - context.BuildConstants(typeof(short)); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - context.IncreaseIndexBy1(); - context.AssertTypeCode(GroBufTypeCode.DateTimeOffset); // Assert typeCode == TypeCode.DateTimeOffset - var il = context.Il; - context.LoadResultByRef(); // stack: [ref result] - il.Dup(); // stack: [ref result, ref result] - il.Initobj(Type); // result = default(DateTimeOffset); stack: [ref result] - - context.LoadData(); // stack: [ref result, data] - context.LoadIndexByRef(); // stack: [ref result, data, ref index] - var dateTime = il.DeclareLocal(typeof(DateTime)); - il.Ldloca(dateTime); // stack: [ref result, data, ref index, ref dateTime] - context.LoadContext(); // stack: [ref result, data, ref index, ref dateTime, context] - context.CallReader(typeof(DateTime)); // reader(pinnedData, ref index, ref dateTime, context); stack: [ref result] - il.Dup(); // stack: [ref result, ref result] - il.Ldloc(dateTime); // stack: [ref result, ref result, dateTime] - il.Stfld(Type.GetField("m_dateTime", BindingFlags.Instance | BindingFlags.NonPublic)); // result.m_dateTime = dateTime; stack: [ref result] - - context.LoadData(); // stack: [ref result, data] - context.LoadIndexByRef(); // stack: [ref result, data, ref index] - var offset = il.DeclareLocal(typeof(short)); - il.Ldloca(offset); // stack: [ref result, data, ref index, ref offset] - context.LoadContext(); // stack: [ref result, data, ref index, ref offset, context] - context.CallReader(typeof(short)); // reader(pinnedData, ref index, ref offset, context); stack: [ref result] - il.Ldloc(offset); // stack: [ref result, ref result, offset] - il.Stfld(Type.GetField("m_offsetMinutes", BindingFlags.Instance | BindingFlags.NonPublic)); // result.m_offsetMinutes = offset; stack: [ref result] - } - - protected override bool IsReference { get { return false; } } - } +using System; +using System.Reflection; + +namespace GroBuf.Readers +{ + internal class DateTimeOffsetReaderBuilder : ReaderBuilderBase + { + public DateTimeOffsetReaderBuilder() + : base(typeof(DateTimeOffset)) + { + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.BuildConstants(typeof(DateTime)); + context.BuildConstants(typeof(short)); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + context.IncreaseIndexBy1(); + context.AssertTypeCode(GroBufTypeCode.DateTimeOffset); // Assert typeCode == TypeCode.DateTimeOffset + var il = context.Il; + context.LoadResultByRef(); // stack: [ref result] + il.Dup(); // stack: [ref result, ref result] + il.Initobj(Type); // result = default(DateTimeOffset); stack: [ref result] + + context.LoadData(); // stack: [ref result, data] + context.LoadIndexByRef(); // stack: [ref result, data, ref index] + var dateTime = il.DeclareLocal(typeof(DateTime)); + il.Ldloca(dateTime); // stack: [ref result, data, ref index, ref dateTime] + context.LoadContext(); // stack: [ref result, data, ref index, ref dateTime, context] + context.CallReader(typeof(DateTime)); // reader(pinnedData, ref index, ref dateTime, context); stack: [ref result] + il.Dup(); // stack: [ref result, ref result] + il.Ldloc(dateTime); // stack: [ref result, ref result, dateTime] + il.Stfld(Type.GetField(PlatformHelpers.DateTimeOffsetDateTimeFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // result.m_dateTime = dateTime; stack: [ref result] + + context.LoadData(); // stack: [ref result, data] + context.LoadIndexByRef(); // stack: [ref result, data, ref index] + var offset = il.DeclareLocal(typeof(short)); + il.Ldloca(offset); // stack: [ref result, data, ref index, ref offset] + context.LoadContext(); // stack: [ref result, data, ref index, ref offset, context] + context.CallReader(typeof(short)); // reader(pinnedData, ref index, ref offset, context); stack: [ref result] + il.Ldloc(offset); // stack: [ref result, ref result, offset] + il.Stfld(Type.GetField(PlatformHelpers.DateTimeOffsetOffsetMinutesFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // result.m_offsetMinutes = offset; stack: [ref result] + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/DateTimeReaderBuilder.cs b/GroBuf/Readers/DateTimeReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/DateTimeReaderBuilder.cs rename to GroBuf/Readers/DateTimeReaderBuilder.cs index cc5adc3..e4e4669 100644 --- a/GroBuf/GroBuf/Readers/DateTimeReaderBuilder.cs +++ b/GroBuf/Readers/DateTimeReaderBuilder.cs @@ -1,94 +1,94 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; - -using GrEmit.Utils; - -namespace GroBuf.Readers -{ - internal class DateTimeReaderBuilder : ReaderBuilderBase - { - public DateTimeReaderBuilder() - : base(typeof(DateTime)) - { - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - var constructor = Type.GetConstructor(new[] {typeof(long), typeof(DateTimeKind)}); - if(constructor == null) - throw new MissingConstructorException(Type, typeof(long), typeof(DateTimeKind)); - var il = context.Il; - - il.Ldloc(context.TypeCode); // stack: [typeCode] - il.Ldc_I4((int)GroBufTypeCode.DateTimeNew); // stack: [typeCode, GroBufTypeCode.DateTimeNew] - var processOldFormatLabel = il.DefineLabel("processOldFormat"); - il.Bne_Un(processOldFormatLabel); // if(typeCode != GroBufTypeCode.DateTimeNew) goto processOldFormat; stack: [] - context.IncreaseIndexBy1(); - il.Ldc_I4(8); // stack: [8] - context.AssertLength(); - context.LoadResultByRef(); // stack: [ref result] - context.GoToCurrentLocation(); // stack: [ref result, &data[index]] - il.Ldind(typeof(long)); // stack: [ref result, (long)data[index]] - il.Call(dateTimeFromBinaryMethod); // stack: [ref result, DateTime.FromBinary((long)data[index])] - il.Stobj(Type); // result = DateTime.FromBinary((long)data[index]) - context.IncreaseIndexBy8(); // index = index + 8 - il.Ret(); - - il.MarkLabel(processOldFormatLabel); - var okLabel = il.DefineLabel("ok"); - il.Ldloc(context.TypeCode); // stack: [typeCode] - il.Ldc_I4((int)GroBufTypeCode.DateTimeOld); // stack: [typeCode, GroBufTypeCode.DateTimeOld] - il.Beq(okLabel); // if(typeCode == GroBufTypeCode.DateTimeOld) goto label - - il.Ldloc(context.TypeCode); // stack: [typeCode] - il.Ldc_I4((int)GroBufTypeCode.Int64); // stack: [typeCode, GroBufTypeCode.Int64] - il.Beq(okLabel); // if(typeCode == GroBufTypeCode.Int64) goto label - - context.SkipValue(); - il.Ret(); - - il.MarkLabel(okLabel); - - context.IncreaseIndexBy1(); - - il.Ldc_I4(8); // stack: [8] - context.AssertLength(); - - context.LoadResultByRef(); // stack: [ref result] - - context.GoToCurrentLocation(); // stack: [ref result, &data[index]] - il.Ldind(typeof(long)); // stack: [ref result, (long)&data[index] = ticks] - il.Dup(); // stack: [ref result, ticks, ticks] - il.Ldc_I8(long.MinValue); // stack: [ref result, ticks, ticks, 0x8000000000000000] - il.And(); // stack: [ref result, ticks, ticks & 0x8000000000000000] - var notUtcLabel = il.DefineLabel("notUtc"); - il.Brtrue(notUtcLabel); // if(ticks & 0x8000000000000000 != 0) goto notUtc; stack: [ref result, ticks] - il.Ldc_I4((int)DateTimeKind.Utc); // stack: [ref result, ticks, DateTimeKind.Utc] - il.Newobj(constructor); // stack: [ref result, new DateTimeOld(ticks, DateTimeKind.Utc)] - il.Stobj(Type); - context.IncreaseIndexBy8(); - il.Ret(); - - il.MarkLabel(notUtcLabel); - context.IncreaseIndexBy8(); - il.Ldc_I4(1); - context.AssertLength(); - il.Ldc_I8(long.MaxValue); // stack: [ref result, ticks, 0x7FFFFFFFFFFFFFFF] - il.And(); // stack: [ref result, ticks & 0x7FFFFFFFFFFFFFFF] - context.GoToCurrentLocation(); // stack: [ref result, ticks & 0x7FFFFFFFFFFFFFFF, &data[index]] - il.Ldind(typeof(byte)); // stack: [ref result, ticks & 0x7FFFFFFFFFFFFFFF, (DateTimeKind)data[index] = kind] - il.Newobj(constructor); // stack: [ref result, new DateTimeOld(ticks, kind)] - il.Stobj(Type); - context.IncreaseIndexBy1(); - } - - protected override bool IsReference { get { return false; } } - - private static readonly MethodInfo dateTimeFromBinaryMethod = HackHelpers.GetMethodDefinition((Expression>)(data => DateTime.FromBinary(data))); - } +using System; +using System.Linq.Expressions; +using System.Reflection; + +using GrEmit.Utils; + +namespace GroBuf.Readers +{ + internal class DateTimeReaderBuilder : ReaderBuilderBase + { + public DateTimeReaderBuilder() + : base(typeof(DateTime)) + { + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + var constructor = Type.GetConstructor(new[] {typeof(long), typeof(DateTimeKind)}); + if(constructor == null) + throw new MissingConstructorException(Type, typeof(long), typeof(DateTimeKind)); + var il = context.Il; + + il.Ldloc(context.TypeCode); // stack: [typeCode] + il.Ldc_I4((int)GroBufTypeCode.DateTimeNew); // stack: [typeCode, GroBufTypeCode.DateTimeNew] + var processOldFormatLabel = il.DefineLabel("processOldFormat"); + il.Bne_Un(processOldFormatLabel); // if(typeCode != GroBufTypeCode.DateTimeNew) goto processOldFormat; stack: [] + context.IncreaseIndexBy1(); + il.Ldc_I4(8); // stack: [8] + context.AssertLength(); + context.LoadResultByRef(); // stack: [ref result] + context.GoToCurrentLocation(); // stack: [ref result, &data[index]] + il.Ldind(typeof(long)); // stack: [ref result, (long)data[index]] + il.Call(dateTimeFromBinaryMethod); // stack: [ref result, DateTime.FromBinary((long)data[index])] + il.Stobj(Type); // result = DateTime.FromBinary((long)data[index]) + context.IncreaseIndexBy8(); // index = index + 8 + il.Ret(); + + il.MarkLabel(processOldFormatLabel); + var okLabel = il.DefineLabel("ok"); + il.Ldloc(context.TypeCode); // stack: [typeCode] + il.Ldc_I4((int)GroBufTypeCode.DateTimeOld); // stack: [typeCode, GroBufTypeCode.DateTimeOld] + il.Beq(okLabel); // if(typeCode == GroBufTypeCode.DateTimeOld) goto label + + il.Ldloc(context.TypeCode); // stack: [typeCode] + il.Ldc_I4((int)GroBufTypeCode.Int64); // stack: [typeCode, GroBufTypeCode.Int64] + il.Beq(okLabel); // if(typeCode == GroBufTypeCode.Int64) goto label + + context.SkipValue(); + il.Ret(); + + il.MarkLabel(okLabel); + + context.IncreaseIndexBy1(); + + il.Ldc_I4(8); // stack: [8] + context.AssertLength(); + + context.LoadResultByRef(); // stack: [ref result] + + context.GoToCurrentLocation(); // stack: [ref result, &data[index]] + il.Ldind(typeof(long)); // stack: [ref result, (long)&data[index] = ticks] + il.Dup(); // stack: [ref result, ticks, ticks] + il.Ldc_I8(long.MinValue); // stack: [ref result, ticks, ticks, 0x8000000000000000] + il.And(); // stack: [ref result, ticks, ticks & 0x8000000000000000] + var notUtcLabel = il.DefineLabel("notUtc"); + il.Brtrue(notUtcLabel); // if(ticks & 0x8000000000000000 != 0) goto notUtc; stack: [ref result, ticks] + il.Ldc_I4((int)DateTimeKind.Utc); // stack: [ref result, ticks, DateTimeKind.Utc] + il.Newobj(constructor); // stack: [ref result, new DateTimeOld(ticks, DateTimeKind.Utc)] + il.Stobj(Type); + context.IncreaseIndexBy8(); + il.Ret(); + + il.MarkLabel(notUtcLabel); + context.IncreaseIndexBy8(); + il.Ldc_I4(1); + context.AssertLength(); + il.Ldc_I8(long.MaxValue); // stack: [ref result, ticks, 0x7FFFFFFFFFFFFFFF] + il.And(); // stack: [ref result, ticks & 0x7FFFFFFFFFFFFFFF] + context.GoToCurrentLocation(); // stack: [ref result, ticks & 0x7FFFFFFFFFFFFFFF, &data[index]] + il.Ldind(typeof(byte)); // stack: [ref result, ticks & 0x7FFFFFFFFFFFFFFF, (DateTimeKind)data[index] = kind] + il.Newobj(constructor); // stack: [ref result, new DateTimeOld(ticks, kind)] + il.Stobj(Type); + context.IncreaseIndexBy1(); + } + + protected override bool IsReference { get { return false; } } + + private static readonly MethodInfo dateTimeFromBinaryMethod = HackHelpers.GetMethodDefinition((Expression>)(data => DateTime.FromBinary(data))); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/DictionaryReaderBuilder.cs b/GroBuf/Readers/DictionaryReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/DictionaryReaderBuilder.cs rename to GroBuf/Readers/DictionaryReaderBuilder.cs index 4c2ec44..29b6ab9 100644 --- a/GroBuf/GroBuf/Readers/DictionaryReaderBuilder.cs +++ b/GroBuf/Readers/DictionaryReaderBuilder.cs @@ -1,108 +1,108 @@ -using System; -using System.Collections.Generic; - -namespace GroBuf.Readers -{ - internal class DictionaryReaderBuilder : ReaderBuilderBase - { - public DictionaryReaderBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Dictionary<,>))) - throw new InvalidOperationException("Dictionary expected but was '" + Type + "'"); - keyType = Type.GetGenericArguments()[0]; - valueType = Type.GetGenericArguments()[1]; - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.BuildConstants(keyType); - context.BuildConstants(valueType); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - context.IncreaseIndexBy1(); - context.AssertTypeCode(GroBufTypeCode.Dictionary); - - var il = context.Il; - var length = context.Length; - - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [data length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] - - context.AssertLength(); - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [array length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] - il.Stloc(length); // length = array length; stack: [] - - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(length); // stack: [ref result, length] - il.Newobj(Type.GetConstructor(new[] {typeof(int)})); // stack: [ref result, new Dictionary(length)] - il.Stind(Type); // result = new Dictionary(length); stack: [] - - context.StoreObject(Type); - - il.Ldloc(length); // stack: [length] - var doneLabel = il.DefineLabel("done"); - il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] - var i = il.DeclareLocal(typeof(uint)); - il.Ldc_I4(0); // stack: [0] - il.Stloc(i); // i = 0; stack: [] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - - context.LoadData(); // stack: [pinnedData] - context.LoadIndexByRef(); // stack: [pinnedData, ref index] - var key = il.DeclareLocal(Type.GetGenericArguments()[0]); - var value = il.DeclareLocal(Type.GetGenericArguments()[1]); - il.Ldloca(key); // stack: [pinnedData, ref index, ref key] - context.LoadContext(); // stack: [pinnedData, ref index, ref key, context] - context.CallReader(keyType); // reader(pinnedData, ref index, ref key, context); stack: [] - - context.LoadData(); // stack: [pinnedData] - context.LoadIndexByRef(); // stack: [pinnedData, ref index] - il.Ldloca(value); // stack: [pinnedData, ref index, ref value] - context.LoadContext(); // stack: [pinnedData, ref index, ref value, context] - context.CallReader(valueType); // reader(pinnedData, ref index, ref value, context); stack: [] - - context.LoadResult(Type); - il.Ldloc(key); - il.Ldloc(value); - il.Call(Type.GetMethod("Add")); - - if(!keyType.IsValueType) - { - il.Ldnull(); - il.Stloc(key); - } - if(!valueType.IsValueType) - { - il.Ldnull(); - il.Stloc(value); - } - - il.Ldloc(i); // stack: [i] - il.Ldc_I4(1); // stack: [i, 1] - il.Add(); // stack: [i + 1] - il.Dup(); // stack: [i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [i] - il.Ldloc(length); // stack: [i, length] - il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart - il.MarkLabel(doneLabel); // stack: [] - } - - protected override bool IsReference { get { return true; } } - - private readonly Type keyType; - private readonly Type valueType; - } +using System; +using System.Collections.Generic; + +namespace GroBuf.Readers +{ + internal class DictionaryReaderBuilder : ReaderBuilderBase + { + public DictionaryReaderBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Dictionary<,>))) + throw new InvalidOperationException("Dictionary expected but was '" + Type + "'"); + keyType = Type.GetGenericArguments()[0]; + valueType = Type.GetGenericArguments()[1]; + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.BuildConstants(keyType); + context.BuildConstants(valueType); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + context.IncreaseIndexBy1(); + context.AssertTypeCode(GroBufTypeCode.Dictionary); + + var il = context.Il; + var length = context.Length; + + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [data length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] + + context.AssertLength(); + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [array length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] + il.Stloc(length); // length = array length; stack: [] + + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(length); // stack: [ref result, length] + il.Newobj(Type.GetConstructor(new[] {typeof(int)})); // stack: [ref result, new Dictionary(length)] + il.Stind(Type); // result = new Dictionary(length); stack: [] + + context.StoreObject(Type); + + il.Ldloc(length); // stack: [length] + var doneLabel = il.DefineLabel("done"); + il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] + var i = il.DeclareLocal(typeof(uint)); + il.Ldc_I4(0); // stack: [0] + il.Stloc(i); // i = 0; stack: [] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + + context.LoadData(); // stack: [pinnedData] + context.LoadIndexByRef(); // stack: [pinnedData, ref index] + var key = il.DeclareLocal(Type.GetGenericArguments()[0]); + var value = il.DeclareLocal(Type.GetGenericArguments()[1]); + il.Ldloca(key); // stack: [pinnedData, ref index, ref key] + context.LoadContext(); // stack: [pinnedData, ref index, ref key, context] + context.CallReader(keyType); // reader(pinnedData, ref index, ref key, context); stack: [] + + context.LoadData(); // stack: [pinnedData] + context.LoadIndexByRef(); // stack: [pinnedData, ref index] + il.Ldloca(value); // stack: [pinnedData, ref index, ref value] + context.LoadContext(); // stack: [pinnedData, ref index, ref value, context] + context.CallReader(valueType); // reader(pinnedData, ref index, ref value, context); stack: [] + + context.LoadResult(Type); + il.Ldloc(key); + il.Ldloc(value); + il.Call(Type.GetMethod("Add")); + + if(!keyType.IsValueType) + { + il.Ldnull(); + il.Stloc(key); + } + if(!valueType.IsValueType) + { + il.Ldnull(); + il.Stloc(value); + } + + il.Ldloc(i); // stack: [i] + il.Ldc_I4(1); // stack: [i, 1] + il.Add(); // stack: [i + 1] + il.Dup(); // stack: [i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [i] + il.Ldloc(length); // stack: [i, length] + il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart + il.MarkLabel(doneLabel); // stack: [] + } + + protected override bool IsReference { get { return true; } } + + private readonly Type keyType; + private readonly Type valueType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/EnumReaderBuilder.cs b/GroBuf/Readers/EnumReaderBuilder.cs similarity index 98% rename from GroBuf/GroBuf/Readers/EnumReaderBuilder.cs rename to GroBuf/Readers/EnumReaderBuilder.cs index f2ccdc4..527b072 100644 --- a/GroBuf/GroBuf/Readers/EnumReaderBuilder.cs +++ b/GroBuf/Readers/EnumReaderBuilder.cs @@ -1,99 +1,99 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace GroBuf.Readers -{ - internal class EnumReaderBuilder : ReaderBuilderBase - { - public EnumReaderBuilder(Type type) - : base(type) - { - if(!Type.IsEnum) throw new InvalidOperationException("Enum expected but was '" + Type + "'"); - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.SetFields(Type, new[] - { - new KeyValuePair("values_" + Type.Name + "_" + Guid.NewGuid(), typeof(int[])), - new KeyValuePair("hashCodes_" + Type.Name + "_" + Guid.NewGuid(), typeof(ulong[])), - }); - context.BuildConstants(typeof(int)); - context.BuildConstants(typeof(string)); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - int[] values; - ulong[] hashCodes; - EnumHelpers.BuildValuesTable(Type, out values, out hashCodes); - var valuesField = context.Context.InitConstField(Type, 0, values); - var hashCodesField = context.Context.InitConstField(Type, 1, hashCodes); - var il = context.Il; - il.Ldloc(context.TypeCode); // stack: [typeCode] - il.Ldc_I4((int)GroBufTypeCode.Enum); - var tryParseLabel = il.DefineLabel("tryParse"); - il.Bne_Un(tryParseLabel); // if(typeCode != GroBufTypeCode.Enum) goto tryParse; - context.IncreaseIndexBy1(); - il.Ldc_I4(8); // stack: [8] - context.AssertLength(); - context.LoadResultByRef(); // stack: [ref result] - context.GoToCurrentLocation(); // stack: [ref result, &result[index]] - il.Ldind(typeof(long)); // stack: [ref result, *(int64*)result[index] = hashCode] - context.IncreaseIndexBy8(); // index = index + 8; stack: [ref result, hashCode] - - var parseByHashCodeLabel = il.DefineLabel("parseByHashCode"); - il.MarkLabel(parseByHashCodeLabel); - - il.Dup(); // stack: [ref result, hashCode, hashCode] - il.Ldc_I8(hashCodes.Length); // stack: [ref result, hashCode, hashCode, (int64)hashCodes.Length] - il.Rem(true); // stack: [ref result, hashCode, hashCode % hashCodes.Length = idx] - il.Conv(); // stack: [ref result, hashCode, (int)(hashCode % hashCodes.Length)] - var idx = context.Length; - il.Stloc(idx); // idx = (int)(hashCode % hashCodes.Length); stack: [ref result, hashCode] - - context.LoadField(hashCodesField); // stack: [ref result, hashCode, hashCodes] - il.Ldloc(idx); // stack: [ref result, hashCode, hashCodes, idx] - il.Ldelem(typeof(long)); // stack: [ref result, hashCode, hashCodes[idx]] - var returnDefaultLabel = il.DefineLabel("returnDefault"); - il.Bne_Un(returnDefaultLabel); // if(hashCode != hashCodes[idx]) goto returnDefault; stack: [ref result] - context.LoadField(valuesField); // stack: [ref result, values] - il.Ldloc(idx); // stack: [ref result, values, idx] - il.Ldelem(typeof(int)); // stack: [ref result, values[idx]] - il.Stind(typeof(int)); // result = values[idx]; stack: [] - il.Ret(); - il.MarkLabel(returnDefaultLabel); - il.Ldc_I4(0); // stack: [0] - il.Stind(typeof(int)); // result = 0 - il.Ret(); - - il.MarkLabel(tryParseLabel); - il.Ldloc(context.TypeCode); // stack: [typeCode] - il.Ldc_I4((int)GroBufTypeCode.String); // stack: [typeCode, GroBufTypeCode.String] - var readAsIntLabel = il.DefineLabel("readAsInt"); - il.Bne_Un(readAsIntLabel); // if(typeCode != GroBufTypeCode.String) goto readAsInt; - var str = il.DeclareLocal(typeof(string)); - - context.LoadData(); // stack: [pinnedData] - context.LoadIndexByRef(); // stack: [pinnedData, ref index] - il.Ldloca(str); // stack: [pinnedData, ref index, ref str] - context.LoadContext(); // stack: [pinnedData, ref index, ref str, context] - context.CallReader(typeof(string)); // reader(pinnedData, ref index, ref str, context); stack: [] - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(str); // stack: [ref result, str] - il.Call(typeof(GroBufHelpers).GetMethod("CalcHash", BindingFlags.Public | BindingFlags.Static)); // stack: [ref result, GroBufHelpers.CalcHash(str)] - il.Br(parseByHashCodeLabel); - - il.MarkLabel(readAsIntLabel); - - context.LoadData(); // stack: [pinnedData] - context.LoadIndexByRef(); // stack: [pinnedData, ref index] - context.LoadResultByRef(); // stack: [pinnedData, ref index, ref result] - context.LoadContext(); // stack: [pinnedData, ref index, ref result, context] - context.CallReader(typeof(int)); // reader(pinnedData, ref index, ref result, context) - } - - protected override bool IsReference { get { return false; } } - } +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace GroBuf.Readers +{ + internal class EnumReaderBuilder : ReaderBuilderBase + { + public EnumReaderBuilder(Type type) + : base(type) + { + if(!Type.IsEnum) throw new InvalidOperationException("Enum expected but was '" + Type + "'"); + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.SetFields(Type, new[] + { + new KeyValuePair("values_" + Type.Name + "_" + Guid.NewGuid(), typeof(int[])), + new KeyValuePair("hashCodes_" + Type.Name + "_" + Guid.NewGuid(), typeof(ulong[])), + }); + context.BuildConstants(typeof(int)); + context.BuildConstants(typeof(string)); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + int[] values; + ulong[] hashCodes; + EnumHelpers.BuildValuesTable(Type, out values, out hashCodes); + var valuesField = context.Context.InitConstField(Type, 0, values); + var hashCodesField = context.Context.InitConstField(Type, 1, hashCodes); + var il = context.Il; + il.Ldloc(context.TypeCode); // stack: [typeCode] + il.Ldc_I4((int)GroBufTypeCode.Enum); + var tryParseLabel = il.DefineLabel("tryParse"); + il.Bne_Un(tryParseLabel); // if(typeCode != GroBufTypeCode.Enum) goto tryParse; + context.IncreaseIndexBy1(); + il.Ldc_I4(8); // stack: [8] + context.AssertLength(); + context.LoadResultByRef(); // stack: [ref result] + context.GoToCurrentLocation(); // stack: [ref result, &result[index]] + il.Ldind(typeof(long)); // stack: [ref result, *(int64*)result[index] = hashCode] + context.IncreaseIndexBy8(); // index = index + 8; stack: [ref result, hashCode] + + var parseByHashCodeLabel = il.DefineLabel("parseByHashCode"); + il.MarkLabel(parseByHashCodeLabel); + + il.Dup(); // stack: [ref result, hashCode, hashCode] + il.Ldc_I8(hashCodes.Length); // stack: [ref result, hashCode, hashCode, (int64)hashCodes.Length] + il.Rem(true); // stack: [ref result, hashCode, hashCode % hashCodes.Length = idx] + il.Conv(); // stack: [ref result, hashCode, (int)(hashCode % hashCodes.Length)] + var idx = context.Length; + il.Stloc(idx); // idx = (int)(hashCode % hashCodes.Length); stack: [ref result, hashCode] + + context.LoadField(hashCodesField); // stack: [ref result, hashCode, hashCodes] + il.Ldloc(idx); // stack: [ref result, hashCode, hashCodes, idx] + il.Ldelem(typeof(long)); // stack: [ref result, hashCode, hashCodes[idx]] + var returnDefaultLabel = il.DefineLabel("returnDefault"); + il.Bne_Un(returnDefaultLabel); // if(hashCode != hashCodes[idx]) goto returnDefault; stack: [ref result] + context.LoadField(valuesField); // stack: [ref result, values] + il.Ldloc(idx); // stack: [ref result, values, idx] + il.Ldelem(typeof(int)); // stack: [ref result, values[idx]] + il.Stind(typeof(int)); // result = values[idx]; stack: [] + il.Ret(); + il.MarkLabel(returnDefaultLabel); + il.Ldc_I4(0); // stack: [0] + il.Stind(typeof(int)); // result = 0 + il.Ret(); + + il.MarkLabel(tryParseLabel); + il.Ldloc(context.TypeCode); // stack: [typeCode] + il.Ldc_I4((int)GroBufTypeCode.String); // stack: [typeCode, GroBufTypeCode.String] + var readAsIntLabel = il.DefineLabel("readAsInt"); + il.Bne_Un(readAsIntLabel); // if(typeCode != GroBufTypeCode.String) goto readAsInt; + var str = il.DeclareLocal(typeof(string)); + + context.LoadData(); // stack: [pinnedData] + context.LoadIndexByRef(); // stack: [pinnedData, ref index] + il.Ldloca(str); // stack: [pinnedData, ref index, ref str] + context.LoadContext(); // stack: [pinnedData, ref index, ref str, context] + context.CallReader(typeof(string)); // reader(pinnedData, ref index, ref str, context); stack: [] + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(str); // stack: [ref result, str] + il.Call(typeof(GroBufHelpers).GetMethod("CalcHash", BindingFlags.Public | BindingFlags.Static)); // stack: [ref result, GroBufHelpers.CalcHash(str)] + il.Br(parseByHashCodeLabel); + + il.MarkLabel(readAsIntLabel); + + context.LoadData(); // stack: [pinnedData] + context.LoadIndexByRef(); // stack: [pinnedData, ref index] + context.LoadResultByRef(); // stack: [pinnedData, ref index, ref result] + context.LoadContext(); // stack: [pinnedData, ref index, ref result, context] + context.CallReader(typeof(int)); // reader(pinnedData, ref index, ref result, context) + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/GuidReaderBuilder.cs b/GroBuf/Readers/GuidReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/GuidReaderBuilder.cs rename to GroBuf/Readers/GuidReaderBuilder.cs index c6ac396..2161ebc 100644 --- a/GroBuf/GroBuf/Readers/GuidReaderBuilder.cs +++ b/GroBuf/Readers/GuidReaderBuilder.cs @@ -1,44 +1,44 @@ -using System; - -namespace GroBuf.Readers -{ - internal class GuidReaderBuilder : ReaderBuilderBase - { - public GuidReaderBuilder() - : base(typeof(Guid)) - { - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - context.IncreaseIndexBy1(); - context.AssertTypeCode(GroBufTypeCode.Guid); // Assert typeCode == TypeCode.Guid - var il = context.Il; - var pinnedResult = il.DeclareLocal(Type.MakeByRefType(), true); - - il.Ldc_I4(16); - context.AssertLength(); - context.LoadResultByRef(); // stack: [ref result] - il.Stloc(pinnedResult); // pinnedResult = ref result - il.Ldloc(pinnedResult); // stack: [&result] - il.Dup(); // stack: [&result, &result] - context.GoToCurrentLocation(); // stack: [&result, &result, &data[index]] - il.Ldind(typeof(long)); // stack: [&result, &result, (int64)data[index]] - il.Stind(typeof(long)); // *result = (int64)data[index]; stack: [&result] - context.IncreaseIndexBy8(); // index = index + 8 - il.Ldc_I4(8); // stack: [&result, 8] - il.Add(); // stack: [&result + 8] - context.GoToCurrentLocation(); // stack: [&result + 8, &data[index]] - il.Ldind(typeof(long)); // stack: [&result + 8, (int64)data[index]] - il.Stind(typeof(long)); // *(&result + 8) = (int64)data[index]; stack: [] - context.IncreaseIndexBy8(); // index = index + 8 - il.FreePinnedLocal(pinnedResult); // pinnedResult = null; stack: [] - } - - protected override bool IsReference { get { return false; } } - } +using System; + +namespace GroBuf.Readers +{ + internal class GuidReaderBuilder : ReaderBuilderBase + { + public GuidReaderBuilder() + : base(typeof(Guid)) + { + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + context.IncreaseIndexBy1(); + context.AssertTypeCode(GroBufTypeCode.Guid); // Assert typeCode == TypeCode.Guid + var il = context.Il; + var pinnedResult = il.DeclareLocal(Type.MakeByRefType(), true); + + il.Ldc_I4(16); + context.AssertLength(); + context.LoadResultByRef(); // stack: [ref result] + il.Stloc(pinnedResult); // pinnedResult = ref result + il.Ldloc(pinnedResult); // stack: [&result] + il.Dup(); // stack: [&result, &result] + context.GoToCurrentLocation(); // stack: [&result, &result, &data[index]] + il.Ldind(typeof(long)); // stack: [&result, &result, (int64)data[index]] + il.Stind(typeof(long)); // *result = (int64)data[index]; stack: [&result] + context.IncreaseIndexBy8(); // index = index + 8 + il.Ldc_I4(8); // stack: [&result, 8] + il.Add(); // stack: [&result + 8] + context.GoToCurrentLocation(); // stack: [&result + 8, &data[index]] + il.Ldind(typeof(long)); // stack: [&result + 8, (int64)data[index]] + il.Stind(typeof(long)); // *(&result + 8) = (int64)data[index]; stack: [] + context.IncreaseIndexBy8(); // index = index + 8 + il.FreePinnedLocal(pinnedResult); // pinnedResult = null; stack: [] + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/HashSetReaderBuilder.cs b/GroBuf/Readers/HashSetReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/HashSetReaderBuilder.cs rename to GroBuf/Readers/HashSetReaderBuilder.cs index 19bc358..3e2baee 100644 --- a/GroBuf/GroBuf/Readers/HashSetReaderBuilder.cs +++ b/GroBuf/Readers/HashSetReaderBuilder.cs @@ -1,96 +1,96 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -namespace GroBuf.Readers -{ - internal class HashSetReaderBuilder : ReaderBuilderBase - { - public HashSetReaderBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(HashSet<>))) - throw new InvalidOperationException("HashSet expected but was '" + Type + "'"); - elementType = Type.GetGenericArguments()[0]; - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - context.IncreaseIndexBy1(); - context.AssertTypeCode(GroBufTypeCode.Array); - - var il = context.Il; - var length = context.Length; - - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [data length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] - - context.AssertLength(); - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [array length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] - il.Stloc(length); // length = array length; stack: [] - - context.LoadResultByRef(); // stack: [ref result] - il.Newobj(Type.GetConstructor(Type.EmptyTypes)); // stack: [ref result, new HashSet() = hashSet] - il.Dup(); // stack: [ref result, hashSet, hashSet] - il.Ldloc(length); // stack: [ref result, hashSet, hashSet, length] - il.Call(Type.GetMethod("Initialize", BindingFlags.Instance | BindingFlags.NonPublic)); // hashSet.Initialize(length); stack: [ref result, hashSet] - il.Stind(Type); // result = hashSet; stack: [] - - context.StoreObject(Type); - - il.Ldloc(length); // stack: [length] - var doneLabel = il.DefineLabel("done"); - il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] - var i = il.DeclareLocal(typeof(uint)); - il.Ldc_I4(0); // stack: [0] - il.Stloc(i); // i = 0; stack: [] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - - context.LoadData(); // stack: [pinnedData] - context.LoadIndexByRef(); // stack: [pinnedData, ref index] - var value = il.DeclareLocal(elementType); - il.Ldloca(value); // stack: [pinnedData, ref index, ref value] - context.LoadContext(); // stack: [pinnedData, ref index, ref value, context] - context.CallReader(elementType); // reader(pinnedData, ref index, ref value, context); stack: [] - - context.LoadResult(Type); // stack: [result] - il.Ldloc(value); // stack: [result, value] - il.Call(Type.GetMethod("Add")); // stack: [result.Add(value)] - il.Pop(); // stack: [] - - if(!elementType.IsValueType) - { - il.Ldnull(); - il.Stloc(value); - } - - il.Ldloc(i); // stack: [i] - il.Ldc_I4(1); // stack: [i, 1] - il.Add(); // stack: [i + 1] - il.Dup(); // stack: [i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [i] - il.Ldloc(length); // stack: [i, length] - il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart - il.MarkLabel(doneLabel); // stack: [] - } - - protected override bool IsReference { get { return true; } } - - private readonly Type elementType; - } +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace GroBuf.Readers +{ + internal class HashSetReaderBuilder : ReaderBuilderBase + { + public HashSetReaderBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(HashSet<>))) + throw new InvalidOperationException("HashSet expected but was '" + Type + "'"); + elementType = Type.GetGenericArguments()[0]; + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + context.IncreaseIndexBy1(); + context.AssertTypeCode(GroBufTypeCode.Array); + + var il = context.Il; + var length = context.Length; + + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [data length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] + + context.AssertLength(); + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [array length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] + il.Stloc(length); // length = array length; stack: [] + + context.LoadResultByRef(); // stack: [ref result] + il.Newobj(Type.GetConstructor(Type.EmptyTypes)); // stack: [ref result, new HashSet() = hashSet] + il.Dup(); // stack: [ref result, hashSet, hashSet] + il.Ldloc(length); // stack: [ref result, hashSet, hashSet, length] + il.Call(Type.GetMethod("Initialize", BindingFlags.Instance | BindingFlags.NonPublic)); // hashSet.Initialize(length); stack: [ref result, hashSet] + il.Stind(Type); // result = hashSet; stack: [] + + context.StoreObject(Type); + + il.Ldloc(length); // stack: [length] + var doneLabel = il.DefineLabel("done"); + il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] + var i = il.DeclareLocal(typeof(uint)); + il.Ldc_I4(0); // stack: [0] + il.Stloc(i); // i = 0; stack: [] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + + context.LoadData(); // stack: [pinnedData] + context.LoadIndexByRef(); // stack: [pinnedData, ref index] + var value = il.DeclareLocal(elementType); + il.Ldloca(value); // stack: [pinnedData, ref index, ref value] + context.LoadContext(); // stack: [pinnedData, ref index, ref value, context] + context.CallReader(elementType); // reader(pinnedData, ref index, ref value, context); stack: [] + + context.LoadResult(Type); // stack: [result] + il.Ldloc(value); // stack: [result, value] + il.Call(Type.GetMethod("Add")); // stack: [result.Add(value)] + il.Pop(); // stack: [] + + if(!elementType.IsValueType) + { + il.Ldnull(); + il.Stloc(value); + } + + il.Ldloc(i); // stack: [i] + il.Ldc_I4(1); // stack: [i, 1] + il.Add(); // stack: [i + 1] + il.Dup(); // stack: [i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [i] + il.Ldloc(length); // stack: [i, length] + il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart + il.MarkLabel(doneLabel); // stack: [] + } + + protected override bool IsReference { get { return true; } } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/HashtableReaderBuilder.cs b/GroBuf/Readers/HashtableReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/HashtableReaderBuilder.cs rename to GroBuf/Readers/HashtableReaderBuilder.cs index fb0f5c5..ac3f18f 100644 --- a/GroBuf/GroBuf/Readers/HashtableReaderBuilder.cs +++ b/GroBuf/Readers/HashtableReaderBuilder.cs @@ -1,93 +1,93 @@ -using System.Collections; - -namespace GroBuf.Readers -{ - internal class HashtableReaderBuilder : ReaderBuilderBase - { - public HashtableReaderBuilder() - : base(typeof(Hashtable)) - { - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.BuildConstants(typeof(object)); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - context.IncreaseIndexBy1(); - context.AssertTypeCode(GroBufTypeCode.Dictionary); - - var il = context.Il; - var length = context.Length; - - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [data length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] - - context.AssertLength(); - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [array length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] - il.Stloc(length); // length = array length; stack: [] - - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(length); // stack: [ref result, length] - il.Newobj(Type.GetConstructor(new[] {typeof(int)})); // stack: [ref result, new Hashtable(length)] - il.Stind(Type); // result = new Hashtable(length); stack: [] - - context.StoreObject(Type); - - il.Ldloc(length); // stack: [length] - var doneLabel = il.DefineLabel("done"); - il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] - var i = il.DeclareLocal(typeof(uint)); - il.Ldc_I4(0); // stack: [0] - il.Stloc(i); // i = 0; stack: [] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - - context.LoadData(); // stack: [pinnedData] - context.LoadIndexByRef(); // stack: [pinnedData, ref index] - var key = il.DeclareLocal(typeof(object)); - var value = il.DeclareLocal(typeof(object)); - il.Ldloca(key); // stack: [pinnedData, ref index, ref key] - context.LoadContext(); // stack: [pinnedData, ref index, ref key, context] - context.CallReader(typeof(object)); // reader(pinnedData, ref index, ref key, context); stack: [] - - context.LoadData(); // stack: [pinnedData] - context.LoadIndexByRef(); // stack: [pinnedData, ref index] - il.Ldloca(value); // stack: [pinnedData, ref index, ref value] - context.LoadContext(); // stack: [pinnedData, ref index, ref value, context] - context.CallReader(typeof(object)); // reader(pinnedData, ref index, ref value, context); stack: [] - - context.LoadResult(Type); - il.Ldloc(key); - il.Ldloc(value); - il.Call(Type.GetMethod("Add")); - - il.Ldnull(); - il.Stloc(key); - il.Ldnull(); - il.Stloc(value); - - il.Ldloc(i); // stack: [i] - il.Ldc_I4(1); // stack: [i, 1] - il.Add(); // stack: [i + 1] - il.Dup(); // stack: [i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [i] - il.Ldloc(length); // stack: [i, length] - il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart - il.MarkLabel(doneLabel); // stack: [] - } - - protected override bool IsReference { get { return true; } } - } +using System.Collections; + +namespace GroBuf.Readers +{ + internal class HashtableReaderBuilder : ReaderBuilderBase + { + public HashtableReaderBuilder() + : base(typeof(Hashtable)) + { + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.BuildConstants(typeof(object)); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + context.IncreaseIndexBy1(); + context.AssertTypeCode(GroBufTypeCode.Dictionary); + + var il = context.Il; + var length = context.Length; + + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [data length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] + + context.AssertLength(); + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [array length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] + il.Stloc(length); // length = array length; stack: [] + + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(length); // stack: [ref result, length] + il.Newobj(Type.GetConstructor(new[] {typeof(int)})); // stack: [ref result, new Hashtable(length)] + il.Stind(Type); // result = new Hashtable(length); stack: [] + + context.StoreObject(Type); + + il.Ldloc(length); // stack: [length] + var doneLabel = il.DefineLabel("done"); + il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] + var i = il.DeclareLocal(typeof(uint)); + il.Ldc_I4(0); // stack: [0] + il.Stloc(i); // i = 0; stack: [] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + + context.LoadData(); // stack: [pinnedData] + context.LoadIndexByRef(); // stack: [pinnedData, ref index] + var key = il.DeclareLocal(typeof(object)); + var value = il.DeclareLocal(typeof(object)); + il.Ldloca(key); // stack: [pinnedData, ref index, ref key] + context.LoadContext(); // stack: [pinnedData, ref index, ref key, context] + context.CallReader(typeof(object)); // reader(pinnedData, ref index, ref key, context); stack: [] + + context.LoadData(); // stack: [pinnedData] + context.LoadIndexByRef(); // stack: [pinnedData, ref index] + il.Ldloca(value); // stack: [pinnedData, ref index, ref value] + context.LoadContext(); // stack: [pinnedData, ref index, ref value, context] + context.CallReader(typeof(object)); // reader(pinnedData, ref index, ref value, context); stack: [] + + context.LoadResult(Type); + il.Ldloc(key); + il.Ldloc(value); + il.Call(Type.GetMethod("Add")); + + il.Ldnull(); + il.Stloc(key); + il.Ldnull(); + il.Stloc(value); + + il.Ldloc(i); // stack: [i] + il.Ldc_I4(1); // stack: [i, 1] + il.Add(); // stack: [i + 1] + il.Dup(); // stack: [i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [i] + il.Ldloc(length); // stack: [i, length] + il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart + il.MarkLabel(doneLabel); // stack: [] + } + + protected override bool IsReference { get { return true; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/IPAddressReaderBuilder.cs b/GroBuf/Readers/IPAddressReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/IPAddressReaderBuilder.cs rename to GroBuf/Readers/IPAddressReaderBuilder.cs index 4530ae5..e7047d3 100644 --- a/GroBuf/GroBuf/Readers/IPAddressReaderBuilder.cs +++ b/GroBuf/Readers/IPAddressReaderBuilder.cs @@ -1,38 +1,38 @@ -using System.Net; - -namespace GroBuf.Readers -{ - internal class IPAddressReaderBuilder : ReaderBuilderBase - { - public IPAddressReaderBuilder() - : base(typeof(IPAddress)) - { - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.BuildConstants(typeof(byte[])); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - var il = context.Il; - context.LoadResultByRef(); // stack: [ref result] - - context.LoadData(); // stack: [ref result, data] - context.LoadIndexByRef(); // stack: [ref result, data, ref index] - var value = il.DeclareLocal(typeof(byte[])); - il.Ldloca(value); // stack: [ref result, data, ref index, ref value] - context.LoadContext(); // stack: [ref result, data, ref index, ref value, context] - context.CallReader(typeof(byte[])); // reader(pinnedData, ref index, ref value, context); stack: [ref result] - il.Ldloc(value); // stack: [ref result, value] - var constructor = Type.GetConstructor(new[] {typeof(byte[])}); - if(constructor == null) - throw new MissingConstructorException(Type, typeof(byte[])); - il.Newobj(constructor); // stack: [ref result, new IPAddress(value)] - il.Stind(Type); // result = new IPAddress(value) - } - - protected override bool IsReference { get { return false; } } - } +using System.Net; + +namespace GroBuf.Readers +{ + internal class IPAddressReaderBuilder : ReaderBuilderBase + { + public IPAddressReaderBuilder() + : base(typeof(IPAddress)) + { + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.BuildConstants(typeof(byte[])); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + var il = context.Il; + context.LoadResultByRef(); // stack: [ref result] + + context.LoadData(); // stack: [ref result, data] + context.LoadIndexByRef(); // stack: [ref result, data, ref index] + var value = il.DeclareLocal(typeof(byte[])); + il.Ldloca(value); // stack: [ref result, data, ref index, ref value] + context.LoadContext(); // stack: [ref result, data, ref index, ref value, context] + context.CallReader(typeof(byte[])); // reader(pinnedData, ref index, ref value, context); stack: [ref result] + il.Ldloc(value); // stack: [ref result, value] + var constructor = Type.GetConstructor(new[] {typeof(byte[])}); + if(constructor == null) + throw new MissingConstructorException(Type, typeof(byte[])); + il.Newobj(constructor); // stack: [ref result, new IPAddress(value)] + il.Stind(Type); // result = new IPAddress(value) + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/IReaderBuilder.cs b/GroBuf/Readers/IReaderBuilder.cs similarity index 96% rename from GroBuf/GroBuf/Readers/IReaderBuilder.cs rename to GroBuf/Readers/IReaderBuilder.cs index fce2d7d..cc6dc5d 100644 --- a/GroBuf/GroBuf/Readers/IReaderBuilder.cs +++ b/GroBuf/Readers/IReaderBuilder.cs @@ -1,8 +1,8 @@ -namespace GroBuf.Readers -{ - internal interface IReaderBuilder - { - void BuildReader(ReaderTypeBuilderContext readerTypeBuilderContext); - void BuildConstants(ReaderConstantsBuilderContext context); - } +namespace GroBuf.Readers +{ + internal interface IReaderBuilder + { + void BuildReader(ReaderTypeBuilderContext readerTypeBuilderContext); + void BuildConstants(ReaderConstantsBuilderContext context); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/IReaderCollection.cs b/GroBuf/Readers/IReaderCollection.cs similarity index 95% rename from GroBuf/GroBuf/Readers/IReaderCollection.cs rename to GroBuf/Readers/IReaderCollection.cs index 73f611d..ee91c6f 100644 --- a/GroBuf/GroBuf/Readers/IReaderCollection.cs +++ b/GroBuf/Readers/IReaderCollection.cs @@ -1,9 +1,9 @@ -using System; - -namespace GroBuf.Readers -{ - internal interface IReaderCollection - { - IReaderBuilder GetReaderBuilder(Type type, bool ignoreCustomSerialization); - } +using System; + +namespace GroBuf.Readers +{ + internal interface IReaderCollection + { + IReaderBuilder GetReaderBuilder(Type type, bool ignoreCustomSerialization); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/LazyReaderBuilder.cs b/GroBuf/Readers/LazyReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/LazyReaderBuilder.cs rename to GroBuf/Readers/LazyReaderBuilder.cs index 62cb299..7b43f47 100644 --- a/GroBuf/GroBuf/Readers/LazyReaderBuilder.cs +++ b/GroBuf/Readers/LazyReaderBuilder.cs @@ -1,143 +1,143 @@ -using System; -using System.Reflection; -using System.Reflection.Emit; - -using GrEmit; - -namespace GroBuf.Readers -{ - internal class LazyReaderBuilder : ReaderBuilderBase - { - public LazyReaderBuilder(Type type, ModuleBuilder module) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Lazy<>))) - throw new InvalidOperationException("Expected Lazy but was '" + Type + "'"); - this.module = module; - readerInvoker = BuildReaderInvoker(); - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.BuildConstants(Type.GetGenericArguments()[0]); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - var il = context.Il; - - var source = il.DeclareLocal(typeof(IntPtr)); - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Stloc(source); // source = &data[index]; stack: [] - context.IncreaseIndexBy1(); // skip type code - context.SkipValue(); - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldloc(source); // stack: [&data[index], source] - il.Sub(); // stack: [&data[index] - source = data length] - var length = il.DeclareLocal(typeof(int)); - il.Stloc(length); // length = &data[index] - source; stack: [] - var array = il.DeclareLocal(typeof(byte[])); - il.Ldloc(length); // stack: [length] - il.Newarr(typeof(byte)); // stack: [new byte[length]] - il.Stloc(array); // array = new byte[length]; stack: [] - var dest = il.DeclareLocal(typeof(byte).MakeByRefType(), true); - il.Ldloc(array); // stack: [array] - il.Ldc_I4(0); // stack: [array, 0] - il.Ldelema(typeof(byte)); // stack: [&array[0]] - il.Stloc(dest); // dest = &array[0]; stack: [] - il.Ldloc(dest); // stack: [dest] - il.Ldloc(source); // stack: [dest, source] - il.Ldloc(length); // stack: [dest, source, length] - il.Cpblk(); // dest = source; stack: [] - il.FreePinnedLocal(dest); // dest = null; stack: [] - - var argumentType = Type.GetGenericArguments()[0]; - context.LoadResultByRef(); // stack: [ref result] - context.LoadSerializerId(); // stack: [ref result, serializerId] - il.Ldloc(array); // stack: [ref result, serializerId, array] - context.LoadReader(argumentType); // stack: [ref result, serializerId, array, reader] - context.LoadSerializerId(); // stack: [ref result, serializerId, array, reader, serializerId] - il.Newobj(readerInvoker.GetConstructor(new[] {typeof(IntPtr), typeof(long)})); // stack: [ref result, serializerId, array, new ReaderInvoker(reader, serializerId)] - il.Ldftn(readerInvoker.GetMethod("Read", BindingFlags.Instance | BindingFlags.Public)); - var readDataFuncType = typeof(Func<,>).MakeGenericType(typeof(byte[]), argumentType); - il.Newobj(readDataFuncType.GetConstructor(new[] {typeof(object), typeof(IntPtr)})); // stack: [ref result, serializerId, array, new Func(..)] - var rawDataType = typeof(RawData<>).MakeGenericType(argumentType); - il.Newobj(rawDataType.GetConstructor(new[] {typeof(long), typeof(byte[]), readDataFuncType})); // stack: [ref result, new RawData(serializerId, array, func)] - il.Ldftn(rawDataType.GetMethod("GetValue", BindingFlags.Instance | BindingFlags.Public)); // stack: [ref result, new RawData(..), RawData.GetValue] - var factoryType = typeof(Func<>).MakeGenericType(argumentType); - il.Newobj(factoryType.GetConstructor(new[] {typeof(object), typeof(IntPtr)})); // stack: [ref result, new Func(new RawData(), RawData.GetValue)] - il.Newobj(Type.GetConstructor(new[] {factoryType})); // stack: [ref result, new Lazy(new Func(new RawData(), RawData.GetValue))] - il.Stind(Type); // result = new Lazy(array, func); stack: [] - } - - protected override bool IsReference { get { return true; } } - - private Type BuildReaderInvoker() - { - var argument = Type.GetGenericArguments()[0]; - var typeBuilder = module.DefineType("ReaderInvoker_" + Type, TypeAttributes.Public | TypeAttributes.Class); - var reader = typeBuilder.DefineField("reader", typeof(IntPtr), FieldAttributes.Private); - var serializerId = typeBuilder.DefineField("serializerId", typeof(long), FieldAttributes.Private); - var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] {typeof(IntPtr), typeof(long)}); - using(var il = new GroboIL(constructor)) - { - il.Ldarg(0); // stack: [this] - il.Ldarg(1); // stack: [this, reader] - il.Stfld(reader); // this.reader = reader; stack: [] - il.Ldarg(0); // stack: [this] - il.Ldarg(2); // stack: [this, serializerId] - il.Stfld(serializerId); // this.serializerId = serializerId; stack: [] - il.Ret(); - } - var method = typeBuilder.DefineMethod("Read", MethodAttributes.Public, argument, new[] {typeof(byte[])}); - using(var il = new GroboIL(method)) - { - var pinnedData = il.DeclareLocal(typeof(byte).MakeByRefType(), "pinnedData", true); - il.Ldarg(1); // stack: [data] - il.Ldc_I4(0); // stack: [data, 0] - il.Ldelema(typeof(byte)); // stack: [&data[0]] - il.Stloc(pinnedData); // pinnedData = &data[0]; stack: [] - var index = il.DeclareLocal(typeof(int), "index"); - il.Ldc_I4(0); // stack: [0] - il.Stloc(index); // index = 0; stack: [] - var context = il.DeclareLocal(typeof(ReaderContext), "context"); - il.Ldarg(0); // stack: [this] - il.Ldfld(serializerId); // stack: [this.serializerId] - il.Ldarg(1); // stack: [this.serializerId, data] - il.Ldlen(); // stack: [this.serializerId, data.Length] - il.Ldc_I4(0); // stack: [this.serializerId, data.Length, 0] - il.Ldc_I4(0); // stack: [this.serializerId, data.Length, 0, 0] - il.Newobj(typeof(ReaderContext).GetConstructor(new[] {typeof(long), typeof(int), typeof(int), typeof(int)})); // stack: [new ReaderContext(this.serializerId, data.Length, 0, 0)] - il.Stloc(context); // context = new ReaderContext(..); stack: [] - - var result = il.DeclareLocal(argument, "result"); - il.Ldloc(pinnedData); // stack: [data] - il.Conv(); // stack: [(IntPtr)data] - il.Ldloca(index); // stack: [(IntPtr)data, ref index] - il.Ldloca(result); // stack: [(IntPtr)data, ref index, ref result] - il.Ldloc(context); // stack: [(IntPtr)data, ref index, ref result, context] - il.Ldarg(0); // stack: [(IntPtr)data, ref index, ref result, context, this] - il.Ldfld(reader); // stack: [(IntPtr)data, ref index, ref result, context, this.reader] - var parameterTypes = new[] {typeof(IntPtr), typeof(int).MakeByRefType(), argument.MakeByRefType(), typeof(ReaderContext)}; - il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // this.reader((IntPtr)data, ref index, ref result, context); stack: [] - il.FreePinnedLocal(pinnedData); // pinnedData = null; stack: [] - var retLabel = il.DefineLabel("ret"); - il.Ldarg(1); // stack: [data] - il.Ldlen(); // stack: [data.Length] - il.Ldloc(index); // stack: [data.Length, index] - il.Beq(retLabel); // if(data.Length == index) goto ret; stack: [] - il.Ldstr("Encountered extra data"); - il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] {typeof(string)})); - il.Throw(); - - il.MarkLabel(retLabel); - il.Ldloc(result); - il.Ret(); - } - return typeBuilder.CreateType(); - } - - private readonly ModuleBuilder module; - private readonly Type readerInvoker; - } +using System; +using System.Reflection; +using System.Reflection.Emit; + +using GrEmit; + +namespace GroBuf.Readers +{ + internal class LazyReaderBuilder : ReaderBuilderBase + { + public LazyReaderBuilder(Type type, ModuleBuilder module) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Lazy<>))) + throw new InvalidOperationException("Expected Lazy but was '" + Type + "'"); + this.module = module; + readerInvoker = BuildReaderInvoker(); + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.BuildConstants(Type.GetGenericArguments()[0]); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + var il = context.Il; + + var source = il.DeclareLocal(typeof(IntPtr)); + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Stloc(source); // source = &data[index]; stack: [] + context.IncreaseIndexBy1(); // skip type code + context.SkipValue(); + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldloc(source); // stack: [&data[index], source] + il.Sub(); // stack: [&data[index] - source = data length] + var length = il.DeclareLocal(typeof(int)); + il.Stloc(length); // length = &data[index] - source; stack: [] + var array = il.DeclareLocal(typeof(byte[])); + il.Ldloc(length); // stack: [length] + il.Newarr(typeof(byte)); // stack: [new byte[length]] + il.Stloc(array); // array = new byte[length]; stack: [] + var dest = il.DeclareLocal(typeof(byte).MakeByRefType(), true); + il.Ldloc(array); // stack: [array] + il.Ldc_I4(0); // stack: [array, 0] + il.Ldelema(typeof(byte)); // stack: [&array[0]] + il.Stloc(dest); // dest = &array[0]; stack: [] + il.Ldloc(dest); // stack: [dest] + il.Ldloc(source); // stack: [dest, source] + il.Ldloc(length); // stack: [dest, source, length] + il.Cpblk(); // dest = source; stack: [] + il.FreePinnedLocal(dest); // dest = null; stack: [] + + var argumentType = Type.GetGenericArguments()[0]; + context.LoadResultByRef(); // stack: [ref result] + context.LoadSerializerId(); // stack: [ref result, serializerId] + il.Ldloc(array); // stack: [ref result, serializerId, array] + context.LoadReader(argumentType); // stack: [ref result, serializerId, array, reader] + context.LoadSerializerId(); // stack: [ref result, serializerId, array, reader, serializerId] + il.Newobj(readerInvoker.GetConstructor(new[] {typeof(IntPtr), typeof(long)})); // stack: [ref result, serializerId, array, new ReaderInvoker(reader, serializerId)] + il.Ldftn(readerInvoker.GetMethod("Read", BindingFlags.Instance | BindingFlags.Public)); + var readDataFuncType = typeof(Func<,>).MakeGenericType(typeof(byte[]), argumentType); + il.Newobj(readDataFuncType.GetConstructor(new[] {typeof(object), typeof(IntPtr)})); // stack: [ref result, serializerId, array, new Func(..)] + var rawDataType = typeof(RawData<>).MakeGenericType(argumentType); + il.Newobj(rawDataType.GetConstructor(new[] {typeof(long), typeof(byte[]), readDataFuncType})); // stack: [ref result, new RawData(serializerId, array, func)] + il.Ldftn(rawDataType.GetMethod("GetValue", BindingFlags.Instance | BindingFlags.Public)); // stack: [ref result, new RawData(..), RawData.GetValue] + var factoryType = typeof(Func<>).MakeGenericType(argumentType); + il.Newobj(factoryType.GetConstructor(new[] {typeof(object), typeof(IntPtr)})); // stack: [ref result, new Func(new RawData(), RawData.GetValue)] + il.Newobj(Type.GetConstructor(new[] {factoryType})); // stack: [ref result, new Lazy(new Func(new RawData(), RawData.GetValue))] + il.Stind(Type); // result = new Lazy(array, func); stack: [] + } + + protected override bool IsReference { get { return true; } } + + private Type BuildReaderInvoker() + { + var argument = Type.GetGenericArguments()[0]; + var typeBuilder = module.DefineType("ReaderInvoker_" + Type, TypeAttributes.Public | TypeAttributes.Class); + var reader = typeBuilder.DefineField("reader", typeof(IntPtr), FieldAttributes.Private); + var serializerId = typeBuilder.DefineField("serializerId", typeof(long), FieldAttributes.Private); + var constructor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new[] {typeof(IntPtr), typeof(long)}); + using(var il = new GroboIL(constructor)) + { + il.Ldarg(0); // stack: [this] + il.Ldarg(1); // stack: [this, reader] + il.Stfld(reader); // this.reader = reader; stack: [] + il.Ldarg(0); // stack: [this] + il.Ldarg(2); // stack: [this, serializerId] + il.Stfld(serializerId); // this.serializerId = serializerId; stack: [] + il.Ret(); + } + var method = typeBuilder.DefineMethod("Read", MethodAttributes.Public, argument, new[] {typeof(byte[])}); + using(var il = new GroboIL(method)) + { + var pinnedData = il.DeclareLocal(typeof(byte).MakeByRefType(), "pinnedData", true); + il.Ldarg(1); // stack: [data] + il.Ldc_I4(0); // stack: [data, 0] + il.Ldelema(typeof(byte)); // stack: [&data[0]] + il.Stloc(pinnedData); // pinnedData = &data[0]; stack: [] + var index = il.DeclareLocal(typeof(int), "index"); + il.Ldc_I4(0); // stack: [0] + il.Stloc(index); // index = 0; stack: [] + var context = il.DeclareLocal(typeof(ReaderContext), "context"); + il.Ldarg(0); // stack: [this] + il.Ldfld(serializerId); // stack: [this.serializerId] + il.Ldarg(1); // stack: [this.serializerId, data] + il.Ldlen(); // stack: [this.serializerId, data.Length] + il.Ldc_I4(0); // stack: [this.serializerId, data.Length, 0] + il.Ldc_I4(0); // stack: [this.serializerId, data.Length, 0, 0] + il.Newobj(typeof(ReaderContext).GetConstructor(new[] {typeof(long), typeof(int), typeof(int), typeof(int)})); // stack: [new ReaderContext(this.serializerId, data.Length, 0, 0)] + il.Stloc(context); // context = new ReaderContext(..); stack: [] + + var result = il.DeclareLocal(argument, "result"); + il.Ldloc(pinnedData); // stack: [data] + il.Conv(); // stack: [(IntPtr)data] + il.Ldloca(index); // stack: [(IntPtr)data, ref index] + il.Ldloca(result); // stack: [(IntPtr)data, ref index, ref result] + il.Ldloc(context); // stack: [(IntPtr)data, ref index, ref result, context] + il.Ldarg(0); // stack: [(IntPtr)data, ref index, ref result, context, this] + il.Ldfld(reader); // stack: [(IntPtr)data, ref index, ref result, context, this.reader] + var parameterTypes = new[] {typeof(IntPtr), typeof(int).MakeByRefType(), argument.MakeByRefType(), typeof(ReaderContext)}; + il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // this.reader((IntPtr)data, ref index, ref result, context); stack: [] + il.FreePinnedLocal(pinnedData); // pinnedData = null; stack: [] + var retLabel = il.DefineLabel("ret"); + il.Ldarg(1); // stack: [data] + il.Ldlen(); // stack: [data.Length] + il.Ldloc(index); // stack: [data.Length, index] + il.Beq(retLabel); // if(data.Length == index) goto ret; stack: [] + il.Ldstr("Encountered extra data"); + il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] {typeof(string)})); + il.Throw(); + + il.MarkLabel(retLabel); + il.Ldloc(result); + il.Ret(); + } + return typeBuilder.CreateTypeInfo(); + } + + private readonly ModuleBuilder module; + private readonly Type readerInvoker; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/ListReaderBuilder.cs b/GroBuf/Readers/ListReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/ListReaderBuilder.cs rename to GroBuf/Readers/ListReaderBuilder.cs index 4bb5136..2b5f2f4 100644 --- a/GroBuf/GroBuf/Readers/ListReaderBuilder.cs +++ b/GroBuf/Readers/ListReaderBuilder.cs @@ -1,133 +1,133 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Reflection; - -namespace GroBuf.Readers -{ - internal class ListReaderBuilder : ReaderBuilderBase - { - public ListReaderBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(List<>))) - throw new InvalidOperationException("Expected list but was '" + Type + "'"); - elementType = Type.GetGenericArguments()[0]; - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - context.IncreaseIndexBy1(); - context.AssertTypeCode(GroBufTypeCode.Array); - - var il = context.Il; - var length = context.Length; - - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [data length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] - - context.AssertLength(); - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [array length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] - il.Stloc(length); // length = array length; stack: [] - - if(context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) - { - var createArrayLabel = il.DefineLabel("createArray"); - context.LoadResult(Type); // stack: [result] - il.Brfalse(createArrayLabel); // if(result == null) goto createArray; - context.LoadResult(Type); // stack: [result] - il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items] - il.Ldlen(); // stack: [result._items.Length] - il.Ldloc(length); // stack: [result._items.Length, length] - - var arrayCreatedLabel = il.DefineLabel("arrayCreated"); - il.Bge(arrayCreatedLabel, false); // if(result._items.Length >= length) goto arrayCreated; - - context.LoadResult(Type); // stack: [result] - il.Ldflda(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [ref result._items] - il.Ldloc(length); // stack: [ref result, length] - il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result._items, length) - il.Br(arrayCreatedLabel); // goto arrayCreated - - il.MarkLabel(createArrayLabel); - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(length); // stack: [ref result, length] - il.Newobj(Type.GetConstructor(new[] {typeof(int)})); // stack: [ref result, new List(length)] - il.Stind(Type); // result = new List(length); stack: [] - - il.MarkLabel(arrayCreatedLabel); - } - else - { - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(length); // stack: [ref result, length] - il.Newobj(Type.GetConstructor(new[] {typeof(int)})); // stack: [ref result, new List(length)] - il.Stind(Type); // result = new List(length); stack: [] - } - - context.StoreObject(Type); - - il.Ldloc(length); // stack: [length] - var doneLabel = il.DefineLabel("done"); - il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] - context.LoadResult(Type); // stack: [result] - il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items] - var items = il.DeclareLocal(elementType.MakeArrayType()); - il.Stloc(items); // items = result._items; stack: [] - var i = il.DeclareLocal(typeof(uint)); - il.Ldc_I4(0); // stack: [0] - il.Stloc(i); // i = 0; stack: [] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - - context.LoadData(); // stack: [pinnedData] - context.LoadIndexByRef(); // stack: [pinnedData, ref index] - il.Ldloc(items); // stack: [pinnedData, ref index, items] - il.Ldloc(i); // stack: [pinnedData, ref index, items, i] - - il.Ldelema(elementType); // stack: [pinnedData, ref index, ref items[i]] - context.LoadContext(); // stack: [pinnedData, ref index, ref items[i], context] - - context.CallReader(elementType); // reader(pinnedData, ref index, ref result[i], context); stack: [] - il.Ldloc(i); // stack: [i] - il.Ldc_I4(1); // stack: [i, 1] - il.Add(); // stack: [i + 1] - il.Dup(); // stack: [i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [i] - il.Ldloc(length); // stack: [i, length] - il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart - - if(context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) - { - context.LoadResult(Type); // stack: [result] - il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result.Count] - il.Ldloc(length); // stack: [result.Count, length] - il.Bge(doneLabel, false); // if(result.Count >= length) goto done; stack: [] - } - context.LoadResult(Type); // stack: [result] - il.Ldloc(length); // stack: [result.Count, length] - il.Stfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // result._size = length; stack: [] - - il.MarkLabel(doneLabel); // stack: [] - } - - protected override bool IsReference { get { return true; } } - - private static readonly MethodInfo resizeMethod = ((MethodCallExpression)((Expression>)(arr => Array.Resize(ref arr, 0))).Body).Method.GetGenericMethodDefinition(); - private readonly Type elementType; - } +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; + +namespace GroBuf.Readers +{ + internal class ListReaderBuilder : ReaderBuilderBase + { + public ListReaderBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(List<>))) + throw new InvalidOperationException("Expected list but was '" + Type + "'"); + elementType = Type.GetGenericArguments()[0]; + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + context.IncreaseIndexBy1(); + context.AssertTypeCode(GroBufTypeCode.Array); + + var il = context.Il; + var length = context.Length; + + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [data length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] + + context.AssertLength(); + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [array length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [array length] + il.Stloc(length); // length = array length; stack: [] + + if(context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) + { + var createArrayLabel = il.DefineLabel("createArray"); + context.LoadResult(Type); // stack: [result] + il.Brfalse(createArrayLabel); // if(result == null) goto createArray; + context.LoadResult(Type); // stack: [result] + il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items] + il.Ldlen(); // stack: [result._items.Length] + il.Ldloc(length); // stack: [result._items.Length, length] + + var arrayCreatedLabel = il.DefineLabel("arrayCreated"); + il.Bge(arrayCreatedLabel, false); // if(result._items.Length >= length) goto arrayCreated; + + context.LoadResult(Type); // stack: [result] + il.Ldflda(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [ref result._items] + il.Ldloc(length); // stack: [ref result, length] + il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result._items, length) + il.Br(arrayCreatedLabel); // goto arrayCreated + + il.MarkLabel(createArrayLabel); + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(length); // stack: [ref result, length] + il.Newobj(Type.GetConstructor(new[] {typeof(int)})); // stack: [ref result, new List(length)] + il.Stind(Type); // result = new List(length); stack: [] + + il.MarkLabel(arrayCreatedLabel); + } + else + { + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(length); // stack: [ref result, length] + il.Newobj(Type.GetConstructor(new[] {typeof(int)})); // stack: [ref result, new List(length)] + il.Stind(Type); // result = new List(length); stack: [] + } + + context.StoreObject(Type); + + il.Ldloc(length); // stack: [length] + var doneLabel = il.DefineLabel("done"); + il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] + context.LoadResult(Type); // stack: [result] + il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items] + var items = il.DeclareLocal(elementType.MakeArrayType()); + il.Stloc(items); // items = result._items; stack: [] + var i = il.DeclareLocal(typeof(uint)); + il.Ldc_I4(0); // stack: [0] + il.Stloc(i); // i = 0; stack: [] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + + context.LoadData(); // stack: [pinnedData] + context.LoadIndexByRef(); // stack: [pinnedData, ref index] + il.Ldloc(items); // stack: [pinnedData, ref index, items] + il.Ldloc(i); // stack: [pinnedData, ref index, items, i] + + il.Ldelema(elementType); // stack: [pinnedData, ref index, ref items[i]] + context.LoadContext(); // stack: [pinnedData, ref index, ref items[i], context] + + context.CallReader(elementType); // reader(pinnedData, ref index, ref result[i], context); stack: [] + il.Ldloc(i); // stack: [i] + il.Ldc_I4(1); // stack: [i, 1] + il.Add(); // stack: [i + 1] + il.Dup(); // stack: [i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [i] + il.Ldloc(length); // stack: [i, length] + il.Blt(cycleStartLabel, true); // if(i < length) goto cycleStart + + if(context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) + { + context.LoadResult(Type); // stack: [result] + il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result.Count] + il.Ldloc(length); // stack: [result.Count, length] + il.Bge(doneLabel, false); // if(result.Count >= length) goto done; stack: [] + } + context.LoadResult(Type); // stack: [result] + il.Ldloc(length); // stack: [result.Count, length] + il.Stfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // result._size = length; stack: [] + + il.MarkLabel(doneLabel); // stack: [] + } + + protected override bool IsReference { get { return true; } } + + private static readonly MethodInfo resizeMethod = ((MethodCallExpression)((Expression>)(arr => Array.Resize(ref arr, 0))).Body).Method.GetGenericMethodDefinition(); + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/NullableReaderBuilder.cs b/GroBuf/Readers/NullableReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/NullableReaderBuilder.cs rename to GroBuf/Readers/NullableReaderBuilder.cs index 47f4cca..709c186 100644 --- a/GroBuf/GroBuf/Readers/NullableReaderBuilder.cs +++ b/GroBuf/Readers/NullableReaderBuilder.cs @@ -1,41 +1,41 @@ -using System; - -namespace GroBuf.Readers -{ - internal class NullableReaderBuilder : ReaderBuilderBase - { - public NullableReaderBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Nullable<>))) - throw new InvalidOperationException("Expected nullable but was '" + Type + "'"); - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.BuildConstants(Type.GetGenericArguments()[0]); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - var il = context.Il; - context.LoadResultByRef(); // stack: [ref result] - - context.LoadData(); // stack: [ref result, data] - context.LoadIndexByRef(); // stack: [ref result, data, ref index] - var argumentType = Type.GetGenericArguments()[0]; - var value = il.DeclareLocal(argumentType); - il.Ldloca(value); // stack: [ref result, data, ref index, ref value] - context.LoadContext(); // stack: [ref result, data, ref index, ref value, context] - context.CallReader(argumentType); // reader(pinnedData, ref index, ref value, context); stack: [ref result] - il.Ldloc(value); // stack: [ref result, value] - var constructor = Type.GetConstructor(new[] {argumentType}); - if(constructor == null) - throw new MissingConstructorException(Type, argumentType); - il.Newobj(constructor); // stack: [ref result, new elementType?(value)] - il.Stobj(Type); // result = new elementType?(value) - } - - protected override bool IsReference { get { return false; } } - } +using System; + +namespace GroBuf.Readers +{ + internal class NullableReaderBuilder : ReaderBuilderBase + { + public NullableReaderBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Nullable<>))) + throw new InvalidOperationException("Expected nullable but was '" + Type + "'"); + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.BuildConstants(Type.GetGenericArguments()[0]); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + var il = context.Il; + context.LoadResultByRef(); // stack: [ref result] + + context.LoadData(); // stack: [ref result, data] + context.LoadIndexByRef(); // stack: [ref result, data, ref index] + var argumentType = Type.GetGenericArguments()[0]; + var value = il.DeclareLocal(argumentType); + il.Ldloca(value); // stack: [ref result, data, ref index, ref value] + context.LoadContext(); // stack: [ref result, data, ref index, ref value, context] + context.CallReader(argumentType); // reader(pinnedData, ref index, ref value, context); stack: [ref result] + il.Ldloc(value); // stack: [ref result, value] + var constructor = Type.GetConstructor(new[] {argumentType}); + if(constructor == null) + throw new MissingConstructorException(Type, argumentType); + il.Newobj(constructor); // stack: [ref result, new elementType?(value)] + il.Stobj(Type); // result = new elementType?(value) + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/ObjectConstructionHelper.cs b/GroBuf/Readers/ObjectConstructionHelper.cs similarity index 97% rename from GroBuf/GroBuf/Readers/ObjectConstructionHelper.cs rename to GroBuf/Readers/ObjectConstructionHelper.cs index bccaeb6..db59036 100644 --- a/GroBuf/GroBuf/Readers/ObjectConstructionHelper.cs +++ b/GroBuf/Readers/ObjectConstructionHelper.cs @@ -1,53 +1,53 @@ -using System; -using System.Reflection; -using System.Runtime.Serialization; - -using GrEmit; -using GrEmit.Utils; - -namespace GroBuf.Readers -{ - public class ObjectConstructionHelper - { - static ObjectConstructionHelper() - { - getTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Public | BindingFlags.Static); - if(getTypeFromHandle == null) - throw new MissingMethodException("GetTypeFromHandle"); - getUninitializedObject = typeof(FormatterServices).GetMethod("GetUninitializedObject", BindingFlags.Public | BindingFlags.Static); - if(getUninitializedObject == null) - throw new MissingMethodException("GetUninitializedObject"); - } - - public static void EmitConstructionOfType(Type type, GroboIL il) - { - ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes); - if(constructor != null) - il.Newobj(constructor); - else - { - il.Ldtoken(type); - il.Call(getTypeFromHandle); - il.Call(getUninitializedObject); - if(type.IsValueType) - il.Unbox_Any(type); - else - il.Castclass(type); - } - } - - public static Func ConstructType(Type type) - { - return EmitHelpers.EmitDynamicMethod>("Construct_" + type.Name + "_" + Guid.NewGuid(), type.Module, il => EmitCode(type, il)); - } - - private static void EmitCode(Type type, GroboIL groboIl) - { - EmitConstructionOfType(type, groboIl); - groboIl.Ret(); - } - - private static readonly MethodInfo getTypeFromHandle; - private static readonly MethodInfo getUninitializedObject; - } +using System; +using System.Reflection; +using System.Runtime.Serialization; + +using GrEmit; +using GrEmit.Utils; + +namespace GroBuf.Readers +{ + public class ObjectConstructionHelper + { + static ObjectConstructionHelper() + { + getTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Public | BindingFlags.Static); + if(getTypeFromHandle == null) + throw new MissingMethodException("GetTypeFromHandle"); + getUninitializedObject = typeof(FormatterServices).GetMethod("GetUninitializedObject", BindingFlags.Public | BindingFlags.Static); + if(getUninitializedObject == null) + throw new MissingMethodException("GetUninitializedObject"); + } + + public static void EmitConstructionOfType(Type type, GroboIL il) + { + ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes); + if(constructor != null) + il.Newobj(constructor); + else + { + il.Ldtoken(type); + il.Call(getTypeFromHandle); + il.Call(getUninitializedObject); + if(type.IsValueType) + il.Unbox_Any(type); + else + il.Castclass(type); + } + } + + public static Func ConstructType(Type type) + { + return EmitHelpers.EmitDynamicMethod>("Construct_" + type.Name + "_" + Guid.NewGuid(), type.Module, il => EmitCode(type, il)); + } + + private static void EmitCode(Type type, GroboIL groboIl) + { + EmitConstructionOfType(type, groboIl); + groboIl.Ret(); + } + + private static readonly MethodInfo getTypeFromHandle; + private static readonly MethodInfo getUninitializedObject; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/ObjectReaderBuilder.cs b/GroBuf/Readers/ObjectReaderBuilder.cs similarity index 98% rename from GroBuf/GroBuf/Readers/ObjectReaderBuilder.cs rename to GroBuf/Readers/ObjectReaderBuilder.cs index 76cba29..079ce55 100644 --- a/GroBuf/GroBuf/Readers/ObjectReaderBuilder.cs +++ b/GroBuf/Readers/ObjectReaderBuilder.cs @@ -1,100 +1,100 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -using GrEmit; - -namespace GroBuf.Readers -{ - internal class ObjectReaderBuilder : ReaderBuilderBase - { - public ObjectReaderBuilder() - : base(typeof(object)) - { - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.SetFields(Type, new[] - { - new KeyValuePair("readers_" + Type.Name + "_" + Guid.NewGuid(), typeof(IntPtr[])), - new KeyValuePair("delegates_" + Type.Name + "_" + Guid.NewGuid(), typeof(Delegate[])) // This field is needed only to save references to the dynamic methods. Otherwise GC will destroy them - }); - Array.ForEach(GroBufHelpers.LeafTypes.Where(type => type != null).ToArray(), type => context.BuildConstants(type)); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - var il = context.Il; - - var readers = GetReaders(context); - var readersField = context.Context.InitConstField(Type, 0, readers.Select(pair => pair.Value).ToArray()); - context.Context.InitConstField(Type, 1, readers.Select(pair => pair.Key).ToArray()); - - context.LoadData(); // stack: [data] - context.LoadIndexByRef(); // stack: [data, ref index] - context.LoadResultByRef(); // stack: [data, ref index, ref result] - context.LoadContext(); // stack: [data, ref index, ref result, context] - context.LoadField(readersField); // stack: [data, ref index, ref result, context, readers] - il.Ldloc(context.TypeCode); // stack: [data, ref index, ref result, context, readers, typeCode] - il.Ldelem(typeof(IntPtr)); // stack: [data, ref index, ref result, context, readers[typeCode]] - il.Dup(); // stack: [data, ref index, ref result, context, readers[typeCode], readers[typeCode]] - var skipValueLabel = il.DefineLabel("skipValue"); - il.Brfalse(skipValueLabel); // if(readers[typeCode] == 0) goto skipValue; - var parameterTypes = new[] {typeof(byte*), typeof(int).MakeByRefType(), typeof(object).MakeByRefType(), typeof(ReaderContext)}; - il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // readers[typeCode](data, ref index, ref result, context); stack: [] - il.Ret(); - il.MarkLabel(skipValueLabel); - il.Pop(); - il.Pop(); - il.Pop(); - il.Pop(); - il.Pop(); - context.IncreaseIndexBy1(); - context.SkipValue(); - } - - protected override bool IsReference { get { return false; } } - - private static KeyValuePair[] GetReaders(ReaderMethodBuilderContext context) - { - var result = new KeyValuePair[256]; - foreach(var type in GroBufHelpers.LeafTypes.Where(type => type != null)) - result[(int)GroBufTypeCodeMap.GetTypeCode(type)] = GetReader(context, type); - result[(int)GroBufTypeCode.DateTimeOld] = result[(int)GroBufTypeCode.DateTimeNew]; - return result; - } - - private static KeyValuePair GetReader(ReaderMethodBuilderContext context, Type type) - { - var method = new DynamicMethod("Read_" + type.Name + "_AndCastToObject_" + Guid.NewGuid(), typeof(void), - new[] - { - typeof(IntPtr), typeof(int).MakeByRefType(), typeof(object).MakeByRefType(), typeof(ReaderContext) - }, context.Context.Module, true); - using(var il = new GroboIL(method)) - { - il.Ldarg(2); // stack: [ref result] - il.Ldarg(0); // stack: [ref result, data] - il.Ldarg(1); // stack: [ref result, data, ref index] - var value = il.DeclareLocal(type); - il.Ldloca(value); // stack: [ref result, data, ref index, ref value] - il.Ldarg(3); // stack: [ref result, data, ref index, ref value, context] - - ReaderMethodBuilderContext.CallReader(il, type, context.Context); - - il.Ldloc(value); // stack: [ref result, value] - if(type.IsValueType) - il.Box(type); // stack: [ref result, (object)value] - else - il.Castclass(type); - il.Stind(typeof(object)); // result = (object)value - il.Ret(); - } - var @delegate = method.CreateDelegate(typeof(ReaderDelegate)); - return new KeyValuePair(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; + +using GrEmit; + +namespace GroBuf.Readers +{ + internal class ObjectReaderBuilder : ReaderBuilderBase + { + public ObjectReaderBuilder() + : base(typeof(object)) + { + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.SetFields(Type, new[] + { + new KeyValuePair("readers_" + Type.Name + "_" + Guid.NewGuid(), typeof(IntPtr[])), + new KeyValuePair("delegates_" + Type.Name + "_" + Guid.NewGuid(), typeof(Delegate[])) // This field is needed only to save references to the dynamic methods. Otherwise GC will destroy them + }); + Array.ForEach(GroBufHelpers.LeafTypes.Where(type => type != null).ToArray(), type => context.BuildConstants(type)); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + var il = context.Il; + + var readers = GetReaders(context); + var readersField = context.Context.InitConstField(Type, 0, readers.Select(pair => pair.Value).ToArray()); + context.Context.InitConstField(Type, 1, readers.Select(pair => pair.Key).ToArray()); + + context.LoadData(); // stack: [data] + context.LoadIndexByRef(); // stack: [data, ref index] + context.LoadResultByRef(); // stack: [data, ref index, ref result] + context.LoadContext(); // stack: [data, ref index, ref result, context] + context.LoadField(readersField); // stack: [data, ref index, ref result, context, readers] + il.Ldloc(context.TypeCode); // stack: [data, ref index, ref result, context, readers, typeCode] + il.Ldelem(typeof(IntPtr)); // stack: [data, ref index, ref result, context, readers[typeCode]] + il.Dup(); // stack: [data, ref index, ref result, context, readers[typeCode], readers[typeCode]] + var skipValueLabel = il.DefineLabel("skipValue"); + il.Brfalse(skipValueLabel); // if(readers[typeCode] == 0) goto skipValue; + var parameterTypes = new[] {typeof(byte*), typeof(int).MakeByRefType(), typeof(object).MakeByRefType(), typeof(ReaderContext)}; + il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // readers[typeCode](data, ref index, ref result, context); stack: [] + il.Ret(); + il.MarkLabel(skipValueLabel); + il.Pop(); + il.Pop(); + il.Pop(); + il.Pop(); + il.Pop(); + context.IncreaseIndexBy1(); + context.SkipValue(); + } + + protected override bool IsReference { get { return false; } } + + private static KeyValuePair[] GetReaders(ReaderMethodBuilderContext context) + { + var result = new KeyValuePair[256]; + foreach(var type in GroBufHelpers.LeafTypes.Where(type => type != null)) + result[(int)GroBufTypeCodeMap.GetTypeCode(type)] = GetReader(context, type); + result[(int)GroBufTypeCode.DateTimeOld] = result[(int)GroBufTypeCode.DateTimeNew]; + return result; + } + + private static KeyValuePair GetReader(ReaderMethodBuilderContext context, Type type) + { + var method = new DynamicMethod("Read_" + type.Name + "_AndCastToObject_" + Guid.NewGuid(), typeof(void), + new[] + { + typeof(IntPtr), typeof(int).MakeByRefType(), typeof(object).MakeByRefType(), typeof(ReaderContext) + }, context.Context.Module, true); + using(var il = new GroboIL(method)) + { + il.Ldarg(2); // stack: [ref result] + il.Ldarg(0); // stack: [ref result, data] + il.Ldarg(1); // stack: [ref result, data, ref index] + var value = il.DeclareLocal(type); + il.Ldloca(value); // stack: [ref result, data, ref index, ref value] + il.Ldarg(3); // stack: [ref result, data, ref index, ref value, context] + + ReaderMethodBuilderContext.CallReader(il, type, context.Context); + + il.Ldloc(value); // stack: [ref result, value] + if(type.IsValueType) + il.Box(type); // stack: [ref result, (object)value] + else + il.Castclass(type); + il.Stind(typeof(object)); // result = (object)value + il.Ret(); + } + var @delegate = method.CreateDelegate(typeof(ReaderDelegate)); + return new KeyValuePair(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)); + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/PrimitivesArrayReaderBuilder.cs b/GroBuf/Readers/PrimitivesArrayReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/PrimitivesArrayReaderBuilder.cs rename to GroBuf/Readers/PrimitivesArrayReaderBuilder.cs index 9e773ab..b0b86c0 100644 --- a/GroBuf/GroBuf/Readers/PrimitivesArrayReaderBuilder.cs +++ b/GroBuf/Readers/PrimitivesArrayReaderBuilder.cs @@ -1,234 +1,234 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.Readers -{ - internal class PrimitivesArrayReaderBuilder : ReaderBuilderBase - { - public PrimitivesArrayReaderBuilder(Type type) - : base(type) - { - if(!Type.IsArray) throw new InvalidOperationException("An array expected but was '" + Type + "'"); - if(Type.GetArrayRank() != 1) throw new NotSupportedException("Arrays with rank greater than 1 are not supported"); - elementType = Type.GetElementType(); - if(!elementType.IsPrimitive) throw new NotSupportedException("Array of primitive type expected but was '" + Type + "'"); - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override unsafe void ReadNotEmpty(ReaderMethodBuilderContext context) - { - var il = context.Il; - - il.Ldloc(context.TypeCode); // stack: [type code] - il.Ldc_I4((int)GroBufTypeCodeMap.GetTypeCode(Type)); // stack: [type code, GroBufTypeCode(Type)] - var tryReadArrayElementLabel = il.DefineLabel("tryReadArrayElement"); - il.Bne_Un(tryReadArrayElementLabel); // if(type code != GroBufTypeCode(Type)) goto tryReadArrayElement; stack: [] - - context.IncreaseIndexBy1(); - - var size = il.DeclareLocal(typeof(int)); - - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [data length] - il.Dup(); // stack: [data length, data length] - il.Stloc(size); // size = data length; stack: [data length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] - context.AssertLength(); - - var length = context.Length; - il.Ldloc(size); // stack: [size] - CountArrayLength(elementType, il); // stack: [array length] - il.Stloc(length); // length = array length - - if(context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) - { - var createArrayLabel = il.DefineLabel("createArray"); - context.LoadResult(Type); // stack: [result] - il.Brfalse(createArrayLabel); // if(result == null) goto createArray; - context.LoadResult(Type); // stack: [result] - il.Ldlen(); // stack: [result.Length] - il.Ldloc(length); // stack: [result.Length, length] - - var arrayCreatedLabel = il.DefineLabel("arrayCreated"); - il.Bge(arrayCreatedLabel, false); // if(result.Length >= length) goto arrayCreated; - - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(length); // stack: [ref result, length] - il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, length) - il.Br(arrayCreatedLabel); // goto arrayCreated - - il.MarkLabel(createArrayLabel); - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(length); // stack: [ref result, length] - il.Newarr(elementType); // stack: [ref result, new type[length]] - il.Stind(Type); // result = new type[length]; stack: [] - - il.MarkLabel(arrayCreatedLabel); - } - else - { - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(length); // stack: [ref result, length] - il.Newarr(elementType); // stack: [ref result, new type[length]] - il.Stind(Type); // result = new type[length]; stack: [] - } - - il.Ldloc(length); - var doneLabel = il.DefineLabel("done"); - il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] - - var arr = il.DeclareLocal(elementType.MakeByRefType(), true); - context.LoadResult(Type); // stack: [result] - il.Ldc_I4(0); // stack: [result, 0] - il.Ldelema(elementType); // stack: [&result[0]] - il.Stloc(arr); // arr = &result[0]; stack: [] - il.Ldloc(arr); // stack: [arr] - context.GoToCurrentLocation(); // stack: [arr, &data[index]] - il.Ldloc(length); // stack: [arr, &data[index], length] - CountArraySize(elementType, il); // stack: [arr, &data[index], size] - il.Cpblk(); // arr = &data[index] - il.FreePinnedLocal(arr); // arr = null; stack: [] - context.LoadIndexByRef(); // stack: [ref index] - context.LoadIndex(); // stack: [ref index, index] - il.Ldloc(size); // stack: [ref index, index, size] - il.Add(); // stack: [ref index, index + size] - il.Stind(typeof(int)); // index = index + size - il.Br(doneLabel); - - il.MarkLabel(tryReadArrayElementLabel); - if(context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) - { - var createArrayLabel = il.DefineLabel("createArray"); - context.LoadResult(Type); // stack: [result] - il.Brfalse(createArrayLabel); // if(result == null) goto createArray; - context.LoadResult(Type); // stack: [result] - il.Ldlen(); // stack: [result.Length] - il.Ldc_I4(1); // stack: [result.Length, 1] - - var arrayCreatedLabel = il.DefineLabel("arrayCreated"); - il.Bge(arrayCreatedLabel, false); // if(result.Length >= 1) goto arrayCreated; - - context.LoadResultByRef(); // stack: [ref result] - il.Ldc_I4(1); // stack: [ref result, 1] - il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, 1) - il.Br(arrayCreatedLabel); // goto arrayCreated - - il.MarkLabel(createArrayLabel); - context.LoadResultByRef(); // stack: [ref result] - il.Ldc_I4(1); // stack: [ref result, 1] - il.Newarr(elementType); // stack: [ref result, new type[1]] - il.Stind(Type); // result = new type[1]; stack: [] - - il.MarkLabel(arrayCreatedLabel); - } - else - { - context.LoadResultByRef(); // stack: [ref result] - il.Ldc_I4(1); // stack: [ref result, 1] - il.Newarr(elementType); // stack: [ref result, new type[1]] - il.Stind(Type); // result = new type[1]; stack: [] - } - - context.LoadData(); // stack: [pinnedData] - context.LoadIndexByRef(); // stack: [pinnedData, ref index] - context.LoadResult(Type); // stack: [pinnedData, ref index, result] - il.Ldc_I4(0); // stack: [pinnedData, ref index, result, 0] - - il.Ldelema(elementType); // stack: [pinnedData, ref index, ref result[0]] - context.LoadContext(); // stack: [pinnedData, ref index, ref result[0], context] - - context.CallReader(elementType); // reader(pinnedData, ref index, ref result[0], context); stack: [] - - il.MarkLabel(doneLabel); // stack: [] - } - - protected override bool IsReference { get { return true; } } - - private static void CountArraySize(Type elementType, GroboIL il) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(1); - il.Shl(); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(3); - il.Shl(); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(3); - il.Shl(); - break; - default: - throw new NotSupportedException("Type '" + elementType + "' is not supported"); - } - } - - private static void CountArrayLength(Type elementType, GroboIL il) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(1); - il.Shr(false); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(2); - il.Shr(false); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(3); - il.Shr(false); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(2); - il.Shr(false); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(3); - il.Shr(false); - break; - default: - throw new NotSupportedException("Type '" + elementType + "' is not supported"); - } - } - - private static readonly MethodInfo resizeMethod = ((MethodCallExpression)((Expression>)(arr => Array.Resize(ref arr, 0))).Body).Method.GetGenericMethodDefinition(); - private readonly Type elementType; - } +using System; +using System.Linq.Expressions; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.Readers +{ + internal class PrimitivesArrayReaderBuilder : ReaderBuilderBase + { + public PrimitivesArrayReaderBuilder(Type type) + : base(type) + { + if(!Type.IsArray) throw new InvalidOperationException("An array expected but was '" + Type + "'"); + if(Type.GetArrayRank() != 1) throw new NotSupportedException("Arrays with rank greater than 1 are not supported"); + elementType = Type.GetElementType(); + if(!elementType.IsPrimitive) throw new NotSupportedException("Array of primitive type expected but was '" + Type + "'"); + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override unsafe void ReadNotEmpty(ReaderMethodBuilderContext context) + { + var il = context.Il; + + il.Ldloc(context.TypeCode); // stack: [type code] + il.Ldc_I4((int)GroBufTypeCodeMap.GetTypeCode(Type)); // stack: [type code, GroBufTypeCode(Type)] + var tryReadArrayElementLabel = il.DefineLabel("tryReadArrayElement"); + il.Bne_Un(tryReadArrayElementLabel); // if(type code != GroBufTypeCode(Type)) goto tryReadArrayElement; stack: [] + + context.IncreaseIndexBy1(); + + var size = il.DeclareLocal(typeof(int)); + + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [data length] + il.Dup(); // stack: [data length, data length] + il.Stloc(size); // size = data length; stack: [data length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] + context.AssertLength(); + + var length = context.Length; + il.Ldloc(size); // stack: [size] + CountArrayLength(elementType, il); // stack: [array length] + il.Stloc(length); // length = array length + + if(context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) + { + var createArrayLabel = il.DefineLabel("createArray"); + context.LoadResult(Type); // stack: [result] + il.Brfalse(createArrayLabel); // if(result == null) goto createArray; + context.LoadResult(Type); // stack: [result] + il.Ldlen(); // stack: [result.Length] + il.Ldloc(length); // stack: [result.Length, length] + + var arrayCreatedLabel = il.DefineLabel("arrayCreated"); + il.Bge(arrayCreatedLabel, false); // if(result.Length >= length) goto arrayCreated; + + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(length); // stack: [ref result, length] + il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, length) + il.Br(arrayCreatedLabel); // goto arrayCreated + + il.MarkLabel(createArrayLabel); + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(length); // stack: [ref result, length] + il.Newarr(elementType); // stack: [ref result, new type[length]] + il.Stind(Type); // result = new type[length]; stack: [] + + il.MarkLabel(arrayCreatedLabel); + } + else + { + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(length); // stack: [ref result, length] + il.Newarr(elementType); // stack: [ref result, new type[length]] + il.Stind(Type); // result = new type[length]; stack: [] + } + + il.Ldloc(length); + var doneLabel = il.DefineLabel("done"); + il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] + + var arr = il.DeclareLocal(elementType.MakeByRefType(), true); + context.LoadResult(Type); // stack: [result] + il.Ldc_I4(0); // stack: [result, 0] + il.Ldelema(elementType); // stack: [&result[0]] + il.Stloc(arr); // arr = &result[0]; stack: [] + il.Ldloc(arr); // stack: [arr] + context.GoToCurrentLocation(); // stack: [arr, &data[index]] + il.Ldloc(length); // stack: [arr, &data[index], length] + CountArraySize(elementType, il); // stack: [arr, &data[index], size] + il.Cpblk(); // arr = &data[index] + il.FreePinnedLocal(arr); // arr = null; stack: [] + context.LoadIndexByRef(); // stack: [ref index] + context.LoadIndex(); // stack: [ref index, index] + il.Ldloc(size); // stack: [ref index, index, size] + il.Add(); // stack: [ref index, index + size] + il.Stind(typeof(int)); // index = index + size + il.Br(doneLabel); + + il.MarkLabel(tryReadArrayElementLabel); + if(context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) + { + var createArrayLabel = il.DefineLabel("createArray"); + context.LoadResult(Type); // stack: [result] + il.Brfalse(createArrayLabel); // if(result == null) goto createArray; + context.LoadResult(Type); // stack: [result] + il.Ldlen(); // stack: [result.Length] + il.Ldc_I4(1); // stack: [result.Length, 1] + + var arrayCreatedLabel = il.DefineLabel("arrayCreated"); + il.Bge(arrayCreatedLabel, false); // if(result.Length >= 1) goto arrayCreated; + + context.LoadResultByRef(); // stack: [ref result] + il.Ldc_I4(1); // stack: [ref result, 1] + il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, 1) + il.Br(arrayCreatedLabel); // goto arrayCreated + + il.MarkLabel(createArrayLabel); + context.LoadResultByRef(); // stack: [ref result] + il.Ldc_I4(1); // stack: [ref result, 1] + il.Newarr(elementType); // stack: [ref result, new type[1]] + il.Stind(Type); // result = new type[1]; stack: [] + + il.MarkLabel(arrayCreatedLabel); + } + else + { + context.LoadResultByRef(); // stack: [ref result] + il.Ldc_I4(1); // stack: [ref result, 1] + il.Newarr(elementType); // stack: [ref result, new type[1]] + il.Stind(Type); // result = new type[1]; stack: [] + } + + context.LoadData(); // stack: [pinnedData] + context.LoadIndexByRef(); // stack: [pinnedData, ref index] + context.LoadResult(Type); // stack: [pinnedData, ref index, result] + il.Ldc_I4(0); // stack: [pinnedData, ref index, result, 0] + + il.Ldelema(elementType); // stack: [pinnedData, ref index, ref result[0]] + context.LoadContext(); // stack: [pinnedData, ref index, ref result[0], context] + + context.CallReader(elementType); // reader(pinnedData, ref index, ref result[0], context); stack: [] + + il.MarkLabel(doneLabel); // stack: [] + } + + protected override bool IsReference { get { return true; } } + + private static void CountArraySize(Type elementType, GroboIL il) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(1); + il.Shl(); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(3); + il.Shl(); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(3); + il.Shl(); + break; + default: + throw new NotSupportedException("Type '" + elementType + "' is not supported"); + } + } + + private static void CountArrayLength(Type elementType, GroboIL il) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(1); + il.Shr(false); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(2); + il.Shr(false); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(3); + il.Shr(false); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(2); + il.Shr(false); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(3); + il.Shr(false); + break; + default: + throw new NotSupportedException("Type '" + elementType + "' is not supported"); + } + } + + private static readonly MethodInfo resizeMethod = ((MethodCallExpression)((Expression>)(arr => Array.Resize(ref arr, 0))).Body).Method.GetGenericMethodDefinition(); + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/PrimitivesArraySegmentReaderBuilder.cs b/GroBuf/Readers/PrimitivesArraySegmentReaderBuilder.cs similarity index 100% rename from GroBuf/GroBuf/Readers/PrimitivesArraySegmentReaderBuilder.cs rename to GroBuf/Readers/PrimitivesArraySegmentReaderBuilder.cs diff --git a/GroBuf/GroBuf/Readers/PrimitivesHashSetReaderBuilder.cs b/GroBuf/Readers/PrimitivesHashSetReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/PrimitivesHashSetReaderBuilder.cs rename to GroBuf/Readers/PrimitivesHashSetReaderBuilder.cs index 6d59109..b0c6bff 100644 --- a/GroBuf/GroBuf/Readers/PrimitivesHashSetReaderBuilder.cs +++ b/GroBuf/Readers/PrimitivesHashSetReaderBuilder.cs @@ -1,169 +1,169 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.Readers -{ - internal class PrimitivesHashSetReaderBuilder : ReaderBuilderBase - { - public PrimitivesHashSetReaderBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(HashSet<>))) - throw new InvalidOperationException("HashSet expected but was '" + Type + "'"); - elementType = Type.GetGenericArguments()[0]; - if(!elementType.IsPrimitive) - throw new NotSupportedException("HashSet of primitive type expected but was '" + Type + "'"); - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - context.IncreaseIndexBy1(); - context.AssertTypeCode(GroBufTypeCodeMap.GetTypeCode(elementType.MakeArrayType())); - - var il = context.Il; - var size = il.DeclareLocal(typeof(int)); - - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [data length] - il.Dup(); // stack: [data length, data length] - il.Stloc(size); // size = data length; stack: [data length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] - context.AssertLength(); - - var count = context.Length; - il.Ldloc(size); // stack: [size] - CountArrayLength(elementType, il); // stack: [array length] - il.Stloc(count); // count = array length - - context.LoadResultByRef(); // stack: [ref result] - il.Newobj(Type.GetConstructor(Type.EmptyTypes)); // stack: [ref result, new HashSet() = hashSet] - il.Dup(); // stack: [ref result, hashSet, hashSet] - il.Ldloc(count); // stack: [ref result, hashSet, hashSet, count] - il.Call(Type.GetMethod("Initialize", BindingFlags.Instance | BindingFlags.NonPublic)); // hashSet.Initialize(count); stack: [ref result, hashSet] - il.Stind(Type); // result = hashSet; stack: [] - - il.Ldloc(count); - var doneLabel = il.DefineLabel("done"); - il.Brfalse(doneLabel); // if(count == 0) goto allDone; stack: [] - - var i = il.DeclareLocal(typeof(int)); - il.Ldc_I4(0); // stack: [0] - il.Stloc(i); // i = 0; stack: [] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - context.LoadResult(Type); // stack: [result] - context.GoToCurrentLocation(); // stack: [result, &data[index]] - il.Ldloc(i); // stack: [result, &data[index], i] - MakeShift(elementType, il); // stack: [result, &data[index], i << x] - il.Add(); // stack: [result, current] - il.Ldind(elementType); // stack: [result, *current] - il.Call(Type.GetMethod("Add")); // stack: [result.Add(*current)] - il.Pop(); // stack: [] - - il.Ldloc(count); // stack: [count] - il.Ldloc(i); // stack: [current, count, i] - il.Ldc_I4(1); // stack: [current, count, i, 1] - il.Add(); // stack: [current, count, i + 1] - il.Dup(); // stack: [current, count, i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [current, count, i] - il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [current] - - context.LoadIndexByRef(); // stack: [ref index] - context.LoadIndex(); // stack: [ref index, index] - il.Ldloc(size); // stack: [ref index, index, size] - il.Add(); // stack: [ref index, index + size] - il.Stind(typeof(int)); // index = index + size - - il.MarkLabel(doneLabel); // stack: [] - } - - protected override bool IsReference { get { return true; } } - - private static void CountArrayLength(Type elementType, GroboIL il) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(1); - il.Shr(false); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(2); - il.Shr(false); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(3); - il.Shr(false); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(2); - il.Shr(false); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(3); - il.Shr(false); - break; - default: - throw new NotSupportedException("Type '" + elementType + "' is not supported"); - } - } - - private static void MakeShift(Type elementType, GroboIL il) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(1); - il.Shl(); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(3); - il.Shl(); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(3); - il.Shl(); - break; - default: - throw new NotSupportedException("Type '" + elementType + "' is not supported"); - } - } - - private readonly Type elementType; - } +using System; +using System.Collections.Generic; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.Readers +{ + internal class PrimitivesHashSetReaderBuilder : ReaderBuilderBase + { + public PrimitivesHashSetReaderBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(HashSet<>))) + throw new InvalidOperationException("HashSet expected but was '" + Type + "'"); + elementType = Type.GetGenericArguments()[0]; + if(!elementType.IsPrimitive) + throw new NotSupportedException("HashSet of primitive type expected but was '" + Type + "'"); + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + context.IncreaseIndexBy1(); + context.AssertTypeCode(GroBufTypeCodeMap.GetTypeCode(elementType.MakeArrayType())); + + var il = context.Il; + var size = il.DeclareLocal(typeof(int)); + + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [data length] + il.Dup(); // stack: [data length, data length] + il.Stloc(size); // size = data length; stack: [data length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] + context.AssertLength(); + + var count = context.Length; + il.Ldloc(size); // stack: [size] + CountArrayLength(elementType, il); // stack: [array length] + il.Stloc(count); // count = array length + + context.LoadResultByRef(); // stack: [ref result] + il.Newobj(Type.GetConstructor(Type.EmptyTypes)); // stack: [ref result, new HashSet() = hashSet] + il.Dup(); // stack: [ref result, hashSet, hashSet] + il.Ldloc(count); // stack: [ref result, hashSet, hashSet, count] + il.Call(Type.GetMethod("Initialize", BindingFlags.Instance | BindingFlags.NonPublic)); // hashSet.Initialize(count); stack: [ref result, hashSet] + il.Stind(Type); // result = hashSet; stack: [] + + il.Ldloc(count); + var doneLabel = il.DefineLabel("done"); + il.Brfalse(doneLabel); // if(count == 0) goto allDone; stack: [] + + var i = il.DeclareLocal(typeof(int)); + il.Ldc_I4(0); // stack: [0] + il.Stloc(i); // i = 0; stack: [] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + context.LoadResult(Type); // stack: [result] + context.GoToCurrentLocation(); // stack: [result, &data[index]] + il.Ldloc(i); // stack: [result, &data[index], i] + MakeShift(elementType, il); // stack: [result, &data[index], i << x] + il.Add(); // stack: [result, current] + il.Ldind(elementType); // stack: [result, *current] + il.Call(Type.GetMethod("Add")); // stack: [result.Add(*current)] + il.Pop(); // stack: [] + + il.Ldloc(count); // stack: [count] + il.Ldloc(i); // stack: [current, count, i] + il.Ldc_I4(1); // stack: [current, count, i, 1] + il.Add(); // stack: [current, count, i + 1] + il.Dup(); // stack: [current, count, i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [current, count, i] + il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [current] + + context.LoadIndexByRef(); // stack: [ref index] + context.LoadIndex(); // stack: [ref index, index] + il.Ldloc(size); // stack: [ref index, index, size] + il.Add(); // stack: [ref index, index + size] + il.Stind(typeof(int)); // index = index + size + + il.MarkLabel(doneLabel); // stack: [] + } + + protected override bool IsReference { get { return true; } } + + private static void CountArrayLength(Type elementType, GroboIL il) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(1); + il.Shr(false); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(2); + il.Shr(false); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(3); + il.Shr(false); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(2); + il.Shr(false); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(3); + il.Shr(false); + break; + default: + throw new NotSupportedException("Type '" + elementType + "' is not supported"); + } + } + + private static void MakeShift(Type elementType, GroboIL il) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(1); + il.Shl(); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(3); + il.Shl(); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(3); + il.Shl(); + break; + default: + throw new NotSupportedException("Type '" + elementType + "' is not supported"); + } + } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/PrimitivesListReaderBuilder.cs b/GroBuf/Readers/PrimitivesListReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/PrimitivesListReaderBuilder.cs rename to GroBuf/Readers/PrimitivesListReaderBuilder.cs index 3a22293..e2cd253 100644 --- a/GroBuf/GroBuf/Readers/PrimitivesListReaderBuilder.cs +++ b/GroBuf/Readers/PrimitivesListReaderBuilder.cs @@ -1,200 +1,200 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.Readers -{ - internal class PrimitivesListReaderBuilder : ReaderBuilderBase - { - public PrimitivesListReaderBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(List<>))) - throw new InvalidOperationException("Expected list but was '" + Type + "'"); - elementType = Type.GetGenericArguments()[0]; - if(!elementType.IsPrimitive) - throw new NotSupportedException("List of primitive type expected but was '" + Type + "'"); - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override unsafe void ReadNotEmpty(ReaderMethodBuilderContext context) - { - context.IncreaseIndexBy1(); - context.AssertTypeCode(GroBufTypeCodeMap.GetTypeCode(elementType.MakeArrayType())); - - var il = context.Il; - var size = il.DeclareLocal(typeof(int)); - - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [data length] - il.Dup(); // stack: [data length, data length] - il.Stloc(size); // size = data length; stack: [data length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] - context.AssertLength(); - - var length = context.Length; - il.Ldloc(size); // stack: [size] - CountArrayLength(elementType, il); // stack: [array length] - il.Stloc(length); // length = array length - - - if (context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) - { - var createArrayLabel = il.DefineLabel("createArray"); - context.LoadResult(Type); // stack: [result] - il.Brfalse(createArrayLabel); // if(result == null) goto createArray; stack: [] - context.LoadResult(Type); // stack: [result] - il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items] - il.Ldlen(); // stack: [result._items.Length] - il.Ldloc(length); // stack: [result.Length, length] - - var arrayCreatedLabel = il.DefineLabel("arrayCreated"); - il.Bge(arrayCreatedLabel, false); // if(result.Length >= length) goto arrayCreated; - - context.LoadResult(Type); // stack: [result] - il.Ldflda(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [ref result._items] - il.Ldloc(length); // stack: [ref result, length] - il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, length) - il.Br(arrayCreatedLabel); // goto arrayCreated - - il.MarkLabel(createArrayLabel); - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(length); // stack: [ref result, length] - il.Newobj(Type.GetConstructor(new[] {typeof(int)})); // stack: [ref result, new List(length)] - il.Stind(Type); // result = new List(length); stack: [] - - il.MarkLabel(arrayCreatedLabel); - } - else - { - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(length); // stack: [ref result, length] - il.Newobj(Type.GetConstructor(new[] { typeof(int) })); // stack: [ref result, new List(length)] - il.Stind(Type); // result = new List(length); stack: [] - } - il.Ldloc(length); - var doneLabel = il.DefineLabel("done"); - il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] - - var arr = il.DeclareLocal(elementType.MakeByRefType(), true); - context.LoadResult(Type); // stack: [result] - il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items] - il.Ldc_I4(0); // stack: [result._items, 0] - il.Ldelema(elementType); // stack: [&result._items[0]] - il.Stloc(arr); // arr = &result._items[0]; stack: [] - il.Ldloc(arr); // stack: [arr] - context.GoToCurrentLocation(); // stack: [arr, &data[index]] - il.Ldloc(length); // stack: [arr, &data[index], length] - CountArraySize(elementType, il); // stack: [arr, &data[index], size] - il.Cpblk(); // arr = &data[index] - il.FreePinnedLocal(arr); // arr = null; stack: [] - context.LoadIndexByRef(); // stack: [ref index] - context.LoadIndex(); // stack: [ref index, index] - il.Ldloc(size); // stack: [ref index, index, size] - il.Add(); // stack: [ref index, index + size] - il.Stind(typeof(int)); // index = index + size - - if (context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) - { - context.LoadResult(Type); // stack: [result] - il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result.Count] - il.Ldloc(length); // stack: [result.Count, length] - il.Bge(doneLabel, false); // if(result.Count >= length) goto done; stack: [] - } - context.LoadResult(Type); // stack: [result] - il.Ldloc(length); // stack: [result.Count, length] - il.Stfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // result._size = length; stack: [] - - il.MarkLabel(doneLabel); // stack: [] - } - - protected override bool IsReference { get { return true; } } - - private static void CountArraySize(Type elementType, GroboIL il) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(1); - il.Shl(); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(3); - il.Shl(); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(3); - il.Shl(); - break; - default: - throw new NotSupportedException("Type '" + elementType + "' is not supported"); - } - } - - private static void CountArrayLength(Type elementType, GroboIL il) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(1); - il.Shr(false); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(2); - il.Shr(false); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(3); - il.Shr(false); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(2); - il.Shr(false); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(3); - il.Shr(false); - break; - default: - throw new NotSupportedException("Type '" + elementType + "' is not supported"); - } - } - - private static readonly MethodInfo resizeMethod = ((MethodCallExpression)((Expression>)(arr => Array.Resize(ref arr, 0))).Body).Method.GetGenericMethodDefinition(); - private readonly Type elementType; - } +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.Readers +{ + internal class PrimitivesListReaderBuilder : ReaderBuilderBase + { + public PrimitivesListReaderBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(List<>))) + throw new InvalidOperationException("Expected list but was '" + Type + "'"); + elementType = Type.GetGenericArguments()[0]; + if(!elementType.IsPrimitive) + throw new NotSupportedException("List of primitive type expected but was '" + Type + "'"); + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override unsafe void ReadNotEmpty(ReaderMethodBuilderContext context) + { + context.IncreaseIndexBy1(); + context.AssertTypeCode(GroBufTypeCodeMap.GetTypeCode(elementType.MakeArrayType())); + + var il = context.Il; + var size = il.DeclareLocal(typeof(int)); + + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [data length] + il.Dup(); // stack: [data length, data length] + il.Stloc(size); // size = data length; stack: [data length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [data length] + context.AssertLength(); + + var length = context.Length; + il.Ldloc(size); // stack: [size] + CountArrayLength(elementType, il); // stack: [array length] + il.Stloc(length); // length = array length + + + if (context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) + { + var createArrayLabel = il.DefineLabel("createArray"); + context.LoadResult(Type); // stack: [result] + il.Brfalse(createArrayLabel); // if(result == null) goto createArray; stack: [] + context.LoadResult(Type); // stack: [result] + il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items] + il.Ldlen(); // stack: [result._items.Length] + il.Ldloc(length); // stack: [result.Length, length] + + var arrayCreatedLabel = il.DefineLabel("arrayCreated"); + il.Bge(arrayCreatedLabel, false); // if(result.Length >= length) goto arrayCreated; + + context.LoadResult(Type); // stack: [result] + il.Ldflda(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [ref result._items] + il.Ldloc(length); // stack: [ref result, length] + il.Call(resizeMethod.MakeGenericMethod(elementType)); // Array.Resize(ref result, length) + il.Br(arrayCreatedLabel); // goto arrayCreated + + il.MarkLabel(createArrayLabel); + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(length); // stack: [ref result, length] + il.Newobj(Type.GetConstructor(new[] {typeof(int)})); // stack: [ref result, new List(length)] + il.Stind(Type); // result = new List(length); stack: [] + + il.MarkLabel(arrayCreatedLabel); + } + else + { + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(length); // stack: [ref result, length] + il.Newobj(Type.GetConstructor(new[] { typeof(int) })); // stack: [ref result, new List(length)] + il.Stind(Type); // result = new List(length); stack: [] + } + il.Ldloc(length); + var doneLabel = il.DefineLabel("done"); + il.Brfalse(doneLabel); // if(length == 0) goto allDone; stack: [] + + var arr = il.DeclareLocal(elementType.MakeByRefType(), true); + context.LoadResult(Type); // stack: [result] + il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result._items] + il.Ldc_I4(0); // stack: [result._items, 0] + il.Ldelema(elementType); // stack: [&result._items[0]] + il.Stloc(arr); // arr = &result._items[0]; stack: [] + il.Ldloc(arr); // stack: [arr] + context.GoToCurrentLocation(); // stack: [arr, &data[index]] + il.Ldloc(length); // stack: [arr, &data[index], length] + CountArraySize(elementType, il); // stack: [arr, &data[index], size] + il.Cpblk(); // arr = &data[index] + il.FreePinnedLocal(arr); // arr = null; stack: [] + context.LoadIndexByRef(); // stack: [ref index] + context.LoadIndex(); // stack: [ref index, index] + il.Ldloc(size); // stack: [ref index, index, size] + il.Add(); // stack: [ref index, index + size] + il.Stind(typeof(int)); // index = index + size + + if (context.Context.GroBufReader.Options.HasFlag(GroBufOptions.MergeOnRead)) + { + context.LoadResult(Type); // stack: [result] + il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [result.Count] + il.Ldloc(length); // stack: [result.Count, length] + il.Bge(doneLabel, false); // if(result.Count >= length) goto done; stack: [] + } + context.LoadResult(Type); // stack: [result] + il.Ldloc(length); // stack: [result.Count, length] + il.Stfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // result._size = length; stack: [] + + il.MarkLabel(doneLabel); // stack: [] + } + + protected override bool IsReference { get { return true; } } + + private static void CountArraySize(Type elementType, GroboIL il) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(1); + il.Shl(); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(3); + il.Shl(); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(3); + il.Shl(); + break; + default: + throw new NotSupportedException("Type '" + elementType + "' is not supported"); + } + } + + private static void CountArrayLength(Type elementType, GroboIL il) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(1); + il.Shr(false); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(2); + il.Shr(false); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(3); + il.Shr(false); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(2); + il.Shr(false); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(3); + il.Shr(false); + break; + default: + throw new NotSupportedException("Type '" + elementType + "' is not supported"); + } + } + + private static readonly MethodInfo resizeMethod = ((MethodCallExpression)((Expression>)(arr => Array.Resize(ref arr, 0))).Body).Method.GetGenericMethodDefinition(); + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/PrimitivesReaderBuilder.cs b/GroBuf/Readers/PrimitivesReaderBuilder.cs similarity index 98% rename from GroBuf/GroBuf/Readers/PrimitivesReaderBuilder.cs rename to GroBuf/Readers/PrimitivesReaderBuilder.cs index 2835177..dbc5d0a 100644 --- a/GroBuf/GroBuf/Readers/PrimitivesReaderBuilder.cs +++ b/GroBuf/Readers/PrimitivesReaderBuilder.cs @@ -1,410 +1,410 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Reflection.Emit; - -using GrEmit; - -namespace GroBuf.Readers -{ - internal class PrimitivesReaderBuilder : ReaderBuilderBase - { - public PrimitivesReaderBuilder(Type type, ModuleBuilder module) - : base(type) - { - if(!Type.IsPrimitive && Type != typeof(decimal)) - throw new InvalidOperationException("Expected primitive type but was '" + Type + "'"); - primitiveReaders = BuildPrimitiveValueReaders(module); - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.SetFields(Type, new[] - { - new KeyValuePair("readers_" + Type.Name + "_" + Guid.NewGuid(), typeof(IntPtr[])), - new KeyValuePair("delegates_" + Type.Name + "_" + Guid.NewGuid(), typeof(Delegate[])), - }); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - context.IncreaseIndexBy1(); - var readersField = context.Context.InitConstField(Type, 0, primitiveReaders.Select(pair => pair.Value).ToArray()); - context.Context.InitConstField(Type, 1, primitiveReaders.Select(pair => pair.Key).ToArray()); - var il = context.Il; - - context.GoToCurrentLocation(); // stack: [&data[index]] - context.LoadResultByRef(); // stack: [&data[index], ref result] - context.SkipValue(); - context.LoadField(readersField); // stack: [&data[index], ref result, readers] - il.Ldloc(context.TypeCode); // stack: [&data[index], ref result, readers, typeCode] - il.Ldelem(typeof(IntPtr)); // stack: [&data[index], ref result, readers[typeCode]] - il.Calli(CallingConventions.Standard, typeof(void), new[] {typeof(byte*), Type.MakeByRefType()}); // readers[typeCode](&data[index], ref result); stack: [] - } - - protected override bool IsReference { get { return false; } } - - private delegate void PrimitiveValueReaderDelegate(IntPtr data, ref T result); - - private KeyValuePair[] BuildPrimitiveValueReaders(ModuleBuilder module) - { - var result = new KeyValuePair[256]; - var defaultReader = BuildDefaultValueReader(module); - for(var i = 0; i < 256; ++i) - result[i] = defaultReader; - foreach(var typeCode in new[] - { - GroBufTypeCode.Int8, GroBufTypeCode.UInt8, - GroBufTypeCode.Int16, GroBufTypeCode.UInt16, - GroBufTypeCode.Int32, GroBufTypeCode.UInt32, - GroBufTypeCode.Int64, GroBufTypeCode.UInt64, - GroBufTypeCode.Single, GroBufTypeCode.Double, - GroBufTypeCode.Boolean, GroBufTypeCode.DateTimeNew, - GroBufTypeCode.Decimal - }) - result[(int)typeCode] = BuildPrimitiveValueReader(module, typeCode); - return result; - } - - // todo: kill - private KeyValuePair BuildDefaultValueReader(ModuleBuilder module) - { - var method = new DynamicMethod("Default_" + Type.Name + "_" + Guid.NewGuid(), typeof(void), new[] {typeof(IntPtr), Type.MakeByRefType()}, module, true); - using(var il = new GroboIL(method)) - { - il.Ldarg(1); // stack: [ref result] - il.Initobj(Type); // [result = default(T)] - il.Ret(); - } - var @delegate = method.CreateDelegate(typeof(PrimitiveValueReaderDelegate<>).MakeGenericType(Type)); - return new KeyValuePair(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)); - } - - private KeyValuePair BuildPrimitiveValueReader(ModuleBuilder module, GroBufTypeCode typeCode) - { - var method = new DynamicMethod("Read_" + Type.Name + "_from_" + typeCode + "_" + Guid.NewGuid(), typeof(void), new[] {typeof(IntPtr), Type.MakeByRefType()}, module, true); - using(var il = new GroboIL(method)) - { - var expectedTypeCode = GroBufTypeCodeMap.GetTypeCode(Type); - - il.Ldarg(1); // stack: [ref result] - if(typeCode == GroBufTypeCode.Decimal) - { - if(expectedTypeCode == GroBufTypeCode.Boolean) - { - il.Ldarg(0); // stack: [ref result, &temp, address] - il.Ldind(typeof(long)); // stack: [ref result, &temp, (long)*address] - il.Ldarg(0); // stack: [ref result, &temp + 8, address] - il.Ldc_I4(8); // stack: [ref result, &temp + 8, address, 8] - il.Add(); // stack: [ref result, &temp + 8, address + 8] - il.Ldind(typeof(long)); // stack: [ref result, &temp + 8, (long)*(address + 8)] - il.Or(); - il.Ldc_I4(0); // stack: [ref result, value, 0] - il.Conv(); - il.Ceq(); // stack: [ref result, value == 0] - il.Ldc_I4(1); // stack: [ref result, value == 0, 1] - il.Xor(); // stack: [ref result, value != 0] - } - else - { - var temp = il.DeclareLocal(typeof(decimal)); - il.Ldloca(temp); // stack: [ref result, &temp] - il.Ldarg(0); // stack: [ref result, &temp, address] - il.Ldind(typeof(long)); // stack: [ref result, &temp, (long)*address] - il.Stind(typeof(long)); // *temp = *address; - il.Ldloca(temp); // stack: [ref result, &temp] - il.Ldc_I4(8); // stack: [ref result, &temp, 8] - il.Add(); // stack: [ref result, &temp + 8] - il.Ldarg(0); // stack: [ref result, &temp + 8, address] - il.Ldc_I4(8); // stack: [ref result, &temp + 8, address, 8] - il.Add(); // stack: [ref result, &temp + 8, address + 8] - il.Ldind(typeof(long)); // stack: [ref result, &temp + 8, (long)*(address + 8)] - il.Stind(typeof(long)); // *(temp + 8) = *(address + 8); - - il.Ldloc(temp); // stack: [ref result, ref temp] - switch(expectedTypeCode) - { - case GroBufTypeCode.Int8: - il.Call(decimalToInt8Method); // stack: [ref result, (sbyte)temp] - break; - case GroBufTypeCode.UInt8: - il.Call(decimalToUInt8Method); // stack: [ref result, (byte)temp] - break; - case GroBufTypeCode.Int16: - il.Call(decimalToInt16Method); // stack: [ref result, (short)temp] - break; - case GroBufTypeCode.UInt16: - il.Call(decimalToUInt16Method); // stack: [ref result, (ushort)temp] - break; - case GroBufTypeCode.Int32: - il.Call(decimalToInt32Method); // stack: [ref result, (int)temp] - break; - case GroBufTypeCode.UInt32: - il.Call(decimalToUInt32Method); // stack: [ref result, (uint)temp] - break; - case GroBufTypeCode.Int64: - il.Call(decimalToInt64Method); // stack: [ref result, (long)temp] - break; - case GroBufTypeCode.UInt64: - il.Call(decimalToUInt64Method); // stack: [ref result, (ulong)temp] - break; - case GroBufTypeCode.Single: - il.Call(decimalToSingleMethod); // stack: [ref result, (float)temp] - break; - case GroBufTypeCode.Double: - il.Call(decimalToDoubleMethod); // stack: [ref result, (double)temp] - break; - case GroBufTypeCode.Decimal: - break; - default: - throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported"); - } - } - } - else - { - il.Ldarg(0); // stack: [ref result, address] - EmitReadPrimitiveValue(il, Type == typeof(bool) ? GetTypeCodeForBool(typeCode) : typeCode); // stack: [ref result, value] - if(Type == typeof(bool)) - { - il.Conv(); - il.Ldc_I4(0); // stack: [ref result, value, 0] - il.Conv(); - il.Ceq(); // stack: [ref result, value == 0] - il.Ldc_I4(1); // stack: [ref result, value == 0, 1] - il.Xor(); // stack: [ref result, value != 0] - } - else - EmitConvertValue(il, typeCode, expectedTypeCode); - } - switch(expectedTypeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - il.Stind(typeof(byte)); // result = value - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Stind(typeof(short)); // result = value - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Stind(typeof(int)); // result = value - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Stind(typeof(long)); // result = value - break; - case GroBufTypeCode.Single: - il.Stind(typeof(float)); // result = value - break; - case GroBufTypeCode.Double: - il.Stind(typeof(double)); // result = value - break; - case GroBufTypeCode.Decimal: - il.Stobj(typeof(decimal)); // result = value - break; - default: - throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported"); - } - il.Ret(); - } - var @delegate = method.CreateDelegate(typeof(PrimitiveValueReaderDelegate<>).MakeGenericType(Type)); - return new KeyValuePair(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)); - } - - private GroBufTypeCode GetTypeCodeForBool(GroBufTypeCode typeCode) - { - if(typeCode == GroBufTypeCode.Single) - return GroBufTypeCode.Int32; - if(typeCode == GroBufTypeCode.Double) - return GroBufTypeCode.Int64; - return typeCode; - } - - private static void EmitConvertValue(GroboIL il, GroBufTypeCode typeCode, GroBufTypeCode expectedTypeCode) - { - if(expectedTypeCode == typeCode) - return; - switch(expectedTypeCode) - { - case GroBufTypeCode.Int8: - il.Conv(); - break; - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - il.Conv(); - break; - case GroBufTypeCode.Int16: - il.Conv(); - break; - case GroBufTypeCode.UInt16: - il.Conv(); - break; - case GroBufTypeCode.Int32: - if(typeCode == GroBufTypeCode.Int64 || typeCode == GroBufTypeCode.UInt64 || typeCode == GroBufTypeCode.Double || typeCode == GroBufTypeCode.Single || typeCode == GroBufTypeCode.DateTimeNew) - il.Conv(); - break; - case GroBufTypeCode.UInt32: - if(typeCode == GroBufTypeCode.Int64 || typeCode == GroBufTypeCode.UInt64 || typeCode == GroBufTypeCode.Double || typeCode == GroBufTypeCode.Single || typeCode == GroBufTypeCode.DateTimeNew) - il.Conv(); - break; - case GroBufTypeCode.Int64: - if(typeCode != GroBufTypeCode.UInt64) - { - if(typeCode == GroBufTypeCode.UInt8 || typeCode == GroBufTypeCode.UInt16 || typeCode == GroBufTypeCode.UInt32) - il.Conv(); - else - il.Conv(); - } - break; - case GroBufTypeCode.UInt64: - if(typeCode != GroBufTypeCode.Int64 && typeCode != GroBufTypeCode.DateTimeNew) - { - if(typeCode == GroBufTypeCode.Int8 || typeCode == GroBufTypeCode.Int16 || typeCode == GroBufTypeCode.Int32) - il.Conv(); - else - il.Conv(); - } - break; - case GroBufTypeCode.Single: - if(typeCode == GroBufTypeCode.UInt64 || typeCode == GroBufTypeCode.UInt32) - il.Conv_R_Un(); - il.Conv(); - break; - case GroBufTypeCode.Double: - if(typeCode == GroBufTypeCode.UInt64 || typeCode == GroBufTypeCode.UInt32) - il.Conv_R_Un(); - il.Conv(); - break; - case GroBufTypeCode.Decimal: - switch(typeCode) - { - case GroBufTypeCode.Boolean: - case GroBufTypeCode.Int8: - case GroBufTypeCode.Int16: - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.UInt16: - il.Newobj(decimalByIntConstructor); - break; - case GroBufTypeCode.UInt32: - il.Newobj(decimalByUIntConstructor); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.DateTimeNew: - il.Newobj(decimalByLongConstructor); - break; - case GroBufTypeCode.UInt64: - il.Newobj(decimalByULongConstructor); - break; - case GroBufTypeCode.Single: - il.Call(decimalByFloatMethod); - break; - case GroBufTypeCode.Double: - il.Call(decimalByDoubleMethod); - break; - default: - throw new NotSupportedException("Type with type code '" + typeCode + "' is not supported"); - } - break; - default: - throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported"); - } - } - - private static void EmitReadPrimitiveValue(GroboIL il, GroBufTypeCode typeCode) - { - switch(typeCode) - { - case GroBufTypeCode.Int8: - il.Ldind(typeof(sbyte)); - break; - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - il.Ldind(typeof(byte)); - break; - case GroBufTypeCode.Int16: - il.Ldind(typeof(short)); - break; - case GroBufTypeCode.UInt16: - il.Ldind(typeof(ushort)); - break; - case GroBufTypeCode.Int32: - il.Ldind(typeof(int)); - break; - case GroBufTypeCode.UInt32: - il.Ldind(typeof(uint)); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.DateTimeNew: - il.Ldind(typeof(long)); - break; - case GroBufTypeCode.UInt64: - il.Ldind(typeof(ulong)); - break; - case GroBufTypeCode.Single: - il.Ldind(typeof(float)); - break; - case GroBufTypeCode.Double: - il.Ldind(typeof(double)); - break; - default: - throw new NotSupportedException("Type with type code '" + typeCode + "' is not supported"); - } - } - - private static decimal DecimalFromDoubleSilent(double x) - { - if(double.IsNaN(x)) - return 0; - if(double.IsPositiveInfinity(x)) - return decimal.MaxValue; - if(double.IsNegativeInfinity(x)) - return decimal.MinValue; - if(x - (double)decimal.MaxValue >= -1e-10) - return decimal.MaxValue; - if((double)decimal.MinValue - x >= -1e-10) - return decimal.MinValue; - return new decimal(x); - } - - private static decimal DecimalFromFloatSilent(float x) - { - if (float.IsNaN(x)) - return 0; - if (float.IsPositiveInfinity(x)) - return decimal.MaxValue; - if (float.IsNegativeInfinity(x)) - return decimal.MinValue; - if (x - (float)decimal.MaxValue >= -1e-8f) - return decimal.MaxValue; - if ((float)decimal.MinValue - x >= -1e-8f) - return decimal.MinValue; - return new decimal(x); - } - - private readonly KeyValuePair[] primitiveReaders; - - private static readonly ConstructorInfo decimalByIntConstructor = ((NewExpression)((Expression>)(i => new decimal(i))).Body).Constructor; - private static readonly ConstructorInfo decimalByUIntConstructor = ((NewExpression)((Expression>)(i => new decimal(i))).Body).Constructor; - private static readonly ConstructorInfo decimalByLongConstructor = ((NewExpression)((Expression>)(i => new decimal(i))).Body).Constructor; - private static readonly ConstructorInfo decimalByULongConstructor = ((NewExpression)((Expression>)(i => new decimal(i))).Body).Constructor; - private static readonly MethodInfo decimalByFloatMethod = ((MethodCallExpression)((Expression>)(x => DecimalFromFloatSilent(x))).Body).Method; - private static readonly MethodInfo decimalByDoubleMethod = ((MethodCallExpression)((Expression>)(x => DecimalFromDoubleSilent(x))).Body).Method; - - private static readonly MethodInfo decimalToInt8Method = ((UnaryExpression)((Expression>)(d => (sbyte)d)).Body).Method; - private static readonly MethodInfo decimalToUInt8Method = ((UnaryExpression)((Expression>)(d => (byte)d)).Body).Method; - private static readonly MethodInfo decimalToInt16Method = ((UnaryExpression)((Expression>)(d => (short)d)).Body).Method; - private static readonly MethodInfo decimalToUInt16Method = ((UnaryExpression)((Expression>)(d => (ushort)d)).Body).Method; - private static readonly MethodInfo decimalToInt32Method = ((UnaryExpression)((Expression>)(d => (int)d)).Body).Method; - private static readonly MethodInfo decimalToUInt32Method = ((UnaryExpression)((Expression>)(d => (uint)d)).Body).Method; - private static readonly MethodInfo decimalToInt64Method = ((UnaryExpression)((Expression>)(d => (long)d)).Body).Method; - private static readonly MethodInfo decimalToUInt64Method = ((UnaryExpression)((Expression>)(d => (ulong)d)).Body).Method; - private static readonly MethodInfo decimalToSingleMethod = ((UnaryExpression)((Expression>)(d => (float)d)).Body).Method; - private static readonly MethodInfo decimalToDoubleMethod = ((UnaryExpression)((Expression>)(d => (double)d)).Body).Method; - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Reflection.Emit; + +using GrEmit; + +namespace GroBuf.Readers +{ + internal class PrimitivesReaderBuilder : ReaderBuilderBase + { + public PrimitivesReaderBuilder(Type type, ModuleBuilder module) + : base(type) + { + if(!Type.IsPrimitive && Type != typeof(decimal)) + throw new InvalidOperationException("Expected primitive type but was '" + Type + "'"); + primitiveReaders = BuildPrimitiveValueReaders(module); + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.SetFields(Type, new[] + { + new KeyValuePair("readers_" + Type.Name + "_" + Guid.NewGuid(), typeof(IntPtr[])), + new KeyValuePair("delegates_" + Type.Name + "_" + Guid.NewGuid(), typeof(Delegate[])), + }); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + context.IncreaseIndexBy1(); + var readersField = context.Context.InitConstField(Type, 0, primitiveReaders.Select(pair => pair.Value).ToArray()); + context.Context.InitConstField(Type, 1, primitiveReaders.Select(pair => pair.Key).ToArray()); + var il = context.Il; + + context.GoToCurrentLocation(); // stack: [&data[index]] + context.LoadResultByRef(); // stack: [&data[index], ref result] + context.SkipValue(); + context.LoadField(readersField); // stack: [&data[index], ref result, readers] + il.Ldloc(context.TypeCode); // stack: [&data[index], ref result, readers, typeCode] + il.Ldelem(typeof(IntPtr)); // stack: [&data[index], ref result, readers[typeCode]] + il.Calli(CallingConventions.Standard, typeof(void), new[] {typeof(byte*), Type.MakeByRefType()}); // readers[typeCode](&data[index], ref result); stack: [] + } + + protected override bool IsReference { get { return false; } } + + private delegate void PrimitiveValueReaderDelegate(IntPtr data, ref T result); + + private KeyValuePair[] BuildPrimitiveValueReaders(ModuleBuilder module) + { + var result = new KeyValuePair[256]; + var defaultReader = BuildDefaultValueReader(module); + for(var i = 0; i < 256; ++i) + result[i] = defaultReader; + foreach(var typeCode in new[] + { + GroBufTypeCode.Int8, GroBufTypeCode.UInt8, + GroBufTypeCode.Int16, GroBufTypeCode.UInt16, + GroBufTypeCode.Int32, GroBufTypeCode.UInt32, + GroBufTypeCode.Int64, GroBufTypeCode.UInt64, + GroBufTypeCode.Single, GroBufTypeCode.Double, + GroBufTypeCode.Boolean, GroBufTypeCode.DateTimeNew, + GroBufTypeCode.Decimal + }) + result[(int)typeCode] = BuildPrimitiveValueReader(module, typeCode); + return result; + } + + // todo: kill + private KeyValuePair BuildDefaultValueReader(ModuleBuilder module) + { + var method = new DynamicMethod("Default_" + Type.Name + "_" + Guid.NewGuid(), typeof(void), new[] {typeof(IntPtr), Type.MakeByRefType()}, module, true); + using(var il = new GroboIL(method)) + { + il.Ldarg(1); // stack: [ref result] + il.Initobj(Type); // [result = default(T)] + il.Ret(); + } + var @delegate = method.CreateDelegate(typeof(PrimitiveValueReaderDelegate<>).MakeGenericType(Type)); + return new KeyValuePair(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)); + } + + private KeyValuePair BuildPrimitiveValueReader(ModuleBuilder module, GroBufTypeCode typeCode) + { + var method = new DynamicMethod("Read_" + Type.Name + "_from_" + typeCode + "_" + Guid.NewGuid(), typeof(void), new[] {typeof(IntPtr), Type.MakeByRefType()}, module, true); + using(var il = new GroboIL(method)) + { + var expectedTypeCode = GroBufTypeCodeMap.GetTypeCode(Type); + + il.Ldarg(1); // stack: [ref result] + if(typeCode == GroBufTypeCode.Decimal) + { + if(expectedTypeCode == GroBufTypeCode.Boolean) + { + il.Ldarg(0); // stack: [ref result, &temp, address] + il.Ldind(typeof(long)); // stack: [ref result, &temp, (long)*address] + il.Ldarg(0); // stack: [ref result, &temp + 8, address] + il.Ldc_I4(8); // stack: [ref result, &temp + 8, address, 8] + il.Add(); // stack: [ref result, &temp + 8, address + 8] + il.Ldind(typeof(long)); // stack: [ref result, &temp + 8, (long)*(address + 8)] + il.Or(); + il.Ldc_I4(0); // stack: [ref result, value, 0] + il.Conv(); + il.Ceq(); // stack: [ref result, value == 0] + il.Ldc_I4(1); // stack: [ref result, value == 0, 1] + il.Xor(); // stack: [ref result, value != 0] + } + else + { + var temp = il.DeclareLocal(typeof(decimal)); + il.Ldloca(temp); // stack: [ref result, &temp] + il.Ldarg(0); // stack: [ref result, &temp, address] + il.Ldind(typeof(long)); // stack: [ref result, &temp, (long)*address] + il.Stind(typeof(long)); // *temp = *address; + il.Ldloca(temp); // stack: [ref result, &temp] + il.Ldc_I4(8); // stack: [ref result, &temp, 8] + il.Add(); // stack: [ref result, &temp + 8] + il.Ldarg(0); // stack: [ref result, &temp + 8, address] + il.Ldc_I4(8); // stack: [ref result, &temp + 8, address, 8] + il.Add(); // stack: [ref result, &temp + 8, address + 8] + il.Ldind(typeof(long)); // stack: [ref result, &temp + 8, (long)*(address + 8)] + il.Stind(typeof(long)); // *(temp + 8) = *(address + 8); + + il.Ldloc(temp); // stack: [ref result, ref temp] + switch(expectedTypeCode) + { + case GroBufTypeCode.Int8: + il.Call(decimalToInt8Method); // stack: [ref result, (sbyte)temp] + break; + case GroBufTypeCode.UInt8: + il.Call(decimalToUInt8Method); // stack: [ref result, (byte)temp] + break; + case GroBufTypeCode.Int16: + il.Call(decimalToInt16Method); // stack: [ref result, (short)temp] + break; + case GroBufTypeCode.UInt16: + il.Call(decimalToUInt16Method); // stack: [ref result, (ushort)temp] + break; + case GroBufTypeCode.Int32: + il.Call(decimalToInt32Method); // stack: [ref result, (int)temp] + break; + case GroBufTypeCode.UInt32: + il.Call(decimalToUInt32Method); // stack: [ref result, (uint)temp] + break; + case GroBufTypeCode.Int64: + il.Call(decimalToInt64Method); // stack: [ref result, (long)temp] + break; + case GroBufTypeCode.UInt64: + il.Call(decimalToUInt64Method); // stack: [ref result, (ulong)temp] + break; + case GroBufTypeCode.Single: + il.Call(decimalToSingleMethod); // stack: [ref result, (float)temp] + break; + case GroBufTypeCode.Double: + il.Call(decimalToDoubleMethod); // stack: [ref result, (double)temp] + break; + case GroBufTypeCode.Decimal: + break; + default: + throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported"); + } + } + } + else + { + il.Ldarg(0); // stack: [ref result, address] + EmitReadPrimitiveValue(il, Type == typeof(bool) ? GetTypeCodeForBool(typeCode) : typeCode); // stack: [ref result, value] + if(Type == typeof(bool)) + { + il.Conv(); + il.Ldc_I4(0); // stack: [ref result, value, 0] + il.Conv(); + il.Ceq(); // stack: [ref result, value == 0] + il.Ldc_I4(1); // stack: [ref result, value == 0, 1] + il.Xor(); // stack: [ref result, value != 0] + } + else + EmitConvertValue(il, typeCode, expectedTypeCode); + } + switch(expectedTypeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + il.Stind(typeof(byte)); // result = value + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Stind(typeof(short)); // result = value + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Stind(typeof(int)); // result = value + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Stind(typeof(long)); // result = value + break; + case GroBufTypeCode.Single: + il.Stind(typeof(float)); // result = value + break; + case GroBufTypeCode.Double: + il.Stind(typeof(double)); // result = value + break; + case GroBufTypeCode.Decimal: + il.Stobj(typeof(decimal)); // result = value + break; + default: + throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported"); + } + il.Ret(); + } + var @delegate = method.CreateDelegate(typeof(PrimitiveValueReaderDelegate<>).MakeGenericType(Type)); + return new KeyValuePair(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)); + } + + private GroBufTypeCode GetTypeCodeForBool(GroBufTypeCode typeCode) + { + if(typeCode == GroBufTypeCode.Single) + return GroBufTypeCode.Int32; + if(typeCode == GroBufTypeCode.Double) + return GroBufTypeCode.Int64; + return typeCode; + } + + private static void EmitConvertValue(GroboIL il, GroBufTypeCode typeCode, GroBufTypeCode expectedTypeCode) + { + if(expectedTypeCode == typeCode) + return; + switch(expectedTypeCode) + { + case GroBufTypeCode.Int8: + il.Conv(); + break; + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + il.Conv(); + break; + case GroBufTypeCode.Int16: + il.Conv(); + break; + case GroBufTypeCode.UInt16: + il.Conv(); + break; + case GroBufTypeCode.Int32: + if(typeCode == GroBufTypeCode.Int64 || typeCode == GroBufTypeCode.UInt64 || typeCode == GroBufTypeCode.Double || typeCode == GroBufTypeCode.Single || typeCode == GroBufTypeCode.DateTimeNew) + il.Conv(); + break; + case GroBufTypeCode.UInt32: + if(typeCode == GroBufTypeCode.Int64 || typeCode == GroBufTypeCode.UInt64 || typeCode == GroBufTypeCode.Double || typeCode == GroBufTypeCode.Single || typeCode == GroBufTypeCode.DateTimeNew) + il.Conv(); + break; + case GroBufTypeCode.Int64: + if(typeCode != GroBufTypeCode.UInt64) + { + if(typeCode == GroBufTypeCode.UInt8 || typeCode == GroBufTypeCode.UInt16 || typeCode == GroBufTypeCode.UInt32) + il.Conv(); + else + il.Conv(); + } + break; + case GroBufTypeCode.UInt64: + if(typeCode != GroBufTypeCode.Int64 && typeCode != GroBufTypeCode.DateTimeNew) + { + if(typeCode == GroBufTypeCode.Int8 || typeCode == GroBufTypeCode.Int16 || typeCode == GroBufTypeCode.Int32) + il.Conv(); + else + il.Conv(); + } + break; + case GroBufTypeCode.Single: + if(typeCode == GroBufTypeCode.UInt64 || typeCode == GroBufTypeCode.UInt32) + il.Conv_R_Un(); + il.Conv(); + break; + case GroBufTypeCode.Double: + if(typeCode == GroBufTypeCode.UInt64 || typeCode == GroBufTypeCode.UInt32) + il.Conv_R_Un(); + il.Conv(); + break; + case GroBufTypeCode.Decimal: + switch(typeCode) + { + case GroBufTypeCode.Boolean: + case GroBufTypeCode.Int8: + case GroBufTypeCode.Int16: + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.UInt16: + il.Newobj(decimalByIntConstructor); + break; + case GroBufTypeCode.UInt32: + il.Newobj(decimalByUIntConstructor); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.DateTimeNew: + il.Newobj(decimalByLongConstructor); + break; + case GroBufTypeCode.UInt64: + il.Newobj(decimalByULongConstructor); + break; + case GroBufTypeCode.Single: + il.Call(decimalByFloatMethod); + break; + case GroBufTypeCode.Double: + il.Call(decimalByDoubleMethod); + break; + default: + throw new NotSupportedException("Type with type code '" + typeCode + "' is not supported"); + } + break; + default: + throw new NotSupportedException("Type with type code '" + expectedTypeCode + "' is not supported"); + } + } + + private static void EmitReadPrimitiveValue(GroboIL il, GroBufTypeCode typeCode) + { + switch(typeCode) + { + case GroBufTypeCode.Int8: + il.Ldind(typeof(sbyte)); + break; + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + il.Ldind(typeof(byte)); + break; + case GroBufTypeCode.Int16: + il.Ldind(typeof(short)); + break; + case GroBufTypeCode.UInt16: + il.Ldind(typeof(ushort)); + break; + case GroBufTypeCode.Int32: + il.Ldind(typeof(int)); + break; + case GroBufTypeCode.UInt32: + il.Ldind(typeof(uint)); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.DateTimeNew: + il.Ldind(typeof(long)); + break; + case GroBufTypeCode.UInt64: + il.Ldind(typeof(ulong)); + break; + case GroBufTypeCode.Single: + il.Ldind(typeof(float)); + break; + case GroBufTypeCode.Double: + il.Ldind(typeof(double)); + break; + default: + throw new NotSupportedException("Type with type code '" + typeCode + "' is not supported"); + } + } + + private static decimal DecimalFromDoubleSilent(double x) + { + if(double.IsNaN(x)) + return 0; + if(double.IsPositiveInfinity(x)) + return decimal.MaxValue; + if(double.IsNegativeInfinity(x)) + return decimal.MinValue; + if(x - (double)decimal.MaxValue >= -1e-10) + return decimal.MaxValue; + if((double)decimal.MinValue - x >= -1e-10) + return decimal.MinValue; + return new decimal(x); + } + + private static decimal DecimalFromFloatSilent(float x) + { + if (float.IsNaN(x)) + return 0; + if (float.IsPositiveInfinity(x)) + return decimal.MaxValue; + if (float.IsNegativeInfinity(x)) + return decimal.MinValue; + if (x - (float)decimal.MaxValue >= -1e-8f) + return decimal.MaxValue; + if ((float)decimal.MinValue - x >= -1e-8f) + return decimal.MinValue; + return new decimal(x); + } + + private readonly KeyValuePair[] primitiveReaders; + + private static readonly ConstructorInfo decimalByIntConstructor = ((NewExpression)((Expression>)(i => new decimal(i))).Body).Constructor; + private static readonly ConstructorInfo decimalByUIntConstructor = ((NewExpression)((Expression>)(i => new decimal(i))).Body).Constructor; + private static readonly ConstructorInfo decimalByLongConstructor = ((NewExpression)((Expression>)(i => new decimal(i))).Body).Constructor; + private static readonly ConstructorInfo decimalByULongConstructor = ((NewExpression)((Expression>)(i => new decimal(i))).Body).Constructor; + private static readonly MethodInfo decimalByFloatMethod = ((MethodCallExpression)((Expression>)(x => DecimalFromFloatSilent(x))).Body).Method; + private static readonly MethodInfo decimalByDoubleMethod = ((MethodCallExpression)((Expression>)(x => DecimalFromDoubleSilent(x))).Body).Method; + + private static readonly MethodInfo decimalToInt8Method = ((UnaryExpression)((Expression>)(d => (sbyte)d)).Body).Method; + private static readonly MethodInfo decimalToUInt8Method = ((UnaryExpression)((Expression>)(d => (byte)d)).Body).Method; + private static readonly MethodInfo decimalToInt16Method = ((UnaryExpression)((Expression>)(d => (short)d)).Body).Method; + private static readonly MethodInfo decimalToUInt16Method = ((UnaryExpression)((Expression>)(d => (ushort)d)).Body).Method; + private static readonly MethodInfo decimalToInt32Method = ((UnaryExpression)((Expression>)(d => (int)d)).Body).Method; + private static readonly MethodInfo decimalToUInt32Method = ((UnaryExpression)((Expression>)(d => (uint)d)).Body).Method; + private static readonly MethodInfo decimalToInt64Method = ((UnaryExpression)((Expression>)(d => (long)d)).Body).Method; + private static readonly MethodInfo decimalToUInt64Method = ((UnaryExpression)((Expression>)(d => (ulong)d)).Body).Method; + private static readonly MethodInfo decimalToSingleMethod = ((UnaryExpression)((Expression>)(d => (float)d)).Body).Method; + private static readonly MethodInfo decimalToDoubleMethod = ((UnaryExpression)((Expression>)(d => (double)d)).Body).Method; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/ReaderBuilderBase.cs b/GroBuf/Readers/ReaderBuilderBase.cs similarity index 98% rename from GroBuf/GroBuf/Readers/ReaderBuilderBase.cs rename to GroBuf/Readers/ReaderBuilderBase.cs index c048a97..affc4fa 100644 --- a/GroBuf/GroBuf/Readers/ReaderBuilderBase.cs +++ b/GroBuf/Readers/ReaderBuilderBase.cs @@ -1,168 +1,168 @@ -using System; -using System.Collections.Generic; -using System.Reflection.Emit; - -using GrEmit; -using GrEmit.Utils; - -namespace GroBuf.Readers -{ - internal abstract class ReaderBuilderBase : IReaderBuilder - { - protected ReaderBuilderBase(Type type) - { - Type = type; - } - - public void BuildReader(ReaderTypeBuilderContext readerTypeBuilderContext) - { - var method = new DynamicMethod("Read_" + Type.Name + "_" + Guid.NewGuid(), typeof(void), - new[] - { - typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext) - }, readerTypeBuilderContext.Module, true); - readerTypeBuilderContext.SetReaderMethod(Type, method); - using(var il = new GroboIL(method)) - { - var context = new ReaderMethodBuilderContext(readerTypeBuilderContext, il, !Type.IsValueType && IsReference); - - ReadTypeCodeAndCheck(context); // Read TypeCode and check - - if(!Type.IsValueType && IsReference) - { - // Read reference - context.LoadContext(); // stack: [context] - il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] - var notReadLabel = il.DefineLabel("notRead"); - il.Brfalse(notReadLabel); - context.LoadIndex(); // stack: [external index] - context.LoadContext(); // stack: [external index, context] - il.Ldfld(ReaderContext.StartField); // stack: [external index, context.start] - il.Sub(); // stack: [external index - context.start] - il.Stloc(context.Index); // index = external index - context.start; stack: [] - - context.LoadContext(); // stack: [context] - il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] - il.Ldloc(context.Index); // stack: [context.objects, index] - var obj = il.DeclareLocal(typeof(object)); - il.Ldloca(obj); - object dummy; - il.Call(HackHelpers.GetMethodDefinition>(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(index, out obj)] - il.Brfalse(notReadLabel); // if(!context.objects.TryGetValue(index, out obj)) goto notRead; - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(obj); // stack: [ref result, obj] - il.Castclass(Type); // stack: [ref result, (Type)obj] - il.Stind(Type); // result = (Type)obj; stack: [] - context.IncreaseIndexBy1(); // Skip type code - context.SkipValue(); // Skip value - it has already been read - il.Ret(); - il.MarkLabel(notReadLabel); - il.Ldloc(context.TypeCode); // stack: [typeCode] - il.Ldc_I4((int)GroBufTypeCode.Reference); // stack: [typeCode, GroBufTypeCode.Reference] - var readUsualLabel = il.DefineLabel("readUsual"); - il.Bne_Un(readUsualLabel); // if(typeCode != GroBufTypeCode.Reference) goto readUsual; stack: [] - - context.LoadContext(); // stack: [context] - il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] - var objectsIsNotNullLabel = il.DefineLabel("objectsIsNotNull"); - il.Brtrue(objectsIsNotNullLabel); // if(context.objects != null) goto objectsIsNotNull; stack: [context.objects] - il.Ldstr("Reference is not valid at this point"); - il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] {typeof(string)})); - il.Throw(); - il.MarkLabel(objectsIsNotNullLabel); - - context.IncreaseIndexBy1(); // index = index + 1; stack: [] - il.Ldc_I4(4); - context.AssertLength(); - context.GoToCurrentLocation(); - var reference = il.DeclareLocal(typeof(int)); - il.Ldind(typeof(int)); // stack: [*(int*)data[index]] - il.Stloc(reference); // reference = *(int*)data[index]; stack: [] - context.IncreaseIndexBy4(); // index = index + 4; stack: [] - il.Ldloc(context.Index); // stack: [index] - il.Ldloc(reference); // stack: [index, reference] - var goodReferenceLabel = il.DefineLabel("goodReference"); - il.Bgt(goodReferenceLabel, false); // if(index > reference) goto goodReference; stack: [] - il.Ldstr("Bad reference"); - il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] {typeof(string)})); - il.Throw(); - il.MarkLabel(goodReferenceLabel); - context.LoadContext(); // stack: [context] - il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] - il.Ldloc(reference); // stack: [context.objects, reference] - il.Ldloca(obj); // stack: [context.objects, reference, ref obj] - il.Call(HackHelpers.GetMethodDefinition>(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(reference, out obj)] - var readObjectLabel = il.DefineLabel("readObject"); - il.Brfalse(readObjectLabel); // if(!context.objects.TryGetValue(reference, out obj)) goto readObjects; stack: [] - context.LoadResultByRef(); // stack: [ref result] - il.Ldloc(obj); // stack: [ref result, obj] - il.Castclass(Type); // stack: [ref result, (Type)obj] - il.Stind(Type); // result = (Type)obj; stack: [] - il.Ret(); - il.MarkLabel(readObjectLabel); - - // Referenced object has not been read - this means that the object reference belongs to is a property that had been deleted - context.LoadData(); // stack: [data] - il.Ldloc(reference); // stack: [data, reference] - context.LoadContext(); // stack: [data, reference, context] - il.Ldfld(ReaderContext.StartField); // stack: [data, reference, context.start] - il.Add(); // stack: [data, reference + context.start] - il.Stloc(reference); // reference += context.start; stack: [data] - il.Ldloca(reference); // stack: [data, ref reference] - context.LoadResultByRef(); // stack: [data, ref reference, ref result] - context.LoadContext(); // stack: [data, ref reference, ref result, context] - context.CallReader(Type); - il.Ret(); - il.MarkLabel(readUsualLabel); - } - - ReadNotEmpty(context); // Read obj - il.Ret(); - } - var @delegate = method.CreateDelegate(typeof(ReaderDelegate<>).MakeGenericType(Type)); - var pointer = GroBufHelpers.ExtractDynamicMethodPointer(method); - readerTypeBuilderContext.SetReaderPointer(Type, pointer, @delegate); - } - - public void BuildConstants(ReaderConstantsBuilderContext context) - { - context.SetFields(Type, new KeyValuePair[0]); - BuildConstantsInternal(context); - } - - protected abstract void BuildConstantsInternal(ReaderConstantsBuilderContext context); - protected abstract void ReadNotEmpty(ReaderMethodBuilderContext context); - - protected abstract bool IsReference { get; } - - protected Type Type { get; private set; } - - /// - /// Reads TypeCode at data[index] and checks it - /// - /// Returns default() if TypeCode = Empty - /// - /// Current context - private static void ReadTypeCodeAndCheck(ReaderMethodBuilderContext context) - { - var il = context.Il; - var notEmptyLabel = il.DefineLabel("notEmpty"); - il.Ldc_I4(1); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(byte)); // stack: [data[index]] - il.Dup(); // stack: [data[index], data[index]] - il.Stloc(context.TypeCode); // typeCode = data[index]; stack: [typeCode] - - il.Brtrue(notEmptyLabel); // if(typeCode != 0) goto notNull; - - context.IncreaseIndexBy1(); // index = index + 1 - il.Ret(); - - il.MarkLabel(notEmptyLabel); - - context.CheckTypeCode(); - } - } +using System; +using System.Collections.Generic; +using System.Reflection.Emit; + +using GrEmit; +using GrEmit.Utils; + +namespace GroBuf.Readers +{ + internal abstract class ReaderBuilderBase : IReaderBuilder + { + protected ReaderBuilderBase(Type type) + { + Type = type; + } + + public void BuildReader(ReaderTypeBuilderContext readerTypeBuilderContext) + { + var method = new DynamicMethod("Read_" + Type.Name + "_" + Guid.NewGuid(), typeof(void), + new[] + { + typeof(IntPtr), typeof(int).MakeByRefType(), Type.MakeByRefType(), typeof(ReaderContext) + }, readerTypeBuilderContext.Module, true); + readerTypeBuilderContext.SetReaderMethod(Type, method); + using(var il = new GroboIL(method)) + { + var context = new ReaderMethodBuilderContext(readerTypeBuilderContext, il, !Type.IsValueType && IsReference); + + ReadTypeCodeAndCheck(context); // Read TypeCode and check + + if(!Type.IsValueType && IsReference) + { + // Read reference + context.LoadContext(); // stack: [context] + il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] + var notReadLabel = il.DefineLabel("notRead"); + il.Brfalse(notReadLabel); + context.LoadIndex(); // stack: [external index] + context.LoadContext(); // stack: [external index, context] + il.Ldfld(ReaderContext.StartField); // stack: [external index, context.start] + il.Sub(); // stack: [external index - context.start] + il.Stloc(context.Index); // index = external index - context.start; stack: [] + + context.LoadContext(); // stack: [context] + il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] + il.Ldloc(context.Index); // stack: [context.objects, index] + var obj = il.DeclareLocal(typeof(object)); + il.Ldloca(obj); + object dummy; + il.Call(HackHelpers.GetMethodDefinition>(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(index, out obj)] + il.Brfalse(notReadLabel); // if(!context.objects.TryGetValue(index, out obj)) goto notRead; + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(obj); // stack: [ref result, obj] + il.Castclass(Type); // stack: [ref result, (Type)obj] + il.Stind(Type); // result = (Type)obj; stack: [] + context.IncreaseIndexBy1(); // Skip type code + context.SkipValue(); // Skip value - it has already been read + il.Ret(); + il.MarkLabel(notReadLabel); + il.Ldloc(context.TypeCode); // stack: [typeCode] + il.Ldc_I4((int)GroBufTypeCode.Reference); // stack: [typeCode, GroBufTypeCode.Reference] + var readUsualLabel = il.DefineLabel("readUsual"); + il.Bne_Un(readUsualLabel); // if(typeCode != GroBufTypeCode.Reference) goto readUsual; stack: [] + + context.LoadContext(); // stack: [context] + il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] + var objectsIsNotNullLabel = il.DefineLabel("objectsIsNotNull"); + il.Brtrue(objectsIsNotNullLabel); // if(context.objects != null) goto objectsIsNotNull; stack: [context.objects] + il.Ldstr("Reference is not valid at this point"); + il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] {typeof(string)})); + il.Throw(); + il.MarkLabel(objectsIsNotNullLabel); + + context.IncreaseIndexBy1(); // index = index + 1; stack: [] + il.Ldc_I4(4); + context.AssertLength(); + context.GoToCurrentLocation(); + var reference = il.DeclareLocal(typeof(int)); + il.Ldind(typeof(int)); // stack: [*(int*)data[index]] + il.Stloc(reference); // reference = *(int*)data[index]; stack: [] + context.IncreaseIndexBy4(); // index = index + 4; stack: [] + il.Ldloc(context.Index); // stack: [index] + il.Ldloc(reference); // stack: [index, reference] + var goodReferenceLabel = il.DefineLabel("goodReference"); + il.Bgt(goodReferenceLabel, false); // if(index > reference) goto goodReference; stack: [] + il.Ldstr("Bad reference"); + il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] {typeof(string)})); + il.Throw(); + il.MarkLabel(goodReferenceLabel); + context.LoadContext(); // stack: [context] + il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] + il.Ldloc(reference); // stack: [context.objects, reference] + il.Ldloca(obj); // stack: [context.objects, reference, ref obj] + il.Call(HackHelpers.GetMethodDefinition>(dict => dict.TryGetValue(0, out dummy))); // stack: [context.objects.TryGetValue(reference, out obj)] + var readObjectLabel = il.DefineLabel("readObject"); + il.Brfalse(readObjectLabel); // if(!context.objects.TryGetValue(reference, out obj)) goto readObjects; stack: [] + context.LoadResultByRef(); // stack: [ref result] + il.Ldloc(obj); // stack: [ref result, obj] + il.Castclass(Type); // stack: [ref result, (Type)obj] + il.Stind(Type); // result = (Type)obj; stack: [] + il.Ret(); + il.MarkLabel(readObjectLabel); + + // Referenced object has not been read - this means that the object reference belongs to is a property that had been deleted + context.LoadData(); // stack: [data] + il.Ldloc(reference); // stack: [data, reference] + context.LoadContext(); // stack: [data, reference, context] + il.Ldfld(ReaderContext.StartField); // stack: [data, reference, context.start] + il.Add(); // stack: [data, reference + context.start] + il.Stloc(reference); // reference += context.start; stack: [data] + il.Ldloca(reference); // stack: [data, ref reference] + context.LoadResultByRef(); // stack: [data, ref reference, ref result] + context.LoadContext(); // stack: [data, ref reference, ref result, context] + context.CallReader(Type); + il.Ret(); + il.MarkLabel(readUsualLabel); + } + + ReadNotEmpty(context); // Read obj + il.Ret(); + } + var @delegate = method.CreateDelegate(typeof(ReaderDelegate<>).MakeGenericType(Type)); + var pointer = GroBufHelpers.ExtractDynamicMethodPointer(method); + readerTypeBuilderContext.SetReaderPointer(Type, pointer, @delegate); + } + + public void BuildConstants(ReaderConstantsBuilderContext context) + { + context.SetFields(Type, new KeyValuePair[0]); + BuildConstantsInternal(context); + } + + protected abstract void BuildConstantsInternal(ReaderConstantsBuilderContext context); + protected abstract void ReadNotEmpty(ReaderMethodBuilderContext context); + + protected abstract bool IsReference { get; } + + protected Type Type { get; private set; } + + /// + /// Reads TypeCode at data[index] and checks it + /// + /// Returns default() if TypeCode = Empty + /// + /// Current context + private static void ReadTypeCodeAndCheck(ReaderMethodBuilderContext context) + { + var il = context.Il; + var notEmptyLabel = il.DefineLabel("notEmpty"); + il.Ldc_I4(1); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(byte)); // stack: [data[index]] + il.Dup(); // stack: [data[index], data[index]] + il.Stloc(context.TypeCode); // typeCode = data[index]; stack: [typeCode] + + il.Brtrue(notEmptyLabel); // if(typeCode != 0) goto notNull; + + context.IncreaseIndexBy1(); // index = index + 1 + il.Ret(); + + il.MarkLabel(notEmptyLabel); + + context.CheckTypeCode(); + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/ReaderCollection.cs b/GroBuf/Readers/ReaderCollection.cs similarity index 98% rename from GroBuf/GroBuf/Readers/ReaderCollection.cs rename to GroBuf/Readers/ReaderCollection.cs index ffbc039..2074848 100644 --- a/GroBuf/GroBuf/Readers/ReaderCollection.cs +++ b/GroBuf/Readers/ReaderCollection.cs @@ -1,95 +1,95 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Net; -using System.Reflection.Emit; - -namespace GroBuf.Readers -{ - internal class ReaderCollection : IReaderCollection - { - public ReaderCollection(IGroBufCustomSerializerCollection customSerializerCollection, Func factory, Func baseFactory, ModuleBuilder module) - { - this.customSerializerCollection = customSerializerCollection; - this.factory = factory; - this.baseFactory = baseFactory; - this.module = module; - } - - public IReaderBuilder GetReaderBuilder(Type type, bool ignoreCustomSerialization) - { - var key = new KeyValuePair(type, ignoreCustomSerialization); - var readerBuilder = (IReaderBuilder)readerBuilders[key]; - if(readerBuilder == null) - { - lock(readerBuildersLock) - { - readerBuilder = (IReaderBuilder)readerBuilders[key]; - if(readerBuilder == null) - { - readerBuilder = GetReaderBuilderInternal(type, ignoreCustomSerialization); - readerBuilders[key] = readerBuilder; - } - } - } - return readerBuilder; - } - - private IReaderBuilder GetReaderBuilderInternal(Type type, bool ignoreCustomSerialization) - { - IReaderBuilder readerBuilder; - IGroBufCustomSerializer customSerializer = null; - if(!ignoreCustomSerialization) - customSerializer = customSerializerCollection.Get(type, factory, baseFactory(type)); - if(customSerializer != null) - readerBuilder = new CustomReaderBuilder(type, customSerializer); - else if(type == typeof(string)) - readerBuilder = new StringReaderBuilder(); - else if(type == typeof(DateTime)) - readerBuilder = new DateTimeReaderBuilder(); - else if(type == typeof(Guid)) - readerBuilder = new GuidReaderBuilder(); - else if(type == typeof(IPAddress)) - readerBuilder = new IPAddressReaderBuilder(); - else if(type == typeof(TimeSpan)) - readerBuilder = new TimeSpanReaderBuilder(); - else if(type == typeof(DateTimeOffset)) - readerBuilder = new DateTimeOffsetReaderBuilder(); - else if(type.IsEnum) - readerBuilder = new EnumReaderBuilder(type); - else if(type.IsPrimitive || type == typeof(decimal)) - readerBuilder = new PrimitivesReaderBuilder(type, module); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) - readerBuilder = new NullableReaderBuilder(type); - else if(type.IsArray) - readerBuilder = type.GetElementType().IsPrimitive ? (IReaderBuilder)new PrimitivesArrayReaderBuilder(type) : new ArrayReaderBuilder(type); - else if(type == typeof(Hashtable)) - readerBuilder = new HashtableReaderBuilder(); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) - readerBuilder = new DictionaryReaderBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>)) - readerBuilder = type.GetGenericArguments()[0].IsPrimitive ? (IReaderBuilder)new PrimitivesHashSetReaderBuilder(type) : new HashSetReaderBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ArraySegment<>)) - readerBuilder = type.GetGenericArguments()[0].IsPrimitive ? (IReaderBuilder)new PrimitivesArraySegmentReaderBuilder(type) : new ArraySegmentReaderBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) - readerBuilder = type.GetGenericArguments()[0].IsPrimitive ? (IReaderBuilder)new PrimitivesListReaderBuilder(type) : new ListReaderBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Lazy<>)) - readerBuilder = new LazyReaderBuilder(type, module); - else if(type.IsTuple()) - readerBuilder = new TupleReaderBuilder(type); - else if(type == typeof(object)) - readerBuilder = new ObjectReaderBuilder(); - else - readerBuilder = new ClassReaderBuilder(type); - return readerBuilder; - } - - private readonly IGroBufCustomSerializerCollection customSerializerCollection; - private readonly Func factory; - private readonly Func baseFactory; - private readonly ModuleBuilder module; - - private readonly Hashtable readerBuilders = new Hashtable(); - private readonly object readerBuildersLock = new object(); - } +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; +using System.Reflection.Emit; + +namespace GroBuf.Readers +{ + internal class ReaderCollection : IReaderCollection + { + public ReaderCollection(IGroBufCustomSerializerCollection customSerializerCollection, Func factory, Func baseFactory, ModuleBuilder module) + { + this.customSerializerCollection = customSerializerCollection; + this.factory = factory; + this.baseFactory = baseFactory; + this.module = module; + } + + public IReaderBuilder GetReaderBuilder(Type type, bool ignoreCustomSerialization) + { + var key = new KeyValuePair(type, ignoreCustomSerialization); + var readerBuilder = (IReaderBuilder)readerBuilders[key]; + if(readerBuilder == null) + { + lock(readerBuildersLock) + { + readerBuilder = (IReaderBuilder)readerBuilders[key]; + if(readerBuilder == null) + { + readerBuilder = GetReaderBuilderInternal(type, ignoreCustomSerialization); + readerBuilders[key] = readerBuilder; + } + } + } + return readerBuilder; + } + + private IReaderBuilder GetReaderBuilderInternal(Type type, bool ignoreCustomSerialization) + { + IReaderBuilder readerBuilder; + IGroBufCustomSerializer customSerializer = null; + if(!ignoreCustomSerialization) + customSerializer = customSerializerCollection.Get(type, factory, baseFactory(type)); + if(customSerializer != null) + readerBuilder = new CustomReaderBuilder(type, customSerializer); + else if(type == typeof(string)) + readerBuilder = new StringReaderBuilder(); + else if(type == typeof(DateTime)) + readerBuilder = new DateTimeReaderBuilder(); + else if(type == typeof(Guid)) + readerBuilder = new GuidReaderBuilder(); + else if(type == typeof(IPAddress)) + readerBuilder = new IPAddressReaderBuilder(); + else if(type == typeof(TimeSpan)) + readerBuilder = new TimeSpanReaderBuilder(); + else if(type == typeof(DateTimeOffset)) + readerBuilder = new DateTimeOffsetReaderBuilder(); + else if(type.IsEnum) + readerBuilder = new EnumReaderBuilder(type); + else if(type.IsPrimitive || type == typeof(decimal)) + readerBuilder = new PrimitivesReaderBuilder(type, module); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + readerBuilder = new NullableReaderBuilder(type); + else if(type.IsArray) + readerBuilder = type.GetElementType().IsPrimitive ? (IReaderBuilder)new PrimitivesArrayReaderBuilder(type) : new ArrayReaderBuilder(type); + else if(type == typeof(Hashtable)) + readerBuilder = new HashtableReaderBuilder(); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + readerBuilder = new DictionaryReaderBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>)) + readerBuilder = type.GetGenericArguments()[0].IsPrimitive ? (IReaderBuilder)new PrimitivesHashSetReaderBuilder(type) : new HashSetReaderBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ArraySegment<>)) + readerBuilder = type.GetGenericArguments()[0].IsPrimitive ? (IReaderBuilder)new PrimitivesArraySegmentReaderBuilder(type) : new ArraySegmentReaderBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) + readerBuilder = type.GetGenericArguments()[0].IsPrimitive ? (IReaderBuilder)new PrimitivesListReaderBuilder(type) : new ListReaderBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Lazy<>)) + readerBuilder = new LazyReaderBuilder(type, module); + else if(type.IsTuple()) + readerBuilder = new TupleReaderBuilder(type); + else if(type == typeof(object)) + readerBuilder = new ObjectReaderBuilder(); + else + readerBuilder = new ClassReaderBuilder(type); + return readerBuilder; + } + + private readonly IGroBufCustomSerializerCollection customSerializerCollection; + private readonly Func factory; + private readonly Func baseFactory; + private readonly ModuleBuilder module; + + private readonly Hashtable readerBuilders = new Hashtable(); + private readonly object readerBuildersLock = new object(); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/ReaderConstantsBuilderContext.cs b/GroBuf/Readers/ReaderConstantsBuilderContext.cs similarity index 97% rename from GroBuf/GroBuf/Readers/ReaderConstantsBuilderContext.cs rename to GroBuf/Readers/ReaderConstantsBuilderContext.cs index 6f5cfb2..5e3013c 100644 --- a/GroBuf/GroBuf/Readers/ReaderConstantsBuilderContext.cs +++ b/GroBuf/Readers/ReaderConstantsBuilderContext.cs @@ -1,56 +1,56 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -using GroBuf.DataMembersExtracters; - -namespace GroBuf.Readers -{ - internal class ReaderConstantsBuilderContext - { - public ReaderConstantsBuilderContext(GroBufReader groBufReader, TypeBuilder constantsBuilder, IReaderCollection readerCollection, IDataMembersExtractor dataMembersExtractor) - { - GroBufReader = groBufReader; - ConstantsBuilder = constantsBuilder; - this.readerCollection = readerCollection; - this.dataMembersExtractor = dataMembersExtractor; - } - - public IDataMember[] GetDataMembers(Type type) - { - return dataMembersExtractor.GetMembers(type); - } - - public void SetFields(Type type, KeyValuePair[] fields) - { - hashtable[type] = fields; - foreach(var field in fields) - ConstantsBuilder.DefineField(field.Key, field.Value, FieldAttributes.Public | FieldAttributes.Static); - } - - public void BuildConstants(Type type, bool isRoot = false, bool ignoreCustomSerialization = false) - { - if (isRoot || GroBufReader.readMethodsWithCustomSerialization[type] == null) - { - if(hashtable[type] == null) - readerCollection.GetReaderBuilder(type, ignoreCustomSerialization).BuildConstants(this); - } - } - - public Dictionary GetFields() - { - return hashtable.Cast().ToDictionary(entry => (Type)entry.Key, entry => ((KeyValuePair[])entry.Value).Select(pair => pair.Key).ToArray()); - } - - public GroBufReader GroBufReader { get; private set; } - public TypeBuilder ConstantsBuilder { get; private set; } - - private readonly Hashtable hashtable = new Hashtable(); - - private readonly IReaderCollection readerCollection; - private readonly IDataMembersExtractor dataMembersExtractor; - } +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; + +using GroBuf.DataMembersExtracters; + +namespace GroBuf.Readers +{ + internal class ReaderConstantsBuilderContext + { + public ReaderConstantsBuilderContext(GroBufReader groBufReader, TypeBuilder constantsBuilder, IReaderCollection readerCollection, IDataMembersExtractor dataMembersExtractor) + { + GroBufReader = groBufReader; + ConstantsBuilder = constantsBuilder; + this.readerCollection = readerCollection; + this.dataMembersExtractor = dataMembersExtractor; + } + + public IDataMember[] GetDataMembers(Type type) + { + return dataMembersExtractor.GetMembers(type); + } + + public void SetFields(Type type, KeyValuePair[] fields) + { + hashtable[type] = fields; + foreach(var field in fields) + ConstantsBuilder.DefineField(field.Key, field.Value, FieldAttributes.Public | FieldAttributes.Static); + } + + public void BuildConstants(Type type, bool isRoot = false, bool ignoreCustomSerialization = false) + { + if (isRoot || GroBufReader.readMethodsWithCustomSerialization[type] == null) + { + if(hashtable[type] == null) + readerCollection.GetReaderBuilder(type, ignoreCustomSerialization).BuildConstants(this); + } + } + + public Dictionary GetFields() + { + return hashtable.Cast().ToDictionary(entry => (Type)entry.Key, entry => ((KeyValuePair[])entry.Value).Select(pair => pair.Key).ToArray()); + } + + public GroBufReader GroBufReader { get; private set; } + public TypeBuilder ConstantsBuilder { get; private set; } + + private readonly Hashtable hashtable = new Hashtable(); + + private readonly IReaderCollection readerCollection; + private readonly IDataMembersExtractor dataMembersExtractor; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/ReaderMethodBuilderContext.cs b/GroBuf/Readers/ReaderMethodBuilderContext.cs similarity index 97% rename from GroBuf/GroBuf/Readers/ReaderMethodBuilderContext.cs rename to GroBuf/Readers/ReaderMethodBuilderContext.cs index 30912a4..5ee14f3 100644 --- a/GroBuf/GroBuf/Readers/ReaderMethodBuilderContext.cs +++ b/GroBuf/Readers/ReaderMethodBuilderContext.cs @@ -1,317 +1,317 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -using GrEmit; -using GrEmit.Utils; - -namespace GroBuf.Readers -{ - internal class ReaderMethodBuilderContext - { - public ReaderMethodBuilderContext(ReaderTypeBuilderContext context, GroboIL il, bool referenceType) - { - Context = context; - Il = il; - TypeCode = il.DeclareLocal(typeof(int)); - Length = il.DeclareLocal(typeof(uint)); - Index = referenceType ? il.DeclareLocal(typeof(int)) : null; - } - - /// - /// Loads pinnedData onto the evaluation stack - /// - public void LoadData() - { - Il.Ldarg(0); - } - - /// - /// Loads ref index onto the evaluation stack - /// - public void LoadIndexByRef() - { - Il.Ldarg(1); - } - - /// - /// Loads index onto the evaluation stack - /// - public void LoadIndex() - { - Il.Ldarg(1); - Il.Ldind(typeof(int)); - } - - /// - /// Loads context onto the evaluation stack - /// - public void LoadContext() - { - Il.Ldarg(3); - } - - /// - /// Loads dataLength onto the evaluation stack - /// - public void LoadDataLength() - { - LoadContext(); - Il.Ldfld(ReaderContext.LengthField); - } - - /// - /// Loads context.serializerId onto the evaluation stack - /// - public void LoadSerializerId() - { - LoadContext(); - Il.Ldfld(ReaderContext.SerializerIdField); - } - - /// - /// Loads ref result onto the evaluation stack - /// - public void LoadResultByRef() - { - Il.Ldarg(2); - } - - /// - /// Loads result onto the evaluation stack - /// - public void LoadResult(Type resultType) - { - Il.Ldarg(2); - Il.Ldind(resultType); - } - - /// - /// Loads the specified field onto the evaluation stack - /// - /// Field to load - public void LoadField(FieldInfo field) - { - Il.Ldfld(field); - } - - /// - /// Increases index by 1 - /// - public void IncreaseIndexBy1() - { - LoadIndexByRef(); // stack: [ref index] - LoadIndex(); // stack: [ref index, index] - Il.Ldc_I4(1); // stack: [ref index, index, 1] - Il.Add(); // stack: [ref index, index + 1] - Il.Stind(typeof(int)); // index = index + 1 - } - - /// - /// Increases index by 2 - /// - public void IncreaseIndexBy2() - { - LoadIndexByRef(); // stack: [ref index] - LoadIndex(); // stack: [ref index, index] - Il.Ldc_I4(2); // stack: [ref index, index, 2] - Il.Add(); // stack: [ref index, index + 2] - Il.Stind(typeof(int)); // index = index + 2 - } - - /// - /// Increases index by 4 - /// - public void IncreaseIndexBy4() - { - LoadIndexByRef(); // stack: [ref index] - LoadIndex(); // stack: [ref index, index] - Il.Ldc_I4(4); // stack: [ref index, index, 4] - Il.Add(); // stack: [ref index, index + 4] - Il.Stind(typeof(int)); // index = index + 4 - } - - /// - /// Increases index by 8 - /// - public void IncreaseIndexBy8() - { - LoadIndexByRef(); // stack: [ref index] - LoadIndex(); // stack: [ref index, index] - Il.Ldc_I4(8); // stack: [ref index, index, 8] - Il.Add(); // stack: [ref index, index + 8] - Il.Stind(typeof(int)); // index = index + 8 - } - - /// - /// Loads &data[index] onto the evaluation stack - /// - public void GoToCurrentLocation() - { - LoadData(); // stack: [pinnedData] - LoadIndex(); // stack: [pinnedData, index] - Il.Add(); // stack: [pinnedData + index] - } - - /// - /// Asserts that the specified number of bytes can be read from data starting at index - /// - /// The number of bytes must be pushed onto the evaluation stack - /// - public void AssertLength() - { - LoadIndex(); // stack: [length, index] - Il.Add(); // stack: [length + index] - LoadDataLength(); // stack: [length + index, dataLength] - var bigEnoughLabel = Il.DefineLabel("bigEnough"); - Il.Ble(bigEnoughLabel, true); - Il.Ldstr("Unexpected end of data"); - var constructor = typeof(DataCorruptedException).GetConstructor(new[] {typeof(string)}); - if(constructor == null) - throw new MissingConstructorException(typeof(DataCorruptedException), typeof(string)); - Il.Newobj(constructor); - Il.Throw(); - Il.MarkLabel(bigEnoughLabel); - } - - /// - /// Checks TypeCode and throws Exception if it is invalid - /// - public void CheckTypeCode() - { - LoadField(Context.Lengths); - Il.Ldloc(TypeCode); // stack: [lengths, typeCode] - Il.Ldelem(typeof(int)); // stack: [lengths[typeCode]] - var okLabel = Il.DefineLabel("ok"); - Il.Brtrue(okLabel); // if(lengths[typeCode] != 0) goto ok; - Il.Ldstr("Unknown type code: "); - Il.Ldloca(TypeCode); - Il.Call(HackHelpers.GetMethodDefinition(x => x.ToString()), typeof(int)); - Il.Call(HackHelpers.GetMethodDefinition(s => s + "zzz")); - var constructor = typeof(DataCorruptedException).GetConstructor(new[] {typeof(string)}); - if(constructor == null) - throw new MissingConstructorException(typeof(DataCorruptedException), typeof(string)); - Il.Newobj(constructor); - Il.Throw(); - Il.MarkLabel(okLabel); - } - - public void SkipValue() - { - LoadIndexByRef(); // stack: [ref index] - LoadIndex(); // stack: [ref index, index] - - // todo: switch - Il.Ldloc(TypeCode); // stack: [ref index, index, TypeCode] - Il.Ldc_I4((int)GroBufTypeCode.DateTimeOld); // stack: [ref index, index, TypeCode, GroBufTypeCode.DateTimeOld] - var notDateTimeLabel = Il.DefineLabel("notDateTime"); - Il.Bne_Un(notDateTimeLabel); // if(TypeCode != GroBufTypeCode.DateTimeOld) goto notDateTime; stack: [ref index, index] - Il.Ldc_I4(8); // stack: [ref index, index, 8] - AssertLength(); - GoToCurrentLocation(); // stack: [ref index, index, &data[index]] - Il.Ldc_I4(4); - Il.Add(); - Il.Ldind(typeof(int)); // stack: [ref index, index, (int)(&data[index])] - Il.Ldc_I4(31); // stack: [ref index, index, (int)&data[index], 31] - Il.Shr(true); // stack: [ref index, index, (int)&data[index] >> 31] - Il.Ldc_I4(8); // stack: [ref index, index, (int)&data[index] >> 31, 8] - Il.Add(); // stack: [ref index, index, (int)&data[index] >> 31 + 8] - var increaseLabel = Il.DefineLabel("increase"); - Il.Br(increaseLabel); - - Il.MarkLabel(notDateTimeLabel); - LoadField(Context.Lengths); - - Il.Ldloc(TypeCode); // stack: [ref index, index, lengths, typeCode] - Il.Ldelem(typeof(int)); // stack: [ref index, index, lengths[typeCode]] - Il.Dup(); // stack: [ref index, index, lengths[typeCode], lengths[typeCode]] - Il.Ldc_I4(-1); // stack: [ref index, index, lengths[typeCode], lengths[typeCode], -1] - Il.Bne_Un(increaseLabel); // if(lengths[typeCode] != -1) goto increase; - - Il.Ldc_I4(4); - AssertLength(); - Il.Pop(); // stack: [ref index, index] - Il.Dup(); // stack: [ref index, index, index] - LoadData(); // stack: [ref index, index, index, pinnedData] - Il.Add(); // stack: [ref index, index, index + pinnedData] - Il.Ldind(typeof(uint)); // stack: [ref index, index, *(uint*)(pinnedData + index)] - Il.Ldc_I4(4); // stack: [ref index, index, *(uint*)(pinnedData + index), 4] - Il.Add(); // stack: [ref index, *(uint*)(pinnedData + index) + 4] - - Il.MarkLabel(increaseLabel); - Il.Dup(); // stack: [ref index, length, length] - AssertLength(); // stack: [ref index, length] - Il.Add(); // stack: [ref index, index + length] - Il.Stind(typeof(int)); // index = index + length - } - - public void AssertTypeCode(GroBufTypeCode expectedTypeCode) - { - Il.Ldloc(TypeCode); // stack: [typeCode] - Il.Ldc_I4((int)expectedTypeCode); // stack: [typeCode, expectedTypeCode] - - var okLabel = Il.DefineLabel("ok"); - Il.Beq(okLabel); - - SkipValue(); - Il.Ret(); - - Il.MarkLabel(okLabel); - } - - public static void LoadReader(GroboIL il, Type type, ReaderTypeBuilderContext context) - { - var counter = context.GetReader(type); - if (counter.Pointer != IntPtr.Zero) - il.Ldc_IntPtr(counter.Pointer); - else - { - il.Ldfld(context.ConstantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic)); - il.Ldc_I4(counter.Index); - il.Ldelem(typeof(IntPtr)); - } - } - - public static void CallReader(GroboIL il, Type type, ReaderTypeBuilderContext context) - { - LoadReader(il, type, context); - il.Calli(CallingConventions.Standard, typeof(void), new[] {typeof(IntPtr), typeof(int).MakeByRefType(), type.MakeByRefType(), typeof(ReaderContext)}); - } - - public void CallReader(Type type) - { - CallReader(Il, type, Context); - } - - public void LoadReader(Type type) - { - LoadReader(Il, type, Context); - } - - public void StoreObject(Type type) - { - if(Index == null) return; - if(type.IsValueType) - throw new InvalidOperationException("A reference type expected"); - // Store in array of all references - LoadContext(); // stack: [context] - Il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] - var doneLabel = Il.DefineLabel("done"); - Il.Brfalse(doneLabel); // if(context.objects == null) goto done; stack: [] - - LoadContext(); // stack: [context] - Il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] - Il.Ldloc(Index); // stack: [context.objects, index] - LoadResult(type); // stack: [context.objects, index, result] - Il.Call(HackHelpers.GetMethodDefinition>(dict => dict.Add(0, null))); // context.objects.Add(index, result) - Il.MarkLabel(doneLabel); - } - - public ReaderTypeBuilderContext Context { get; private set; } - public GroboIL Il { get; private set; } - - public GroboIL.Local TypeCode { get; private set; } - public GroboIL.Local Length { get; private set; } - public GroboIL.Local Index { get; private set; } - } +using System; +using System.Collections.Generic; +using System.Reflection; + +using GrEmit; +using GrEmit.Utils; + +namespace GroBuf.Readers +{ + internal class ReaderMethodBuilderContext + { + public ReaderMethodBuilderContext(ReaderTypeBuilderContext context, GroboIL il, bool referenceType) + { + Context = context; + Il = il; + TypeCode = il.DeclareLocal(typeof(int)); + Length = il.DeclareLocal(typeof(uint)); + Index = referenceType ? il.DeclareLocal(typeof(int)) : null; + } + + /// + /// Loads pinnedData onto the evaluation stack + /// + public void LoadData() + { + Il.Ldarg(0); + } + + /// + /// Loads ref index onto the evaluation stack + /// + public void LoadIndexByRef() + { + Il.Ldarg(1); + } + + /// + /// Loads index onto the evaluation stack + /// + public void LoadIndex() + { + Il.Ldarg(1); + Il.Ldind(typeof(int)); + } + + /// + /// Loads context onto the evaluation stack + /// + public void LoadContext() + { + Il.Ldarg(3); + } + + /// + /// Loads dataLength onto the evaluation stack + /// + public void LoadDataLength() + { + LoadContext(); + Il.Ldfld(ReaderContext.LengthField); + } + + /// + /// Loads context.serializerId onto the evaluation stack + /// + public void LoadSerializerId() + { + LoadContext(); + Il.Ldfld(ReaderContext.SerializerIdField); + } + + /// + /// Loads ref result onto the evaluation stack + /// + public void LoadResultByRef() + { + Il.Ldarg(2); + } + + /// + /// Loads result onto the evaluation stack + /// + public void LoadResult(Type resultType) + { + Il.Ldarg(2); + Il.Ldind(resultType); + } + + /// + /// Loads the specified field onto the evaluation stack + /// + /// Field to load + public void LoadField(FieldInfo field) + { + Il.Ldfld(field); + } + + /// + /// Increases index by 1 + /// + public void IncreaseIndexBy1() + { + LoadIndexByRef(); // stack: [ref index] + LoadIndex(); // stack: [ref index, index] + Il.Ldc_I4(1); // stack: [ref index, index, 1] + Il.Add(); // stack: [ref index, index + 1] + Il.Stind(typeof(int)); // index = index + 1 + } + + /// + /// Increases index by 2 + /// + public void IncreaseIndexBy2() + { + LoadIndexByRef(); // stack: [ref index] + LoadIndex(); // stack: [ref index, index] + Il.Ldc_I4(2); // stack: [ref index, index, 2] + Il.Add(); // stack: [ref index, index + 2] + Il.Stind(typeof(int)); // index = index + 2 + } + + /// + /// Increases index by 4 + /// + public void IncreaseIndexBy4() + { + LoadIndexByRef(); // stack: [ref index] + LoadIndex(); // stack: [ref index, index] + Il.Ldc_I4(4); // stack: [ref index, index, 4] + Il.Add(); // stack: [ref index, index + 4] + Il.Stind(typeof(int)); // index = index + 4 + } + + /// + /// Increases index by 8 + /// + public void IncreaseIndexBy8() + { + LoadIndexByRef(); // stack: [ref index] + LoadIndex(); // stack: [ref index, index] + Il.Ldc_I4(8); // stack: [ref index, index, 8] + Il.Add(); // stack: [ref index, index + 8] + Il.Stind(typeof(int)); // index = index + 8 + } + + /// + /// Loads &data[index] onto the evaluation stack + /// + public void GoToCurrentLocation() + { + LoadData(); // stack: [pinnedData] + LoadIndex(); // stack: [pinnedData, index] + Il.Add(); // stack: [pinnedData + index] + } + + /// + /// Asserts that the specified number of bytes can be read from data starting at index + /// + /// The number of bytes must be pushed onto the evaluation stack + /// + public void AssertLength() + { + LoadIndex(); // stack: [length, index] + Il.Add(); // stack: [length + index] + LoadDataLength(); // stack: [length + index, dataLength] + var bigEnoughLabel = Il.DefineLabel("bigEnough"); + Il.Ble(bigEnoughLabel, true); + Il.Ldstr("Unexpected end of data"); + var constructor = typeof(DataCorruptedException).GetConstructor(new[] {typeof(string)}); + if(constructor == null) + throw new MissingConstructorException(typeof(DataCorruptedException), typeof(string)); + Il.Newobj(constructor); + Il.Throw(); + Il.MarkLabel(bigEnoughLabel); + } + + /// + /// Checks TypeCode and throws Exception if it is invalid + /// + public void CheckTypeCode() + { + LoadField(Context.Lengths); + Il.Ldloc(TypeCode); // stack: [lengths, typeCode] + Il.Ldelem(typeof(int)); // stack: [lengths[typeCode]] + var okLabel = Il.DefineLabel("ok"); + Il.Brtrue(okLabel); // if(lengths[typeCode] != 0) goto ok; + Il.Ldstr("Unknown type code: "); + Il.Ldloca(TypeCode); + Il.Call(HackHelpers.GetMethodDefinition(x => x.ToString()), typeof(int)); + Il.Call(HackHelpers.GetMethodDefinition(s => s + "zzz")); + var constructor = typeof(DataCorruptedException).GetConstructor(new[] {typeof(string)}); + if(constructor == null) + throw new MissingConstructorException(typeof(DataCorruptedException), typeof(string)); + Il.Newobj(constructor); + Il.Throw(); + Il.MarkLabel(okLabel); + } + + public void SkipValue() + { + LoadIndexByRef(); // stack: [ref index] + LoadIndex(); // stack: [ref index, index] + + // todo: switch + Il.Ldloc(TypeCode); // stack: [ref index, index, TypeCode] + Il.Ldc_I4((int)GroBufTypeCode.DateTimeOld); // stack: [ref index, index, TypeCode, GroBufTypeCode.DateTimeOld] + var notDateTimeLabel = Il.DefineLabel("notDateTime"); + Il.Bne_Un(notDateTimeLabel); // if(TypeCode != GroBufTypeCode.DateTimeOld) goto notDateTime; stack: [ref index, index] + Il.Ldc_I4(8); // stack: [ref index, index, 8] + AssertLength(); + GoToCurrentLocation(); // stack: [ref index, index, &data[index]] + Il.Ldc_I4(4); + Il.Add(); + Il.Ldind(typeof(int)); // stack: [ref index, index, (int)(&data[index])] + Il.Ldc_I4(31); // stack: [ref index, index, (int)&data[index], 31] + Il.Shr(true); // stack: [ref index, index, (int)&data[index] >> 31] + Il.Ldc_I4(8); // stack: [ref index, index, (int)&data[index] >> 31, 8] + Il.Add(); // stack: [ref index, index, (int)&data[index] >> 31 + 8] + var increaseLabel = Il.DefineLabel("increase"); + Il.Br(increaseLabel); + + Il.MarkLabel(notDateTimeLabel); + LoadField(Context.Lengths); + + Il.Ldloc(TypeCode); // stack: [ref index, index, lengths, typeCode] + Il.Ldelem(typeof(int)); // stack: [ref index, index, lengths[typeCode]] + Il.Dup(); // stack: [ref index, index, lengths[typeCode], lengths[typeCode]] + Il.Ldc_I4(-1); // stack: [ref index, index, lengths[typeCode], lengths[typeCode], -1] + Il.Bne_Un(increaseLabel); // if(lengths[typeCode] != -1) goto increase; + + Il.Ldc_I4(4); + AssertLength(); + Il.Pop(); // stack: [ref index, index] + Il.Dup(); // stack: [ref index, index, index] + LoadData(); // stack: [ref index, index, index, pinnedData] + Il.Add(); // stack: [ref index, index, index + pinnedData] + Il.Ldind(typeof(uint)); // stack: [ref index, index, *(uint*)(pinnedData + index)] + Il.Ldc_I4(4); // stack: [ref index, index, *(uint*)(pinnedData + index), 4] + Il.Add(); // stack: [ref index, *(uint*)(pinnedData + index) + 4] + + Il.MarkLabel(increaseLabel); + Il.Dup(); // stack: [ref index, length, length] + AssertLength(); // stack: [ref index, length] + Il.Add(); // stack: [ref index, index + length] + Il.Stind(typeof(int)); // index = index + length + } + + public void AssertTypeCode(GroBufTypeCode expectedTypeCode) + { + Il.Ldloc(TypeCode); // stack: [typeCode] + Il.Ldc_I4((int)expectedTypeCode); // stack: [typeCode, expectedTypeCode] + + var okLabel = Il.DefineLabel("ok"); + Il.Beq(okLabel); + + SkipValue(); + Il.Ret(); + + Il.MarkLabel(okLabel); + } + + public static void LoadReader(GroboIL il, Type type, ReaderTypeBuilderContext context) + { + var counter = context.GetReader(type); + if (counter.Pointer != IntPtr.Zero) + il.Ldc_IntPtr(counter.Pointer); + else + { + il.Ldfld(context.ConstantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic)); + il.Ldc_I4(counter.Index); + il.Ldelem(typeof(IntPtr)); + } + } + + public static void CallReader(GroboIL il, Type type, ReaderTypeBuilderContext context) + { + LoadReader(il, type, context); + il.Calli(CallingConventions.Standard, typeof(void), new[] {typeof(IntPtr), typeof(int).MakeByRefType(), type.MakeByRefType(), typeof(ReaderContext)}); + } + + public void CallReader(Type type) + { + CallReader(Il, type, Context); + } + + public void LoadReader(Type type) + { + LoadReader(Il, type, Context); + } + + public void StoreObject(Type type) + { + if(Index == null) return; + if(type.IsValueType) + throw new InvalidOperationException("A reference type expected"); + // Store in array of all references + LoadContext(); // stack: [context] + Il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] + var doneLabel = Il.DefineLabel("done"); + Il.Brfalse(doneLabel); // if(context.objects == null) goto done; stack: [] + + LoadContext(); // stack: [context] + Il.Ldfld(ReaderContext.ObjectsField); // stack: [context.objects] + Il.Ldloc(Index); // stack: [context.objects, index] + LoadResult(type); // stack: [context.objects, index, result] + Il.Call(HackHelpers.GetMethodDefinition>(dict => dict.Add(0, null))); // context.objects.Add(index, result) + Il.MarkLabel(doneLabel); + } + + public ReaderTypeBuilderContext Context { get; private set; } + public GroboIL Il { get; private set; } + + public GroboIL.Local TypeCode { get; private set; } + public GroboIL.Local Length { get; private set; } + public GroboIL.Local Index { get; private set; } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/ReaderTypeBuilder.cs b/GroBuf/Readers/ReaderTypeBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/ReaderTypeBuilder.cs rename to GroBuf/Readers/ReaderTypeBuilder.cs index 4f41964..6c90431 100644 --- a/GroBuf/GroBuf/Readers/ReaderTypeBuilder.cs +++ b/GroBuf/Readers/ReaderTypeBuilder.cs @@ -1,89 +1,89 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -using GroBuf.DataMembersExtracters; - -namespace GroBuf.Readers -{ - internal class ReaderTypeBuilder - { - public ReaderTypeBuilder(GroBufReader groBufReader, ModuleBuilder module, IReaderCollection readerCollection, IDataMembersExtractor dataMembersExtractor) - { - this.groBufReader = groBufReader; - this.module = module; - this.readerCollection = readerCollection; - this.dataMembersExtractor = dataMembersExtractor; - } - - public IntPtr BuildReader(Type type, bool ignoreCustomSerialization) - { - var constantsBuilder = module.DefineType(type.Name + "_GroBufReader_" + Guid.NewGuid(), TypeAttributes.Class | TypeAttributes.Public); - constantsBuilder.DefineField("pointers", typeof(IntPtr[]), FieldAttributes.Private | FieldAttributes.Static); - constantsBuilder.DefineField("delegates", typeof(Delegate[]), FieldAttributes.Private | FieldAttributes.Static); - var constantsBuilderContext = new ReaderConstantsBuilderContext(groBufReader, constantsBuilder, readerCollection, dataMembersExtractor); - constantsBuilderContext.BuildConstants(type, true, ignoreCustomSerialization); - var constantsType = constantsBuilder.CreateType(); - var fields = constantsBuilderContext.GetFields().ToDictionary(pair => pair.Key, pair => pair.Value.Select(constantsType.GetField).ToArray()); - var context = new ReaderTypeBuilderContext(groBufReader, module, constantsType, fields, readerCollection, dataMembersExtractor); - var reader = context.GetReader(type, true, ignoreCustomSerialization); - - var initializer = BuildInitializer(constantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic), constantsType.GetField("delegates", BindingFlags.Static | BindingFlags.NonPublic)); - - var compiledDynamicMethods = context.GetMethods(); - var pointers = new IntPtr[compiledDynamicMethods.Length]; - var delegates = new Delegate[compiledDynamicMethods.Length]; - foreach(var pair in compiledDynamicMethods) - { - var compiledDynamicMethod = pair.Value; - var index = compiledDynamicMethod.Index; - pointers[index] = compiledDynamicMethod.Pointer; - delegates[index] = compiledDynamicMethod.Delegate; - if (compiledDynamicMethod.Pointer != reader.Pointer) - groBufReader.readMethodsWithCustomSerialization[pair.Key] = (IntPtr?)compiledDynamicMethod.Pointer; - } - initializer(pointers, delegates, context.GetFieldInitializers()); - return reader.Pointer; - } - - private Action BuildInitializer(FieldInfo pointersField, FieldInfo delegatesField) - { - var initializer = new DynamicMethod("Init", typeof(void), new[] {typeof(IntPtr[]), typeof(Delegate[]), typeof(Action[])}, module, true); - var il = initializer.GetILGenerator(); - var retLabel = il.DefineLabel(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Stsfld, pointersField); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Stsfld, delegatesField); - il.Emit(OpCodes.Ldarg_2); // stack: [initializers] - il.Emit(OpCodes.Brfalse, retLabel); // if(initializers == null) goto ret; - il.Emit(OpCodes.Ldarg_2); // stack: [initializers] - il.Emit(OpCodes.Ldlen); // stack: [initializers.Length] - il.Emit(OpCodes.Dup); // stack: [initializers.Length, initializers.Length] - var index = il.DeclareLocal(typeof(int)); - il.Emit(OpCodes.Stloc, index); // index = initializers.Length; stack: [initializers.Length] - il.Emit(OpCodes.Brfalse, retLabel); // if(initializers.Length == 0) goto ret; - var cycleStart = il.DefineLabel(); - il.MarkLabel(cycleStart); - il.Emit(OpCodes.Ldarg_2); // stack: [initializers] - il.Emit(OpCodes.Ldloc, index); // stack: [initializers, index] - il.Emit(OpCodes.Ldc_I4_1); // stack: [initializers, index, 1] - il.Emit(OpCodes.Sub); // stack: [initializers, index - 1] - il.Emit(OpCodes.Dup); // stack: [initializers, index - 1, index - 1] - il.Emit(OpCodes.Stloc, index); // index = index - 1; // stack: [initializers, index] - il.Emit(OpCodes.Ldelem_Ref); // stack: [initializers[index]] - il.Emit(OpCodes.Call, typeof(Action).GetMethod("Invoke")); // intializers[index]() - il.Emit(OpCodes.Ldloc, index); - il.Emit(OpCodes.Brtrue, cycleStart); - il.MarkLabel(retLabel); - il.Emit(OpCodes.Ret); - return (Action)initializer.CreateDelegate(typeof(Action)); - } - - private readonly GroBufReader groBufReader; - private readonly ModuleBuilder module; - private readonly IReaderCollection readerCollection; - private readonly IDataMembersExtractor dataMembersExtractor; - } +using System; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; + +using GroBuf.DataMembersExtracters; + +namespace GroBuf.Readers +{ + internal class ReaderTypeBuilder + { + public ReaderTypeBuilder(GroBufReader groBufReader, ModuleBuilder module, IReaderCollection readerCollection, IDataMembersExtractor dataMembersExtractor) + { + this.groBufReader = groBufReader; + this.module = module; + this.readerCollection = readerCollection; + this.dataMembersExtractor = dataMembersExtractor; + } + + public IntPtr BuildReader(Type type, bool ignoreCustomSerialization) + { + var constantsBuilder = module.DefineType(type.Name + "_GroBufReader_" + Guid.NewGuid(), TypeAttributes.Class | TypeAttributes.Public); + constantsBuilder.DefineField("pointers", typeof(IntPtr[]), FieldAttributes.Private | FieldAttributes.Static); + constantsBuilder.DefineField("delegates", typeof(Delegate[]), FieldAttributes.Private | FieldAttributes.Static); + var constantsBuilderContext = new ReaderConstantsBuilderContext(groBufReader, constantsBuilder, readerCollection, dataMembersExtractor); + constantsBuilderContext.BuildConstants(type, true, ignoreCustomSerialization); + var constantsType = constantsBuilder.CreateTypeInfo(); + var fields = constantsBuilderContext.GetFields().ToDictionary(pair => pair.Key, pair => pair.Value.Select(constantsType.GetField).ToArray()); + var context = new ReaderTypeBuilderContext(groBufReader, module, constantsType, fields, readerCollection, dataMembersExtractor); + var reader = context.GetReader(type, true, ignoreCustomSerialization); + + var initializer = BuildInitializer(constantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic), constantsType.GetField("delegates", BindingFlags.Static | BindingFlags.NonPublic)); + + var compiledDynamicMethods = context.GetMethods(); + var pointers = new IntPtr[compiledDynamicMethods.Length]; + var delegates = new Delegate[compiledDynamicMethods.Length]; + foreach(var pair in compiledDynamicMethods) + { + var compiledDynamicMethod = pair.Value; + var index = compiledDynamicMethod.Index; + pointers[index] = compiledDynamicMethod.Pointer; + delegates[index] = compiledDynamicMethod.Delegate; + if (compiledDynamicMethod.Pointer != reader.Pointer) + groBufReader.readMethodsWithCustomSerialization[pair.Key] = (IntPtr?)compiledDynamicMethod.Pointer; + } + initializer(pointers, delegates, context.GetFieldInitializers()); + return reader.Pointer; + } + + private Action BuildInitializer(FieldInfo pointersField, FieldInfo delegatesField) + { + var initializer = new DynamicMethod("Init", typeof(void), new[] {typeof(IntPtr[]), typeof(Delegate[]), typeof(Action[])}, module, true); + var il = initializer.GetILGenerator(); + var retLabel = il.DefineLabel(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Stsfld, pointersField); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Stsfld, delegatesField); + il.Emit(OpCodes.Ldarg_2); // stack: [initializers] + il.Emit(OpCodes.Brfalse, retLabel); // if(initializers == null) goto ret; + il.Emit(OpCodes.Ldarg_2); // stack: [initializers] + il.Emit(OpCodes.Ldlen); // stack: [initializers.Length] + il.Emit(OpCodes.Dup); // stack: [initializers.Length, initializers.Length] + var index = il.DeclareLocal(typeof(int)); + il.Emit(OpCodes.Stloc, index); // index = initializers.Length; stack: [initializers.Length] + il.Emit(OpCodes.Brfalse, retLabel); // if(initializers.Length == 0) goto ret; + var cycleStart = il.DefineLabel(); + il.MarkLabel(cycleStart); + il.Emit(OpCodes.Ldarg_2); // stack: [initializers] + il.Emit(OpCodes.Ldloc, index); // stack: [initializers, index] + il.Emit(OpCodes.Ldc_I4_1); // stack: [initializers, index, 1] + il.Emit(OpCodes.Sub); // stack: [initializers, index - 1] + il.Emit(OpCodes.Dup); // stack: [initializers, index - 1, index - 1] + il.Emit(OpCodes.Stloc, index); // index = index - 1; // stack: [initializers, index] + il.Emit(OpCodes.Ldelem_Ref); // stack: [initializers[index]] + il.Emit(OpCodes.Call, typeof(Action).GetMethod("Invoke")); // intializers[index]() + il.Emit(OpCodes.Ldloc, index); + il.Emit(OpCodes.Brtrue, cycleStart); + il.MarkLabel(retLabel); + il.Emit(OpCodes.Ret); + return (Action)initializer.CreateDelegate(typeof(Action)); + } + + private readonly GroBufReader groBufReader; + private readonly ModuleBuilder module; + private readonly IReaderCollection readerCollection; + private readonly IDataMembersExtractor dataMembersExtractor; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/ReaderTypeBuilderContext.cs b/GroBuf/Readers/ReaderTypeBuilderContext.cs similarity index 97% rename from GroBuf/GroBuf/Readers/ReaderTypeBuilderContext.cs rename to GroBuf/Readers/ReaderTypeBuilderContext.cs index d62c307..be343d2 100644 --- a/GroBuf/GroBuf/Readers/ReaderTypeBuilderContext.cs +++ b/GroBuf/Readers/ReaderTypeBuilderContext.cs @@ -1,109 +1,109 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -using GrEmit; - -using GroBuf.DataMembersExtracters; - -namespace GroBuf.Readers -{ - internal class ReaderTypeBuilderContext - { - public ReaderTypeBuilderContext(GroBufReader groBufReader, ModuleBuilder module, Type constantsType, Dictionary fields, IReaderCollection readerCollection, IDataMembersExtractor dataMembersExtractor) - { - GroBufReader = groBufReader; - Module = module; - ConstantsType = constantsType; - this.fields = fields; - this.readerCollection = readerCollection; - this.dataMembersExtractor = dataMembersExtractor; - Lengths = typeof(GroBufHelpers).GetField("Lengths", BindingFlags.Static | BindingFlags.Public); - } - - public IDataMember[] GetDataMembers(Type type) - { - return dataMembersExtractor.GetMembers(type); - } - - public FieldInfo InitConstField(Type type, int index, T value) - { - var field = fields[type][index]; - initializers.Add(field.Name, ((Func)(f => BuildFieldInitializer(f, value)))(field)); - return field; - } - - public Action[] GetFieldInitializers() - { - return (from object value in initializers.Values select ((Action)value)).ToArray(); - } - - public KeyValuePair[] GetMethods() - { - return readers.Cast().Select(entry => new KeyValuePair((Type)entry.Key, (CompiledDynamicMethod)entry.Value)).ToArray(); - } - - public void SetReaderMethod(Type type, DynamicMethod method) - { - if(readers[type] != null) - throw new InvalidOperationException(); - readers[type] = new CompiledDynamicMethod {Method = method, Index = readers.Count}; - } - - public void SetReaderPointer(Type type, IntPtr readerPointer, Delegate reader) - { - if(readers[type] == null) - throw new InvalidOperationException(); - var compiledDynamicMethod = (CompiledDynamicMethod)readers[type]; - compiledDynamicMethod.Pointer = readerPointer; - compiledDynamicMethod.Delegate = reader; - } - - public CompiledDynamicMethod GetReader(Type type, bool isRoot = false, bool ignoreCustomSerialization = false) - { - var reader = (CompiledDynamicMethod)readers[type]; - if(reader == null) - { - if (!isRoot) - { - var pointer = (IntPtr?)GroBufReader.readMethodsWithCustomSerialization[type]; - if (pointer != null) - return new CompiledDynamicMethod { Pointer = pointer.Value }; - } - readerCollection.GetReaderBuilder(type, ignoreCustomSerialization).BuildReader(this); - reader = (CompiledDynamicMethod)readers[type]; - if(reader == null) - throw new InvalidOperationException(); - } - return reader; - } - - public GroBufReader GroBufReader { get; private set; } - public ModuleBuilder Module { get; private set; } - public Type ConstantsType { get; private set; } - public FieldInfo Lengths { get; private set; } - - private Action BuildFieldInitializer(FieldInfo field, T value) - { - var method = new DynamicMethod(field.Name + "_Init_" + Guid.NewGuid(), typeof(void), new[] {typeof(T)}, Module); - using(var il = new GroboIL(method)) - { - il.Ldarg(0); - il.Stfld(field); - il.Ret(); - } - var action = (Action)method.CreateDelegate(typeof(Action)); - return () => action(value); - } - - private readonly Dictionary fields; - private readonly IReaderCollection readerCollection; - private readonly IDataMembersExtractor dataMembersExtractor; - - private readonly Hashtable readers = new Hashtable(); - private readonly Hashtable initializers = new Hashtable(); - } +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; + +using GrEmit; + +using GroBuf.DataMembersExtracters; + +namespace GroBuf.Readers +{ + internal class ReaderTypeBuilderContext + { + public ReaderTypeBuilderContext(GroBufReader groBufReader, ModuleBuilder module, Type constantsType, Dictionary fields, IReaderCollection readerCollection, IDataMembersExtractor dataMembersExtractor) + { + GroBufReader = groBufReader; + Module = module; + ConstantsType = constantsType; + this.fields = fields; + this.readerCollection = readerCollection; + this.dataMembersExtractor = dataMembersExtractor; + Lengths = typeof(GroBufHelpers).GetField("Lengths", BindingFlags.Static | BindingFlags.Public); + } + + public IDataMember[] GetDataMembers(Type type) + { + return dataMembersExtractor.GetMembers(type); + } + + public FieldInfo InitConstField(Type type, int index, T value) + { + var field = fields[type][index]; + initializers.Add(field.Name, ((Func)(f => BuildFieldInitializer(f, value)))(field)); + return field; + } + + public Action[] GetFieldInitializers() + { + return (from object value in initializers.Values select ((Action)value)).ToArray(); + } + + public KeyValuePair[] GetMethods() + { + return readers.Cast().Select(entry => new KeyValuePair((Type)entry.Key, (CompiledDynamicMethod)entry.Value)).ToArray(); + } + + public void SetReaderMethod(Type type, DynamicMethod method) + { + if(readers[type] != null) + throw new InvalidOperationException(); + readers[type] = new CompiledDynamicMethod {Method = method, Index = readers.Count}; + } + + public void SetReaderPointer(Type type, IntPtr readerPointer, Delegate reader) + { + if(readers[type] == null) + throw new InvalidOperationException(); + var compiledDynamicMethod = (CompiledDynamicMethod)readers[type]; + compiledDynamicMethod.Pointer = readerPointer; + compiledDynamicMethod.Delegate = reader; + } + + public CompiledDynamicMethod GetReader(Type type, bool isRoot = false, bool ignoreCustomSerialization = false) + { + var reader = (CompiledDynamicMethod)readers[type]; + if(reader == null) + { + if (!isRoot) + { + var pointer = (IntPtr?)GroBufReader.readMethodsWithCustomSerialization[type]; + if (pointer != null) + return new CompiledDynamicMethod { Pointer = pointer.Value }; + } + readerCollection.GetReaderBuilder(type, ignoreCustomSerialization).BuildReader(this); + reader = (CompiledDynamicMethod)readers[type]; + if(reader == null) + throw new InvalidOperationException(); + } + return reader; + } + + public GroBufReader GroBufReader { get; private set; } + public ModuleBuilder Module { get; private set; } + public Type ConstantsType { get; private set; } + public FieldInfo Lengths { get; private set; } + + private Action BuildFieldInitializer(FieldInfo field, T value) + { + var method = new DynamicMethod(field.Name + "_Init_" + Guid.NewGuid(), typeof(void), new[] {typeof(T)}, Module); + using(var il = new GroboIL(method)) + { + il.Ldarg(0); + il.Stfld(field); + il.Ret(); + } + var action = (Action)method.CreateDelegate(typeof(Action)); + return () => action(value); + } + + private readonly Dictionary fields; + private readonly IReaderCollection readerCollection; + private readonly IDataMembersExtractor dataMembersExtractor; + + private readonly Hashtable readers = new Hashtable(); + private readonly Hashtable initializers = new Hashtable(); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/StringReaderBuilder.cs b/GroBuf/Readers/StringReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/StringReaderBuilder.cs rename to GroBuf/Readers/StringReaderBuilder.cs index 7b1e47c..5b39ff9 100644 --- a/GroBuf/GroBuf/Readers/StringReaderBuilder.cs +++ b/GroBuf/Readers/StringReaderBuilder.cs @@ -1,66 +1,66 @@ -namespace GroBuf.Readers -{ - internal class StringReaderBuilder : ReaderBuilderBase - { - public StringReaderBuilder() - : base(typeof(string)) - { - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - context.IncreaseIndexBy1(); // Skip typeCode - context.AssertTypeCode(GroBufTypeCode.String); // Assert typeCode == TypeCode.String - - var il = context.Il; - il.Ldc_I4(4); - context.AssertLength(); - - var length = context.Length; - - context.GoToCurrentLocation(); // stack: [&data[index]] - il.Ldind(typeof(uint)); // stack: [(uint)data[index]] - il.Dup(); // stack: [(uint)data[index], (uint)data[index]] - il.Stloc(length); // length = (uint)data[index]; stack: [length] - context.IncreaseIndexBy4(); // index = index + 4; stack: [length] - - var stringIsEmptyLabel = il.DefineLabel("stringIsEmpty"); - il.Brfalse(stringIsEmptyLabel); - - il.Ldloc(length); // stack: [length] - context.AssertLength(); - - context.LoadResultByRef(); // stack: [ref result] - context.GoToCurrentLocation(); // stack: [ref result, &data[index]] - il.Ldc_I4(0); // stack: [ref result, &data[index], 0] - il.Ldloc(length); // stack: [ref result, &data[index], 0, length] - il.Ldc_I4(1); // stack: [ref result, &data[index], 0, length, 1] - il.Shr(true); // stack: [ref result, &data[index], 0, length >> 1] - var constructor = Type.GetConstructor(new[] {typeof(char*), typeof(int), typeof(int)}); - if(constructor == null) - throw new MissingConstructorException(Type, typeof(char*), typeof(int), typeof(int)); - il.Newobj(constructor); // stack: [ref result, new string(&data[index], 0, length >> 1)] - il.Stind(typeof(string)); // result = new string(&data[index], 0, length >> 1); stack: [] - - context.StoreObject(Type); - - context.LoadIndexByRef(); // stack: [ref index] - context.LoadIndex(); // stack: [ref index, index] - il.Ldloc(length); // stack: [ref index, index, length] - il.Add(); // stack: [ref index, index + length] - il.Stind(typeof(int)); // index = index + length; stack: [] - il.Ret(); - - il.MarkLabel(stringIsEmptyLabel); - context.LoadResultByRef(); // stack: [ref result] - il.Ldstr(""); // stack: [ref result, ""] - il.Stind(typeof(string)); // result = ""; stack: [] - } - - protected override bool IsReference { get { return true; } } - } +namespace GroBuf.Readers +{ + internal class StringReaderBuilder : ReaderBuilderBase + { + public StringReaderBuilder() + : base(typeof(string)) + { + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + context.IncreaseIndexBy1(); // Skip typeCode + context.AssertTypeCode(GroBufTypeCode.String); // Assert typeCode == TypeCode.String + + var il = context.Il; + il.Ldc_I4(4); + context.AssertLength(); + + var length = context.Length; + + context.GoToCurrentLocation(); // stack: [&data[index]] + il.Ldind(typeof(uint)); // stack: [(uint)data[index]] + il.Dup(); // stack: [(uint)data[index], (uint)data[index]] + il.Stloc(length); // length = (uint)data[index]; stack: [length] + context.IncreaseIndexBy4(); // index = index + 4; stack: [length] + + var stringIsEmptyLabel = il.DefineLabel("stringIsEmpty"); + il.Brfalse(stringIsEmptyLabel); + + il.Ldloc(length); // stack: [length] + context.AssertLength(); + + context.LoadResultByRef(); // stack: [ref result] + context.GoToCurrentLocation(); // stack: [ref result, &data[index]] + il.Ldc_I4(0); // stack: [ref result, &data[index], 0] + il.Ldloc(length); // stack: [ref result, &data[index], 0, length] + il.Ldc_I4(1); // stack: [ref result, &data[index], 0, length, 1] + il.Shr(true); // stack: [ref result, &data[index], 0, length >> 1] + var constructor = Type.GetConstructor(new[] {typeof(char*), typeof(int), typeof(int)}); + if(constructor == null) + throw new MissingConstructorException(Type, typeof(char*), typeof(int), typeof(int)); + il.Newobj(constructor); // stack: [ref result, new string(&data[index], 0, length >> 1)] + il.Stind(typeof(string)); // result = new string(&data[index], 0, length >> 1); stack: [] + + context.StoreObject(Type); + + context.LoadIndexByRef(); // stack: [ref index] + context.LoadIndex(); // stack: [ref index, index] + il.Ldloc(length); // stack: [ref index, index, length] + il.Add(); // stack: [ref index, index + length] + il.Stind(typeof(int)); // index = index + length; stack: [] + il.Ret(); + + il.MarkLabel(stringIsEmptyLabel); + context.LoadResultByRef(); // stack: [ref result] + il.Ldstr(""); // stack: [ref result, ""] + il.Stind(typeof(string)); // result = ""; stack: [] + } + + protected override bool IsReference { get { return true; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/TimeSpanReaderBuilder.cs b/GroBuf/Readers/TimeSpanReaderBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Readers/TimeSpanReaderBuilder.cs rename to GroBuf/Readers/TimeSpanReaderBuilder.cs index 03a49b1..e7ae331 100644 --- a/GroBuf/GroBuf/Readers/TimeSpanReaderBuilder.cs +++ b/GroBuf/Readers/TimeSpanReaderBuilder.cs @@ -1,38 +1,38 @@ -using System; - -namespace GroBuf.Readers -{ - internal class TimeSpanReaderBuilder : ReaderBuilderBase - { - public TimeSpanReaderBuilder() - : base(typeof(TimeSpan)) - { - } - - protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) - { - context.BuildConstants(typeof(long)); - } - - protected override void ReadNotEmpty(ReaderMethodBuilderContext context) - { - var il = context.Il; - context.LoadResultByRef(); // stack: [ref result] - - context.LoadData(); // stack: [ref result, data] - context.LoadIndexByRef(); // stack: [ref result, data, ref index] - var ticks = il.DeclareLocal(typeof(long)); - il.Ldloca(ticks); // stack: [ref result, data, ref index, ref value] - context.LoadContext(); // stack: [ref result, data, ref index, ref value, context] - context.CallReader(typeof(long)); // reader(pinnedData, ref index, ref value, context); stack: [ref result] - il.Ldloc(ticks); // stack: [ref result, value] - var constructor = Type.GetConstructor(new[] {typeof(long)}); - if(constructor == null) - throw new MissingConstructorException(Type, typeof(long)); - il.Newobj(constructor); // stack: [ref result, new TimeSpan(ticks)] - il.Stobj(Type); // result = new TimeSpan(ticks) - } - - protected override bool IsReference { get { return false; } } - } +using System; + +namespace GroBuf.Readers +{ + internal class TimeSpanReaderBuilder : ReaderBuilderBase + { + public TimeSpanReaderBuilder() + : base(typeof(TimeSpan)) + { + } + + protected override void BuildConstantsInternal(ReaderConstantsBuilderContext context) + { + context.BuildConstants(typeof(long)); + } + + protected override void ReadNotEmpty(ReaderMethodBuilderContext context) + { + var il = context.Il; + context.LoadResultByRef(); // stack: [ref result] + + context.LoadData(); // stack: [ref result, data] + context.LoadIndexByRef(); // stack: [ref result, data, ref index] + var ticks = il.DeclareLocal(typeof(long)); + il.Ldloca(ticks); // stack: [ref result, data, ref index, ref value] + context.LoadContext(); // stack: [ref result, data, ref index, ref value, context] + context.CallReader(typeof(long)); // reader(pinnedData, ref index, ref value, context); stack: [ref result] + il.Ldloc(ticks); // stack: [ref result, value] + var constructor = Type.GetConstructor(new[] {typeof(long)}); + if(constructor == null) + throw new MissingConstructorException(Type, typeof(long)); + il.Newobj(constructor); // stack: [ref result, new TimeSpan(ticks)] + il.Stobj(Type); // result = new TimeSpan(ticks) + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Readers/TupleReaderBuilder.cs b/GroBuf/Readers/TupleReaderBuilder.cs similarity index 100% rename from GroBuf/GroBuf/Readers/TupleReaderBuilder.cs rename to GroBuf/Readers/TupleReaderBuilder.cs diff --git a/GroBuf/GroBuf/Serializer.cs b/GroBuf/Serializer.cs similarity index 96% rename from GroBuf/GroBuf/Serializer.cs rename to GroBuf/Serializer.cs index 2a4b9ba..ebf4a57 100644 --- a/GroBuf/GroBuf/Serializer.cs +++ b/GroBuf/Serializer.cs @@ -1,210 +1,210 @@ -using System; -using System.Runtime.InteropServices; -using System.Threading; - -using GroBuf.DataMembersExtracters; - -namespace GroBuf -{ - public class Serializer : ISerializer - { - public Serializer(IDataMembersExtractor dataMembersExtractor, IGroBufCustomSerializerCollection customSerializerCollection = null, GroBufOptions options = GroBufOptions.None) - { - customSerializerCollection = customSerializerCollection ?? new DefaultGroBufCustomSerializerCollection(); - Func factory = type => new InternalSerializer(writer, reader, type, false); - Func baseFactory = type => new InternalSerializer(writer, reader, type, true); - var id = Interlocked.Increment(ref serializerId) - 1; - writer = new GroBufWriter(id, dataMembersExtractor, customSerializerCollection, options, factory, baseFactory); - reader = new GroBufReader(id, dataMembersExtractor, customSerializerCollection, options, factory, baseFactory); - if(options.HasFlag(GroBufOptions.WriteEmptyObjects)) - writerWritingEmptyObjects = writer; - else - { - id = Interlocked.Increment(ref serializerId) - 1; - writerWritingEmptyObjects = new GroBufWriter(id, dataMembersExtractor, customSerializerCollection, options | GroBufOptions.WriteEmptyObjects, factory, baseFactory); - } - } - - public int GetSize(T obj) - { - return writer.GetSize(obj); - } - - public void Serialize(T obj, byte[] result, ref int index) - { - writer.Write(obj, result, ref index); - } - - public void Serialize(T obj, IntPtr result, ref int index, int length) - { - writer.Write(obj, result, ref index, length); - } - - public byte[] Serialize(T obj) - { - return writer.Write(obj); - } - - public T Deserialize(byte[] data) - { - return reader.Read(data); - } - - public T Deserialize(byte[] data, ref int index) - { - return reader.Read(data, ref index); - } - - public T Deserialize(byte[] data, int length) - { - return reader.Read(data, length); - } - - public T Deserialize(byte[] data, ref int index, int length) - { - return reader.Read(data, ref index, length); - } - - public T Deserialize(IntPtr data, ref int index, int length) - { - return reader.Read(data, ref index, length); - } - - public int GetSize(Type type, object obj) - { - return writer.GetSize(type, obj); - } - - public void Serialize(Type type, object obj, byte[] result, ref int index) - { - writer.Write(type, obj, result, ref index); - } - - public void Serialize(Type type, object obj, IntPtr result, ref int index, int length) - { - writer.Write(type, obj, result, ref index, length); - } - - public byte[] Serialize(Type type, object obj) - { - return writer.Write(type, obj); - } - - public object Deserialize(Type type, byte[] data) - { - return reader.Read(type, data); - } - - public object Deserialize(Type type, byte[] data, ref int index) - { - return reader.Read(type, data, ref index); - } - - public object Deserialize(Type type, byte[] data, int length) - { - return reader.Read(type, data, length); - } - - public object Deserialize(Type type, byte[] data, ref int index, int length) - { - return reader.Read(type, data, ref index, length); - } - - public object Deserialize(Type type, IntPtr data, ref int index, int length) - { - return reader.Read(type, data, ref index, length); - } - - void ISerializer.Merge(T from, ref T to) - { - ChangeType(from, ref to); - } - - public void Merge(TFrom from, ref TTo to) - { - ChangeType(from, ref to); - } - - public TTo ChangeType(TFrom obj) - { - var result = default(TTo); - ChangeType(obj, ref result); - return result; - } - - public T Copy(T obj) - { - return ChangeType(obj); - } - - public object ChangeType(Type from, Type to, object obj) - { - object result = null; - ChangeType(from, to, obj, ref result); - return result; - } - - public object Copy(Type type, object obj) - { - return ChangeType(type, type, obj); - } - - private void ChangeType(TFrom obj, ref TTo result) - { - var size = writerWritingEmptyObjects.GetSize(obj); - if(size <= 768) - { - var buf = new byte[size]; - var index = 0; - writerWritingEmptyObjects.Write(obj, buf, ref index); - reader.Read(buf, ref result); - } - else - { - var buf = Marshal.AllocHGlobal(size); - try - { - writerWritingEmptyObjects.Write(obj, buf, size); - var index = 0; - reader.Read(buf, ref index, size, ref result); - } - finally - { - Marshal.FreeHGlobal(buf); - } - } - } - - private void ChangeType(Type from, Type to, object obj, ref object result) - { - var size = writerWritingEmptyObjects.GetSize(from, obj); - if(size <= 768) - { - var buf = new byte[size]; - var index = 0; - writerWritingEmptyObjects.Write(from, obj, buf, ref index); - reader.Read(to, buf, ref result); - } - else - { - var buf = Marshal.AllocHGlobal(size); - try - { - writerWritingEmptyObjects.Write(from, obj, buf, size); - var index = 0; - reader.Read(to, buf, ref index, size, ref result); - } - finally - { - Marshal.FreeHGlobal(buf); - } - } - } - - private static long serializerId; - - private readonly GroBufWriter writer; - private readonly GroBufWriter writerWritingEmptyObjects; - private readonly GroBufReader reader; - } +using System; +using System.Runtime.InteropServices; +using System.Threading; + +using GroBuf.DataMembersExtracters; + +namespace GroBuf +{ + public class Serializer : ISerializer + { + public Serializer(IDataMembersExtractor dataMembersExtractor, IGroBufCustomSerializerCollection customSerializerCollection = null, GroBufOptions options = GroBufOptions.None) + { + customSerializerCollection = customSerializerCollection ?? new DefaultGroBufCustomSerializerCollection(); + Func factory = type => new InternalSerializer(writer, reader, type, false); + Func baseFactory = type => new InternalSerializer(writer, reader, type, true); + var id = Interlocked.Increment(ref serializerId) - 1; + writer = new GroBufWriter(id, dataMembersExtractor, customSerializerCollection, options, factory, baseFactory); + reader = new GroBufReader(id, dataMembersExtractor, customSerializerCollection, options, factory, baseFactory); + if(options.HasFlag(GroBufOptions.WriteEmptyObjects)) + writerWritingEmptyObjects = writer; + else + { + id = Interlocked.Increment(ref serializerId) - 1; + writerWritingEmptyObjects = new GroBufWriter(id, dataMembersExtractor, customSerializerCollection, options | GroBufOptions.WriteEmptyObjects, factory, baseFactory); + } + } + + public int GetSize(T obj) + { + return writer.GetSize(obj); + } + + public void Serialize(T obj, byte[] result, ref int index) + { + writer.Write(obj, result, ref index); + } + + public void Serialize(T obj, IntPtr result, ref int index, int length) + { + writer.Write(obj, result, ref index, length); + } + + public byte[] Serialize(T obj) + { + return writer.Write(obj); + } + + public T Deserialize(byte[] data) + { + return reader.Read(data); + } + + public T Deserialize(byte[] data, ref int index) + { + return reader.Read(data, ref index); + } + + public T Deserialize(byte[] data, int length) + { + return reader.Read(data, length); + } + + public T Deserialize(byte[] data, ref int index, int length) + { + return reader.Read(data, ref index, length); + } + + public T Deserialize(IntPtr data, ref int index, int length) + { + return reader.Read(data, ref index, length); + } + + public int GetSize(Type type, object obj) + { + return writer.GetSize(type, obj); + } + + public void Serialize(Type type, object obj, byte[] result, ref int index) + { + writer.Write(type, obj, result, ref index); + } + + public void Serialize(Type type, object obj, IntPtr result, ref int index, int length) + { + writer.Write(type, obj, result, ref index, length); + } + + public byte[] Serialize(Type type, object obj) + { + return writer.Write(type, obj); + } + + public object Deserialize(Type type, byte[] data) + { + return reader.Read(type, data); + } + + public object Deserialize(Type type, byte[] data, ref int index) + { + return reader.Read(type, data, ref index); + } + + public object Deserialize(Type type, byte[] data, int length) + { + return reader.Read(type, data, length); + } + + public object Deserialize(Type type, byte[] data, ref int index, int length) + { + return reader.Read(type, data, ref index, length); + } + + public object Deserialize(Type type, IntPtr data, ref int index, int length) + { + return reader.Read(type, data, ref index, length); + } + + void ISerializer.Merge(T from, ref T to) + { + ChangeType(from, ref to); + } + + public void Merge(TFrom from, ref TTo to) + { + ChangeType(from, ref to); + } + + public TTo ChangeType(TFrom obj) + { + var result = default(TTo); + ChangeType(obj, ref result); + return result; + } + + public T Copy(T obj) + { + return ChangeType(obj); + } + + public object ChangeType(Type from, Type to, object obj) + { + object result = null; + ChangeType(from, to, obj, ref result); + return result; + } + + public object Copy(Type type, object obj) + { + return ChangeType(type, type, obj); + } + + private void ChangeType(TFrom obj, ref TTo result) + { + var size = writerWritingEmptyObjects.GetSize(obj); + if(size <= 768) + { + var buf = new byte[size]; + var index = 0; + writerWritingEmptyObjects.Write(obj, buf, ref index); + reader.Read(buf, ref result); + } + else + { + var buf = Marshal.AllocHGlobal(size); + try + { + writerWritingEmptyObjects.Write(obj, buf, size); + var index = 0; + reader.Read(buf, ref index, size, ref result); + } + finally + { + Marshal.FreeHGlobal(buf); + } + } + } + + private void ChangeType(Type from, Type to, object obj, ref object result) + { + var size = writerWritingEmptyObjects.GetSize(from, obj); + if(size <= 768) + { + var buf = new byte[size]; + var index = 0; + writerWritingEmptyObjects.Write(from, obj, buf, ref index); + reader.Read(to, buf, ref result); + } + else + { + var buf = Marshal.AllocHGlobal(size); + try + { + writerWritingEmptyObjects.Write(from, obj, buf, size); + var index = 0; + reader.Read(to, buf, ref index, size, ref result); + } + finally + { + Marshal.FreeHGlobal(buf); + } + } + } + + private static long serializerId; + + private readonly GroBufWriter writer; + private readonly GroBufWriter writerWritingEmptyObjects; + private readonly GroBufReader reader; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SerializerExtensions.cs b/GroBuf/SerializerExtensions.cs similarity index 98% rename from GroBuf/GroBuf/SerializerExtensions.cs rename to GroBuf/SerializerExtensions.cs index b3c38dc..4e1d61f 100644 --- a/GroBuf/GroBuf/SerializerExtensions.cs +++ b/GroBuf/SerializerExtensions.cs @@ -1,65 +1,65 @@ -namespace GroBuf -{ - public static class SerializerExtensions - { - public static byte[] Serialize(this ISerializer serializer, T1 param1, T2 param2) - { - int size = serializer.GetSize(param1) + serializer.GetSize(param2); - var result = new byte[size]; - int index = 0; - serializer.Serialize(param1, result, ref index); - serializer.Serialize(param2, result, ref index); - return result; - } - - public static byte[] Serialize(this ISerializer serializer, T1 param1, T2 param2, T3 param3) - { - int size = serializer.GetSize(param1) + serializer.GetSize(param2) + serializer.GetSize(param3); - var result = new byte[size]; - int index = 0; - serializer.Serialize(param1, result, ref index); - serializer.Serialize(param2, result, ref index); - serializer.Serialize(param3, result, ref index); - return result; - } - - public static byte[] Serialize(this ISerializer serializer, T1 param1, T2 param2, T3 param3, T4 param4) - { - int size = serializer.GetSize(param1) + serializer.GetSize(param2) + serializer.GetSize(param3) + serializer.GetSize(param4); - var result = new byte[size]; - int index = 0; - serializer.Serialize(param1, result, ref index); - serializer.Serialize(param2, result, ref index); - serializer.Serialize(param3, result, ref index); - serializer.Serialize(param4, result, ref index); - return result; - } - - public static byte[] Serialize(this ISerializer serializer, T1 param1, T2 param2, T3 param3, T4 param4, T5 param5) - { - int size = serializer.GetSize(param1) + serializer.GetSize(param2) + serializer.GetSize(param3) + serializer.GetSize(param4) + serializer.GetSize(param5); - var result = new byte[size]; - int index = 0; - serializer.Serialize(param1, result, ref index); - serializer.Serialize(param2, result, ref index); - serializer.Serialize(param3, result, ref index); - serializer.Serialize(param4, result, ref index); - serializer.Serialize(param5, result, ref index); - return result; - } - - public static byte[] Serialize(this ISerializer serializer, T1 param1, T2 param2, T3 param3, T4 param4, T5 param5, T6 param6) - { - int size = serializer.GetSize(param1) + serializer.GetSize(param2) + serializer.GetSize(param3) + serializer.GetSize(param4) + serializer.GetSize(param5) + serializer.GetSize(param6); - var result = new byte[size]; - int index = 0; - serializer.Serialize(param1, result, ref index); - serializer.Serialize(param2, result, ref index); - serializer.Serialize(param3, result, ref index); - serializer.Serialize(param4, result, ref index); - serializer.Serialize(param5, result, ref index); - serializer.Serialize(param6, result, ref index); - return result; - } - } +namespace GroBuf +{ + public static class SerializerExtensions + { + public static byte[] Serialize(this ISerializer serializer, T1 param1, T2 param2) + { + int size = serializer.GetSize(param1) + serializer.GetSize(param2); + var result = new byte[size]; + int index = 0; + serializer.Serialize(param1, result, ref index); + serializer.Serialize(param2, result, ref index); + return result; + } + + public static byte[] Serialize(this ISerializer serializer, T1 param1, T2 param2, T3 param3) + { + int size = serializer.GetSize(param1) + serializer.GetSize(param2) + serializer.GetSize(param3); + var result = new byte[size]; + int index = 0; + serializer.Serialize(param1, result, ref index); + serializer.Serialize(param2, result, ref index); + serializer.Serialize(param3, result, ref index); + return result; + } + + public static byte[] Serialize(this ISerializer serializer, T1 param1, T2 param2, T3 param3, T4 param4) + { + int size = serializer.GetSize(param1) + serializer.GetSize(param2) + serializer.GetSize(param3) + serializer.GetSize(param4); + var result = new byte[size]; + int index = 0; + serializer.Serialize(param1, result, ref index); + serializer.Serialize(param2, result, ref index); + serializer.Serialize(param3, result, ref index); + serializer.Serialize(param4, result, ref index); + return result; + } + + public static byte[] Serialize(this ISerializer serializer, T1 param1, T2 param2, T3 param3, T4 param4, T5 param5) + { + int size = serializer.GetSize(param1) + serializer.GetSize(param2) + serializer.GetSize(param3) + serializer.GetSize(param4) + serializer.GetSize(param5); + var result = new byte[size]; + int index = 0; + serializer.Serialize(param1, result, ref index); + serializer.Serialize(param2, result, ref index); + serializer.Serialize(param3, result, ref index); + serializer.Serialize(param4, result, ref index); + serializer.Serialize(param5, result, ref index); + return result; + } + + public static byte[] Serialize(this ISerializer serializer, T1 param1, T2 param2, T3 param3, T4 param4, T5 param5, T6 param6) + { + int size = serializer.GetSize(param1) + serializer.GetSize(param2) + serializer.GetSize(param3) + serializer.GetSize(param4) + serializer.GetSize(param5) + serializer.GetSize(param6); + var result = new byte[size]; + int index = 0; + serializer.Serialize(param1, result, ref index); + serializer.Serialize(param2, result, ref index); + serializer.Serialize(param3, result, ref index); + serializer.Serialize(param4, result, ref index); + serializer.Serialize(param5, result, ref index); + serializer.Serialize(param6, result, ref index); + return result; + } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounterDelegate.cs b/GroBuf/SizeCounterDelegate.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounterDelegate.cs rename to GroBuf/SizeCounterDelegate.cs index e6fd8c3..41b35b4 100644 --- a/GroBuf/GroBuf/SizeCounterDelegate.cs +++ b/GroBuf/SizeCounterDelegate.cs @@ -1,6 +1,6 @@ -namespace GroBuf -{ - public delegate int SizeCounterDelegate(T obj, bool writeEmpty, WriterContext context); - - public delegate int SizeCounterDelegate(object obj, bool writeEmpty, WriterContext context); +namespace GroBuf +{ + public delegate int SizeCounterDelegate(T obj, bool writeEmpty, WriterContext context); + + public delegate int SizeCounterDelegate(object obj, bool writeEmpty, WriterContext context); } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/ArraySegmentSizeCounterBuilder.cs b/GroBuf/SizeCounters/ArraySegmentSizeCounterBuilder.cs similarity index 100% rename from GroBuf/GroBuf/SizeCounters/ArraySegmentSizeCounterBuilder.cs rename to GroBuf/SizeCounters/ArraySegmentSizeCounterBuilder.cs diff --git a/GroBuf/GroBuf/SizeCounters/ArraySizeCounterBuilder.cs b/GroBuf/SizeCounters/ArraySizeCounterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/ArraySizeCounterBuilder.cs rename to GroBuf/SizeCounters/ArraySizeCounterBuilder.cs index fdc55de..ef7f11e 100644 --- a/GroBuf/GroBuf/SizeCounters/ArraySizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/ArraySizeCounterBuilder.cs @@ -1,78 +1,78 @@ -using System; - -using GrEmit; - -namespace GroBuf.SizeCounters -{ - internal class ArraySizeCounterBuilder : SizeCounterBuilderBase - { - public ArraySizeCounterBuilder(Type type) - : base(type) - { - if(!Type.IsArray) throw new InvalidOperationException("An array expected but was '" + Type + "'"); - if(Type.GetArrayRank() != 1) throw new NotSupportedException("Arrays with rank greater than 1 are not supported"); - elementType = Type.GetElementType(); - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - var il = context.Il; - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = il.DefineLabel("empty"); - il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - il.Ldlen(); // stack: [obj.Length] - il.Brtrue(notEmptyLabel); // if(obj.Length != 0) goto notEmpty; - il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + array length - - var length = il.DeclareLocal(typeof(int)); - context.LoadObj(); // stack: [9, obj] - il.Ldlen(); // stack: [9, obj.Length] - il.Stloc(length); // length = obj.Length; stack: [9] - var doneLabel = il.DefineLabel("done"); - il.Ldloc(length); // stack: [size, length] - il.Brfalse(doneLabel); // if(length == 0) goto done; stack: [size] - var i = il.DeclareLocal(typeof(int)); - il.Ldc_I4(0); // stack: [size, 0] - il.Stloc(i); // i = 0; stack: [size] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - context.LoadObj(); // stack: [size, obj] - il.Ldloc(i); // stack: [size, obj, i] - il.Ldelem(elementType); - il.Ldc_I4(1); // stack: [size, obj[i], true] - context.LoadContext(); // stack: [size, obj[i], true, context] - context.CallSizeCounter(elementType); // stack: [size, writer(obj[i], true, context) = itemSize] - il.Add(); // stack: [size + itemSize] - il.Ldloc(length); // stack: [size, length] - il.Ldloc(i); // stack: [size, length, i] - il.Ldc_I4(1); // stack: [size, length, i, 1] - il.Add(); // stack: [size, length, i + 1] - il.Dup(); // stack: [size, length, i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [size, length, i] - il.Bgt(cycleStartLabel, false); // if(length > i) goto cycleStart; stack: [size] - il.MarkLabel(doneLabel); - } - - private readonly Type elementType; - } +using System; + +using GrEmit; + +namespace GroBuf.SizeCounters +{ + internal class ArraySizeCounterBuilder : SizeCounterBuilderBase + { + public ArraySizeCounterBuilder(Type type) + : base(type) + { + if(!Type.IsArray) throw new InvalidOperationException("An array expected but was '" + Type + "'"); + if(Type.GetArrayRank() != 1) throw new NotSupportedException("Arrays with rank greater than 1 are not supported"); + elementType = Type.GetElementType(); + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + var il = context.Il; + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = il.DefineLabel("empty"); + il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + il.Ldlen(); // stack: [obj.Length] + il.Brtrue(notEmptyLabel); // if(obj.Length != 0) goto notEmpty; + il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + array length + + var length = il.DeclareLocal(typeof(int)); + context.LoadObj(); // stack: [9, obj] + il.Ldlen(); // stack: [9, obj.Length] + il.Stloc(length); // length = obj.Length; stack: [9] + var doneLabel = il.DefineLabel("done"); + il.Ldloc(length); // stack: [size, length] + il.Brfalse(doneLabel); // if(length == 0) goto done; stack: [size] + var i = il.DeclareLocal(typeof(int)); + il.Ldc_I4(0); // stack: [size, 0] + il.Stloc(i); // i = 0; stack: [size] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + context.LoadObj(); // stack: [size, obj] + il.Ldloc(i); // stack: [size, obj, i] + il.Ldelem(elementType); + il.Ldc_I4(1); // stack: [size, obj[i], true] + context.LoadContext(); // stack: [size, obj[i], true, context] + context.CallSizeCounter(elementType); // stack: [size, writer(obj[i], true, context) = itemSize] + il.Add(); // stack: [size + itemSize] + il.Ldloc(length); // stack: [size, length] + il.Ldloc(i); // stack: [size, length, i] + il.Ldc_I4(1); // stack: [size, length, i, 1] + il.Add(); // stack: [size, length, i + 1] + il.Dup(); // stack: [size, length, i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [size, length, i] + il.Bgt(cycleStartLabel, false); // if(length > i) goto cycleStart; stack: [size] + il.MarkLabel(doneLabel); + } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/ClassSizeCounterBuilder.cs b/GroBuf/SizeCounters/ClassSizeCounterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/ClassSizeCounterBuilder.cs rename to GroBuf/SizeCounters/ClassSizeCounterBuilder.cs index 4bedef7..ff4df4f 100644 --- a/GroBuf/GroBuf/SizeCounters/ClassSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/ClassSizeCounterBuilder.cs @@ -1,94 +1,94 @@ -using System; -using System.Reflection; - -namespace GroBuf.SizeCounters -{ - internal class ClassSizeCounterBuilder : SizeCounterBuilderBase - { - public ClassSizeCounterBuilder(Type type) - : base(type) - { - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - foreach(var member in context.GetDataMembers(Type)) - { - Type memberType; - switch(member.Member.MemberType) - { - case MemberTypes.Property: - memberType = ((PropertyInfo)member.Member).PropertyType; - break; - case MemberTypes.Field: - memberType = ((FieldInfo)member.Member).FieldType; - break; - default: - throw new NotSupportedException("Data member of type " + member.Member.MemberType + " is not supported"); - } - context.BuildConstants(memberType); - } - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - - il.Ldc_I4(0); // stack: [0 = size] - - var dataMembers = context.Context.GetDataMembers(Type); - foreach(var member in dataMembers) - { - if(Type.IsValueType) - context.LoadObjByRef(); // stack: [size, ref obj] - else - context.LoadObj(); // stack: [size, obj] - Type memberType; - switch(member.Member.MemberType) - { - case MemberTypes.Property: - var property = (PropertyInfo)member.Member; - var getter = property.GetGetMethod(true); - if(getter == null) - throw new MissingMethodException(Type.Name, property.Name + "_get"); - il.Call(getter, Type); // stack: [size, obj.prop] - memberType = property.PropertyType; - break; - case MemberTypes.Field: - var field = (FieldInfo)member.Member; - il.Ldfld(field); // stack: [size, obj.field] - memberType = field.FieldType; - break; - default: - throw new NotSupportedException("Data member of type " + member.Member.MemberType + " is not supported"); - } - il.Ldc_I4(0); // stack: [size, obj.member, false] - context.LoadContext(); // stack: [size, obj.member, false, context] - context.CallSizeCounter(memberType); // stack: [size, writers[i](obj.member, false, context) = memberSize] - il.Dup(); // stack: [size, memberSize, memberSize] - var nextLabel = il.DefineLabel("next"); - il.Brfalse(nextLabel); // if(memberSize = 0) goto next; stack: [size, memberSize] - - il.Ldc_I4(8); // stack: [size, memberSize, 8] - il.Add(); // stack: [size, memberSize + 8] - il.MarkLabel(nextLabel); - il.Add(); // stack: [size + curSize] - } - - if(!context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - { - var countLengthLabel = il.DefineLabel("countLength"); - il.Dup(); // stack: [size, size] - il.Brtrue(countLengthLabel); // if(size != 0) goto countLength; stack: [size] - il.Pop(); // stack: [] - context.ReturnForNull(); - il.Ret(); - il.MarkLabel(countLengthLabel); - } - il.Ldc_I4(5); // stack: [size, 5] - il.Add(); // stack: [size + 5] - } - - protected override bool IsReference { get { return true; } } - } +using System; +using System.Reflection; + +namespace GroBuf.SizeCounters +{ + internal class ClassSizeCounterBuilder : SizeCounterBuilderBase + { + public ClassSizeCounterBuilder(Type type) + : base(type) + { + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + foreach(var member in context.GetDataMembers(Type)) + { + Type memberType; + switch(member.Member.MemberType) + { + case MemberTypes.Property: + memberType = ((PropertyInfo)member.Member).PropertyType; + break; + case MemberTypes.Field: + memberType = ((FieldInfo)member.Member).FieldType; + break; + default: + throw new NotSupportedException("Data member of type " + member.Member.MemberType + " is not supported"); + } + context.BuildConstants(memberType); + } + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + + il.Ldc_I4(0); // stack: [0 = size] + + var dataMembers = context.Context.GetDataMembers(Type); + foreach(var member in dataMembers) + { + if(Type.IsValueType) + context.LoadObjByRef(); // stack: [size, ref obj] + else + context.LoadObj(); // stack: [size, obj] + Type memberType; + switch(member.Member.MemberType) + { + case MemberTypes.Property: + var property = (PropertyInfo)member.Member; + var getter = property.GetGetMethod(true); + if(getter == null) + throw new MissingMethodException(Type.Name, property.Name + "_get"); + il.Call(getter, Type); // stack: [size, obj.prop] + memberType = property.PropertyType; + break; + case MemberTypes.Field: + var field = (FieldInfo)member.Member; + il.Ldfld(field); // stack: [size, obj.field] + memberType = field.FieldType; + break; + default: + throw new NotSupportedException("Data member of type " + member.Member.MemberType + " is not supported"); + } + il.Ldc_I4(0); // stack: [size, obj.member, false] + context.LoadContext(); // stack: [size, obj.member, false, context] + context.CallSizeCounter(memberType); // stack: [size, writers[i](obj.member, false, context) = memberSize] + il.Dup(); // stack: [size, memberSize, memberSize] + var nextLabel = il.DefineLabel("next"); + il.Brfalse(nextLabel); // if(memberSize = 0) goto next; stack: [size, memberSize] + + il.Ldc_I4(8); // stack: [size, memberSize, 8] + il.Add(); // stack: [size, memberSize + 8] + il.MarkLabel(nextLabel); + il.Add(); // stack: [size + curSize] + } + + if(!context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + { + var countLengthLabel = il.DefineLabel("countLength"); + il.Dup(); // stack: [size, size] + il.Brtrue(countLengthLabel); // if(size != 0) goto countLength; stack: [size] + il.Pop(); // stack: [] + context.ReturnForNull(); + il.Ret(); + il.MarkLabel(countLengthLabel); + } + il.Ldc_I4(5); // stack: [size, 5] + il.Add(); // stack: [size + 5] + } + + protected override bool IsReference { get { return true; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/CustomSizeCounterBuilder.cs b/GroBuf/SizeCounters/CustomSizeCounterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/CustomSizeCounterBuilder.cs rename to GroBuf/SizeCounters/CustomSizeCounterBuilder.cs index 24d6660..bb93150 100644 --- a/GroBuf/GroBuf/SizeCounters/CustomSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/CustomSizeCounterBuilder.cs @@ -1,49 +1,49 @@ -using System; -using System.Collections.Generic; - -using GrEmit.Utils; - -namespace GroBuf.SizeCounters -{ - internal class CustomSizeCounterBuilder : SizeCounterBuilderBase - { - public CustomSizeCounterBuilder(Type type, IGroBufCustomSerializer customSerializer) - : base(type) - { - this.customSerializer = customSerializer; - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - context.SetFields(Type, new[] {new KeyValuePair("customSerializer_" + Type.Name + "_" + Guid.NewGuid(), typeof(IGroBufCustomSerializer))}); - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var customSerializerField = context.Context.InitConstField(Type, 0, customSerializer); - var il = context.Il; - - context.LoadField(customSerializerField); // stack: [customSerializer] - context.LoadObj(); // stack: [customSerializer, obj] - if(Type.IsValueType) - il.Box(Type); // stack: [customSerializer, (object)obj] - context.LoadWriteEmpty(); // stack: [customSerializer, (object)obj, writeEmpty] - context.LoadContext(); // stack: [customSerializer, (object)obj, writeEmpty, context] - il.Call(HackHelpers.GetMethodDefinition(serializer => serializer.CountSize(null, false, null))); // stack: [customSerializer.CountSize((object)obj, writeEmpty, context)] - - var countLengthLabel = il.DefineLabel("countLength"); - il.Dup(); // stack: [size, size] - il.Brtrue(countLengthLabel); // if(size != 0) goto countLength; stack: [size] - il.Pop(); // stack: [] - context.ReturnForNull(); - il.Ret(); - il.MarkLabel(countLengthLabel); - il.Ldc_I4(5); // stack: [size, 5] - il.Add(); // stack: [size + 5] - } - - protected override bool IsReference { get { return false; } } - - private readonly IGroBufCustomSerializer customSerializer; - } +using System; +using System.Collections.Generic; + +using GrEmit.Utils; + +namespace GroBuf.SizeCounters +{ + internal class CustomSizeCounterBuilder : SizeCounterBuilderBase + { + public CustomSizeCounterBuilder(Type type, IGroBufCustomSerializer customSerializer) + : base(type) + { + this.customSerializer = customSerializer; + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + context.SetFields(Type, new[] {new KeyValuePair("customSerializer_" + Type.Name + "_" + Guid.NewGuid(), typeof(IGroBufCustomSerializer))}); + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var customSerializerField = context.Context.InitConstField(Type, 0, customSerializer); + var il = context.Il; + + context.LoadField(customSerializerField); // stack: [customSerializer] + context.LoadObj(); // stack: [customSerializer, obj] + if(Type.IsValueType) + il.Box(Type); // stack: [customSerializer, (object)obj] + context.LoadWriteEmpty(); // stack: [customSerializer, (object)obj, writeEmpty] + context.LoadContext(); // stack: [customSerializer, (object)obj, writeEmpty, context] + il.Call(HackHelpers.GetMethodDefinition(serializer => serializer.CountSize(null, false, null))); // stack: [customSerializer.CountSize((object)obj, writeEmpty, context)] + + var countLengthLabel = il.DefineLabel("countLength"); + il.Dup(); // stack: [size, size] + il.Brtrue(countLengthLabel); // if(size != 0) goto countLength; stack: [size] + il.Pop(); // stack: [] + context.ReturnForNull(); + il.Ret(); + il.MarkLabel(countLengthLabel); + il.Ldc_I4(5); // stack: [size, 5] + il.Add(); // stack: [size + 5] + } + + protected override bool IsReference { get { return false; } } + + private readonly IGroBufCustomSerializer customSerializer; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/DateTimeOffsetSizeCounterBuilder.cs b/GroBuf/SizeCounters/DateTimeOffsetSizeCounterBuilder.cs similarity index 96% rename from GroBuf/GroBuf/SizeCounters/DateTimeOffsetSizeCounterBuilder.cs rename to GroBuf/SizeCounters/DateTimeOffsetSizeCounterBuilder.cs index 48f7ab5..ba08f17 100644 --- a/GroBuf/GroBuf/SizeCounters/DateTimeOffsetSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/DateTimeOffsetSizeCounterBuilder.cs @@ -1,24 +1,24 @@ -using System; - -namespace GroBuf.SizeCounters -{ - internal class DateTimeOffsetSizeCounterBuilder : SizeCounterBuilderBase - { - public DateTimeOffsetSizeCounterBuilder() - : base(typeof(DateTimeOffset)) - { - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - // TODO call sub size counters - context.Il.Ldc_I4(1 + 9 + 3); // stack: [13] - } - - protected override bool IsReference { get { return false; } } - } +using System; + +namespace GroBuf.SizeCounters +{ + internal class DateTimeOffsetSizeCounterBuilder : SizeCounterBuilderBase + { + public DateTimeOffsetSizeCounterBuilder() + : base(typeof(DateTimeOffset)) + { + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + // TODO call sub size counters + context.Il.Ldc_I4(1 + 9 + 3); // stack: [13] + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/DateTimeSizeCounterBuilder.cs b/GroBuf/SizeCounters/DateTimeSizeCounterBuilder.cs similarity index 96% rename from GroBuf/GroBuf/SizeCounters/DateTimeSizeCounterBuilder.cs rename to GroBuf/SizeCounters/DateTimeSizeCounterBuilder.cs index 10caf70..7333e29 100644 --- a/GroBuf/GroBuf/SizeCounters/DateTimeSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/DateTimeSizeCounterBuilder.cs @@ -1,24 +1,24 @@ -using System; - -namespace GroBuf.SizeCounters -{ - internal class DateTimeSizeCounterBuilder : SizeCounterBuilderBase - { - public DateTimeSizeCounterBuilder() - : base(typeof(DateTime)) - { - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - il.Ldc_I4(9); // stack: [9] - } - - protected override bool IsReference { get { return false; } } - } +using System; + +namespace GroBuf.SizeCounters +{ + internal class DateTimeSizeCounterBuilder : SizeCounterBuilderBase + { + public DateTimeSizeCounterBuilder() + : base(typeof(DateTime)) + { + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + il.Ldc_I4(9); // stack: [9] + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/DictionarySizeCounterBuilder.cs b/GroBuf/SizeCounters/DictionarySizeCounterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/DictionarySizeCounterBuilder.cs rename to GroBuf/SizeCounters/DictionarySizeCounterBuilder.cs index 138d012..b7bcef8 100644 --- a/GroBuf/GroBuf/SizeCounters/DictionarySizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/DictionarySizeCounterBuilder.cs @@ -1,110 +1,110 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.SizeCounters -{ - internal class DictionarySizeCounterBuilder : SizeCounterBuilderBase - { - public DictionarySizeCounterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Dictionary<,>))) - throw new InvalidOperationException("Dictionary expected but was '" + Type + "'"); - keyType = Type.GetGenericArguments()[0]; - valueType = Type.GetGenericArguments()[1]; - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - context.BuildConstants(keyType); - context.BuildConstants(valueType); - } - - protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Count] - context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + dictionary count - context.LoadObj(); // stack: [size, obj] - var count = il.DeclareLocal(typeof(int)); - // traverse all buckets - il.Ldfld(Type.GetField("count", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [size, obj.Count] - il.Stloc(count); // count = obj.Count; stack: [size] - - var doneLabel = il.DefineLabel("done"); - il.Ldloc(count); // stack: [size, count] - il.Brfalse(doneLabel); // if(count == 0) goto done; stack: [size] - - context.LoadObj(); // stack: [size, obj] - var entryType = Type.GetNestedType("Entry", BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); - var entries = il.DeclareLocal(entryType.MakeArrayType()); - il.Ldfld(Type.GetField("entries", BindingFlags.Instance | BindingFlags.NonPublic)); - il.Stloc(entries); - - var i = il.DeclareLocal(typeof(int)); - il.Ldc_I4(0); // stack: [9, 0] - il.Stloc(i); // i = 0; stack: [9] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - il.Ldloc(entries); // stack: [size, entries] - il.Ldloc(i); // stack: [size, entries, i] - il.Ldelema(entryType); // stack: [size, &entries[i]] - il.Dup(); // stack: [size, &entries[i], &entries[i]] - var entry = il.DeclareLocal(entryType.MakeByRefType()); - il.Stloc(entry); // entry = &entries[i]; stack: [size, entry] - il.Ldfld(entryType.GetField("hashCode")); // stack: [size, entry.hashCode] - il.Ldc_I4(0); // stack: [size, entry.hashCode, 0] - var nextLabel = il.DefineLabel("next"); - il.Blt(nextLabel, false); // if(entry.hashCode < 0) goto next; stack: [size] - - il.Ldloc(entry); // stack: [size, entry] - il.Ldfld(entryType.GetField("key")); // stack: [size, entry.key] - il.Ldc_I4(1); // stack: [size, entry.key, true] - context.LoadContext(); // stack: [size, entry.key, true, context] - context.CallSizeCounter(keyType); // stack: [size, writer(entry.key, true, context) = keySize] - il.Add(); // stack: [size + keySize] - - il.Ldloc(entry); // stack: [size, entry] - il.Ldfld(entryType.GetField("value")); // stack: [size, entry.value] - il.Ldc_I4(1); // stack: [size, entry.value, true] - context.LoadContext(); // stack: [size, entry.value, true, context] - context.CallSizeCounter(valueType); // stack: [size, writer(entry.value, true, context) = valueSize] - il.Add(); // stack: [size + valueSize] - - il.MarkLabel(nextLabel); - il.Ldloc(count); // stack: [size, count] - il.Ldloc(i); // stack: [size, count, i] - il.Ldc_I4(1); // stack: [size, count, i, 1] - il.Add(); // stack: [size, count, i + 1] - il.Dup(); // stack: [size, count, i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [size, count, i] - il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [size] - - il.MarkLabel(doneLabel); - } - - private readonly Type keyType; - private readonly Type valueType; - } +using System; +using System.Collections.Generic; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.SizeCounters +{ + internal class DictionarySizeCounterBuilder : SizeCounterBuilderBase + { + public DictionarySizeCounterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Dictionary<,>))) + throw new InvalidOperationException("Dictionary expected but was '" + Type + "'"); + keyType = Type.GetGenericArguments()[0]; + valueType = Type.GetGenericArguments()[1]; + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + context.BuildConstants(keyType); + context.BuildConstants(valueType); + } + + protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Count] + context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + dictionary count + context.LoadObj(); // stack: [size, obj] + var count = il.DeclareLocal(typeof(int)); + // traverse all buckets + il.Ldfld(Type.GetField("count", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [size, obj.Count] + il.Stloc(count); // count = obj.Count; stack: [size] + + var doneLabel = il.DefineLabel("done"); + il.Ldloc(count); // stack: [size, count] + il.Brfalse(doneLabel); // if(count == 0) goto done; stack: [size] + + context.LoadObj(); // stack: [size, obj] + var entryType = Type.GetNestedType("Entry", BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); + var entries = il.DeclareLocal(entryType.MakeArrayType()); + il.Ldfld(Type.GetField("entries", BindingFlags.Instance | BindingFlags.NonPublic)); + il.Stloc(entries); + + var i = il.DeclareLocal(typeof(int)); + il.Ldc_I4(0); // stack: [9, 0] + il.Stloc(i); // i = 0; stack: [9] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + il.Ldloc(entries); // stack: [size, entries] + il.Ldloc(i); // stack: [size, entries, i] + il.Ldelema(entryType); // stack: [size, &entries[i]] + il.Dup(); // stack: [size, &entries[i], &entries[i]] + var entry = il.DeclareLocal(entryType.MakeByRefType()); + il.Stloc(entry); // entry = &entries[i]; stack: [size, entry] + il.Ldfld(entryType.GetField("hashCode")); // stack: [size, entry.hashCode] + il.Ldc_I4(0); // stack: [size, entry.hashCode, 0] + var nextLabel = il.DefineLabel("next"); + il.Blt(nextLabel, false); // if(entry.hashCode < 0) goto next; stack: [size] + + il.Ldloc(entry); // stack: [size, entry] + il.Ldfld(entryType.GetField("key")); // stack: [size, entry.key] + il.Ldc_I4(1); // stack: [size, entry.key, true] + context.LoadContext(); // stack: [size, entry.key, true, context] + context.CallSizeCounter(keyType); // stack: [size, writer(entry.key, true, context) = keySize] + il.Add(); // stack: [size + keySize] + + il.Ldloc(entry); // stack: [size, entry] + il.Ldfld(entryType.GetField("value")); // stack: [size, entry.value] + il.Ldc_I4(1); // stack: [size, entry.value, true] + context.LoadContext(); // stack: [size, entry.value, true, context] + context.CallSizeCounter(valueType); // stack: [size, writer(entry.value, true, context) = valueSize] + il.Add(); // stack: [size + valueSize] + + il.MarkLabel(nextLabel); + il.Ldloc(count); // stack: [size, count] + il.Ldloc(i); // stack: [size, count, i] + il.Ldc_I4(1); // stack: [size, count, i, 1] + il.Add(); // stack: [size, count, i + 1] + il.Dup(); // stack: [size, count, i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [size, count, i] + il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [size] + + il.MarkLabel(doneLabel); + } + + private readonly Type keyType; + private readonly Type valueType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/EnumSizeCounterBuilder.cs b/GroBuf/SizeCounters/EnumSizeCounterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/EnumSizeCounterBuilder.cs rename to GroBuf/SizeCounters/EnumSizeCounterBuilder.cs index 2260b1c..70bd3c1 100644 --- a/GroBuf/GroBuf/SizeCounters/EnumSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/EnumSizeCounterBuilder.cs @@ -1,55 +1,55 @@ -using System; -using System.Collections.Generic; - -namespace GroBuf.SizeCounters -{ - internal class EnumSizeCounterBuilder : SizeCounterBuilderBase - { - public EnumSizeCounterBuilder(Type type) - : base(type) - { - if(!Type.IsEnum) throw new InvalidOperationException("Enum expected but was '" + Type + "'"); - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - context.SetFields(Type, new[] - { - new KeyValuePair("hashCodes_" + Type.Name + "_" + Guid.NewGuid(), typeof(ulong[])), - new KeyValuePair("values_" + Type.Name + "_" + Guid.NewGuid(), typeof(int[])), - }); - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - int[] values; - ulong[] hashCodes; - EnumHelpers.BuildHashCodesTable(Type, out values, out hashCodes); - var hashCodesField = context.Context.InitConstField(Type, 0, hashCodes); - var valuesField = context.Context.InitConstField(Type, 1, values); - - var il = context.Il; - context.LoadField(valuesField); // stack: [values] - context.LoadObj(); // stack: [values, obj] - il.Ldc_I4(values.Length); // stack: [values, obj, values.Length] - il.Rem(true); // stack: [values, obj % values.Length] - il.Ldelem(typeof(int)); // stack: [values[obj % values.Length]] - context.LoadObj(); // stack: [values[obj % values.Length], obj] - il.Ceq(); // stack: [values[obj % values.Length] == obj] - var countAsIntLabel = il.DefineLabel("countAsInt"); - il.Brfalse(countAsIntLabel); // if(values[obj % values.Length] != obj) goto countAsInt - context.LoadField(hashCodesField); // stack: [hashCodes] - context.LoadObj(); // stack: [hashCodes, obj] - il.Ldc_I4(hashCodes.Length); // stack: [hashCodes, obj, hashCodes.Length] - il.Rem(true); // stack: [hashCodes, obj % hashCodes.Length] - il.Ldelem(typeof(long)); // stack: [hashCodes[obj % hashCodes.Length] = hashCode] - il.Brfalse(countAsIntLabel); // if(hashCode == 0) goto countAsInt; - il.Ldc_I4(9); // stack: [9] - il.Ret(); // return 9; - il.MarkLabel(countAsIntLabel); - il.Ldc_I4(5); // stack: [5] - } - - protected override bool IsReference { get { return false; } } - } +using System; +using System.Collections.Generic; + +namespace GroBuf.SizeCounters +{ + internal class EnumSizeCounterBuilder : SizeCounterBuilderBase + { + public EnumSizeCounterBuilder(Type type) + : base(type) + { + if(!Type.IsEnum) throw new InvalidOperationException("Enum expected but was '" + Type + "'"); + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + context.SetFields(Type, new[] + { + new KeyValuePair("hashCodes_" + Type.Name + "_" + Guid.NewGuid(), typeof(ulong[])), + new KeyValuePair("values_" + Type.Name + "_" + Guid.NewGuid(), typeof(int[])), + }); + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + int[] values; + ulong[] hashCodes; + EnumHelpers.BuildHashCodesTable(Type, out values, out hashCodes); + var hashCodesField = context.Context.InitConstField(Type, 0, hashCodes); + var valuesField = context.Context.InitConstField(Type, 1, values); + + var il = context.Il; + context.LoadField(valuesField); // stack: [values] + context.LoadObj(); // stack: [values, obj] + il.Ldc_I4(values.Length); // stack: [values, obj, values.Length] + il.Rem(true); // stack: [values, obj % values.Length] + il.Ldelem(typeof(int)); // stack: [values[obj % values.Length]] + context.LoadObj(); // stack: [values[obj % values.Length], obj] + il.Ceq(); // stack: [values[obj % values.Length] == obj] + var countAsIntLabel = il.DefineLabel("countAsInt"); + il.Brfalse(countAsIntLabel); // if(values[obj % values.Length] != obj) goto countAsInt + context.LoadField(hashCodesField); // stack: [hashCodes] + context.LoadObj(); // stack: [hashCodes, obj] + il.Ldc_I4(hashCodes.Length); // stack: [hashCodes, obj, hashCodes.Length] + il.Rem(true); // stack: [hashCodes, obj % hashCodes.Length] + il.Ldelem(typeof(long)); // stack: [hashCodes[obj % hashCodes.Length] = hashCode] + il.Brfalse(countAsIntLabel); // if(hashCode == 0) goto countAsInt; + il.Ldc_I4(9); // stack: [9] + il.Ret(); // return 9; + il.MarkLabel(countAsIntLabel); + il.Ldc_I4(5); // stack: [5] + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/GuidSizeCounterBuilder.cs b/GroBuf/SizeCounters/GuidSizeCounterBuilder.cs similarity index 96% rename from GroBuf/GroBuf/SizeCounters/GuidSizeCounterBuilder.cs rename to GroBuf/SizeCounters/GuidSizeCounterBuilder.cs index 76c958a..a628f6d 100644 --- a/GroBuf/GroBuf/SizeCounters/GuidSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/GuidSizeCounterBuilder.cs @@ -1,23 +1,23 @@ -using System; - -namespace GroBuf.SizeCounters -{ - internal class GuidSizeCounterBuilder : SizeCounterBuilderBase - { - public GuidSizeCounterBuilder() - : base(typeof(Guid)) - { - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - context.Il.Ldc_I4(17); // stack: [17] - } - - protected override bool IsReference { get { return false; } } - } +using System; + +namespace GroBuf.SizeCounters +{ + internal class GuidSizeCounterBuilder : SizeCounterBuilderBase + { + public GuidSizeCounterBuilder() + : base(typeof(Guid)) + { + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + context.Il.Ldc_I4(17); // stack: [17] + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/HashSetSizeCounterBuilder.cs b/GroBuf/SizeCounters/HashSetSizeCounterBuilder.cs similarity index 93% rename from GroBuf/GroBuf/SizeCounters/HashSetSizeCounterBuilder.cs rename to GroBuf/SizeCounters/HashSetSizeCounterBuilder.cs index 22dd2a8..08b5698 100644 --- a/GroBuf/GroBuf/SizeCounters/HashSetSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/HashSetSizeCounterBuilder.cs @@ -1,100 +1,100 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.SizeCounters -{ - internal class HashSetSizeCounterBuilder : SizeCounterBuilderBase - { - public HashSetSizeCounterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(HashSet<>))) - throw new InvalidOperationException("HashSet expected but was '" + Type + "'"); - elementType = Type.GetGenericArguments()[0]; - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Count] - context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + hashset count - - context.LoadObj(); // stack: [size, obj] - var count = il.DeclareLocal(typeof(int)); - il.Ldfld(Type.GetField("m_lastIndex", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [size, obj.m_lastIndex] - il.Dup(); - il.Stloc(count); // count = obj.m_lastIndex; stack: [size, count] - var doneLabel = il.DefineLabel("done"); - il.Brfalse(doneLabel); // if(!count) goto done; stack: [size] - - context.LoadObj(); // stack: [size, obj] - var slotType = Type.GetNestedType("Slot", BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); - var slots = il.DeclareLocal(slotType.MakeArrayType()); - il.Ldfld(Type.GetField("m_slots", BindingFlags.Instance | BindingFlags.NonPublic)); - il.Stloc(slots); - - var i = il.DeclareLocal(typeof(int)); - il.Ldc_I4(0); // stack: [9, 0] - il.Stloc(i); // i = 0; stack: [9] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - il.Ldloc(slots); // stack: [size, slots] - il.Ldloc(i); // stack: [size, slots, i] - il.Ldelema(slotType); // stack: [size, &slots[i]] - il.Dup(); // stack: [size, &slots[i], &slots[i]] - var slot = il.DeclareLocal(slotType.MakeByRefType()); - il.Stloc(slot); // slot = &slots[i]; stack: [size, slot] - il.Ldfld(slotType.GetField("hashCode", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [size, slot.hashCode] - il.Ldc_I4(0); // stack: [size, slot.hashCode, 0] - var nextLabel = il.DefineLabel("next"); - il.Blt(nextLabel, false); // if(slot.hashCode < 0) goto next; stack: [size] - - il.Ldloc(slot); // stack: [size, slot] - il.Ldfld(slotType.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [size, slot.value] - il.Ldc_I4(1); // stack: [size, slot.value, true] - context.LoadContext(); // stack: [size, slot.value, true, context] - context.CallSizeCounter(elementType); // stack: [size, writer(slot.value, true, context) = valueSize] - il.Add(); // stack: [size + valueSize] - - il.MarkLabel(nextLabel); - - il.Ldloc(count); // stack: [size, count] - il.Ldloc(i); // stack: [size, count, i] - il.Ldc_I4(1); // stack: [size, count, i, 1] - il.Add(); // stack: [size, count, i + 1] - il.Dup(); // stack: [size, count, i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [size, count, i] - il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [size] - - il.MarkLabel(doneLabel); - } - - private readonly Type elementType; - } +using System; +using System.Collections.Generic; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.SizeCounters +{ + internal class HashSetSizeCounterBuilder : SizeCounterBuilderBase + { + public HashSetSizeCounterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(HashSet<>))) + throw new InvalidOperationException("HashSet expected but was '" + Type + "'"); + elementType = Type.GetGenericArguments()[0]; + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Count] + context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + hashset count + + context.LoadObj(); // stack: [size, obj] + var count = il.DeclareLocal(typeof(int)); + il.Ldfld(Type.GetField(PlatformHelpers.HashSetLastIndexFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [size, obj.m_lastIndex] + il.Dup(); + il.Stloc(count); // count = obj.m_lastIndex; stack: [size, count] + var doneLabel = il.DefineLabel("done"); + il.Brfalse(doneLabel); // if(!count) goto done; stack: [size] + + context.LoadObj(); // stack: [size, obj] + var slotType = Type.GetNestedType("Slot", BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); + var slots = il.DeclareLocal(slotType.MakeArrayType()); + il.Ldfld(Type.GetField(PlatformHelpers.HashSetSlotsFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); + il.Stloc(slots); + + var i = il.DeclareLocal(typeof(int)); + il.Ldc_I4(0); // stack: [9, 0] + il.Stloc(i); // i = 0; stack: [9] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + il.Ldloc(slots); // stack: [size, slots] + il.Ldloc(i); // stack: [size, slots, i] + il.Ldelema(slotType); // stack: [size, &slots[i]] + il.Dup(); // stack: [size, &slots[i], &slots[i]] + var slot = il.DeclareLocal(slotType.MakeByRefType()); + il.Stloc(slot); // slot = &slots[i]; stack: [size, slot] + il.Ldfld(slotType.GetField("hashCode", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [size, slot.hashCode] + il.Ldc_I4(0); // stack: [size, slot.hashCode, 0] + var nextLabel = il.DefineLabel("next"); + il.Blt(nextLabel, false); // if(slot.hashCode < 0) goto next; stack: [size] + + il.Ldloc(slot); // stack: [size, slot] + il.Ldfld(slotType.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [size, slot.value] + il.Ldc_I4(1); // stack: [size, slot.value, true] + context.LoadContext(); // stack: [size, slot.value, true, context] + context.CallSizeCounter(elementType); // stack: [size, writer(slot.value, true, context) = valueSize] + il.Add(); // stack: [size + valueSize] + + il.MarkLabel(nextLabel); + + il.Ldloc(count); // stack: [size, count] + il.Ldloc(i); // stack: [size, count, i] + il.Ldc_I4(1); // stack: [size, count, i, 1] + il.Add(); // stack: [size, count, i + 1] + il.Dup(); // stack: [size, count, i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [size, count, i] + il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [size] + + il.MarkLabel(doneLabel); + } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/HashtableSizeCounterBuilder.cs b/GroBuf/SizeCounters/HashtableSizeCounterBuilder.cs similarity index 91% rename from GroBuf/GroBuf/SizeCounters/HashtableSizeCounterBuilder.cs rename to GroBuf/SizeCounters/HashtableSizeCounterBuilder.cs index 80283dd..29b3378 100644 --- a/GroBuf/GroBuf/SizeCounters/HashtableSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/HashtableSizeCounterBuilder.cs @@ -1,109 +1,109 @@ -using System.Collections; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.SizeCounters -{ - internal class HashtableSizeCounterBuilder : SizeCounterBuilderBase - { - public HashtableSizeCounterBuilder() - : base(typeof(Hashtable)) - { - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - context.BuildConstants(typeof(object)); - } - - protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Ldfld(Type.GetField("count", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] - context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + dictionary count - context.LoadObj(); // stack: [size, obj] - il.Ldfld(Type.GetField("count", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [size, obj.Count] - - var doneLabel = il.DefineLabel("done"); - il.Brfalse(doneLabel); // if(count == 0) goto done; stack: [size] - - context.LoadObj(); // stack: [size, obj] - var bucketType = Type.GetNestedType("bucket", BindingFlags.NonPublic); - var buckets = il.DeclareLocal(bucketType.MakeArrayType()); - var bucketsField = Type.GetField("buckets", BindingFlags.Instance | BindingFlags.NonPublic); - il.Ldfld(bucketsField); // stack: [size, obj.buckets] - il.Stloc(buckets); // buckets = obj.buckets; stack: [size] - var length = il.DeclareLocal(typeof(int)); - il.Ldloc(buckets); // stack: [size, buckets] - il.Ldlen(); // stack: [size, buckets.Length] - il.Stloc(length); // length = buckets.Length - - var i = il.DeclareLocal(typeof(int)); - il.Ldc_I4(0); // stack: [9, 0] - il.Stloc(i); // i = 0; stack: [9] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - il.Ldloc(buckets); // stack: [size, buckets] - il.Ldloc(i); // stack: [size, buckets, i] - il.Ldelema(bucketType); // stack: [size, &buckets[i]] - il.Dup(); // stack: [size, &entries[i], &buckets[i]] - var bucket = il.DeclareLocal(bucketType.MakeByRefType()); - il.Stloc(bucket); // bucket = &buckets[i]; stack: [size, bucket] - il.Ldfld(bucketType.GetField("key", BindingFlags.Public | BindingFlags.Instance)); // stack: [size, bucket.key] - il.Dup(); // stack: [size, bucket.key, bucket.key] - var key = il.DeclareLocal(typeof(object)); - il.Stloc(key); // key = bucket.key; stack: [size, key] - - var nextLabel = il.DefineLabel("next"); - il.Brfalse(nextLabel); // if(bucket.key == null) goto next; stack: [size] - - il.Ldloc(key); // stack: [size, key] - context.LoadObj(); // stack: [size, key, obj] - il.Ldfld(bucketsField); // stack: [size, key, obj.buckets] - il.Beq(nextLabel); // if(key == obj.buckets) goto next; stack: [size] - - il.Ldloc(key); // stack: [size, key] - il.Ldc_I4(1); // stack: [size, key, true] - context.LoadContext(); // stack: [size, key, true, context] - context.CallSizeCounter(typeof(object)); // stack: [size, writer(key, true, context) = keySize] - il.Add(); // stack: [size + keySize] - - il.Ldloc(bucket); // stack: [size, bucket] - il.Ldfld(bucketType.GetField("val", BindingFlags.Public | BindingFlags.Instance)); // stack: [size, bucket.val] - il.Ldc_I4(1); // stack: [size, bucket.val, true] - context.LoadContext(); // stack: [size, bucket.val, true, context] - context.CallSizeCounter(typeof(object)); // stack: [size, writer(bucket.val, true, context) = valueSize] - il.Add(); // stack: [size + valueSize] - - il.MarkLabel(nextLabel); - il.Ldloc(length); // stack: [size, length] - il.Ldloc(i); // stack: [size, length, i] - il.Ldc_I4(1); // stack: [size, length, i, 1] - il.Add(); // stack: [size, length, i + 1] - il.Dup(); // stack: [size, length, i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [size, length, i] - il.Bgt(cycleStartLabel, false); // if(length > i) goto cycleStart; stack: [size] - - il.MarkLabel(doneLabel); - } - - protected override bool IsReference { get { return true; } } - } +using System.Collections; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.SizeCounters +{ + internal class HashtableSizeCounterBuilder : SizeCounterBuilderBase + { + public HashtableSizeCounterBuilder() + : base(typeof(Hashtable)) + { + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + context.BuildConstants(typeof(object)); + } + + protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Ldfld(Type.GetField(PlatformHelpers.HashtableCountFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] + context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + dictionary count + context.LoadObj(); // stack: [size, obj] + il.Ldfld(Type.GetField(PlatformHelpers.HashtableCountFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [size, obj.Count] + + var doneLabel = il.DefineLabel("done"); + il.Brfalse(doneLabel); // if(count == 0) goto done; stack: [size] + + context.LoadObj(); // stack: [size, obj] + var bucketType = Type.GetNestedType("bucket", BindingFlags.NonPublic); + var buckets = il.DeclareLocal(bucketType.MakeArrayType()); + var bucketsField = Type.GetField(PlatformHelpers.HashtableBucketsFieldName, BindingFlags.Instance | BindingFlags.NonPublic); + il.Ldfld(bucketsField); // stack: [size, obj.buckets] + il.Stloc(buckets); // buckets = obj.buckets; stack: [size] + var length = il.DeclareLocal(typeof(int)); + il.Ldloc(buckets); // stack: [size, buckets] + il.Ldlen(); // stack: [size, buckets.Length] + il.Stloc(length); // length = buckets.Length + + var i = il.DeclareLocal(typeof(int)); + il.Ldc_I4(0); // stack: [9, 0] + il.Stloc(i); // i = 0; stack: [9] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + il.Ldloc(buckets); // stack: [size, buckets] + il.Ldloc(i); // stack: [size, buckets, i] + il.Ldelema(bucketType); // stack: [size, &buckets[i]] + il.Dup(); // stack: [size, &entries[i], &buckets[i]] + var bucket = il.DeclareLocal(bucketType.MakeByRefType()); + il.Stloc(bucket); // bucket = &buckets[i]; stack: [size, bucket] + il.Ldfld(bucketType.GetField("key", BindingFlags.Public | BindingFlags.Instance)); // stack: [size, bucket.key] + il.Dup(); // stack: [size, bucket.key, bucket.key] + var key = il.DeclareLocal(typeof(object)); + il.Stloc(key); // key = bucket.key; stack: [size, key] + + var nextLabel = il.DefineLabel("next"); + il.Brfalse(nextLabel); // if(bucket.key == null) goto next; stack: [size] + + il.Ldloc(key); // stack: [size, key] + context.LoadObj(); // stack: [size, key, obj] + il.Ldfld(bucketsField); // stack: [size, key, obj.buckets] + il.Beq(nextLabel); // if(key == obj.buckets) goto next; stack: [size] + + il.Ldloc(key); // stack: [size, key] + il.Ldc_I4(1); // stack: [size, key, true] + context.LoadContext(); // stack: [size, key, true, context] + context.CallSizeCounter(typeof(object)); // stack: [size, writer(key, true, context) = keySize] + il.Add(); // stack: [size + keySize] + + il.Ldloc(bucket); // stack: [size, bucket] + il.Ldfld(bucketType.GetField("val", BindingFlags.Public | BindingFlags.Instance)); // stack: [size, bucket.val] + il.Ldc_I4(1); // stack: [size, bucket.val, true] + context.LoadContext(); // stack: [size, bucket.val, true, context] + context.CallSizeCounter(typeof(object)); // stack: [size, writer(bucket.val, true, context) = valueSize] + il.Add(); // stack: [size + valueSize] + + il.MarkLabel(nextLabel); + il.Ldloc(length); // stack: [size, length] + il.Ldloc(i); // stack: [size, length, i] + il.Ldc_I4(1); // stack: [size, length, i, 1] + il.Add(); // stack: [size, length, i + 1] + il.Dup(); // stack: [size, length, i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [size, length, i] + il.Bgt(cycleStartLabel, false); // if(length > i) goto cycleStart; stack: [size] + + il.MarkLabel(doneLabel); + } + + protected override bool IsReference { get { return true; } } + } } \ No newline at end of file diff --git a/GroBuf/SizeCounters/IPAddressSizeCounterBuilder.cs b/GroBuf/SizeCounters/IPAddressSizeCounterBuilder.cs new file mode 100644 index 0000000..60eb541 --- /dev/null +++ b/GroBuf/SizeCounters/IPAddressSizeCounterBuilder.cs @@ -0,0 +1,36 @@ +using System.Net; +using System.Net.Sockets; +using System.Reflection; + +namespace GroBuf.SizeCounters +{ + internal class IPAddressSizeCounterBuilder : SizeCounterBuilderBase + { + public IPAddressSizeCounterBuilder() + : base(typeof(IPAddress)) + { + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + + il.Ldc_I4(4); // stack: [4] + context.LoadObj(); // stack: [4, obj] + il.Call(Type.GetProperty("AddressFamily", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [4, obj.AddressFamily] + il.Ldc_I4((int)AddressFamily.InterNetworkV6); // stack: [4, obj.AddressFamily, AddressFamily.InterNetworkV6] + il.Ceq(); // stack: [4, obj.AddressFamily == AddressFamily.InterNetworkV6] + il.Ldc_I4(1); // stack: [4, obj.AddressFamily == AddressFamily.InterNetworkV6, 1] + il.Shl(); // stack: [4, (obj.AddressFamily == AddressFamily.InterNetworkV6) << 1] + il.Shl(); // stack: [4 << ((obj.AddressFamily == AddressFamily.InterNetworkV6) << 1)] + il.Ldc_I4(5); // stack: [4 << ((obj.AddressFamily == AddressFamily.InterNetworkV6) << 1), 5] + il.Add(); // stack: [4 << ((obj.AddressFamily == AddressFamily.InterNetworkV6) << 1) + 5] + } + + protected override bool IsReference { get { return false; } } + } +} \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/ISizeCounterBuilder.cs b/GroBuf/SizeCounters/ISizeCounterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/ISizeCounterBuilder.cs rename to GroBuf/SizeCounters/ISizeCounterBuilder.cs index d6be863..3602f9a 100644 --- a/GroBuf/GroBuf/SizeCounters/ISizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/ISizeCounterBuilder.cs @@ -1,8 +1,8 @@ -namespace GroBuf.SizeCounters -{ - internal interface ISizeCounterBuilder - { - void BuildSizeCounter(SizeCounterBuilderContext sizeCounterBuilderContext); - void BuildConstants(SizeCounterConstantsBuilderContext context); - } +namespace GroBuf.SizeCounters +{ + internal interface ISizeCounterBuilder + { + void BuildSizeCounter(SizeCounterBuilderContext sizeCounterBuilderContext); + void BuildConstants(SizeCounterConstantsBuilderContext context); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/ISizeCounterCollection.cs b/GroBuf/SizeCounters/ISizeCounterCollection.cs similarity index 96% rename from GroBuf/GroBuf/SizeCounters/ISizeCounterCollection.cs rename to GroBuf/SizeCounters/ISizeCounterCollection.cs index 1ef5d68..60fba39 100644 --- a/GroBuf/GroBuf/SizeCounters/ISizeCounterCollection.cs +++ b/GroBuf/SizeCounters/ISizeCounterCollection.cs @@ -1,9 +1,9 @@ -using System; - -namespace GroBuf.SizeCounters -{ - internal interface ISizeCounterCollection - { - ISizeCounterBuilder GetSizeCounterBuilder(Type type, bool ignoreCustomSerialization); - } +using System; + +namespace GroBuf.SizeCounters +{ + internal interface ISizeCounterCollection + { + ISizeCounterBuilder GetSizeCounterBuilder(Type type, bool ignoreCustomSerialization); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/LazySizeCounterBuilder.cs b/GroBuf/SizeCounters/LazySizeCounterBuilder.cs similarity index 87% rename from GroBuf/GroBuf/SizeCounters/LazySizeCounterBuilder.cs rename to GroBuf/SizeCounters/LazySizeCounterBuilder.cs index 3e65636..c1ea838 100644 --- a/GroBuf/GroBuf/SizeCounters/LazySizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/LazySizeCounterBuilder.cs @@ -1,60 +1,59 @@ -using System; -using System.Reflection; - -namespace GroBuf.SizeCounters -{ - internal class LazySizeCounterBuilder : SizeCounterBuilderBase - { - public LazySizeCounterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Lazy<>))) - throw new InvalidOperationException("Expected Lazy but was '" + Type + "'"); - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - context.BuildConstants(Type.GetGenericArguments()[0]); - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - var argument = Type.GetGenericArguments()[0]; - - context.LoadObj(); // stack: [obj] - var factoryField = Type.GetField("m_valueFactory", BindingFlags.Instance | BindingFlags.NonPublic); - il.Ldfld(factoryField); // stack: [obj.m_valueFactory] - var factory = il.DeclareLocal(typeof(Func<>).MakeGenericType(argument)); - il.Dup(); - il.Stloc(factory); // factory = obj.m_valueFactory; stack: [factory] - var countUsual = il.DefineLabel("countUsual"); - il.Brfalse(countUsual); // if(factory == null) goto countUsual; stack: [] - il.Ldloc(factory); // stack: [factory] - string targetFieldName = GroBufHelpers.IsMono ? "m_target" : "_target"; - il.Ldfld(typeof(Delegate).GetField(targetFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [factory.target] - var rawData = il.DeclareLocal(typeof(RawData<>).MakeGenericType(Type.GetGenericArguments())); - il.Isinst(rawData.Type); // stack: [factory.target as RawData] - il.Dup(); - il.Stloc(rawData); // rawData = factory.target as RawData; stack: [rawData] - il.Brfalse(countUsual); // if(!(rawData is RawData)) goto countUsual; stack: [] - il.Ldloc(rawData); // stack: [rawData] - il.Ldfld(rawData.Type.GetField("serializerId", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [rawData.serializerId] - context.LoadSerializerId(); // stack: [rawData.serializerId, context.serializerId] - il.Bne_Un(countUsual); // if(rawData.serializerId != context.serializerId) goto countUsual; stack: [] - il.Ldloc(rawData); // stack: [rawData] - il.Ldfld(rawData.Type.GetField("data", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [rawData.data] - il.Ldlen(); // stack: [rawData.data.Length] - il.Ret(); - - il.MarkLabel(countUsual); - context.LoadObj(); // stack: [obj] - il.Call(Type.GetProperty("Value", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Value] - context.LoadWriteEmpty(); // stack: [obj.Value, writeEmpty] - context.LoadContext(); // stack: [obj.Value, writeEmpty, context] - context.CallSizeCounter(argument); // stack: [counter(obj.Value, writeEmpty, context)] - } - - protected override bool IsReference { get { return false; } } - } +using System; +using System.Reflection; + +namespace GroBuf.SizeCounters +{ + internal class LazySizeCounterBuilder : SizeCounterBuilderBase + { + public LazySizeCounterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Lazy<>))) + throw new InvalidOperationException("Expected Lazy but was '" + Type + "'"); + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + context.BuildConstants(Type.GetGenericArguments()[0]); + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + var argument = Type.GetGenericArguments()[0]; + + context.LoadObj(); // stack: [obj] + var factoryField = Type.GetField(PlatformHelpers.LazyValueFactoryFieldName, BindingFlags.Instance | BindingFlags.NonPublic); + il.Ldfld(factoryField); // stack: [obj.m_valueFactory] + var factory = il.DeclareLocal(typeof(Func<>).MakeGenericType(argument)); + il.Dup(); + il.Stloc(factory); // factory = obj.m_valueFactory; stack: [factory] + var countUsual = il.DefineLabel("countUsual"); + il.Brfalse(countUsual); // if(factory == null) goto countUsual; stack: [] + il.Ldloc(factory); // stack: [factory] + il.Ldfld(typeof(Delegate).GetField(PlatformHelpers.DelegateTargetFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [factory.target] + var rawData = il.DeclareLocal(typeof(RawData<>).MakeGenericType(Type.GetGenericArguments())); + il.Isinst(rawData.Type); // stack: [factory.target as RawData] + il.Dup(); + il.Stloc(rawData); // rawData = factory.target as RawData; stack: [rawData] + il.Brfalse(countUsual); // if(!(rawData is RawData)) goto countUsual; stack: [] + il.Ldloc(rawData); // stack: [rawData] + il.Ldfld(rawData.Type.GetField("serializerId", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [rawData.serializerId] + context.LoadSerializerId(); // stack: [rawData.serializerId, context.serializerId] + il.Bne_Un(countUsual); // if(rawData.serializerId != context.serializerId) goto countUsual; stack: [] + il.Ldloc(rawData); // stack: [rawData] + il.Ldfld(rawData.Type.GetField("data", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [rawData.data] + il.Ldlen(); // stack: [rawData.data.Length] + il.Ret(); + + il.MarkLabel(countUsual); + context.LoadObj(); // stack: [obj] + il.Call(Type.GetProperty("Value", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Value] + context.LoadWriteEmpty(); // stack: [obj.Value, writeEmpty] + context.LoadContext(); // stack: [obj.Value, writeEmpty, context] + context.CallSizeCounter(argument); // stack: [counter(obj.Value, writeEmpty, context)] + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/ListSizeCounterBuilder.cs b/GroBuf/SizeCounters/ListSizeCounterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/ListSizeCounterBuilder.cs rename to GroBuf/SizeCounters/ListSizeCounterBuilder.cs index e15b08d..458cc90 100644 --- a/GroBuf/GroBuf/SizeCounters/ListSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/ListSizeCounterBuilder.cs @@ -1,87 +1,87 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.SizeCounters -{ - internal class ListSizeCounterBuilder : SizeCounterBuilderBase - { - public ListSizeCounterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(List<>))) - throw new InvalidOperationException("Expected list but was '" + Type + "'"); - elementType = Type.GetGenericArguments()[0]; - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] - context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + array length - - var count = il.DeclareLocal(typeof(int)); - context.LoadObj(); // stack: [9, obj] - il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [9, obj.Count] - il.Stloc(count); // count = obj.Count; stack: [9] - - il.Ldloc(count); // stack: [9, count] - var doneLabel = il.DefineLabel("done"); - il.Brfalse(doneLabel); // if(count == 0) goto done; stack: [9] - - var items = il.DeclareLocal(elementType.MakeArrayType()); - context.LoadObj(); // stack: [9, obj] - il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [9, obj._items] - il.Stloc(items); // items = obj._items; stack: [9] - var i = il.DeclareLocal(typeof(int)); - il.Ldc_I4(0); // stack: [9, 0] - il.Stloc(i); // i = 0; stack: [9] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - - il.Ldloc(items); // stack: [size, items] - il.Ldloc(i); // stack: [size, items, i] - il.Ldelem(elementType); - il.Ldc_I4(1); // stack: [size, obj[i], true] - context.LoadContext(); // stack: [size, obj[i], true, context] - context.CallSizeCounter(elementType); // stack: [size, writer(obj[i], true, context) = itemSize] - il.Add(); // stack: [size + itemSize] - il.Ldloc(count); // stack: [size, length] - il.Ldloc(i); // stack: [size, length, i] - il.Ldc_I4(1); // stack: [size, length, i, 1] - il.Add(); // stack: [size, length, i + 1] - il.Dup(); // stack: [size, length, i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [size, length, i] - il.Bgt(cycleStartLabel, false); // if(length > i) goto cycleStart; stack: [size] - - il.MarkLabel(doneLabel); - } - - private readonly Type elementType; - } +using System; +using System.Collections.Generic; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.SizeCounters +{ + internal class ListSizeCounterBuilder : SizeCounterBuilderBase + { + public ListSizeCounterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(List<>))) + throw new InvalidOperationException("Expected list but was '" + Type + "'"); + elementType = Type.GetGenericArguments()[0]; + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] + context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + il.Ldc_I4(9); // stack: [9 = size] 9 = type code + data length + array length + + var count = il.DeclareLocal(typeof(int)); + context.LoadObj(); // stack: [9, obj] + il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [9, obj.Count] + il.Stloc(count); // count = obj.Count; stack: [9] + + il.Ldloc(count); // stack: [9, count] + var doneLabel = il.DefineLabel("done"); + il.Brfalse(doneLabel); // if(count == 0) goto done; stack: [9] + + var items = il.DeclareLocal(elementType.MakeArrayType()); + context.LoadObj(); // stack: [9, obj] + il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [9, obj._items] + il.Stloc(items); // items = obj._items; stack: [9] + var i = il.DeclareLocal(typeof(int)); + il.Ldc_I4(0); // stack: [9, 0] + il.Stloc(i); // i = 0; stack: [9] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + + il.Ldloc(items); // stack: [size, items] + il.Ldloc(i); // stack: [size, items, i] + il.Ldelem(elementType); + il.Ldc_I4(1); // stack: [size, obj[i], true] + context.LoadContext(); // stack: [size, obj[i], true, context] + context.CallSizeCounter(elementType); // stack: [size, writer(obj[i], true, context) = itemSize] + il.Add(); // stack: [size + itemSize] + il.Ldloc(count); // stack: [size, length] + il.Ldloc(i); // stack: [size, length, i] + il.Ldc_I4(1); // stack: [size, length, i, 1] + il.Add(); // stack: [size, length, i + 1] + il.Dup(); // stack: [size, length, i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [size, length, i] + il.Bgt(cycleStartLabel, false); // if(length > i) goto cycleStart; stack: [size] + + il.MarkLabel(doneLabel); + } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/NullableSizeCounterBuilder.cs b/GroBuf/SizeCounters/NullableSizeCounterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/NullableSizeCounterBuilder.cs rename to GroBuf/SizeCounters/NullableSizeCounterBuilder.cs index 46ef733..3479b75 100644 --- a/GroBuf/GroBuf/SizeCounters/NullableSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/NullableSizeCounterBuilder.cs @@ -1,42 +1,42 @@ -using System; - -using GrEmit; - -namespace GroBuf.SizeCounters -{ - internal class NullableSizeCounterBuilder : SizeCounterBuilderBase - { - public NullableSizeCounterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Nullable<>))) - throw new InvalidOperationException("Expected nullable but was '" + Type + "'"); - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - context.BuildConstants(Type.GetGenericArguments()[0]); - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - - context.LoadObjByRef(); // stack: [&obj] - il.Call(Type.GetProperty("Value").GetGetMethod()); // stack: [obj.Value] - context.LoadWriteEmpty(); // stack: [obj.Value, writeEmpty] - context.LoadContext(); // stack: [obj.Value, writeEmpty, context] - context.CallSizeCounter(Type.GetGenericArguments()[0]); // stack: [counter(obj.Value, writeEmpty, context)] - } - - protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObjByRef(); // stack: [&obj] - context.Il.Call(Type.GetProperty("HasValue").GetGetMethod()); // stack: obj.HasValue - context.Il.Brtrue(notEmptyLabel); // if(obj.HasValue) goto notEmpty; - return true; - } - - protected override bool IsReference { get { return false; } } - } +using System; + +using GrEmit; + +namespace GroBuf.SizeCounters +{ + internal class NullableSizeCounterBuilder : SizeCounterBuilderBase + { + public NullableSizeCounterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Nullable<>))) + throw new InvalidOperationException("Expected nullable but was '" + Type + "'"); + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + context.BuildConstants(Type.GetGenericArguments()[0]); + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + + context.LoadObjByRef(); // stack: [&obj] + il.Call(Type.GetProperty("Value").GetGetMethod()); // stack: [obj.Value] + context.LoadWriteEmpty(); // stack: [obj.Value, writeEmpty] + context.LoadContext(); // stack: [obj.Value, writeEmpty, context] + context.CallSizeCounter(Type.GetGenericArguments()[0]); // stack: [counter(obj.Value, writeEmpty, context)] + } + + protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObjByRef(); // stack: [&obj] + context.Il.Call(Type.GetProperty("HasValue").GetGetMethod()); // stack: obj.HasValue + context.Il.Brtrue(notEmptyLabel); // if(obj.HasValue) goto notEmpty; + return true; + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/ObjectSizeCounterBuilder.cs b/GroBuf/SizeCounters/ObjectSizeCounterBuilder.cs similarity index 98% rename from GroBuf/GroBuf/SizeCounters/ObjectSizeCounterBuilder.cs rename to GroBuf/SizeCounters/ObjectSizeCounterBuilder.cs index 8f4c6d4..2ab5df4 100644 --- a/GroBuf/GroBuf/SizeCounters/ObjectSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/ObjectSizeCounterBuilder.cs @@ -1,116 +1,116 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Reflection.Emit; - -using GrEmit; - -namespace GroBuf.SizeCounters -{ - internal class ObjectSizeCounterBuilder : SizeCounterBuilderBase - { - public ObjectSizeCounterBuilder() - : base(typeof(object)) - { - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - context.SetFields(Type, new[] - { - new KeyValuePair("counters_" + Type.Name + "_" + Guid.NewGuid(), typeof(IntPtr[])), - new KeyValuePair("delegates_" + Type.Name + "_" + Guid.NewGuid(), typeof(Delegate[])) // This field is needed only to save references to the dynamic methods. Otherwise GC will destroy them - }); - Array.ForEach(GroBufHelpers.LeafTypes.Where(type => type != null).ToArray(), type => context.BuildConstants(type)); - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - - var counters = GroBufHelpers.LeafTypes.Select(type1 => type1 == null ? new KeyValuePair(null, IntPtr.Zero) : GetCounter(context, type1)).ToArray(); - var countersField = context.Context.InitConstField(Type, 0, counters.Select(pair => pair.Value).ToArray()); - context.Context.InitConstField(Type, 1, counters.Select(pair => pair.Key).ToArray()); - - il.Ldfld(typeof(GroBufHelpers).GetField("LeafTypeHandles", BindingFlags.Public | BindingFlags.Static)); // stack: [LeafTypeHandles] - context.LoadObj(); // stack: [LeafTypeHandles, obj] - il.Call(getTypeMethod); // stack: [LeafTypeHandles, obj.GetType()] - var type = il.DeclareLocal(typeof(Type)); - il.Dup(); // stack: [LeafTypeHandles, obj.GetType(), obj.GetType()] - il.Stloc(type); // type = obj.GetType(); stack: [LeafTypeHandles, obj.GetType()] - il.Call(typeTypeHandleProperty.GetGetMethod()); // stack: [LeafTypeHandles, obj.GetType().TypeHandle] - var typeHandle = il.DeclareLocal(typeof(RuntimeTypeHandle)); - il.Stloc(typeHandle); // typeHandle = obj.GetType().TypeHandle; stack: [LeafTypeHandles] - il.Ldloca(typeHandle); // stack: [LeafTypeHandles, ref typeHandle] - il.Call(runtimeTypeHandleValueProperty.GetGetMethod(), typeof(RuntimeTypeHandle)); // stack: [LeafTypeHandles, obj.GetType().TypeHandle.Value] - var handle = il.DeclareLocal(typeof(IntPtr)); - il.Dup(); // stack: [LeafTypeHandles, obj.GetType().TypeHandle.Value, obj.GetType().TypeHandle.Value] - il.Stloc(handle); // handle = obj.GetType().TypeHandle.Value; stack: [LeafTypeHandles, handle] - il.Ldc_I4(counters.Length); // stack: [LeafTypeHandles, handle, LeafTypeHandles.Length] - il.Rem(true); // stack: [LeafTypeHandles, handle % LeafTypeHandles.Length] - var index = il.DeclareLocal(typeof(int)); - il.Conv(); // stack: [LeafTypeHandles, (int)(handle % LeafTypeHandles.Length)] - il.Dup(); // stack: [LeafTypeHandles, (int)(handle % LeafTypeHandles.Length), (int)(handle % LeafTypeHandles.Length)] - il.Stloc(index); // index = (int)(handle % LeafTypeHandles.Length); stack: [LeafTypeHandles, index] - il.Ldelem(typeof(IntPtr)); // stack: [LeafTypeHandles[index]] - il.Ldloc(handle); // stack: [LeafTypeHandles[index], handle] - var tryAsArrayLabel = il.DefineLabel("tryAsArray"); - il.Bne_Un(tryAsArrayLabel); // if(LeafTypeHandles[index] != handle) goto tryAsArray; stack: [] - context.LoadObj(); // stack: [obj] - context.LoadWriteEmpty(); // stack: [obj, writeEmpty] - context.LoadContext(); // stack: [obj, writeEmpty, context] - context.LoadField(countersField); // stack: [obj, writeEmpty, context, counters] - il.Ldloc(index); // stack: [obj, writeEmpty, context, counters, index] - il.Ldelem(typeof(IntPtr)); // stack: [obj, writeEmpty, context, counters[index]] - var parameterTypes = new[] {typeof(object), typeof(bool), typeof(WriterContext)}; - il.Calli(CallingConventions.Standard, typeof(int), parameterTypes); // stack: [counters[index](obj, writeEmpty)] - il.Ret(); - - il.MarkLabel(tryAsArrayLabel); - il.Ldloc(type); // stack: [obj.GetType()] - il.Call(typeIsArrayProperty.GetGetMethod()); // stack: [obj.GetType().IsArray] - var returnForNullLabel = il.DefineLabel("returnForNull"); - il.Brfalse(returnForNullLabel); - context.LoadObj(); // stack: [obj] - context.LoadWriteEmpty(); // stack: [obj, writeEmpty] - context.LoadContext(); // stack: [obj, writeEmpty, context] - context.LoadField(countersField); // stack: [obj, writeEmpty, context, counters] - il.Ldc_I4(Array.IndexOf(GroBufHelpers.LeafTypes, typeof(object[]))); // stack: [obj, writeEmpty, context, counters, index of typeof(object[])] - il.Ldelem(typeof(IntPtr)); // stack: [obj, writeEmpty, context, counters[index of typeof(object[])]] - parameterTypes = new[] {typeof(object), typeof(bool), typeof(WriterContext)}; - il.Calli(CallingConventions.Standard, typeof(int), parameterTypes); // stack: [counters[index of typeof(object[])](obj, writeEmpty)] - il.Ret(); - - il.MarkLabel(returnForNullLabel); - context.ReturnForNull(); - } - - protected override bool IsReference { get { return false; } } - - private static KeyValuePair GetCounter(SizeCounterMethodBuilderContext context, Type type) - { - var method = new DynamicMethod("CastTo_" + type.Name + "_AndCount_" + Guid.NewGuid(), typeof(int), new[] {typeof(object), typeof(bool), typeof(WriterContext)}, context.Context.Module, true); - using (var il = new GroboIL(method)) - { - il.Ldarg(0); // stack: [obj] - if(type.IsValueType) - il.Unbox_Any(type); // stack: [(type)obj] - else - il.Castclass(type); // stack: [(type)obj] - il.Ldarg(1); // stack: [(type)obj, writeEmpty] - il.Ldarg(2); // stack: [(type)obj, writeEmpty, context] - context.CallSizeCounter(il, type); - il.Ret(); - } - var @delegate = method.CreateDelegate(typeof(SizeCounterDelegate)); - return new KeyValuePair(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)); - } - - private static readonly MethodInfo getTypeMethod = ((MethodCallExpression)((Expression>)(obj => obj.GetType())).Body).Method; - private static readonly PropertyInfo typeTypeHandleProperty = (PropertyInfo)((MemberExpression)((Expression>)(type => type.TypeHandle)).Body).Member; - private static readonly PropertyInfo runtimeTypeHandleValueProperty = (PropertyInfo)((MemberExpression)((Expression>)(handle => handle.Value)).Body).Member; - private static readonly PropertyInfo typeIsArrayProperty = (PropertyInfo)((MemberExpression)((Expression>)(type => type.IsArray)).Body).Member; - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Reflection.Emit; + +using GrEmit; + +namespace GroBuf.SizeCounters +{ + internal class ObjectSizeCounterBuilder : SizeCounterBuilderBase + { + public ObjectSizeCounterBuilder() + : base(typeof(object)) + { + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + context.SetFields(Type, new[] + { + new KeyValuePair("counters_" + Type.Name + "_" + Guid.NewGuid(), typeof(IntPtr[])), + new KeyValuePair("delegates_" + Type.Name + "_" + Guid.NewGuid(), typeof(Delegate[])) // This field is needed only to save references to the dynamic methods. Otherwise GC will destroy them + }); + Array.ForEach(GroBufHelpers.LeafTypes.Where(type => type != null).ToArray(), type => context.BuildConstants(type)); + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + + var counters = GroBufHelpers.LeafTypes.Select(type1 => type1 == null ? new KeyValuePair(null, IntPtr.Zero) : GetCounter(context, type1)).ToArray(); + var countersField = context.Context.InitConstField(Type, 0, counters.Select(pair => pair.Value).ToArray()); + context.Context.InitConstField(Type, 1, counters.Select(pair => pair.Key).ToArray()); + + il.Ldfld(typeof(GroBufHelpers).GetField("LeafTypeHandles", BindingFlags.Public | BindingFlags.Static)); // stack: [LeafTypeHandles] + context.LoadObj(); // stack: [LeafTypeHandles, obj] + il.Call(getTypeMethod); // stack: [LeafTypeHandles, obj.GetType()] + var type = il.DeclareLocal(typeof(Type)); + il.Dup(); // stack: [LeafTypeHandles, obj.GetType(), obj.GetType()] + il.Stloc(type); // type = obj.GetType(); stack: [LeafTypeHandles, obj.GetType()] + il.Call(typeTypeHandleProperty.GetGetMethod()); // stack: [LeafTypeHandles, obj.GetType().TypeHandle] + var typeHandle = il.DeclareLocal(typeof(RuntimeTypeHandle)); + il.Stloc(typeHandle); // typeHandle = obj.GetType().TypeHandle; stack: [LeafTypeHandles] + il.Ldloca(typeHandle); // stack: [LeafTypeHandles, ref typeHandle] + il.Call(runtimeTypeHandleValueProperty.GetGetMethod(), typeof(RuntimeTypeHandle)); // stack: [LeafTypeHandles, obj.GetType().TypeHandle.Value] + var handle = il.DeclareLocal(typeof(IntPtr)); + il.Dup(); // stack: [LeafTypeHandles, obj.GetType().TypeHandle.Value, obj.GetType().TypeHandle.Value] + il.Stloc(handle); // handle = obj.GetType().TypeHandle.Value; stack: [LeafTypeHandles, handle] + il.Ldc_I4(counters.Length); // stack: [LeafTypeHandles, handle, LeafTypeHandles.Length] + il.Rem(true); // stack: [LeafTypeHandles, handle % LeafTypeHandles.Length] + var index = il.DeclareLocal(typeof(int)); + il.Conv(); // stack: [LeafTypeHandles, (int)(handle % LeafTypeHandles.Length)] + il.Dup(); // stack: [LeafTypeHandles, (int)(handle % LeafTypeHandles.Length), (int)(handle % LeafTypeHandles.Length)] + il.Stloc(index); // index = (int)(handle % LeafTypeHandles.Length); stack: [LeafTypeHandles, index] + il.Ldelem(typeof(IntPtr)); // stack: [LeafTypeHandles[index]] + il.Ldloc(handle); // stack: [LeafTypeHandles[index], handle] + var tryAsArrayLabel = il.DefineLabel("tryAsArray"); + il.Bne_Un(tryAsArrayLabel); // if(LeafTypeHandles[index] != handle) goto tryAsArray; stack: [] + context.LoadObj(); // stack: [obj] + context.LoadWriteEmpty(); // stack: [obj, writeEmpty] + context.LoadContext(); // stack: [obj, writeEmpty, context] + context.LoadField(countersField); // stack: [obj, writeEmpty, context, counters] + il.Ldloc(index); // stack: [obj, writeEmpty, context, counters, index] + il.Ldelem(typeof(IntPtr)); // stack: [obj, writeEmpty, context, counters[index]] + var parameterTypes = new[] {typeof(object), typeof(bool), typeof(WriterContext)}; + il.Calli(CallingConventions.Standard, typeof(int), parameterTypes); // stack: [counters[index](obj, writeEmpty)] + il.Ret(); + + il.MarkLabel(tryAsArrayLabel); + il.Ldloc(type); // stack: [obj.GetType()] + il.Call(typeIsArrayProperty.GetGetMethod()); // stack: [obj.GetType().IsArray] + var returnForNullLabel = il.DefineLabel("returnForNull"); + il.Brfalse(returnForNullLabel); + context.LoadObj(); // stack: [obj] + context.LoadWriteEmpty(); // stack: [obj, writeEmpty] + context.LoadContext(); // stack: [obj, writeEmpty, context] + context.LoadField(countersField); // stack: [obj, writeEmpty, context, counters] + il.Ldc_I4(Array.IndexOf(GroBufHelpers.LeafTypes, typeof(object[]))); // stack: [obj, writeEmpty, context, counters, index of typeof(object[])] + il.Ldelem(typeof(IntPtr)); // stack: [obj, writeEmpty, context, counters[index of typeof(object[])]] + parameterTypes = new[] {typeof(object), typeof(bool), typeof(WriterContext)}; + il.Calli(CallingConventions.Standard, typeof(int), parameterTypes); // stack: [counters[index of typeof(object[])](obj, writeEmpty)] + il.Ret(); + + il.MarkLabel(returnForNullLabel); + context.ReturnForNull(); + } + + protected override bool IsReference { get { return false; } } + + private static KeyValuePair GetCounter(SizeCounterMethodBuilderContext context, Type type) + { + var method = new DynamicMethod("CastTo_" + type.Name + "_AndCount_" + Guid.NewGuid(), typeof(int), new[] {typeof(object), typeof(bool), typeof(WriterContext)}, context.Context.Module, true); + using (var il = new GroboIL(method)) + { + il.Ldarg(0); // stack: [obj] + if(type.IsValueType) + il.Unbox_Any(type); // stack: [(type)obj] + else + il.Castclass(type); // stack: [(type)obj] + il.Ldarg(1); // stack: [(type)obj, writeEmpty] + il.Ldarg(2); // stack: [(type)obj, writeEmpty, context] + context.CallSizeCounter(il, type); + il.Ret(); + } + var @delegate = method.CreateDelegate(typeof(SizeCounterDelegate)); + return new KeyValuePair(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)); + } + + private static readonly MethodInfo getTypeMethod = ((MethodCallExpression)((Expression>)(obj => obj.GetType())).Body).Method; + private static readonly PropertyInfo typeTypeHandleProperty = (PropertyInfo)((MemberExpression)((Expression>)(type => type.TypeHandle)).Body).Member; + private static readonly PropertyInfo runtimeTypeHandleValueProperty = (PropertyInfo)((MemberExpression)((Expression>)(handle => handle.Value)).Body).Member; + private static readonly PropertyInfo typeIsArrayProperty = (PropertyInfo)((MemberExpression)((Expression>)(type => type.IsArray)).Body).Member; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/PrimitivesArraySegmentSizeCounterBuilder.cs b/GroBuf/SizeCounters/PrimitivesArraySegmentSizeCounterBuilder.cs similarity index 100% rename from GroBuf/GroBuf/SizeCounters/PrimitivesArraySegmentSizeCounterBuilder.cs rename to GroBuf/SizeCounters/PrimitivesArraySegmentSizeCounterBuilder.cs diff --git a/GroBuf/GroBuf/SizeCounters/PrimitivesArraySizeCounterBuilder.cs b/GroBuf/SizeCounters/PrimitivesArraySizeCounterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/PrimitivesArraySizeCounterBuilder.cs rename to GroBuf/SizeCounters/PrimitivesArraySizeCounterBuilder.cs index ba27dec..6719132 100644 --- a/GroBuf/GroBuf/SizeCounters/PrimitivesArraySizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/PrimitivesArraySizeCounterBuilder.cs @@ -1,91 +1,91 @@ -using System; - -using GrEmit; - -namespace GroBuf.SizeCounters -{ - internal class PrimitivesArraySizeCounterBuilder : SizeCounterBuilderBase - { - public PrimitivesArraySizeCounterBuilder(Type type) - : base(type) - { - if(!Type.IsArray) throw new InvalidOperationException("An array expected but was '" + Type + "'"); - if(Type.GetArrayRank() != 1) throw new NotSupportedException("Arrays with rank greater than 1 are not supported"); - elementType = Type.GetElementType(); - if(!elementType.IsPrimitive) throw new NotSupportedException("Array of primitive type expected but was '" + Type + "'"); - } - - protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Ldlen(); // stack: [obj.Length] - context.Il.Brtrue(notEmptyLabel); // if(obj.Length != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - il.Ldc_I4(5); // stack: [5 = size] 5 = type code + data length - context.LoadObj(); // stack: [5, obj] - il.Ldlen(); // stack: [5, obj.Length] - CountArraySize(elementType, il); // stack: [5, obj length] - il.Add(); // stack: [5 + obj length] - } - - private static void CountArraySize(Type elementType, GroboIL il) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(1); - il.Shl(); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(3); - il.Shl(); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(3); - il.Shl(); - break; - default: - throw new NotSupportedException("Type '" + elementType + "' is not supported"); - } - } - - private readonly Type elementType; - } +using System; + +using GrEmit; + +namespace GroBuf.SizeCounters +{ + internal class PrimitivesArraySizeCounterBuilder : SizeCounterBuilderBase + { + public PrimitivesArraySizeCounterBuilder(Type type) + : base(type) + { + if(!Type.IsArray) throw new InvalidOperationException("An array expected but was '" + Type + "'"); + if(Type.GetArrayRank() != 1) throw new NotSupportedException("Arrays with rank greater than 1 are not supported"); + elementType = Type.GetElementType(); + if(!elementType.IsPrimitive) throw new NotSupportedException("Array of primitive type expected but was '" + Type + "'"); + } + + protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Ldlen(); // stack: [obj.Length] + context.Il.Brtrue(notEmptyLabel); // if(obj.Length != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + il.Ldc_I4(5); // stack: [5 = size] 5 = type code + data length + context.LoadObj(); // stack: [5, obj] + il.Ldlen(); // stack: [5, obj.Length] + CountArraySize(elementType, il); // stack: [5, obj length] + il.Add(); // stack: [5 + obj length] + } + + private static void CountArraySize(Type elementType, GroboIL il) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(1); + il.Shl(); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(3); + il.Shl(); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(3); + il.Shl(); + break; + default: + throw new NotSupportedException("Type '" + elementType + "' is not supported"); + } + } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/PrimitivesHashSetSizeCounterBuilder.cs b/GroBuf/SizeCounters/PrimitivesHashSetSizeCounterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/PrimitivesHashSetSizeCounterBuilder.cs rename to GroBuf/SizeCounters/PrimitivesHashSetSizeCounterBuilder.cs index 5531095..a29e578 100644 --- a/GroBuf/GroBuf/SizeCounters/PrimitivesHashSetSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/PrimitivesHashSetSizeCounterBuilder.cs @@ -1,94 +1,94 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.SizeCounters -{ - internal class PrimitivesHashSetSizeCounterBuilder : SizeCounterBuilderBase - { - public PrimitivesHashSetSizeCounterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(HashSet<>))) - throw new InvalidOperationException("HashSet expected but was '" + Type + "'"); - elementType = Type.GetGenericArguments()[0]; - if(!elementType.IsPrimitive) - throw new NotSupportedException("HashSet of primitive type expected but was '" + Type + "'"); - } - - protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [&result[index], obj.Count] - context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - il.Ldc_I4(5); // stack: [5 = size] 5 = type code + data length - context.LoadObj(); // stack: [5, obj] - context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [5, obj.Count] - CountArraySize(elementType, il); // stack: [5, obj length] - il.Add(); // stack: [5 + obj length] - } - - private static void CountArraySize(Type elementType, GroboIL il) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(1); - il.Shl(); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(3); - il.Shl(); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(3); - il.Shl(); - break; - default: - throw new NotSupportedException("Type '" + elementType + "' is not supported"); - } - } - - private readonly Type elementType; - } +using System; +using System.Collections.Generic; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.SizeCounters +{ + internal class PrimitivesHashSetSizeCounterBuilder : SizeCounterBuilderBase + { + public PrimitivesHashSetSizeCounterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(HashSet<>))) + throw new InvalidOperationException("HashSet expected but was '" + Type + "'"); + elementType = Type.GetGenericArguments()[0]; + if(!elementType.IsPrimitive) + throw new NotSupportedException("HashSet of primitive type expected but was '" + Type + "'"); + } + + protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [&result[index], obj.Count] + context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + il.Ldc_I4(5); // stack: [5 = size] 5 = type code + data length + context.LoadObj(); // stack: [5, obj] + context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [5, obj.Count] + CountArraySize(elementType, il); // stack: [5, obj length] + il.Add(); // stack: [5 + obj length] + } + + private static void CountArraySize(Type elementType, GroboIL il) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(1); + il.Shl(); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(3); + il.Shl(); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(3); + il.Shl(); + break; + default: + throw new NotSupportedException("Type '" + elementType + "' is not supported"); + } + } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/PrimitivesListSizeCounterBuilder.cs b/GroBuf/SizeCounters/PrimitivesListSizeCounterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/PrimitivesListSizeCounterBuilder.cs rename to GroBuf/SizeCounters/PrimitivesListSizeCounterBuilder.cs index 00e4258..9fb8db6 100644 --- a/GroBuf/GroBuf/SizeCounters/PrimitivesListSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/PrimitivesListSizeCounterBuilder.cs @@ -1,94 +1,94 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.SizeCounters -{ - internal class PrimitivesListSizeCounterBuilder : SizeCounterBuilderBase - { - public PrimitivesListSizeCounterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(List<>))) - throw new InvalidOperationException("Expected list but was '" + Type + "'"); - elementType = Type.GetGenericArguments()[0]; - if(!elementType.IsPrimitive) - throw new NotSupportedException("List of primitive type expected but was '" + Type + "'"); - } - - protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] - context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - il.Ldc_I4(5); // stack: [5 = size] 5 = type code + data length - context.LoadObj(); // stack: [5, obj] - il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [5, obj.Count] - CountArraySize(elementType, il); // stack: [5, obj length] - il.Add(); // stack: [5 + obj length] - } - - private static void CountArraySize(Type elementType, GroboIL il) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(1); - il.Shl(); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(3); - il.Shl(); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(3); - il.Shl(); - break; - default: - throw new NotSupportedException("Type '" + elementType + "' is not supported"); - } - } - - private readonly Type elementType; - } +using System; +using System.Collections.Generic; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.SizeCounters +{ + internal class PrimitivesListSizeCounterBuilder : SizeCounterBuilderBase + { + public PrimitivesListSizeCounterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(List<>))) + throw new InvalidOperationException("Expected list but was '" + Type + "'"); + elementType = Type.GetGenericArguments()[0]; + if(!elementType.IsPrimitive) + throw new NotSupportedException("List of primitive type expected but was '" + Type + "'"); + } + + protected override bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] + context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + il.Ldc_I4(5); // stack: [5 = size] 5 = type code + data length + context.LoadObj(); // stack: [5, obj] + il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [5, obj.Count] + CountArraySize(elementType, il); // stack: [5, obj length] + il.Add(); // stack: [5 + obj length] + } + + private static void CountArraySize(Type elementType, GroboIL il) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(1); + il.Shl(); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(3); + il.Shl(); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(3); + il.Shl(); + break; + default: + throw new NotSupportedException("Type '" + elementType + "' is not supported"); + } + } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/PrimitivesSizeCounterBuilder.cs b/GroBuf/SizeCounters/PrimitivesSizeCounterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/PrimitivesSizeCounterBuilder.cs rename to GroBuf/SizeCounters/PrimitivesSizeCounterBuilder.cs index 95a5997..a21e639 100644 --- a/GroBuf/GroBuf/SizeCounters/PrimitivesSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/PrimitivesSizeCounterBuilder.cs @@ -1,56 +1,56 @@ -using System; - -namespace GroBuf.SizeCounters -{ - internal class PrimitivesSizeCounterBuilder : SizeCounterBuilderBase - { - public PrimitivesSizeCounterBuilder(Type type) - : base(type) - { - if(!Type.IsPrimitive && Type != typeof(decimal)) throw new InvalidOperationException("Expected primitive type but was '" + Type + "'"); - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(Type); - var il = context.Il; - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - il.Ldc_I4(2); - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(3); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(5); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(9); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(5); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(9); - break; - case GroBufTypeCode.Decimal: - il.Ldc_I4(17); - break; - default: - throw new NotSupportedException("Type '" + Type + "' is not supported"); - } - } - - protected override bool IsReference { get { return false; } } - } +using System; + +namespace GroBuf.SizeCounters +{ + internal class PrimitivesSizeCounterBuilder : SizeCounterBuilderBase + { + public PrimitivesSizeCounterBuilder(Type type) + : base(type) + { + if(!Type.IsPrimitive && Type != typeof(decimal)) throw new InvalidOperationException("Expected primitive type but was '" + Type + "'"); + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(Type); + var il = context.Il; + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + il.Ldc_I4(2); + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(3); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(5); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(9); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(5); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(9); + break; + case GroBufTypeCode.Decimal: + il.Ldc_I4(17); + break; + default: + throw new NotSupportedException("Type '" + Type + "' is not supported"); + } + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/SizeCounterBuilderBase.cs b/GroBuf/SizeCounters/SizeCounterBuilderBase.cs similarity index 98% rename from GroBuf/GroBuf/SizeCounters/SizeCounterBuilderBase.cs rename to GroBuf/SizeCounters/SizeCounterBuilderBase.cs index bb95070..1f29322 100644 --- a/GroBuf/GroBuf/SizeCounters/SizeCounterBuilderBase.cs +++ b/GroBuf/SizeCounters/SizeCounterBuilderBase.cs @@ -1,96 +1,96 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Reflection.Emit; - -using GrEmit; -using GrEmit.Utils; - -namespace GroBuf.SizeCounters -{ - internal abstract class SizeCounterBuilderBase : ISizeCounterBuilder - { - protected SizeCounterBuilderBase(Type type) - { - Type = type; - } - - public void BuildSizeCounter(SizeCounterBuilderContext sizeCounterBuilderContext) - { - var method = new DynamicMethod("Count_" + Type.Name + "_" + Guid.NewGuid(), typeof(int), new[] {Type, typeof(bool), typeof(WriterContext)}, sizeCounterBuilderContext.Module, true); - sizeCounterBuilderContext.SetSizeCounterMethod(Type, method); - using (var il = new GroboIL(method)) - { - var context = new SizeCounterMethodBuilderContext(sizeCounterBuilderContext, il); - - var notEmptyLabel = il.DefineLabel("notEmpty"); - if(CheckEmpty(context, notEmptyLabel)) // Check if obj is empty - context.ReturnForNull(); // return for null - il.MarkLabel(notEmptyLabel); // Now we know that obj is not empty - - if(!Type.IsValueType && IsReference && sizeCounterBuilderContext.GroBufWriter.Options.HasFlag(GroBufOptions.PackReferences)) - { - // Pack reference - var index = il.DeclareLocal(typeof(int)); - context.LoadContext(); // stack: [context] - il.Dup(); // stack: [context, context] - il.Ldfld(WriterContext.IndexField); // stack: [context, context.index] - il.Stloc(index); // index = context.index; stack: [context] - il.Ldfld(WriterContext.ObjectsField); // stack: [context.objects] - context.LoadObj(); // stack: [context.objects, obj] - il.Call(HackHelpers.GetMethodDefinition>(dict => dict.ContainsKey(null))); // stack: [context.object.ContainsKey(obj)] - var storeLocationLabel = il.DefineLabel("storeLocation"); - il.Brfalse(storeLocationLabel); // if(!context.objects.ContainsKey(obj)) goto storeLocation; stack: [] - context.LoadContext(); // stack: [context] - il.Dup(); // stack: [context, context] - il.Ldfld(WriterContext.ReferencesField); // stack: [context, context.references] - il.Ldc_I4(1); // stack: [context, context.references, 1] - il.Add(); // stack: [context, context.references + 1] - il.Stfld(WriterContext.ReferencesField); // context.references += 1; stack: [] - il.Ldc_I4(5); // stack: [5] - il.Ret(); // return 5 - il.MarkLabel(storeLocationLabel); - context.LoadContext(); // stack: [context] - il.Ldfld(typeof(WriterContext).GetField("objects", BindingFlags.Public | BindingFlags.Instance)); // stack: [context.objects] - context.LoadObj(); // stack: [context.objects, obj] - il.Ldloc(index); // stack: [context.objects, obj, index] - il.Call(HackHelpers.GetMethodDefinition>(dict => dict.Add(null, 0))); // context.objects.Add(obj, index); - } - - CountSizeNotEmpty(context); // Count size - il.Ret(); - } - var @delegate = method.CreateDelegate(typeof(SizeCounterDelegate<>).MakeGenericType(Type)); - var pointer = GroBufHelpers.ExtractDynamicMethodPointer(method); - sizeCounterBuilderContext.SetSizeCounterPointer(Type, pointer, @delegate); - } - - public void BuildConstants(SizeCounterConstantsBuilderContext context) - { - context.SetFields(Type, new KeyValuePair[0]); - BuildConstantsInternal(context); - } - - protected abstract void BuildConstantsInternal(SizeCounterConstantsBuilderContext context); - - protected abstract void CountSizeNotEmpty(SizeCounterMethodBuilderContext context); - - /// - /// Checks whether obj is empty - /// - /// Current context - /// Label where to go if obj is not empty - /// true if obj can be empty - protected virtual bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - if(Type.IsValueType) return false; - context.LoadObj(); // stack: [obj] - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - return true; - } - - protected abstract bool IsReference { get; } - - protected Type Type { get; private set; } - } +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; + +using GrEmit; +using GrEmit.Utils; + +namespace GroBuf.SizeCounters +{ + internal abstract class SizeCounterBuilderBase : ISizeCounterBuilder + { + protected SizeCounterBuilderBase(Type type) + { + Type = type; + } + + public void BuildSizeCounter(SizeCounterBuilderContext sizeCounterBuilderContext) + { + var method = new DynamicMethod("Count_" + Type.Name + "_" + Guid.NewGuid(), typeof(int), new[] {Type, typeof(bool), typeof(WriterContext)}, sizeCounterBuilderContext.Module, true); + sizeCounterBuilderContext.SetSizeCounterMethod(Type, method); + using (var il = new GroboIL(method)) + { + var context = new SizeCounterMethodBuilderContext(sizeCounterBuilderContext, il); + + var notEmptyLabel = il.DefineLabel("notEmpty"); + if(CheckEmpty(context, notEmptyLabel)) // Check if obj is empty + context.ReturnForNull(); // return for null + il.MarkLabel(notEmptyLabel); // Now we know that obj is not empty + + if(!Type.IsValueType && IsReference && sizeCounterBuilderContext.GroBufWriter.Options.HasFlag(GroBufOptions.PackReferences)) + { + // Pack reference + var index = il.DeclareLocal(typeof(int)); + context.LoadContext(); // stack: [context] + il.Dup(); // stack: [context, context] + il.Ldfld(WriterContext.IndexField); // stack: [context, context.index] + il.Stloc(index); // index = context.index; stack: [context] + il.Ldfld(WriterContext.ObjectsField); // stack: [context.objects] + context.LoadObj(); // stack: [context.objects, obj] + il.Call(HackHelpers.GetMethodDefinition>(dict => dict.ContainsKey(null))); // stack: [context.object.ContainsKey(obj)] + var storeLocationLabel = il.DefineLabel("storeLocation"); + il.Brfalse(storeLocationLabel); // if(!context.objects.ContainsKey(obj)) goto storeLocation; stack: [] + context.LoadContext(); // stack: [context] + il.Dup(); // stack: [context, context] + il.Ldfld(WriterContext.ReferencesField); // stack: [context, context.references] + il.Ldc_I4(1); // stack: [context, context.references, 1] + il.Add(); // stack: [context, context.references + 1] + il.Stfld(WriterContext.ReferencesField); // context.references += 1; stack: [] + il.Ldc_I4(5); // stack: [5] + il.Ret(); // return 5 + il.MarkLabel(storeLocationLabel); + context.LoadContext(); // stack: [context] + il.Ldfld(typeof(WriterContext).GetField("objects", BindingFlags.Public | BindingFlags.Instance)); // stack: [context.objects] + context.LoadObj(); // stack: [context.objects, obj] + il.Ldloc(index); // stack: [context.objects, obj, index] + il.Call(HackHelpers.GetMethodDefinition>(dict => dict.Add(null, 0))); // context.objects.Add(obj, index); + } + + CountSizeNotEmpty(context); // Count size + il.Ret(); + } + var @delegate = method.CreateDelegate(typeof(SizeCounterDelegate<>).MakeGenericType(Type)); + var pointer = GroBufHelpers.ExtractDynamicMethodPointer(method); + sizeCounterBuilderContext.SetSizeCounterPointer(Type, pointer, @delegate); + } + + public void BuildConstants(SizeCounterConstantsBuilderContext context) + { + context.SetFields(Type, new KeyValuePair[0]); + BuildConstantsInternal(context); + } + + protected abstract void BuildConstantsInternal(SizeCounterConstantsBuilderContext context); + + protected abstract void CountSizeNotEmpty(SizeCounterMethodBuilderContext context); + + /// + /// Checks whether obj is empty + /// + /// Current context + /// Label where to go if obj is not empty + /// true if obj can be empty + protected virtual bool CheckEmpty(SizeCounterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + if(Type.IsValueType) return false; + context.LoadObj(); // stack: [obj] + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + return true; + } + + protected abstract bool IsReference { get; } + + protected Type Type { get; private set; } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/SizeCounterBuilderContext.cs b/GroBuf/SizeCounters/SizeCounterBuilderContext.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/SizeCounterBuilderContext.cs rename to GroBuf/SizeCounters/SizeCounterBuilderContext.cs index c8a2d4f..d160753 100644 --- a/GroBuf/GroBuf/SizeCounters/SizeCounterBuilderContext.cs +++ b/GroBuf/SizeCounters/SizeCounterBuilderContext.cs @@ -1,107 +1,107 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -using GrEmit; - -using GroBuf.DataMembersExtracters; - -namespace GroBuf.SizeCounters -{ - internal class SizeCounterBuilderContext - { - public SizeCounterBuilderContext(GroBufWriter groBufWriter, ModuleBuilder module, Type constantsType, Dictionary fields, ISizeCounterCollection sizeCounterCollection, IDataMembersExtractor dataMembersExtractor) - { - GroBufWriter = groBufWriter; - Module = module; - ConstantsType = constantsType; - this.fields = fields; - this.sizeCounterCollection = sizeCounterCollection; - this.dataMembersExtractor = dataMembersExtractor; - } - - public IDataMember[] GetDataMembers(Type type) - { - return dataMembersExtractor.GetMembers(type); - } - - public FieldInfo InitConstField(Type type, int index, T value) - { - var field = fields[type][index]; - initializers.Add(field.Name, ((Func)(f => BuildFieldInitializer(f, value)))(field)); - return field; - } - - public Action[] GetFieldInitializers() - { - return (from object value in initializers.Values select ((Action)value)).ToArray(); - } - - public KeyValuePair[] GetMethods() - { - return sizeCounters.Cast().Select(entry => new KeyValuePair((Type)entry.Key, (CompiledDynamicMethod)entry.Value)).ToArray(); - } - - public void SetSizeCounterMethod(Type type, DynamicMethod method) - { - if(sizeCounters[type] != null) - throw new InvalidOperationException(); - sizeCounters[type] = new CompiledDynamicMethod {Method = method, Index = sizeCounters.Count}; - } - - public void SetSizeCounterPointer(Type type, IntPtr sizeCounterPointer, Delegate sizeCounter) - { - if(sizeCounters[type] == null) - throw new InvalidOperationException(); - var compiledDynamicMethod = (CompiledDynamicMethod)sizeCounters[type]; - compiledDynamicMethod.Pointer = sizeCounterPointer; - compiledDynamicMethod.Delegate = sizeCounter; - } - - public CompiledDynamicMethod GetCounter(Type type, bool isRoot = false, bool ignoreCustomSerialization = false) - { - var sizeCounter = (CompiledDynamicMethod)sizeCounters[type]; - if (sizeCounter == null) - { - if (!isRoot) - { - var pointer = (IntPtr?)GroBufWriter.countersWithCustomSerialization[type]; - if (pointer != null) - return new CompiledDynamicMethod { Pointer = pointer.Value }; - } - sizeCounterCollection.GetSizeCounterBuilder(type, ignoreCustomSerialization).BuildSizeCounter(this); - sizeCounter = (CompiledDynamicMethod)sizeCounters[type]; - if(sizeCounter == null) - throw new InvalidOperationException(); - } - return sizeCounter; - } - - public GroBufWriter GroBufWriter { get; private set; } - public ModuleBuilder Module { get; set; } - public Type ConstantsType { get; set; } - - private Action BuildFieldInitializer(FieldInfo field, T value) - { - var method = new DynamicMethod(field.Name + "_Init_" + Guid.NewGuid(), typeof(void), new[] {typeof(T)}, Module); - using (var il = new GroboIL(method)) - { - il.Ldarg(0); - il.Stfld(field); - il.Ret(); - } - var action = (Action)method.CreateDelegate(typeof(Action)); - return () => action(value); - } - - private readonly Dictionary fields; - private readonly ISizeCounterCollection sizeCounterCollection; - private readonly IDataMembersExtractor dataMembersExtractor; - - private readonly Hashtable sizeCounters = new Hashtable(); - private readonly Hashtable initializers = new Hashtable(); - } +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; + +using GrEmit; + +using GroBuf.DataMembersExtracters; + +namespace GroBuf.SizeCounters +{ + internal class SizeCounterBuilderContext + { + public SizeCounterBuilderContext(GroBufWriter groBufWriter, ModuleBuilder module, Type constantsType, Dictionary fields, ISizeCounterCollection sizeCounterCollection, IDataMembersExtractor dataMembersExtractor) + { + GroBufWriter = groBufWriter; + Module = module; + ConstantsType = constantsType; + this.fields = fields; + this.sizeCounterCollection = sizeCounterCollection; + this.dataMembersExtractor = dataMembersExtractor; + } + + public IDataMember[] GetDataMembers(Type type) + { + return dataMembersExtractor.GetMembers(type); + } + + public FieldInfo InitConstField(Type type, int index, T value) + { + var field = fields[type][index]; + initializers.Add(field.Name, ((Func)(f => BuildFieldInitializer(f, value)))(field)); + return field; + } + + public Action[] GetFieldInitializers() + { + return (from object value in initializers.Values select ((Action)value)).ToArray(); + } + + public KeyValuePair[] GetMethods() + { + return sizeCounters.Cast().Select(entry => new KeyValuePair((Type)entry.Key, (CompiledDynamicMethod)entry.Value)).ToArray(); + } + + public void SetSizeCounterMethod(Type type, DynamicMethod method) + { + if(sizeCounters[type] != null) + throw new InvalidOperationException(); + sizeCounters[type] = new CompiledDynamicMethod {Method = method, Index = sizeCounters.Count}; + } + + public void SetSizeCounterPointer(Type type, IntPtr sizeCounterPointer, Delegate sizeCounter) + { + if(sizeCounters[type] == null) + throw new InvalidOperationException(); + var compiledDynamicMethod = (CompiledDynamicMethod)sizeCounters[type]; + compiledDynamicMethod.Pointer = sizeCounterPointer; + compiledDynamicMethod.Delegate = sizeCounter; + } + + public CompiledDynamicMethod GetCounter(Type type, bool isRoot = false, bool ignoreCustomSerialization = false) + { + var sizeCounter = (CompiledDynamicMethod)sizeCounters[type]; + if (sizeCounter == null) + { + if (!isRoot) + { + var pointer = (IntPtr?)GroBufWriter.countersWithCustomSerialization[type]; + if (pointer != null) + return new CompiledDynamicMethod { Pointer = pointer.Value }; + } + sizeCounterCollection.GetSizeCounterBuilder(type, ignoreCustomSerialization).BuildSizeCounter(this); + sizeCounter = (CompiledDynamicMethod)sizeCounters[type]; + if(sizeCounter == null) + throw new InvalidOperationException(); + } + return sizeCounter; + } + + public GroBufWriter GroBufWriter { get; private set; } + public ModuleBuilder Module { get; set; } + public Type ConstantsType { get; set; } + + private Action BuildFieldInitializer(FieldInfo field, T value) + { + var method = new DynamicMethod(field.Name + "_Init_" + Guid.NewGuid(), typeof(void), new[] {typeof(T)}, Module); + using (var il = new GroboIL(method)) + { + il.Ldarg(0); + il.Stfld(field); + il.Ret(); + } + var action = (Action)method.CreateDelegate(typeof(Action)); + return () => action(value); + } + + private readonly Dictionary fields; + private readonly ISizeCounterCollection sizeCounterCollection; + private readonly IDataMembersExtractor dataMembersExtractor; + + private readonly Hashtable sizeCounters = new Hashtable(); + private readonly Hashtable initializers = new Hashtable(); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/SizeCounterCollection.cs b/GroBuf/SizeCounters/SizeCounterCollection.cs similarity index 98% rename from GroBuf/GroBuf/SizeCounters/SizeCounterCollection.cs rename to GroBuf/SizeCounters/SizeCounterCollection.cs index c9ecaac..b4057ec 100644 --- a/GroBuf/GroBuf/SizeCounters/SizeCounterCollection.cs +++ b/GroBuf/SizeCounters/SizeCounterCollection.cs @@ -1,92 +1,92 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Net; - -namespace GroBuf.SizeCounters -{ - internal class SizeCounterCollection : ISizeCounterCollection - { - public SizeCounterCollection(IGroBufCustomSerializerCollection customSerializerCollection, Func factory, Func baseFactory) - { - this.customSerializerCollection = customSerializerCollection; - this.factory = factory; - this.baseFactory = baseFactory; - } - - public ISizeCounterBuilder GetSizeCounterBuilder(Type type, bool ignoreCustomSerialization) - { - var key = new KeyValuePair(type, ignoreCustomSerialization); - var sizeCounterBuilder = (ISizeCounterBuilder)sizeCounterBuilders[key]; - if(sizeCounterBuilder == null) - { - lock(sizeCounterBuildersLock) - { - sizeCounterBuilder = (ISizeCounterBuilder)sizeCounterBuilders[key]; - if(sizeCounterBuilder == null) - { - sizeCounterBuilder = GetSizeCounterBuilderInternal(type, ignoreCustomSerialization); - sizeCounterBuilders[key] = sizeCounterBuilder; - } - } - } - return sizeCounterBuilder; - } - - private ISizeCounterBuilder GetSizeCounterBuilderInternal(Type type, bool ignoreCustomSerialization) - { - ISizeCounterBuilder sizeCounterBuilder; - IGroBufCustomSerializer customSerializer = null; - if(!ignoreCustomSerialization) - customSerializer = customSerializerCollection.Get(type, factory, baseFactory(type)); - if(customSerializer != null) - sizeCounterBuilder = new CustomSizeCounterBuilder(type, customSerializer); - else if(type == typeof(string)) - sizeCounterBuilder = new StringSizeCounterBuilder(); - else if(type == typeof(DateTime)) - sizeCounterBuilder = new DateTimeSizeCounterBuilder(); - else if(type == typeof(Guid)) - sizeCounterBuilder = new GuidSizeCounterBuilder(); - else if(type == typeof(IPAddress)) - sizeCounterBuilder = new IPAddressSizeCounterBuilder(); - else if(type == typeof(TimeSpan)) - sizeCounterBuilder = new TimeSpanSizeCounterBuilder(); - else if(type == typeof(DateTimeOffset)) - sizeCounterBuilder = new DateTimeOffsetSizeCounterBuilder(); - else if(type.IsEnum) - sizeCounterBuilder = new EnumSizeCounterBuilder(type); - else if(type.IsPrimitive || type == typeof(decimal)) - sizeCounterBuilder = new PrimitivesSizeCounterBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) - sizeCounterBuilder = new NullableSizeCounterBuilder(type); - else if(type.IsArray) - sizeCounterBuilder = type.GetElementType().IsPrimitive ? (ISizeCounterBuilder)new PrimitivesArraySizeCounterBuilder(type) : new ArraySizeCounterBuilder(type); - else if(type == typeof(Hashtable)) - sizeCounterBuilder = new HashtableSizeCounterBuilder(); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) - sizeCounterBuilder = new DictionarySizeCounterBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ArraySegment<>)) - sizeCounterBuilder = type.GetGenericArguments()[0].IsPrimitive ? (ISizeCounterBuilder)new PrimitivesArraySegmentSizeCounterBuilder(type) : new ArraySegmentSizeCounterBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>)) - sizeCounterBuilder = type.GetGenericArguments()[0].IsPrimitive ? (ISizeCounterBuilder)new PrimitivesHashSetSizeCounterBuilder(type) : new HashSetSizeCounterBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) - sizeCounterBuilder = type.GetGenericArguments()[0].IsPrimitive ? (ISizeCounterBuilder)new PrimitivesListSizeCounterBuilder(type) : new ListSizeCounterBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Lazy<>)) - sizeCounterBuilder = new LazySizeCounterBuilder(type); - else if(type.IsTuple()) - sizeCounterBuilder = new TupleSizeCounterBuilder(type); - else if(type == typeof(object)) - sizeCounterBuilder = new ObjectSizeCounterBuilder(); - else - sizeCounterBuilder = new ClassSizeCounterBuilder(type); - return sizeCounterBuilder; - } - - private readonly IGroBufCustomSerializerCollection customSerializerCollection; - private readonly Func factory; - private readonly Func baseFactory; - - private readonly Hashtable sizeCounterBuilders = new Hashtable(); - private readonly object sizeCounterBuildersLock = new object(); - } +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; + +namespace GroBuf.SizeCounters +{ + internal class SizeCounterCollection : ISizeCounterCollection + { + public SizeCounterCollection(IGroBufCustomSerializerCollection customSerializerCollection, Func factory, Func baseFactory) + { + this.customSerializerCollection = customSerializerCollection; + this.factory = factory; + this.baseFactory = baseFactory; + } + + public ISizeCounterBuilder GetSizeCounterBuilder(Type type, bool ignoreCustomSerialization) + { + var key = new KeyValuePair(type, ignoreCustomSerialization); + var sizeCounterBuilder = (ISizeCounterBuilder)sizeCounterBuilders[key]; + if(sizeCounterBuilder == null) + { + lock(sizeCounterBuildersLock) + { + sizeCounterBuilder = (ISizeCounterBuilder)sizeCounterBuilders[key]; + if(sizeCounterBuilder == null) + { + sizeCounterBuilder = GetSizeCounterBuilderInternal(type, ignoreCustomSerialization); + sizeCounterBuilders[key] = sizeCounterBuilder; + } + } + } + return sizeCounterBuilder; + } + + private ISizeCounterBuilder GetSizeCounterBuilderInternal(Type type, bool ignoreCustomSerialization) + { + ISizeCounterBuilder sizeCounterBuilder; + IGroBufCustomSerializer customSerializer = null; + if(!ignoreCustomSerialization) + customSerializer = customSerializerCollection.Get(type, factory, baseFactory(type)); + if(customSerializer != null) + sizeCounterBuilder = new CustomSizeCounterBuilder(type, customSerializer); + else if(type == typeof(string)) + sizeCounterBuilder = new StringSizeCounterBuilder(); + else if(type == typeof(DateTime)) + sizeCounterBuilder = new DateTimeSizeCounterBuilder(); + else if(type == typeof(Guid)) + sizeCounterBuilder = new GuidSizeCounterBuilder(); + else if(type == typeof(IPAddress)) + sizeCounterBuilder = new IPAddressSizeCounterBuilder(); + else if(type == typeof(TimeSpan)) + sizeCounterBuilder = new TimeSpanSizeCounterBuilder(); + else if(type == typeof(DateTimeOffset)) + sizeCounterBuilder = new DateTimeOffsetSizeCounterBuilder(); + else if(type.IsEnum) + sizeCounterBuilder = new EnumSizeCounterBuilder(type); + else if(type.IsPrimitive || type == typeof(decimal)) + sizeCounterBuilder = new PrimitivesSizeCounterBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + sizeCounterBuilder = new NullableSizeCounterBuilder(type); + else if(type.IsArray) + sizeCounterBuilder = type.GetElementType().IsPrimitive ? (ISizeCounterBuilder)new PrimitivesArraySizeCounterBuilder(type) : new ArraySizeCounterBuilder(type); + else if(type == typeof(Hashtable)) + sizeCounterBuilder = new HashtableSizeCounterBuilder(); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + sizeCounterBuilder = new DictionarySizeCounterBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ArraySegment<>)) + sizeCounterBuilder = type.GetGenericArguments()[0].IsPrimitive ? (ISizeCounterBuilder)new PrimitivesArraySegmentSizeCounterBuilder(type) : new ArraySegmentSizeCounterBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>)) + sizeCounterBuilder = type.GetGenericArguments()[0].IsPrimitive ? (ISizeCounterBuilder)new PrimitivesHashSetSizeCounterBuilder(type) : new HashSetSizeCounterBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) + sizeCounterBuilder = type.GetGenericArguments()[0].IsPrimitive ? (ISizeCounterBuilder)new PrimitivesListSizeCounterBuilder(type) : new ListSizeCounterBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Lazy<>)) + sizeCounterBuilder = new LazySizeCounterBuilder(type); + else if(type.IsTuple()) + sizeCounterBuilder = new TupleSizeCounterBuilder(type); + else if(type == typeof(object)) + sizeCounterBuilder = new ObjectSizeCounterBuilder(); + else + sizeCounterBuilder = new ClassSizeCounterBuilder(type); + return sizeCounterBuilder; + } + + private readonly IGroBufCustomSerializerCollection customSerializerCollection; + private readonly Func factory; + private readonly Func baseFactory; + + private readonly Hashtable sizeCounterBuilders = new Hashtable(); + private readonly object sizeCounterBuildersLock = new object(); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/SizeCounterConstantsBuilderContext.cs b/GroBuf/SizeCounters/SizeCounterConstantsBuilderContext.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/SizeCounterConstantsBuilderContext.cs rename to GroBuf/SizeCounters/SizeCounterConstantsBuilderContext.cs index 7e9a9fb..5a0d2c4 100644 --- a/GroBuf/GroBuf/SizeCounters/SizeCounterConstantsBuilderContext.cs +++ b/GroBuf/SizeCounters/SizeCounterConstantsBuilderContext.cs @@ -1,56 +1,56 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -using GroBuf.DataMembersExtracters; - -namespace GroBuf.SizeCounters -{ - internal class SizeCounterConstantsBuilderContext - { - public SizeCounterConstantsBuilderContext(GroBufWriter groBufWriter, TypeBuilder constantsBuilder, ISizeCounterCollection sizeCounterCollection, IDataMembersExtractor dataMembersExtractor) - { - GroBufWriter = groBufWriter; - ConstantsBuilder = constantsBuilder; - this.sizeCounterCollection = sizeCounterCollection; - this.dataMembersExtractor = dataMembersExtractor; - } - - public IDataMember[] GetDataMembers(Type type) - { - return dataMembersExtractor.GetMembers(type); - } - - public void SetFields(Type type, KeyValuePair[] fields) - { - hashtable[type] = fields; - foreach(var field in fields) - ConstantsBuilder.DefineField(field.Key, field.Value, FieldAttributes.Public | FieldAttributes.Static); - } - - public void BuildConstants(Type type, bool isRoot = false, bool ignoreCustomSerialization = false) - { - if(isRoot || GroBufWriter.countersWithCustomSerialization[type] == null) - { - if(hashtable[type] == null) - sizeCounterCollection.GetSizeCounterBuilder(type, ignoreCustomSerialization).BuildConstants(this); - } - } - - public Dictionary GetFields() - { - return hashtable.Cast().ToDictionary(entry => (Type)entry.Key, entry => ((KeyValuePair[])entry.Value).Select(pair => pair.Key).ToArray()); - } - - public GroBufWriter GroBufWriter { get; private set; } - public TypeBuilder ConstantsBuilder { get; private set; } - - private readonly Hashtable hashtable = new Hashtable(); - - private readonly ISizeCounterCollection sizeCounterCollection; - private readonly IDataMembersExtractor dataMembersExtractor; - } +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; + +using GroBuf.DataMembersExtracters; + +namespace GroBuf.SizeCounters +{ + internal class SizeCounterConstantsBuilderContext + { + public SizeCounterConstantsBuilderContext(GroBufWriter groBufWriter, TypeBuilder constantsBuilder, ISizeCounterCollection sizeCounterCollection, IDataMembersExtractor dataMembersExtractor) + { + GroBufWriter = groBufWriter; + ConstantsBuilder = constantsBuilder; + this.sizeCounterCollection = sizeCounterCollection; + this.dataMembersExtractor = dataMembersExtractor; + } + + public IDataMember[] GetDataMembers(Type type) + { + return dataMembersExtractor.GetMembers(type); + } + + public void SetFields(Type type, KeyValuePair[] fields) + { + hashtable[type] = fields; + foreach(var field in fields) + ConstantsBuilder.DefineField(field.Key, field.Value, FieldAttributes.Public | FieldAttributes.Static); + } + + public void BuildConstants(Type type, bool isRoot = false, bool ignoreCustomSerialization = false) + { + if(isRoot || GroBufWriter.countersWithCustomSerialization[type] == null) + { + if(hashtable[type] == null) + sizeCounterCollection.GetSizeCounterBuilder(type, ignoreCustomSerialization).BuildConstants(this); + } + } + + public Dictionary GetFields() + { + return hashtable.Cast().ToDictionary(entry => (Type)entry.Key, entry => ((KeyValuePair[])entry.Value).Select(pair => pair.Key).ToArray()); + } + + public GroBufWriter GroBufWriter { get; private set; } + public TypeBuilder ConstantsBuilder { get; private set; } + + private readonly Hashtable hashtable = new Hashtable(); + + private readonly ISizeCounterCollection sizeCounterCollection; + private readonly IDataMembersExtractor dataMembersExtractor; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/SizeCounterMethodBuilderContext.cs b/GroBuf/SizeCounters/SizeCounterMethodBuilderContext.cs similarity index 96% rename from GroBuf/GroBuf/SizeCounters/SizeCounterMethodBuilderContext.cs rename to GroBuf/SizeCounters/SizeCounterMethodBuilderContext.cs index 06f73ba..d8acf6d 100644 --- a/GroBuf/GroBuf/SizeCounters/SizeCounterMethodBuilderContext.cs +++ b/GroBuf/SizeCounters/SizeCounterMethodBuilderContext.cs @@ -1,97 +1,97 @@ -using System; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.SizeCounters -{ - internal class SizeCounterMethodBuilderContext - { - public SizeCounterMethodBuilderContext(SizeCounterBuilderContext context, GroboIL il) - { - Context = context; - Il = il; - } - - /// - /// Loads obj onto the evaluation stack - /// - public void LoadObj() - { - Il.Ldarg(0); - } - - /// - /// Loads ref obj onto the evaluation stack - /// - public void LoadObjByRef() - { - Il.Ldarga(0); - } - - /// - /// Loads writeEmpty onto the evaluation stack - /// - public void LoadWriteEmpty() - { - Il.Ldarg(1); - } - - /// - /// Loads context onto the evaluation stack - /// - public void LoadContext() - { - Il.Ldarg(2); - } - - /// - /// Loads context.serializerId onto the evaluation stack - /// - public void LoadSerializerId() - { - LoadContext(); - Il.Ldfld(WriterContext.SerializerIdField); - } - - /// - /// Loads the specified field onto the evaluation stack - /// - /// Field to load - public void LoadField(FieldInfo field) - { - Il.Ldfld(field); - } - - /// - /// obj is empty. Return (int)writeEmpty - /// - public void ReturnForNull() - { - LoadWriteEmpty(); // stack: [writeEmpty] - Il.Ret(); - } - - public void CallSizeCounter(GroboIL il, Type type) - { - var counter = Context.GetCounter(type); - if(counter.Pointer != IntPtr.Zero) - il.Ldc_IntPtr(counter.Pointer); - else - { - il.Ldfld(Context.ConstantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic)); - il.Ldc_I4(counter.Index); - il.Ldelem(typeof(IntPtr)); - } - il.Calli(CallingConventions.Standard, typeof(int), new[] {type, typeof(bool), typeof(WriterContext)}); - } - - public void CallSizeCounter(Type type) - { - CallSizeCounter(Il, type); - } - - public SizeCounterBuilderContext Context { get; private set; } - public GroboIL Il { get; private set; } - } +using System; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.SizeCounters +{ + internal class SizeCounterMethodBuilderContext + { + public SizeCounterMethodBuilderContext(SizeCounterBuilderContext context, GroboIL il) + { + Context = context; + Il = il; + } + + /// + /// Loads obj onto the evaluation stack + /// + public void LoadObj() + { + Il.Ldarg(0); + } + + /// + /// Loads ref obj onto the evaluation stack + /// + public void LoadObjByRef() + { + Il.Ldarga(0); + } + + /// + /// Loads writeEmpty onto the evaluation stack + /// + public void LoadWriteEmpty() + { + Il.Ldarg(1); + } + + /// + /// Loads context onto the evaluation stack + /// + public void LoadContext() + { + Il.Ldarg(2); + } + + /// + /// Loads context.serializerId onto the evaluation stack + /// + public void LoadSerializerId() + { + LoadContext(); + Il.Ldfld(WriterContext.SerializerIdField); + } + + /// + /// Loads the specified field onto the evaluation stack + /// + /// Field to load + public void LoadField(FieldInfo field) + { + Il.Ldfld(field); + } + + /// + /// obj is empty. Return (int)writeEmpty + /// + public void ReturnForNull() + { + LoadWriteEmpty(); // stack: [writeEmpty] + Il.Ret(); + } + + public void CallSizeCounter(GroboIL il, Type type) + { + var counter = Context.GetCounter(type); + if(counter.Pointer != IntPtr.Zero) + il.Ldc_IntPtr(counter.Pointer); + else + { + il.Ldfld(Context.ConstantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic)); + il.Ldc_I4(counter.Index); + il.Ldelem(typeof(IntPtr)); + } + il.Calli(CallingConventions.Standard, typeof(int), new[] {type, typeof(bool), typeof(WriterContext)}); + } + + public void CallSizeCounter(Type type) + { + CallSizeCounter(Il, type); + } + + public SizeCounterBuilderContext Context { get; private set; } + public GroboIL Il { get; private set; } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/SizeCounterTypeBuilder.cs b/GroBuf/SizeCounters/SizeCounterTypeBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/SizeCounterTypeBuilder.cs rename to GroBuf/SizeCounters/SizeCounterTypeBuilder.cs index 23b1670..9fc2592 100644 --- a/GroBuf/GroBuf/SizeCounters/SizeCounterTypeBuilder.cs +++ b/GroBuf/SizeCounters/SizeCounterTypeBuilder.cs @@ -1,90 +1,90 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -using GroBuf.DataMembersExtracters; - -namespace GroBuf.SizeCounters -{ - internal class SizeCounterTypeBuilder - { - public SizeCounterTypeBuilder(GroBufWriter groBufWriter, ModuleBuilder module, ISizeCounterCollection sizeCounterCollection, IDataMembersExtractor dataMembersExtractor) - { - this.groBufWriter = groBufWriter; - this.module = module; - this.sizeCounterCollection = sizeCounterCollection; - this.dataMembersExtractor = dataMembersExtractor; - } - - public IntPtr BuildSizeCounter(Type type, bool ignoreCustomSerialization) - { - var constantsBuilder = module.DefineType(type.Name + "_GroBufSizeCounterConstants_" + Guid.NewGuid(), TypeAttributes.Class | TypeAttributes.Public); - constantsBuilder.DefineField("pointers", typeof(IntPtr[]), FieldAttributes.Private | FieldAttributes.Static); - constantsBuilder.DefineField("delegates", typeof(Delegate[]), FieldAttributes.Private | FieldAttributes.Static); - var constantsBuilderContext = new SizeCounterConstantsBuilderContext(groBufWriter, constantsBuilder, sizeCounterCollection, dataMembersExtractor); - constantsBuilderContext.BuildConstants(type, true, ignoreCustomSerialization); - var constantsType = constantsBuilder.CreateType(); - var fields = constantsBuilderContext.GetFields().ToDictionary(pair => pair.Key, pair => pair.Value.Select(constantsType.GetField).ToArray()); - var context = new SizeCounterBuilderContext(groBufWriter, module, constantsType, fields, sizeCounterCollection, dataMembersExtractor); - var sizeCounter = context.GetCounter(type, true, ignoreCustomSerialization); - - var initializer = BuildInitializer(constantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic), - constantsType.GetField("delegates", BindingFlags.Static | BindingFlags.NonPublic)); - - var compiledDynamicMethods = context.GetMethods(); - var pointers = new IntPtr[compiledDynamicMethods.Length]; - var delegates = new Delegate[compiledDynamicMethods.Length]; - foreach(var pair in compiledDynamicMethods) - { - var compiledDynamicMethod = pair.Value; - var index = compiledDynamicMethod.Index; - pointers[index] = compiledDynamicMethod.Pointer; - delegates[index] = compiledDynamicMethod.Delegate; - if(compiledDynamicMethod.Pointer != sizeCounter.Pointer) - groBufWriter.countersWithCustomSerialization[pair.Key] = (IntPtr?)compiledDynamicMethod.Pointer; - } - initializer(pointers, delegates, context.GetFieldInitializers()); - return sizeCounter.Pointer; - } - - private Action BuildInitializer(FieldInfo pointersField, FieldInfo delegatesField) - { - var initializer = new DynamicMethod("Init", typeof(void), new[] {typeof(IntPtr[]), typeof(Delegate[]), typeof(Action[])}, module, true); - var il = initializer.GetILGenerator(); - var retLabel = il.DefineLabel(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Stsfld, pointersField); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Stsfld, delegatesField); - il.Emit(OpCodes.Ldarg_2); // stack: [initializers] - il.Emit(OpCodes.Brfalse, retLabel); // if(initializers == null) goto ret; - il.Emit(OpCodes.Ldarg_2); // stack: [initializers] - il.Emit(OpCodes.Ldlen); // stack: [initializers.Length] - il.Emit(OpCodes.Dup); // stack: [initializers.Length, initializers.Length] - var index = il.DeclareLocal(typeof(int)); - il.Emit(OpCodes.Stloc, index); // index = initializers.Length; stack: [initializers.Length] - il.Emit(OpCodes.Brfalse, retLabel); // if(initializers.Length == 0) goto ret; - var cycleStart = il.DefineLabel(); - il.MarkLabel(cycleStart); - il.Emit(OpCodes.Ldarg_2); // stack: [initializers] - il.Emit(OpCodes.Ldloc, index); // stack: [initializers, index] - il.Emit(OpCodes.Ldc_I4_1); // stack: [initializers, index, 1] - il.Emit(OpCodes.Sub); // stack: [initializers, index - 1] - il.Emit(OpCodes.Dup); // stack: [initializers, index - 1, index - 1] - il.Emit(OpCodes.Stloc, index); // index = index - 1; // stack: [initializers, index] - il.Emit(OpCodes.Ldelem_Ref); // stack: [initializers[index]] - il.Emit(OpCodes.Call, typeof(Action).GetMethod("Invoke")); // intializers[index]() - il.Emit(OpCodes.Ldloc, index); - il.Emit(OpCodes.Brtrue, cycleStart); - il.MarkLabel(retLabel); - il.Emit(OpCodes.Ret); - return (Action)initializer.CreateDelegate(typeof(Action)); - } - - private readonly ModuleBuilder module; - private readonly ISizeCounterCollection sizeCounterCollection; - private readonly IDataMembersExtractor dataMembersExtractor; - private readonly GroBufWriter groBufWriter; - } +using System; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; + +using GroBuf.DataMembersExtracters; + +namespace GroBuf.SizeCounters +{ + internal class SizeCounterTypeBuilder + { + public SizeCounterTypeBuilder(GroBufWriter groBufWriter, ModuleBuilder module, ISizeCounterCollection sizeCounterCollection, IDataMembersExtractor dataMembersExtractor) + { + this.groBufWriter = groBufWriter; + this.module = module; + this.sizeCounterCollection = sizeCounterCollection; + this.dataMembersExtractor = dataMembersExtractor; + } + + public IntPtr BuildSizeCounter(Type type, bool ignoreCustomSerialization) + { + var constantsBuilder = module.DefineType(type.Name + "_GroBufSizeCounterConstants_" + Guid.NewGuid(), TypeAttributes.Class | TypeAttributes.Public); + constantsBuilder.DefineField("pointers", typeof(IntPtr[]), FieldAttributes.Private | FieldAttributes.Static); + constantsBuilder.DefineField("delegates", typeof(Delegate[]), FieldAttributes.Private | FieldAttributes.Static); + var constantsBuilderContext = new SizeCounterConstantsBuilderContext(groBufWriter, constantsBuilder, sizeCounterCollection, dataMembersExtractor); + constantsBuilderContext.BuildConstants(type, true, ignoreCustomSerialization); + var constantsType = constantsBuilder.CreateTypeInfo(); + var fields = constantsBuilderContext.GetFields().ToDictionary(pair => pair.Key, pair => pair.Value.Select(constantsType.GetField).ToArray()); + var context = new SizeCounterBuilderContext(groBufWriter, module, constantsType, fields, sizeCounterCollection, dataMembersExtractor); + var sizeCounter = context.GetCounter(type, true, ignoreCustomSerialization); + + var initializer = BuildInitializer(constantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic), + constantsType.GetField("delegates", BindingFlags.Static | BindingFlags.NonPublic)); + + var compiledDynamicMethods = context.GetMethods(); + var pointers = new IntPtr[compiledDynamicMethods.Length]; + var delegates = new Delegate[compiledDynamicMethods.Length]; + foreach(var pair in compiledDynamicMethods) + { + var compiledDynamicMethod = pair.Value; + var index = compiledDynamicMethod.Index; + pointers[index] = compiledDynamicMethod.Pointer; + delegates[index] = compiledDynamicMethod.Delegate; + if(compiledDynamicMethod.Pointer != sizeCounter.Pointer) + groBufWriter.countersWithCustomSerialization[pair.Key] = (IntPtr?)compiledDynamicMethod.Pointer; + } + initializer(pointers, delegates, context.GetFieldInitializers()); + return sizeCounter.Pointer; + } + + private Action BuildInitializer(FieldInfo pointersField, FieldInfo delegatesField) + { + var initializer = new DynamicMethod("Init", typeof(void), new[] {typeof(IntPtr[]), typeof(Delegate[]), typeof(Action[])}, module, true); + var il = initializer.GetILGenerator(); + var retLabel = il.DefineLabel(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Stsfld, pointersField); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Stsfld, delegatesField); + il.Emit(OpCodes.Ldarg_2); // stack: [initializers] + il.Emit(OpCodes.Brfalse, retLabel); // if(initializers == null) goto ret; + il.Emit(OpCodes.Ldarg_2); // stack: [initializers] + il.Emit(OpCodes.Ldlen); // stack: [initializers.Length] + il.Emit(OpCodes.Dup); // stack: [initializers.Length, initializers.Length] + var index = il.DeclareLocal(typeof(int)); + il.Emit(OpCodes.Stloc, index); // index = initializers.Length; stack: [initializers.Length] + il.Emit(OpCodes.Brfalse, retLabel); // if(initializers.Length == 0) goto ret; + var cycleStart = il.DefineLabel(); + il.MarkLabel(cycleStart); + il.Emit(OpCodes.Ldarg_2); // stack: [initializers] + il.Emit(OpCodes.Ldloc, index); // stack: [initializers, index] + il.Emit(OpCodes.Ldc_I4_1); // stack: [initializers, index, 1] + il.Emit(OpCodes.Sub); // stack: [initializers, index - 1] + il.Emit(OpCodes.Dup); // stack: [initializers, index - 1, index - 1] + il.Emit(OpCodes.Stloc, index); // index = index - 1; // stack: [initializers, index] + il.Emit(OpCodes.Ldelem_Ref); // stack: [initializers[index]] + il.Emit(OpCodes.Call, typeof(Action).GetMethod("Invoke")); // intializers[index]() + il.Emit(OpCodes.Ldloc, index); + il.Emit(OpCodes.Brtrue, cycleStart); + il.MarkLabel(retLabel); + il.Emit(OpCodes.Ret); + return (Action)initializer.CreateDelegate(typeof(Action)); + } + + private readonly ModuleBuilder module; + private readonly ISizeCounterCollection sizeCounterCollection; + private readonly IDataMembersExtractor dataMembersExtractor; + private readonly GroBufWriter groBufWriter; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/StringSizeCounterBuilder.cs b/GroBuf/SizeCounters/StringSizeCounterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/SizeCounters/StringSizeCounterBuilder.cs rename to GroBuf/SizeCounters/StringSizeCounterBuilder.cs index 17b94ca..01f19fc 100644 --- a/GroBuf/GroBuf/SizeCounters/StringSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/StringSizeCounterBuilder.cs @@ -1,33 +1,33 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; - -namespace GroBuf.SizeCounters -{ - internal class StringSizeCounterBuilder : SizeCounterBuilderBase - { - public StringSizeCounterBuilder() - : base(typeof(string)) - { - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - var il = context.Il; - context.LoadObj(); // stack: [obj] - il.Call(lengthPropertyGetter); // stack: [obj.Length] - il.Ldc_I4(1); // stack: [obj.Length, 1] - il.Shl(); // stack: [obj.Length << 1] - il.Ldc_I4(5); // stack: [obj.Length << 1, 5] - il.Add(); // stack: [obj.Length << 1 + 5] - } - - protected override bool IsReference { get { return true; } } - - private static readonly MethodInfo lengthPropertyGetter = ((PropertyInfo)((MemberExpression)((Expression>)(s => s.Length)).Body).Member).GetGetMethod(); - } +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace GroBuf.SizeCounters +{ + internal class StringSizeCounterBuilder : SizeCounterBuilderBase + { + public StringSizeCounterBuilder() + : base(typeof(string)) + { + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + var il = context.Il; + context.LoadObj(); // stack: [obj] + il.Call(lengthPropertyGetter); // stack: [obj.Length] + il.Ldc_I4(1); // stack: [obj.Length, 1] + il.Shl(); // stack: [obj.Length << 1] + il.Ldc_I4(5); // stack: [obj.Length << 1, 5] + il.Add(); // stack: [obj.Length << 1 + 5] + } + + protected override bool IsReference { get { return true; } } + + private static readonly MethodInfo lengthPropertyGetter = ((PropertyInfo)((MemberExpression)((Expression>)(s => s.Length)).Body).Member).GetGetMethod(); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/TimeSpanSizeCounterBuilder.cs b/GroBuf/SizeCounters/TimeSpanSizeCounterBuilder.cs similarity index 96% rename from GroBuf/GroBuf/SizeCounters/TimeSpanSizeCounterBuilder.cs rename to GroBuf/SizeCounters/TimeSpanSizeCounterBuilder.cs index a3b22d0..db6ce63 100644 --- a/GroBuf/GroBuf/SizeCounters/TimeSpanSizeCounterBuilder.cs +++ b/GroBuf/SizeCounters/TimeSpanSizeCounterBuilder.cs @@ -1,23 +1,23 @@ -using System; - -namespace GroBuf.SizeCounters -{ - internal class TimeSpanSizeCounterBuilder : SizeCounterBuilderBase - { - public TimeSpanSizeCounterBuilder() - : base(typeof(TimeSpan)) - { - } - - protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) - { - } - - protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) - { - context.Il.Ldc_I4(9); // stack: [9] - } - - protected override bool IsReference { get { return false; } } - } +using System; + +namespace GroBuf.SizeCounters +{ + internal class TimeSpanSizeCounterBuilder : SizeCounterBuilderBase + { + public TimeSpanSizeCounterBuilder() + : base(typeof(TimeSpan)) + { + } + + protected override void BuildConstantsInternal(SizeCounterConstantsBuilderContext context) + { + } + + protected override void CountSizeNotEmpty(SizeCounterMethodBuilderContext context) + { + context.Il.Ldc_I4(9); // stack: [9] + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/SizeCounters/TupleSizeCounterBuilder.cs b/GroBuf/SizeCounters/TupleSizeCounterBuilder.cs similarity index 100% rename from GroBuf/GroBuf/SizeCounters/TupleSizeCounterBuilder.cs rename to GroBuf/SizeCounters/TupleSizeCounterBuilder.cs diff --git a/GroBuf/Tests/Properties/AssemblyInfo.cs b/GroBuf/Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index 116c18f..0000000 --- a/GroBuf/Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. - -[assembly : AssemblyTitle("Tests")] -[assembly : AssemblyDescription("")] -[assembly : AssemblyConfiguration("")] -[assembly : AssemblyCompany("")] -[assembly : AssemblyProduct("Tests")] -[assembly : AssemblyCopyright("Copyright © 2011")] -[assembly : AssemblyTrademark("")] -[assembly : AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. - -[assembly : ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM - -[assembly : Guid("514a588f-3f7b-4eeb-ab27-77466afd9f07")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] - -[assembly : AssemblyVersion("1.0.0.0")] -[assembly : AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/GroBuf/Tests/Tests.csproj b/GroBuf/Tests/Tests.csproj deleted file mode 100644 index 6455232..0000000 --- a/GroBuf/Tests/Tests.csproj +++ /dev/null @@ -1,239 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {60E8EA76-2CBB-4A14-B9AA-F639E1D131BC} - Library - Properties - GroBuf.Tests - GroBuf.Tests - v4.5 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - true - false - - - true - bin\x86\Debug\ - DEBUG;TRACE - full - x86 - bin\Debug\GroBuf.Tests.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - MinimumRecommendedRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - true - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - true - false - - - bin\x86\Release\ - TRACE - true - pdbonly - x86 - bin\Release\GroBuf.Tests.dll.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - MinimumRecommendedRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - - - - ..\packages\GrEmit.2.1.9\lib\net40\GrEmit.dll - - - ..\packages\NUnit.2.6.4\lib\nunit.framework.dll - - - ..\packages\protobuf-net.2.3.2\lib\net40\protobuf-net.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {80D1D3A4-A424-43C3-B46B-3A87941A68B4} - GroBuf - - - - - - - - \ No newline at end of file diff --git a/GroBuf/Tests/packages.config b/GroBuf/Tests/packages.config deleted file mode 100644 index 689b8aa..0000000 --- a/GroBuf/Tests/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/GroBuf/GroBuf/WriterContext.cs b/GroBuf/WriterContext.cs similarity index 98% rename from GroBuf/GroBuf/WriterContext.cs rename to GroBuf/WriterContext.cs index 479ce2c..9c40e03 100644 --- a/GroBuf/GroBuf/WriterContext.cs +++ b/GroBuf/WriterContext.cs @@ -1,33 +1,33 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Reflection; - -namespace GroBuf -{ - public class WriterContext - { - public WriterContext(long serializerId, int length, int start, bool trackReferences) - { - this.serializerId = serializerId; - this.length = length; - this.start = start; - if(trackReferences) - objects = new Dictionary(); - } - - public readonly long serializerId; - public int length; - public int start; - public int index; - public int references; - public readonly Dictionary objects; - - public static readonly FieldInfo IndexField = (FieldInfo)((MemberExpression)((Expression>)(context => context.index)).Body).Member; - public static readonly FieldInfo LengthField = (FieldInfo)((MemberExpression)((Expression>)(context => context.length)).Body).Member; - public static readonly FieldInfo StartField = (FieldInfo)((MemberExpression)((Expression>)(context => context.start)).Body).Member; - public static readonly FieldInfo ReferencesField = (FieldInfo)((MemberExpression)((Expression>)(context => context.references)).Body).Member; - public static readonly FieldInfo ObjectsField = (FieldInfo)((MemberExpression)((Expression>>)(context => context.objects)).Body).Member; - public static readonly FieldInfo SerializerIdField = (FieldInfo)((MemberExpression)((Expression>)(context => context.serializerId)).Body).Member; - } +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using System.Reflection; + +namespace GroBuf +{ + public class WriterContext + { + public WriterContext(long serializerId, int length, int start, bool trackReferences) + { + this.serializerId = serializerId; + this.length = length; + this.start = start; + if(trackReferences) + objects = new Dictionary(); + } + + public readonly long serializerId; + public int length; + public int start; + public int index; + public int references; + public readonly Dictionary objects; + + public static readonly FieldInfo IndexField = (FieldInfo)((MemberExpression)((Expression>)(context => context.index)).Body).Member; + public static readonly FieldInfo LengthField = (FieldInfo)((MemberExpression)((Expression>)(context => context.length)).Body).Member; + public static readonly FieldInfo StartField = (FieldInfo)((MemberExpression)((Expression>)(context => context.start)).Body).Member; + public static readonly FieldInfo ReferencesField = (FieldInfo)((MemberExpression)((Expression>)(context => context.references)).Body).Member; + public static readonly FieldInfo ObjectsField = (FieldInfo)((MemberExpression)((Expression>>)(context => context.objects)).Body).Member; + public static readonly FieldInfo SerializerIdField = (FieldInfo)((MemberExpression)((Expression>)(context => context.serializerId)).Body).Member; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/WriterDelegate.cs b/GroBuf/WriterDelegate.cs similarity index 97% rename from GroBuf/GroBuf/WriterDelegate.cs rename to GroBuf/WriterDelegate.cs index cac6270..4012588 100644 --- a/GroBuf/GroBuf/WriterDelegate.cs +++ b/GroBuf/WriterDelegate.cs @@ -1,8 +1,8 @@ -using System; - -namespace GroBuf -{ - public delegate void WriterDelegate(T obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context); - - public delegate void WriterDelegate(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context); +using System; + +namespace GroBuf +{ + public delegate void WriterDelegate(T obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context); + + public delegate void WriterDelegate(object obj, bool writeEmpty, IntPtr result, ref int index, WriterContext context); } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/ArraySegmentWriterBuilder.cs b/GroBuf/Writers/ArraySegmentWriterBuilder.cs similarity index 100% rename from GroBuf/GroBuf/Writers/ArraySegmentWriterBuilder.cs rename to GroBuf/Writers/ArraySegmentWriterBuilder.cs diff --git a/GroBuf/GroBuf/Writers/ArrayWriterBuilder.cs b/GroBuf/Writers/ArrayWriterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/ArrayWriterBuilder.cs rename to GroBuf/Writers/ArrayWriterBuilder.cs index 93d3746..4b9ae8f 100644 --- a/GroBuf/GroBuf/Writers/ArrayWriterBuilder.cs +++ b/GroBuf/Writers/ArrayWriterBuilder.cs @@ -1,100 +1,100 @@ -using System; - -using GrEmit; - -namespace GroBuf.Writers -{ - internal class ArrayWriterBuilder : WriterBuilderBase - { - public ArrayWriterBuilder(Type type) - : base(type) - { - if(!Type.IsArray) throw new InvalidOperationException("An array expected but was '" + Type + "'"); - if(Type.GetArrayRank() != 1) throw new NotSupportedException("Arrays with rank greater than 1 are not supported"); - elementType = Type.GetElementType(); - } - - protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Ldlen(); // stack: [obj.Length] - context.Il.Brtrue(notEmptyLabel); // if(obj.Length != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - context.WriteTypeCode(GroBufTypeCode.Array); - var length = il.DeclareLocal(typeof(int)); - context.LoadObj(); // stack: [obj] - il.Ldlen(); // stack: [obj.Length] - il.Stloc(length); // length = obj.Length - context.LoadIndex(); // stack: [index] - var start = context.LocalInt; - il.Stloc(start); // start = index - il.Ldc_I4(8); - context.AssertLength(); // 8 = data size + array length - context.IncreaseIndexBy4(); // index = index + 4 - context.GoToCurrentLocation(); // stack: [&result[index]] - il.Ldloc(length); // stack: [&result[index], length] - il.Stind(typeof(int)); // *(int*)&result[index] = length; stack: [] - context.IncreaseIndexBy4(); // index = index + 4 - - var writeDataLengthLabel = il.DefineLabel("writeDataLength"); - il.Ldloc(length); // stack: [length] - il.Brfalse(writeDataLengthLabel); // if(length == 0) goto writeDataLength; stack: [] - - var i = il.DeclareLocal(typeof(int)); - il.Ldc_I4(0); // stack: [0] - il.Stloc(i); // i = 0; stack: [] - var cycleStart = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStart); - - context.LoadObj(); // stack: [obj] - il.Ldloc(i); // stack: [obj, i] - il.Ldelem(elementType); - il.Ldc_I4(1); // stack: [obj[i], true] - context.LoadResult(); // stack: [obj[i], true, result] - context.LoadIndexByRef(); // stack: [obj[i], true, result, ref index] - context.LoadContext(); // stack: [obj[i], true, result, ref index, context] - context.CallWriter(elementType); // writer(obj[i], true, result, ref index, context); stack: [] - il.Ldloc(length); // stack: [length] - il.Ldloc(i); // stack: [length, i] - il.Ldc_I4(1); // stack: [length, i, 1] - il.Add(); // stack: [length, i + 1] - il.Dup(); // stack: [length, i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [length, i] - il.Bgt(cycleStart, false); // if(length > i) goto cycleStart; stack: [] - - il.MarkLabel(writeDataLengthLabel); - context.LoadResult(); // stack: [result] - il.Ldloc(start); // stack: [result, start] - il.Add(); // stack: [result + start] - context.LoadIndex(); // stack: [result + start, index] - il.Ldloc(start); // stack: [result + start, index, start] - il.Sub(); // stack: [result + start, index - start] - il.Ldc_I4(4); // stack: [result + start, index - start, 4] - il.Sub(); // stack: [result + start, index - start - 4] - il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 - } - - private readonly Type elementType; - } +using System; + +using GrEmit; + +namespace GroBuf.Writers +{ + internal class ArrayWriterBuilder : WriterBuilderBase + { + public ArrayWriterBuilder(Type type) + : base(type) + { + if(!Type.IsArray) throw new InvalidOperationException("An array expected but was '" + Type + "'"); + if(Type.GetArrayRank() != 1) throw new NotSupportedException("Arrays with rank greater than 1 are not supported"); + elementType = Type.GetElementType(); + } + + protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Ldlen(); // stack: [obj.Length] + context.Il.Brtrue(notEmptyLabel); // if(obj.Length != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + context.WriteTypeCode(GroBufTypeCode.Array); + var length = il.DeclareLocal(typeof(int)); + context.LoadObj(); // stack: [obj] + il.Ldlen(); // stack: [obj.Length] + il.Stloc(length); // length = obj.Length + context.LoadIndex(); // stack: [index] + var start = context.LocalInt; + il.Stloc(start); // start = index + il.Ldc_I4(8); + context.AssertLength(); // 8 = data size + array length + context.IncreaseIndexBy4(); // index = index + 4 + context.GoToCurrentLocation(); // stack: [&result[index]] + il.Ldloc(length); // stack: [&result[index], length] + il.Stind(typeof(int)); // *(int*)&result[index] = length; stack: [] + context.IncreaseIndexBy4(); // index = index + 4 + + var writeDataLengthLabel = il.DefineLabel("writeDataLength"); + il.Ldloc(length); // stack: [length] + il.Brfalse(writeDataLengthLabel); // if(length == 0) goto writeDataLength; stack: [] + + var i = il.DeclareLocal(typeof(int)); + il.Ldc_I4(0); // stack: [0] + il.Stloc(i); // i = 0; stack: [] + var cycleStart = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStart); + + context.LoadObj(); // stack: [obj] + il.Ldloc(i); // stack: [obj, i] + il.Ldelem(elementType); + il.Ldc_I4(1); // stack: [obj[i], true] + context.LoadResult(); // stack: [obj[i], true, result] + context.LoadIndexByRef(); // stack: [obj[i], true, result, ref index] + context.LoadContext(); // stack: [obj[i], true, result, ref index, context] + context.CallWriter(elementType); // writer(obj[i], true, result, ref index, context); stack: [] + il.Ldloc(length); // stack: [length] + il.Ldloc(i); // stack: [length, i] + il.Ldc_I4(1); // stack: [length, i, 1] + il.Add(); // stack: [length, i + 1] + il.Dup(); // stack: [length, i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [length, i] + il.Bgt(cycleStart, false); // if(length > i) goto cycleStart; stack: [] + + il.MarkLabel(writeDataLengthLabel); + context.LoadResult(); // stack: [result] + il.Ldloc(start); // stack: [result, start] + il.Add(); // stack: [result + start] + context.LoadIndex(); // stack: [result + start, index] + il.Ldloc(start); // stack: [result + start, index, start] + il.Sub(); // stack: [result + start, index - start] + il.Ldc_I4(4); // stack: [result + start, index - start, 4] + il.Sub(); // stack: [result + start, index - start - 4] + il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 + } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/ClassWriterBuilder.cs b/GroBuf/Writers/ClassWriterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/ClassWriterBuilder.cs rename to GroBuf/Writers/ClassWriterBuilder.cs index 1f7d49f..fb5ea82 100644 --- a/GroBuf/GroBuf/Writers/ClassWriterBuilder.cs +++ b/GroBuf/Writers/ClassWriterBuilder.cs @@ -1,146 +1,146 @@ -using System; -using System.Reflection; - -namespace GroBuf.Writers -{ - internal class ClassWriterBuilder : WriterBuilderBase - { - public ClassWriterBuilder(Type type) - : base(type) - { - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - foreach(var member in context.GetDataMembers(Type)) - { - Type memberType; - switch(member.Member.MemberType) - { - case MemberTypes.Property: - memberType = ((PropertyInfo)member.Member).PropertyType; - break; - case MemberTypes.Field: - memberType = ((FieldInfo)member.Member).FieldType; - break; - default: - throw new NotSupportedException("Data member of type " + member.Member.MemberType + " is not supported"); - } - context.BuildConstants(memberType); - } - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - var length = context.LocalInt; - var start = il.DeclareLocal(typeof(int)); - context.LoadIndexByRef(); // stack: [ref index] - context.LoadIndex(); // stack: [ref index, index] - il.Dup(); // stack: [ref index, index, index] - il.Stloc(start); // start = index; stack: [ref index, index] - il.Ldc_I4(5); // stack: [ref index, index, 5] - il.Add(); // stack: [ref index, index + 5] - il.Stind(typeof(int)); // index = index + 5; stack: [] - - var dataMembers = context.Context.GetDataMembers(Type); - var hashCodes = GroBufHelpers.CalcHashesAndCheck(dataMembers); - var prev = il.DeclareLocal(typeof(int)); - for(var i = 0; i < dataMembers.Length; i++) - { - var member = dataMembers[i]; - - if(Type.IsValueType) - context.LoadObjByRef(); // stack: [ref obj] - else - context.LoadObj(); // stack: [obj] - Type memberType; - switch(member.Member.MemberType) - { - case MemberTypes.Property: - var property = (PropertyInfo)member.Member; - var getter = property.GetGetMethod(true); - if(getter == null) - throw new MissingMethodException(Type.Name, property.Name + "_get"); - il.Call(getter, Type); // stack: [obj.prop] - memberType = property.PropertyType; - break; - case MemberTypes.Field: - var field = (FieldInfo)member.Member; - il.Ldfld(field); // stack: [obj.field] - memberType = field.FieldType; - break; - default: - throw new NotSupportedException("Data member of type " + member.Member.MemberType + " is not supported"); - } - il.Ldc_I4(0); // stack: [obj.prop, false] - context.LoadResult(); // stack: [obj.prop, false, result] - context.LoadIndexByRef(); // stack: [obj.prop, false, result, ref index] - il.Dup(); // stack: [obj.prop, false, result, ref index, ref index] - context.LoadIndex(); // stack: [obj.prop, false, result, ref index, ref index, index] - il.Dup(); // stack: [obj.prop, false, result, ref index, ref index, index, index] - il.Stloc(prev); // prev = index; stack: [obj.prop, false, result, ref index, ref index, index] - il.Ldc_I4(8); // stack: [obj.prop, false, result, ref index, ref index, index, 8] - il.Add(); // stack: [obj.prop, false, result, ref index, ref index, index + 8] - il.Stind(typeof(int)); // index = index + 8; stack: [obj.prop, false, result, ref index] - context.LoadContext(); // stack: [obj.prop, false, result, ref index, context] - context.CallWriter(memberType); // writers[i](obj.prop, false, result, ref index, ref result, context) - context.LoadIndex(); // stack: [index] - il.Ldc_I4(8); // stack: [index, 8] - il.Sub(); // stack: [index - 8] - il.Ldloc(prev); // stack: [index - 8, prev] - var writeHashCodeLabel = il.DefineLabel("writeHashCode"); - il.Bgt(writeHashCodeLabel, false); // if(index - 8 > prev) goto writeHashCode; - context.LoadIndexByRef(); // stack: [ref index] - il.Ldloc(prev); // stack: [ref index, prev] - il.Stind(typeof(int)); // index = prev; - var nextLabel = il.DefineLabel("next"); - il.Br(nextLabel); // goto next; - - il.MarkLabel(writeHashCodeLabel); - - context.LoadResult(); // stack: [result] - il.Ldloc(prev); // stack: [result, prev] - il.Add(); // stack: [result + prev] - il.Ldc_I8((long)hashCodes[i]); // stack: [&result[index], prop.Name.HashCode] - il.Stind(typeof(long)); // *(long*)(result + prev) = prop.Name.HashCode; stack: [] - - il.MarkLabel(nextLabel); - } - - context.LoadIndex(); // stack: [index] - il.Ldloc(start); // stack: [index, start] - il.Sub(); // stack: [index - start] - il.Ldc_I4(5); // stack: [index - start, 5] - il.Sub(); // stack: [index - start - 5] - - il.Stloc(length); // length = index - start - 5; stack: [] - - if(!context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - { - var writeLengthLabel = il.DefineLabel("writeLength"); - il.Ldloc(length); // stack: [length] - il.Brtrue(writeLengthLabel); // if(length != 0) goto writeLength; - - context.LoadIndexByRef(); // stack: [ref index] - il.Ldloc(start); // stack: [ref index, start] - il.Stind(typeof(int)); // index = start - context.WriteNull(); - - il.MarkLabel(writeLengthLabel); - } - context.LoadResult(); // stack: [result] - il.Ldloc(start); // stack: [result, start] - il.Add(); // stack: [result + start] - il.Dup(); // stack: [result + start, result + start] - il.Ldc_I4((int)GroBufTypeCode.Object); // stack: [result + start, result + start, TypeCode.Object] - il.Stind(typeof(byte)); // *(result + start) = TypeCode.Object; stack: [result + start] - il.Ldc_I4(1); // stack: [result + start, 1] - il.Add(); // stack: [result + start + 1] - il.Ldloc(length); // stack: [result + start + 1, length] - il.Stind(typeof(int)); // *(int*)(result + start + 1) = length - } - - protected override bool IsReference { get { return true; } } - } +using System; +using System.Reflection; + +namespace GroBuf.Writers +{ + internal class ClassWriterBuilder : WriterBuilderBase + { + public ClassWriterBuilder(Type type) + : base(type) + { + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + foreach(var member in context.GetDataMembers(Type)) + { + Type memberType; + switch(member.Member.MemberType) + { + case MemberTypes.Property: + memberType = ((PropertyInfo)member.Member).PropertyType; + break; + case MemberTypes.Field: + memberType = ((FieldInfo)member.Member).FieldType; + break; + default: + throw new NotSupportedException("Data member of type " + member.Member.MemberType + " is not supported"); + } + context.BuildConstants(memberType); + } + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + var length = context.LocalInt; + var start = il.DeclareLocal(typeof(int)); + context.LoadIndexByRef(); // stack: [ref index] + context.LoadIndex(); // stack: [ref index, index] + il.Dup(); // stack: [ref index, index, index] + il.Stloc(start); // start = index; stack: [ref index, index] + il.Ldc_I4(5); // stack: [ref index, index, 5] + il.Add(); // stack: [ref index, index + 5] + il.Stind(typeof(int)); // index = index + 5; stack: [] + + var dataMembers = context.Context.GetDataMembers(Type); + var hashCodes = GroBufHelpers.CalcHashesAndCheck(dataMembers); + var prev = il.DeclareLocal(typeof(int)); + for(var i = 0; i < dataMembers.Length; i++) + { + var member = dataMembers[i]; + + if(Type.IsValueType) + context.LoadObjByRef(); // stack: [ref obj] + else + context.LoadObj(); // stack: [obj] + Type memberType; + switch(member.Member.MemberType) + { + case MemberTypes.Property: + var property = (PropertyInfo)member.Member; + var getter = property.GetGetMethod(true); + if(getter == null) + throw new MissingMethodException(Type.Name, property.Name + "_get"); + il.Call(getter, Type); // stack: [obj.prop] + memberType = property.PropertyType; + break; + case MemberTypes.Field: + var field = (FieldInfo)member.Member; + il.Ldfld(field); // stack: [obj.field] + memberType = field.FieldType; + break; + default: + throw new NotSupportedException("Data member of type " + member.Member.MemberType + " is not supported"); + } + il.Ldc_I4(0); // stack: [obj.prop, false] + context.LoadResult(); // stack: [obj.prop, false, result] + context.LoadIndexByRef(); // stack: [obj.prop, false, result, ref index] + il.Dup(); // stack: [obj.prop, false, result, ref index, ref index] + context.LoadIndex(); // stack: [obj.prop, false, result, ref index, ref index, index] + il.Dup(); // stack: [obj.prop, false, result, ref index, ref index, index, index] + il.Stloc(prev); // prev = index; stack: [obj.prop, false, result, ref index, ref index, index] + il.Ldc_I4(8); // stack: [obj.prop, false, result, ref index, ref index, index, 8] + il.Add(); // stack: [obj.prop, false, result, ref index, ref index, index + 8] + il.Stind(typeof(int)); // index = index + 8; stack: [obj.prop, false, result, ref index] + context.LoadContext(); // stack: [obj.prop, false, result, ref index, context] + context.CallWriter(memberType); // writers[i](obj.prop, false, result, ref index, ref result, context) + context.LoadIndex(); // stack: [index] + il.Ldc_I4(8); // stack: [index, 8] + il.Sub(); // stack: [index - 8] + il.Ldloc(prev); // stack: [index - 8, prev] + var writeHashCodeLabel = il.DefineLabel("writeHashCode"); + il.Bgt(writeHashCodeLabel, false); // if(index - 8 > prev) goto writeHashCode; + context.LoadIndexByRef(); // stack: [ref index] + il.Ldloc(prev); // stack: [ref index, prev] + il.Stind(typeof(int)); // index = prev; + var nextLabel = il.DefineLabel("next"); + il.Br(nextLabel); // goto next; + + il.MarkLabel(writeHashCodeLabel); + + context.LoadResult(); // stack: [result] + il.Ldloc(prev); // stack: [result, prev] + il.Add(); // stack: [result + prev] + il.Ldc_I8((long)hashCodes[i]); // stack: [&result[index], prop.Name.HashCode] + il.Stind(typeof(long)); // *(long*)(result + prev) = prop.Name.HashCode; stack: [] + + il.MarkLabel(nextLabel); + } + + context.LoadIndex(); // stack: [index] + il.Ldloc(start); // stack: [index, start] + il.Sub(); // stack: [index - start] + il.Ldc_I4(5); // stack: [index - start, 5] + il.Sub(); // stack: [index - start - 5] + + il.Stloc(length); // length = index - start - 5; stack: [] + + if(!context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + { + var writeLengthLabel = il.DefineLabel("writeLength"); + il.Ldloc(length); // stack: [length] + il.Brtrue(writeLengthLabel); // if(length != 0) goto writeLength; + + context.LoadIndexByRef(); // stack: [ref index] + il.Ldloc(start); // stack: [ref index, start] + il.Stind(typeof(int)); // index = start + context.WriteNull(); + + il.MarkLabel(writeLengthLabel); + } + context.LoadResult(); // stack: [result] + il.Ldloc(start); // stack: [result, start] + il.Add(); // stack: [result + start] + il.Dup(); // stack: [result + start, result + start] + il.Ldc_I4((int)GroBufTypeCode.Object); // stack: [result + start, result + start, TypeCode.Object] + il.Stind(typeof(byte)); // *(result + start) = TypeCode.Object; stack: [result + start] + il.Ldc_I4(1); // stack: [result + start, 1] + il.Add(); // stack: [result + start + 1] + il.Ldloc(length); // stack: [result + start + 1, length] + il.Stind(typeof(int)); // *(int*)(result + start + 1) = length + } + + protected override bool IsReference { get { return true; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/CustomWriterBuilder.cs b/GroBuf/Writers/CustomWriterBuilder.cs similarity index 98% rename from GroBuf/GroBuf/Writers/CustomWriterBuilder.cs rename to GroBuf/Writers/CustomWriterBuilder.cs index 283127a..8716d70 100644 --- a/GroBuf/GroBuf/Writers/CustomWriterBuilder.cs +++ b/GroBuf/Writers/CustomWriterBuilder.cs @@ -1,83 +1,83 @@ -using System; -using System.Collections.Generic; - -using GrEmit.Utils; - -namespace GroBuf.Writers -{ - internal class CustomWriterBuilder : WriterBuilderBase - { - public CustomWriterBuilder(Type type, IGroBufCustomSerializer customSerializer) - : base(type) - { - this.customSerializer = customSerializer; - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.SetFields(Type, new[] {new KeyValuePair("customSerializer_" + Type.Name + "_" + Guid.NewGuid(), typeof(IGroBufCustomSerializer))}); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var customSerializerField = context.Context.InitConstField(Type, 0, customSerializer); - var il = context.Il; - - var length = context.LocalInt; - var start = il.DeclareLocal(typeof(int)); - context.LoadIndexByRef(); // stack: [ref index] - context.LoadIndex(); // stack: [ref index, index] - il.Dup(); // stack: [ref index, index, index] - il.Stloc(start); // start = index; stack: [ref index, index] - il.Ldc_I4(5); // stack: [ref index, index, 5] - il.Add(); // stack: [ref index, index + 5] - il.Stind(typeof(int)); // index = index + 5; stack: [] - - context.LoadField(customSerializerField); // stack: [customSerializer] - context.LoadObj(); // stack: [customSerializer, obj] - if(Type.IsValueType) - il.Box(Type); // stack: [customSerializer, (object)obj] - context.LoadWriteEmpty(); // stack: [customSerializer, (object)obj, writeEmpty] - context.LoadResult(); // stack: [customSerializer, (object)obj, writeEmpty, result] - context.LoadIndexByRef(); // stack: [customSerializer, (object)obj, writeEmpty, result, ref index] - context.LoadContext(); // stack: [customSerializer, (object)obj, writeEmpty, result, ref index, context] - int dummy = 0; - var writeMethod = HackHelpers.GetMethodDefinition(serializer => serializer.Write(null, false, IntPtr.Zero, ref dummy, null)); - il.Call(writeMethod); // customSerializer.Write((object)obj, writeEmpty, result, ref index, context); stack: [] - - context.LoadIndex(); // stack: [index] - il.Ldloc(start); // stack: [index, start] - il.Sub(); // stack: [index - start] - il.Ldc_I4(5); // stack: [index - start, 5] - il.Sub(); // stack: [index - start - 5] - - var writeLengthLabel = il.DefineLabel("writeLength"); - var doneLabel = il.DefineLabel("done"); - il.Dup(); // stack: [index - start - 5, index - start - 5] - il.Stloc(length); // length = index - start - 5; stack: [length] - il.Brtrue(writeLengthLabel); // if(length != 0) goto writeLength; - - context.LoadIndexByRef(); // stack: [ref index] - il.Ldloc(start); // stack: [ref index, start] - il.Stind(typeof(int)); // index = start - context.WriteNull(); - - il.MarkLabel(writeLengthLabel); - context.LoadResult(); // stack: [result] - il.Ldloc(start); // stack: [result, start] - il.Add(); // stack: [result + start] - il.Dup(); // stack: [result + start, result + start] - il.Ldc_I4((int)GroBufTypeCode.CustomData); // stack: [result + start, result + start, TypeCode.Object] - il.Stind(typeof(byte)); // *(result + start) = TypeCode.Object; stack: [result + start] - il.Ldc_I4(1); // stack: [result + start, 1] - il.Add(); // stack: [result + start + 1] - il.Ldloc(length); // stack: [result + start + 1, length] - il.Stind(typeof(int)); // *(int*)(result + start + 1) = length - il.MarkLabel(doneLabel); - } - - protected override bool IsReference { get { return false; } } - - private readonly IGroBufCustomSerializer customSerializer; - } +using System; +using System.Collections.Generic; + +using GrEmit.Utils; + +namespace GroBuf.Writers +{ + internal class CustomWriterBuilder : WriterBuilderBase + { + public CustomWriterBuilder(Type type, IGroBufCustomSerializer customSerializer) + : base(type) + { + this.customSerializer = customSerializer; + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.SetFields(Type, new[] {new KeyValuePair("customSerializer_" + Type.Name + "_" + Guid.NewGuid(), typeof(IGroBufCustomSerializer))}); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var customSerializerField = context.Context.InitConstField(Type, 0, customSerializer); + var il = context.Il; + + var length = context.LocalInt; + var start = il.DeclareLocal(typeof(int)); + context.LoadIndexByRef(); // stack: [ref index] + context.LoadIndex(); // stack: [ref index, index] + il.Dup(); // stack: [ref index, index, index] + il.Stloc(start); // start = index; stack: [ref index, index] + il.Ldc_I4(5); // stack: [ref index, index, 5] + il.Add(); // stack: [ref index, index + 5] + il.Stind(typeof(int)); // index = index + 5; stack: [] + + context.LoadField(customSerializerField); // stack: [customSerializer] + context.LoadObj(); // stack: [customSerializer, obj] + if(Type.IsValueType) + il.Box(Type); // stack: [customSerializer, (object)obj] + context.LoadWriteEmpty(); // stack: [customSerializer, (object)obj, writeEmpty] + context.LoadResult(); // stack: [customSerializer, (object)obj, writeEmpty, result] + context.LoadIndexByRef(); // stack: [customSerializer, (object)obj, writeEmpty, result, ref index] + context.LoadContext(); // stack: [customSerializer, (object)obj, writeEmpty, result, ref index, context] + int dummy = 0; + var writeMethod = HackHelpers.GetMethodDefinition(serializer => serializer.Write(null, false, IntPtr.Zero, ref dummy, null)); + il.Call(writeMethod); // customSerializer.Write((object)obj, writeEmpty, result, ref index, context); stack: [] + + context.LoadIndex(); // stack: [index] + il.Ldloc(start); // stack: [index, start] + il.Sub(); // stack: [index - start] + il.Ldc_I4(5); // stack: [index - start, 5] + il.Sub(); // stack: [index - start - 5] + + var writeLengthLabel = il.DefineLabel("writeLength"); + var doneLabel = il.DefineLabel("done"); + il.Dup(); // stack: [index - start - 5, index - start - 5] + il.Stloc(length); // length = index - start - 5; stack: [length] + il.Brtrue(writeLengthLabel); // if(length != 0) goto writeLength; + + context.LoadIndexByRef(); // stack: [ref index] + il.Ldloc(start); // stack: [ref index, start] + il.Stind(typeof(int)); // index = start + context.WriteNull(); + + il.MarkLabel(writeLengthLabel); + context.LoadResult(); // stack: [result] + il.Ldloc(start); // stack: [result, start] + il.Add(); // stack: [result + start] + il.Dup(); // stack: [result + start, result + start] + il.Ldc_I4((int)GroBufTypeCode.CustomData); // stack: [result + start, result + start, TypeCode.Object] + il.Stind(typeof(byte)); // *(result + start) = TypeCode.Object; stack: [result + start] + il.Ldc_I4(1); // stack: [result + start, 1] + il.Add(); // stack: [result + start + 1] + il.Ldloc(length); // stack: [result + start + 1, length] + il.Stind(typeof(int)); // *(int*)(result + start + 1) = length + il.MarkLabel(doneLabel); + } + + protected override bool IsReference { get { return false; } } + + private readonly IGroBufCustomSerializer customSerializer; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/DateTimeOffsetWriterBuilder.cs b/GroBuf/Writers/DateTimeOffsetWriterBuilder.cs similarity index 84% rename from GroBuf/GroBuf/Writers/DateTimeOffsetWriterBuilder.cs rename to GroBuf/Writers/DateTimeOffsetWriterBuilder.cs index 7ae6949..b933742 100644 --- a/GroBuf/GroBuf/Writers/DateTimeOffsetWriterBuilder.cs +++ b/GroBuf/Writers/DateTimeOffsetWriterBuilder.cs @@ -1,43 +1,43 @@ -using System; -using System.Reflection; - -namespace GroBuf.Writers -{ - internal class DateTimeOffsetWriterBuilder : WriterBuilderBase - { - public DateTimeOffsetWriterBuilder() - : base(typeof(DateTimeOffset)) - { - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.BuildConstants(typeof(DateTime)); - context.BuildConstants(typeof(short)); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - - context.WriteTypeCode(GroBufTypeCode.DateTimeOffset); - context.LoadObjByRef(); // stack: [obj] - il.Ldfld(Type.GetField("m_dateTime", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.m_dateTime] - context.LoadWriteEmpty(); // stack: [obj.m_dateTime, writeEmpty] - context.LoadResult(); // stack: [obj.m_dateTime, writeEmpty, result] - context.LoadIndexByRef(); // stack: [obj.m_dateTime, writeEmpty, result, ref index] - context.LoadContext(); // stack: [obj.m_dateTime, writeEmpty, result, ref index, context] - context.CallWriter(typeof(DateTime)); // writer(obj.m_dateTime, writeEmpty, result, ref index, context) - - context.LoadObjByRef(); // stack: [obj] - il.Ldfld(Type.GetField("m_offsetMinutes", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.m_offsetMinutes] - context.LoadWriteEmpty(); // stack: [obj.m_offsetMinutes, writeEmpty] - context.LoadResult(); // stack: [obj.m_offsetMinutes, writeEmpty, result] - context.LoadIndexByRef(); // stack: [obj.m_offsetMinutes, writeEmpty, result, ref index] - context.LoadContext(); // stack: [obj.m_offsetMinutes, writeEmpty, result, ref index, context] - context.CallWriter(typeof(short)); // writer(obj.m_offsetMinutes, writeEmpty, result, ref index, context) - } - - protected override bool IsReference { get { return false; } } - } +using System; +using System.Reflection; + +namespace GroBuf.Writers +{ + internal class DateTimeOffsetWriterBuilder : WriterBuilderBase + { + public DateTimeOffsetWriterBuilder() + : base(typeof(DateTimeOffset)) + { + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.BuildConstants(typeof(DateTime)); + context.BuildConstants(typeof(short)); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + + context.WriteTypeCode(GroBufTypeCode.DateTimeOffset); + context.LoadObjByRef(); // stack: [obj] + il.Ldfld(Type.GetField(PlatformHelpers.DateTimeOffsetDateTimeFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.m_dateTime] + context.LoadWriteEmpty(); // stack: [obj.m_dateTime, writeEmpty] + context.LoadResult(); // stack: [obj.m_dateTime, writeEmpty, result] + context.LoadIndexByRef(); // stack: [obj.m_dateTime, writeEmpty, result, ref index] + context.LoadContext(); // stack: [obj.m_dateTime, writeEmpty, result, ref index, context] + context.CallWriter(typeof(DateTime)); // writer(obj.m_dateTime, writeEmpty, result, ref index, context) + + context.LoadObjByRef(); // stack: [obj] + il.Ldfld(Type.GetField(PlatformHelpers.DateTimeOffsetOffsetMinutesFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.m_offsetMinutes] + context.LoadWriteEmpty(); // stack: [obj.m_offsetMinutes, writeEmpty] + context.LoadResult(); // stack: [obj.m_offsetMinutes, writeEmpty, result] + context.LoadIndexByRef(); // stack: [obj.m_offsetMinutes, writeEmpty, result, ref index] + context.LoadContext(); // stack: [obj.m_offsetMinutes, writeEmpty, result, ref index, context] + context.CallWriter(typeof(short)); // writer(obj.m_offsetMinutes, writeEmpty, result, ref index, context) + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/DateTimeWriterBuilder.cs b/GroBuf/Writers/DateTimeWriterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/DateTimeWriterBuilder.cs rename to GroBuf/Writers/DateTimeWriterBuilder.cs index 5b1f2b6..2f5c9de 100644 --- a/GroBuf/GroBuf/Writers/DateTimeWriterBuilder.cs +++ b/GroBuf/Writers/DateTimeWriterBuilder.cs @@ -1,35 +1,35 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; - -namespace GroBuf.Writers -{ - internal class DateTimeWriterBuilder : WriterBuilderBase - { - public DateTimeWriterBuilder() - : base(typeof(DateTime)) - { - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - context.WriteTypeCode(GroBufTypeCode.DateTimeNew); - il.Ldc_I4(8); - context.AssertLength(); - context.GoToCurrentLocation(); // stack: [&result[index]] - context.LoadObjByRef(); // stack: [&result[index], &obj] - il.Call(dateTimeToBinaryMethod, Type); // stack: [&result[index], obj.ToBinary()] - il.Stind(typeof(long)); // result[index] = obj.ToBinary() - context.IncreaseIndexBy8(); // index = index + 8 - } - - protected override bool IsReference { get { return false; } } - - private static readonly MethodInfo dateTimeToBinaryMethod = ((MethodCallExpression)((Expression>)(dateTime => dateTime.ToBinary())).Body).Method; - } +using System; +using System.Linq.Expressions; +using System.Reflection; + +namespace GroBuf.Writers +{ + internal class DateTimeWriterBuilder : WriterBuilderBase + { + public DateTimeWriterBuilder() + : base(typeof(DateTime)) + { + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + context.WriteTypeCode(GroBufTypeCode.DateTimeNew); + il.Ldc_I4(8); + context.AssertLength(); + context.GoToCurrentLocation(); // stack: [&result[index]] + context.LoadObjByRef(); // stack: [&result[index], &obj] + il.Call(dateTimeToBinaryMethod, Type); // stack: [&result[index], obj.ToBinary()] + il.Stind(typeof(long)); // result[index] = obj.ToBinary() + context.IncreaseIndexBy8(); // index = index + 8 + } + + protected override bool IsReference { get { return false; } } + + private static readonly MethodInfo dateTimeToBinaryMethod = ((MethodCallExpression)((Expression>)(dateTime => dateTime.ToBinary())).Body).Method; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/DictionaryWriterBuilder.cs b/GroBuf/Writers/DictionaryWriterBuilder.cs similarity index 98% rename from GroBuf/GroBuf/Writers/DictionaryWriterBuilder.cs rename to GroBuf/Writers/DictionaryWriterBuilder.cs index bb482d9..2634101 100644 --- a/GroBuf/GroBuf/Writers/DictionaryWriterBuilder.cs +++ b/GroBuf/Writers/DictionaryWriterBuilder.cs @@ -1,133 +1,133 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.Writers -{ - internal class DictionaryWriterBuilder : WriterBuilderBase - { - public DictionaryWriterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Dictionary<,>))) - throw new InvalidOperationException("Dictionary expected but was '" + Type + "'"); - keyType = Type.GetGenericArguments()[0]; - valueType = Type.GetGenericArguments()[1]; - } - - protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Count] - context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.BuildConstants(keyType); - context.BuildConstants(valueType); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - context.WriteTypeCode(GroBufTypeCode.Dictionary); - context.LoadIndex(); // stack: [index] - var start = context.LocalInt; - il.Stloc(start); // start = index - il.Ldc_I4(8); // data length + dict size = 8 - context.AssertLength(); - context.IncreaseIndexBy4(); // index = index + 4 - context.GoToCurrentLocation(); // stack: [&result[index]] - context.LoadObj(); // stack: [&result[index], obj] - il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [&result[index], obj.Count] - il.Stind(typeof(int)); // *(int*)&result[index] = obj.Count; stack: [] - context.IncreaseIndexBy4(); // index = index + 4; stack: [] - - context.LoadObj(); // stack: [obj] - // traverse all buckets - il.Ldfld(Type.GetField("count", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.count] - var count = il.DeclareLocal(typeof(int)); - il.Stloc(count); // count = obj.count; stack: [] - - var writeDataLengthLabel = il.DefineLabel("writeDataLength"); - il.Ldloc(count); // stack: [count] - il.Brfalse(writeDataLengthLabel); // if(count == 0) goto writeDataLength; stack: [] - - context.LoadObj(); // stack: [obj] - var entryType = Type.GetNestedType("Entry", BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); - var entries = il.DeclareLocal(entryType.MakeArrayType()); - il.Ldfld(Type.GetField("entries", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.entries] - il.Stloc(entries); // entries = obj.entries; stack: [] - - var i = il.DeclareLocal(typeof(int)); - il.Ldc_I4(0); // stack: [0] - il.Stloc(i); // i = 0; stack: [] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - il.Ldloc(entries); // stack: [entries] - il.Ldloc(i); // stack: [entries, i] - il.Ldelema(entryType); // stack: [&entries[i]] - il.Dup(); // stack: [&entries[i], &entries[i]] - var entry = il.DeclareLocal(entryType.MakeByRefType()); - il.Stloc(entry); // entry = &entries[i]; stack: [entry] - il.Ldfld(entryType.GetField("hashCode")); // stack: [entry.hashCode] - il.Ldc_I4(0); // stack: [entry.hashCode, 0] - var nextLabel = il.DefineLabel("next"); - il.Blt(nextLabel, false); // if(entry.hashCode < 0) goto next; stack: [] - - il.Ldloc(entry); // stack: [entry] - il.Ldfld(entryType.GetField("key")); // stack: [entry.key] - il.Ldc_I4(1); // stack: [obj[i].key, true] - context.LoadResult(); // stack: [obj[i].key, true, result] - context.LoadIndexByRef(); // stack: [obj[i].key, true, result, ref index] - context.LoadContext(); // stack: [obj[i].key, true, result, ref index, context] - context.CallWriter(keyType); // write(obj[i].key, true, result, ref index, context); stack: [] - - il.Ldloc(entry); // stack: [entry] - il.Ldfld(entryType.GetField("value")); // stack: [entry.value] - il.Ldc_I4(1); // stack: [obj[i].value, true] - context.LoadResult(); // stack: [obj[i].value, true, result] - context.LoadIndexByRef(); // stack: [obj[i].value, true, result, ref index] - context.LoadContext(); // stack: [obj[i].value, true, result, ref index, context] - context.CallWriter(valueType); // writer(obj[i].value, true, result, ref index, context); stack: [] - - il.MarkLabel(nextLabel); - il.Ldloc(count); // stack: [ count] - il.Ldloc(i); // stack: [count, i] - il.Ldc_I4(1); // stack: [count, i, 1] - il.Add(); // stack: [count, i + 1] - il.Dup(); // stack: [count, i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [count, i] - il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [] - - il.MarkLabel(writeDataLengthLabel); - context.LoadResult(); // stack: [result] - il.Ldloc(start); // stack: [result, start] - il.Add(); // stack: [result + start] - context.LoadIndex(); // stack: [result + start, index] - il.Ldloc(start); // stack: [result + start, index, start] - il.Sub(); // stack: [result + start, index - start] - il.Ldc_I4(4); // stack: [result + start, index - start, 4] - il.Sub(); // stack: [result + start, index - start - 4] - il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 - } - - private readonly Type keyType; - private readonly Type valueType; - } +using System; +using System.Collections.Generic; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.Writers +{ + internal class DictionaryWriterBuilder : WriterBuilderBase + { + public DictionaryWriterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Dictionary<,>))) + throw new InvalidOperationException("Dictionary expected but was '" + Type + "'"); + keyType = Type.GetGenericArguments()[0]; + valueType = Type.GetGenericArguments()[1]; + } + + protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Count] + context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.BuildConstants(keyType); + context.BuildConstants(valueType); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + context.WriteTypeCode(GroBufTypeCode.Dictionary); + context.LoadIndex(); // stack: [index] + var start = context.LocalInt; + il.Stloc(start); // start = index + il.Ldc_I4(8); // data length + dict size = 8 + context.AssertLength(); + context.IncreaseIndexBy4(); // index = index + 4 + context.GoToCurrentLocation(); // stack: [&result[index]] + context.LoadObj(); // stack: [&result[index], obj] + il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [&result[index], obj.Count] + il.Stind(typeof(int)); // *(int*)&result[index] = obj.Count; stack: [] + context.IncreaseIndexBy4(); // index = index + 4; stack: [] + + context.LoadObj(); // stack: [obj] + // traverse all buckets + il.Ldfld(Type.GetField("count", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.count] + var count = il.DeclareLocal(typeof(int)); + il.Stloc(count); // count = obj.count; stack: [] + + var writeDataLengthLabel = il.DefineLabel("writeDataLength"); + il.Ldloc(count); // stack: [count] + il.Brfalse(writeDataLengthLabel); // if(count == 0) goto writeDataLength; stack: [] + + context.LoadObj(); // stack: [obj] + var entryType = Type.GetNestedType("Entry", BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); + var entries = il.DeclareLocal(entryType.MakeArrayType()); + il.Ldfld(Type.GetField("entries", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.entries] + il.Stloc(entries); // entries = obj.entries; stack: [] + + var i = il.DeclareLocal(typeof(int)); + il.Ldc_I4(0); // stack: [0] + il.Stloc(i); // i = 0; stack: [] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + il.Ldloc(entries); // stack: [entries] + il.Ldloc(i); // stack: [entries, i] + il.Ldelema(entryType); // stack: [&entries[i]] + il.Dup(); // stack: [&entries[i], &entries[i]] + var entry = il.DeclareLocal(entryType.MakeByRefType()); + il.Stloc(entry); // entry = &entries[i]; stack: [entry] + il.Ldfld(entryType.GetField("hashCode")); // stack: [entry.hashCode] + il.Ldc_I4(0); // stack: [entry.hashCode, 0] + var nextLabel = il.DefineLabel("next"); + il.Blt(nextLabel, false); // if(entry.hashCode < 0) goto next; stack: [] + + il.Ldloc(entry); // stack: [entry] + il.Ldfld(entryType.GetField("key")); // stack: [entry.key] + il.Ldc_I4(1); // stack: [obj[i].key, true] + context.LoadResult(); // stack: [obj[i].key, true, result] + context.LoadIndexByRef(); // stack: [obj[i].key, true, result, ref index] + context.LoadContext(); // stack: [obj[i].key, true, result, ref index, context] + context.CallWriter(keyType); // write(obj[i].key, true, result, ref index, context); stack: [] + + il.Ldloc(entry); // stack: [entry] + il.Ldfld(entryType.GetField("value")); // stack: [entry.value] + il.Ldc_I4(1); // stack: [obj[i].value, true] + context.LoadResult(); // stack: [obj[i].value, true, result] + context.LoadIndexByRef(); // stack: [obj[i].value, true, result, ref index] + context.LoadContext(); // stack: [obj[i].value, true, result, ref index, context] + context.CallWriter(valueType); // writer(obj[i].value, true, result, ref index, context); stack: [] + + il.MarkLabel(nextLabel); + il.Ldloc(count); // stack: [ count] + il.Ldloc(i); // stack: [count, i] + il.Ldc_I4(1); // stack: [count, i, 1] + il.Add(); // stack: [count, i + 1] + il.Dup(); // stack: [count, i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [count, i] + il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [] + + il.MarkLabel(writeDataLengthLabel); + context.LoadResult(); // stack: [result] + il.Ldloc(start); // stack: [result, start] + il.Add(); // stack: [result + start] + context.LoadIndex(); // stack: [result + start, index] + il.Ldloc(start); // stack: [result + start, index, start] + il.Sub(); // stack: [result + start, index - start] + il.Ldc_I4(4); // stack: [result + start, index - start, 4] + il.Sub(); // stack: [result + start, index - start - 4] + il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 + } + + private readonly Type keyType; + private readonly Type valueType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/EnumWriterBuilder.cs b/GroBuf/Writers/EnumWriterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/EnumWriterBuilder.cs rename to GroBuf/Writers/EnumWriterBuilder.cs index 17cd8de..6635fac 100644 --- a/GroBuf/GroBuf/Writers/EnumWriterBuilder.cs +++ b/GroBuf/Writers/EnumWriterBuilder.cs @@ -1,71 +1,71 @@ -using System; -using System.Collections.Generic; - -namespace GroBuf.Writers -{ - internal class EnumWriterBuilder : WriterBuilderBase - { - public EnumWriterBuilder(Type type) - : base(type) - { - if(!Type.IsEnum) throw new InvalidOperationException("Enum expected but was " + Type); - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.SetFields(Type, new[] - { - new KeyValuePair("hashCodes_" + Type.Name + "_" + Guid.NewGuid(), typeof(ulong[])), - new KeyValuePair("values_" + Type.Name + "_" + Guid.NewGuid(), typeof(int[])), - }); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - int[] values; - ulong[] hashCodes; - EnumHelpers.BuildHashCodesTable(Type, out values, out hashCodes); - var hashCodesField = context.Context.InitConstField(Type, 0, hashCodes); - var valuesField = context.Context.InitConstField(Type, 1, values); - - var il = context.Il; - context.LoadField(valuesField); // stack: [values] - context.LoadObj(); // stack: [values, obj] - il.Ldc_I4(values.Length); // stack: [values, obj, values.Length] - il.Rem(true); // stack: [values, obj % values.Length] - il.Ldelem(typeof(int)); // stack: [values[obj % values.Length]] - context.LoadObj(); // stack: [values[obj % values.Length], obj] - il.Ceq(); // stack: [values[obj % values.Length] == obj] - var writeIntLabel = il.DefineLabel("writeInt"); - il.Brfalse(writeIntLabel); // if(values[obj % values.Length] != obj) goto writeInt - - context.LoadField(hashCodesField); // stack: [hashCodes] - context.LoadObj(); // stack: [hashCodes, obj] - il.Ldc_I4(hashCodes.Length); // stack: [hashCodes, obj, hashCodes.Length] - il.Rem(true); // stack: [hashCodes, obj % hashCodes.Length] - il.Ldelem(typeof(long)); // stack: [hashCodes[obj % hashCodes.Length] = hashCode] - var hashCode = il.DeclareLocal(typeof(ulong)); - il.Dup(); // stack: [hashCode, hashCode] - il.Stloc(hashCode); // hashCode = hashCodes[obj % hashCodes.Length]; stack: [hashCode] - il.Brfalse(writeIntLabel); - context.WriteTypeCode(GroBufTypeCode.Enum); - il.Ldc_I4(8); - context.AssertLength(); - context.GoToCurrentLocation(); // stack: [&result[index]] - il.Ldloc(hashCode); // stack: [&result[index], hashCode] - il.Stind(typeof(long)); // *(int64*)&result[index] = hashCode - context.IncreaseIndexBy8(); // index = index + 8; - il.Ret(); - il.MarkLabel(writeIntLabel); - context.WriteTypeCode(GroBufTypeCode.Int32); - il.Ldc_I4(4); - context.AssertLength(); - context.GoToCurrentLocation(); // stack: [&result[index]] - context.LoadObj(); // stack: [&result[index], obj] - il.Stind(typeof(int)); // result[index] = obj - context.IncreaseIndexBy4(); // index = index + 4 - } - - protected override bool IsReference { get { return false; } } - } +using System; +using System.Collections.Generic; + +namespace GroBuf.Writers +{ + internal class EnumWriterBuilder : WriterBuilderBase + { + public EnumWriterBuilder(Type type) + : base(type) + { + if(!Type.IsEnum) throw new InvalidOperationException("Enum expected but was " + Type); + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.SetFields(Type, new[] + { + new KeyValuePair("hashCodes_" + Type.Name + "_" + Guid.NewGuid(), typeof(ulong[])), + new KeyValuePair("values_" + Type.Name + "_" + Guid.NewGuid(), typeof(int[])), + }); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + int[] values; + ulong[] hashCodes; + EnumHelpers.BuildHashCodesTable(Type, out values, out hashCodes); + var hashCodesField = context.Context.InitConstField(Type, 0, hashCodes); + var valuesField = context.Context.InitConstField(Type, 1, values); + + var il = context.Il; + context.LoadField(valuesField); // stack: [values] + context.LoadObj(); // stack: [values, obj] + il.Ldc_I4(values.Length); // stack: [values, obj, values.Length] + il.Rem(true); // stack: [values, obj % values.Length] + il.Ldelem(typeof(int)); // stack: [values[obj % values.Length]] + context.LoadObj(); // stack: [values[obj % values.Length], obj] + il.Ceq(); // stack: [values[obj % values.Length] == obj] + var writeIntLabel = il.DefineLabel("writeInt"); + il.Brfalse(writeIntLabel); // if(values[obj % values.Length] != obj) goto writeInt + + context.LoadField(hashCodesField); // stack: [hashCodes] + context.LoadObj(); // stack: [hashCodes, obj] + il.Ldc_I4(hashCodes.Length); // stack: [hashCodes, obj, hashCodes.Length] + il.Rem(true); // stack: [hashCodes, obj % hashCodes.Length] + il.Ldelem(typeof(long)); // stack: [hashCodes[obj % hashCodes.Length] = hashCode] + var hashCode = il.DeclareLocal(typeof(ulong)); + il.Dup(); // stack: [hashCode, hashCode] + il.Stloc(hashCode); // hashCode = hashCodes[obj % hashCodes.Length]; stack: [hashCode] + il.Brfalse(writeIntLabel); + context.WriteTypeCode(GroBufTypeCode.Enum); + il.Ldc_I4(8); + context.AssertLength(); + context.GoToCurrentLocation(); // stack: [&result[index]] + il.Ldloc(hashCode); // stack: [&result[index], hashCode] + il.Stind(typeof(long)); // *(int64*)&result[index] = hashCode + context.IncreaseIndexBy8(); // index = index + 8; + il.Ret(); + il.MarkLabel(writeIntLabel); + context.WriteTypeCode(GroBufTypeCode.Int32); + il.Ldc_I4(4); + context.AssertLength(); + context.GoToCurrentLocation(); // stack: [&result[index]] + context.LoadObj(); // stack: [&result[index], obj] + il.Stind(typeof(int)); // result[index] = obj + context.IncreaseIndexBy4(); // index = index + 4 + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/GuidWriterBuilder.cs b/GroBuf/Writers/GuidWriterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/GuidWriterBuilder.cs rename to GroBuf/Writers/GuidWriterBuilder.cs index e1f1bfc..1b4808c 100644 --- a/GroBuf/GroBuf/Writers/GuidWriterBuilder.cs +++ b/GroBuf/Writers/GuidWriterBuilder.cs @@ -1,38 +1,38 @@ -using System; - -namespace GroBuf.Writers -{ - internal class GuidWriterBuilder : WriterBuilderBase - { - public GuidWriterBuilder() - : base(typeof(Guid)) - { - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - context.WriteTypeCode(GroBufTypeCode.Guid); - il.Ldc_I4(16); - context.AssertLength(); - context.GoToCurrentLocation(); // stack: [&result[index]] - context.LoadObjByRef(); // stack: [&result[index], &obj] - il.Ldind(typeof(long)); // stack: [&result[index], (int64)*obj] - il.Stind(typeof(long)); // result[index] = (int64)*obj - context.IncreaseIndexBy8(); // index = index + 8 - context.GoToCurrentLocation(); // stack: [&result[index]] - context.LoadObjByRef(); // stack: [&result[index], &obj] - il.Ldc_I4(8); // stack: [&result[index], &obj, 8] - il.Add(); // stack: [&result[index], &obj + 8] - il.Ldind(typeof(long)); // stack: [&result[index], *(&obj+8)] - il.Stind(typeof(long)); // result[index] = (int64)*(obj + 8) - context.IncreaseIndexBy8(); // index = index + 8 - } - - protected override bool IsReference { get { return false; } } - } +using System; + +namespace GroBuf.Writers +{ + internal class GuidWriterBuilder : WriterBuilderBase + { + public GuidWriterBuilder() + : base(typeof(Guid)) + { + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + context.WriteTypeCode(GroBufTypeCode.Guid); + il.Ldc_I4(16); + context.AssertLength(); + context.GoToCurrentLocation(); // stack: [&result[index]] + context.LoadObjByRef(); // stack: [&result[index], &obj] + il.Ldind(typeof(long)); // stack: [&result[index], (int64)*obj] + il.Stind(typeof(long)); // result[index] = (int64)*obj + context.IncreaseIndexBy8(); // index = index + 8 + context.GoToCurrentLocation(); // stack: [&result[index]] + context.LoadObjByRef(); // stack: [&result[index], &obj] + il.Ldc_I4(8); // stack: [&result[index], &obj, 8] + il.Add(); // stack: [&result[index], &obj + 8] + il.Ldind(typeof(long)); // stack: [&result[index], *(&obj+8)] + il.Stind(typeof(long)); // result[index] = (int64)*(obj + 8) + context.IncreaseIndexBy8(); // index = index + 8 + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/HashSetWriterBuilder.cs b/GroBuf/Writers/HashSetWriterBuilder.cs similarity index 94% rename from GroBuf/GroBuf/Writers/HashSetWriterBuilder.cs rename to GroBuf/Writers/HashSetWriterBuilder.cs index 2068ba4..d813bee 100644 --- a/GroBuf/GroBuf/Writers/HashSetWriterBuilder.cs +++ b/GroBuf/Writers/HashSetWriterBuilder.cs @@ -1,121 +1,121 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.Writers -{ - internal class HashSetWriterBuilder : WriterBuilderBase - { - public HashSetWriterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(HashSet<>))) - throw new InvalidOperationException("HashSet expected but was '" + Type + "'"); - elementType = Type.GetGenericArguments()[0]; - } - - protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [&result[index], obj.Count] - context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - context.WriteTypeCode(GroBufTypeCode.Array); - context.LoadIndex(); // stack: [index] - var start = context.LocalInt; - il.Stloc(start); // start = index - il.Ldc_I4(8); - context.AssertLength(); // data length + hashset size = 8 - context.IncreaseIndexBy4(); // index = index + 4 - context.GoToCurrentLocation(); // stack: [&result[index]] - context.LoadObj(); // stack: [&result[index], obj] - il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [&result[index], obj.Count] - il.Stind(typeof(int)); // *(int*)&result[index] = obj.Count; stack: [] - context.IncreaseIndexBy4(); // index = index + 4; stack: [] - - context.LoadObj(); // stack: [obj] - var count = il.DeclareLocal(typeof(int)); - il.Ldfld(Type.GetField("m_lastIndex", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.m_lastIndex] - il.Dup(); - il.Stloc(count); // count = obj.m_lastIndex; stack: [] - var writeDataLengthLabel = il.DefineLabel("writeDataLength"); - il.Brfalse(writeDataLengthLabel); - - context.LoadObj(); // stack: [obj] - var slotType = Type.GetNestedType("Slot", BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); - var slots = il.DeclareLocal(slotType.MakeArrayType()); - il.Ldfld(Type.GetField("m_slots", BindingFlags.Instance | BindingFlags.NonPublic)); - il.Stloc(slots); - - var i = il.DeclareLocal(typeof(int)); - il.Ldc_I4(0); // stack: [0] - il.Stloc(i); // i = 0; stack: [] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - il.Ldloc(slots); // stack: [slots] - il.Ldloc(i); // stack: [slots, i] - il.Ldelema(slotType); // stack: [&slots[i]] - il.Dup(); // stack: [&slots[i], &slots[i]] - var slot = il.DeclareLocal(slotType.MakeByRefType()); - il.Stloc(slot); // slot = &slots[i]; stack: [slot] - il.Ldfld(slotType.GetField("hashCode", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [slot.hashCode] - - il.Ldc_I4(0); // stack: [slot.hashCode, 0] - var nextLabel = il.DefineLabel("next"); - il.Blt(nextLabel, false); // if(slot.hashCode < 0) goto next; stack: [] - - il.Ldloc(slot); // stack: [slot] - il.Ldfld(slotType.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [slot.value] - il.Ldc_I4(1); // stack: [obj[i], true] - context.LoadResult(); // stack: [obj[i], true, result] - context.LoadIndexByRef(); // stack: [obj[i], true, result, ref index] - context.LoadContext(); // stack: [obj[i], true, result, ref index, context] - context.CallWriter(elementType); // write(obj[i], true, result, ref index, context) - - il.MarkLabel(nextLabel); - il.Ldloc(count); // stack: [count] - il.Ldloc(i); // stack: [count, i] - il.Ldc_I4(1); // stack: [count, i, 1] - il.Add(); // stack: [count, i + 1] - il.Dup(); // stack: [count, i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [count, i] - il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [] - - il.MarkLabel(writeDataLengthLabel); - context.LoadResult(); // stack: [result] - il.Ldloc(start); // stack: [result, start] - il.Add(); // stack: [result + start] - context.LoadIndex(); // stack: [result + start, index] - il.Ldloc(start); // stack: [result + start, index, start] - il.Sub(); // stack: [result + start, index - start] - il.Ldc_I4(4); // stack: [result + start, index - start, 4] - il.Sub(); // stack: [result + start, index - start - 4] - il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 - } - - private readonly Type elementType; - } +using System; +using System.Collections.Generic; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.Writers +{ + internal class HashSetWriterBuilder : WriterBuilderBase + { + public HashSetWriterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(HashSet<>))) + throw new InvalidOperationException("HashSet expected but was '" + Type + "'"); + elementType = Type.GetGenericArguments()[0]; + } + + protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [&result[index], obj.Count] + context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + context.WriteTypeCode(GroBufTypeCode.Array); + context.LoadIndex(); // stack: [index] + var start = context.LocalInt; + il.Stloc(start); // start = index + il.Ldc_I4(8); + context.AssertLength(); // data length + hashset size = 8 + context.IncreaseIndexBy4(); // index = index + 4 + context.GoToCurrentLocation(); // stack: [&result[index]] + context.LoadObj(); // stack: [&result[index], obj] + il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [&result[index], obj.Count] + il.Stind(typeof(int)); // *(int*)&result[index] = obj.Count; stack: [] + context.IncreaseIndexBy4(); // index = index + 4; stack: [] + + context.LoadObj(); // stack: [obj] + var count = il.DeclareLocal(typeof(int)); + il.Ldfld(Type.GetField(PlatformHelpers.HashSetLastIndexFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.m_lastIndex] + il.Dup(); + il.Stloc(count); // count = obj.m_lastIndex; stack: [] + var writeDataLengthLabel = il.DefineLabel("writeDataLength"); + il.Brfalse(writeDataLengthLabel); + + context.LoadObj(); // stack: [obj] + var slotType = Type.GetNestedType("Slot", BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); + var slots = il.DeclareLocal(slotType.MakeArrayType()); + il.Ldfld(Type.GetField(PlatformHelpers.HashSetSlotsFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); + il.Stloc(slots); + + var i = il.DeclareLocal(typeof(int)); + il.Ldc_I4(0); // stack: [0] + il.Stloc(i); // i = 0; stack: [] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + il.Ldloc(slots); // stack: [slots] + il.Ldloc(i); // stack: [slots, i] + il.Ldelema(slotType); // stack: [&slots[i]] + il.Dup(); // stack: [&slots[i], &slots[i]] + var slot = il.DeclareLocal(slotType.MakeByRefType()); + il.Stloc(slot); // slot = &slots[i]; stack: [slot] + il.Ldfld(slotType.GetField("hashCode", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [slot.hashCode] + + il.Ldc_I4(0); // stack: [slot.hashCode, 0] + var nextLabel = il.DefineLabel("next"); + il.Blt(nextLabel, false); // if(slot.hashCode < 0) goto next; stack: [] + + il.Ldloc(slot); // stack: [slot] + il.Ldfld(slotType.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [slot.value] + il.Ldc_I4(1); // stack: [obj[i], true] + context.LoadResult(); // stack: [obj[i], true, result] + context.LoadIndexByRef(); // stack: [obj[i], true, result, ref index] + context.LoadContext(); // stack: [obj[i], true, result, ref index, context] + context.CallWriter(elementType); // write(obj[i], true, result, ref index, context) + + il.MarkLabel(nextLabel); + il.Ldloc(count); // stack: [count] + il.Ldloc(i); // stack: [count, i] + il.Ldc_I4(1); // stack: [count, i, 1] + il.Add(); // stack: [count, i + 1] + il.Dup(); // stack: [count, i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [count, i] + il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [] + + il.MarkLabel(writeDataLengthLabel); + context.LoadResult(); // stack: [result] + il.Ldloc(start); // stack: [result, start] + il.Add(); // stack: [result + start] + context.LoadIndex(); // stack: [result + start, index] + il.Ldloc(start); // stack: [result + start, index, start] + il.Sub(); // stack: [result + start, index - start] + il.Ldc_I4(4); // stack: [result + start, index - start, 4] + il.Sub(); // stack: [result + start, index - start - 4] + il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 + } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/HashtableWriterBuilder.cs b/GroBuf/Writers/HashtableWriterBuilder.cs similarity index 92% rename from GroBuf/GroBuf/Writers/HashtableWriterBuilder.cs rename to GroBuf/Writers/HashtableWriterBuilder.cs index 3d0a13f..56e4e7a 100644 --- a/GroBuf/GroBuf/Writers/HashtableWriterBuilder.cs +++ b/GroBuf/Writers/HashtableWriterBuilder.cs @@ -1,131 +1,131 @@ -using System.Collections; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.Writers -{ - internal class HashtableWriterBuilder : WriterBuilderBase - { - public HashtableWriterBuilder() - : base(typeof(Hashtable)) - { - } - - protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Ldfld(Type.GetField("count", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] - context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.BuildConstants(typeof(object)); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - context.WriteTypeCode(GroBufTypeCode.Dictionary); - context.LoadIndex(); // stack: [index] - var start = context.LocalInt; - il.Stloc(start); // start = index - il.Ldc_I4(8); // data length + dict size = 8 - context.AssertLength(); - context.IncreaseIndexBy4(); // index = index + 4 - context.GoToCurrentLocation(); // stack: [&result[index]] - context.LoadObj(); // stack: [&result[index], obj] - il.Ldfld(Type.GetField("count", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [&result[index], obj.Count] - il.Dup(); - var count = il.DeclareLocal(typeof(int)); - il.Stloc(count); // count = obj.Count; stack: [&result[index], obj.Count] - il.Stind(typeof(int)); // *(int*)&result[index] = count; stack: [] - context.IncreaseIndexBy4(); // index = index + 4; stack: [] - - var writeDataLengthLabel = il.DefineLabel("writeDataLength"); - il.Ldloc(count); // stack: [count] - il.Brfalse(writeDataLengthLabel); // if(count == 0) goto writeDataLength; stack: [] - - context.LoadObj(); // stack: [obj] - var bucketType = Type.GetNestedType("bucket", BindingFlags.NonPublic); - var buckets = il.DeclareLocal(bucketType.MakeArrayType()); - var bucketsField = Type.GetField("buckets", BindingFlags.Instance | BindingFlags.NonPublic); - il.Ldfld(bucketsField); // stack: [obj.buckets] - il.Stloc(buckets); // buckets = obj.buckets; stack: [] - il.Ldloc(buckets); // stack: [buckets] - il.Ldlen(); // stack: [buckets.Length] - il.Stloc(count); // count = buckets.Length; stack: [] - - var i = il.DeclareLocal(typeof(int)); - il.Ldc_I4(0); // stack: [0] - il.Stloc(i); // i = 0; stack: [] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - il.Ldloc(buckets); // stack: [buckets] - il.Ldloc(i); // stack: [buckets, i] - il.Ldelema(bucketType); // stack: [&buckets[i]] - il.Dup(); // stack: [&buckets[i], &buckets[i]] - var bucket = il.DeclareLocal(bucketType.MakeByRefType()); - il.Stloc(bucket); // bucket = &buckets[i]; stack: [bucket] - il.Ldfld(bucketType.GetField("key")); // stack: [bucket.key] - il.Dup(); // stack: [bucket.key, bucket.key] - var key = il.DeclareLocal(typeof(object)); - il.Stloc(key); // key = bucket.key; stack: [key] - - var nextLabel = il.DefineLabel("next"); - il.Brfalse(nextLabel); // if(bucket.key == null) goto next; stack: [] - il.Ldloc(key); // stack: [key] - context.LoadObj(); // stack: [key, obj] - il.Ldfld(bucketsField); // stack: [key, obj.buckets] - il.Beq(nextLabel); // if(key == obj.buckets) goto next; stack: [] - - il.Ldloc(key); // stack: [obj[i].key] - il.Ldc_I4(1); // stack: [obj[i].key, true] - context.LoadResult(); // stack: [obj[i].key, true, result] - context.LoadIndexByRef(); // stack: [obj[i].key, true, result, ref index] - context.LoadContext(); // stack: [obj[i].key, true, result, ref index, context] - context.CallWriter(typeof(object)); // write(obj[i].key, true, result, ref index, context); stack: [] - - il.Ldloc(bucket); // stack: [bucket] - il.Ldfld(bucketType.GetField("val")); // stack: [bucket.val] - il.Ldc_I4(1); // stack: [obj[i].value, true] - context.LoadResult(); // stack: [obj[i].value, true, result] - context.LoadIndexByRef(); // stack: [obj[i].value, true, result, ref index] - context.LoadContext(); // stack: [obj[i].value, true, result, ref index, context] - context.CallWriter(typeof(object)); // writer(obj[i].value, true, result, ref index, context); stack: [] - - il.MarkLabel(nextLabel); - il.Ldloc(count); // stack: [ count] - il.Ldloc(i); // stack: [count, i] - il.Ldc_I4(1); // stack: [count, i, 1] - il.Add(); // stack: [count, i + 1] - il.Dup(); // stack: [count, i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [count, i] - il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [] - - il.MarkLabel(writeDataLengthLabel); - context.LoadResult(); // stack: [result] - il.Ldloc(start); // stack: [result, start] - il.Add(); // stack: [result + start] - context.LoadIndex(); // stack: [result + start, index] - il.Ldloc(start); // stack: [result + start, index, start] - il.Sub(); // stack: [result + start, index - start] - il.Ldc_I4(4); // stack: [result + start, index - start, 4] - il.Sub(); // stack: [result + start, index - start - 4] - il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 - } - - protected override bool IsReference { get { return true; } } - } +using System.Collections; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.Writers +{ + internal class HashtableWriterBuilder : WriterBuilderBase + { + public HashtableWriterBuilder() + : base(typeof(Hashtable)) + { + } + + protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Ldfld(Type.GetField(PlatformHelpers.HashtableCountFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] + context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.BuildConstants(typeof(object)); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + context.WriteTypeCode(GroBufTypeCode.Dictionary); + context.LoadIndex(); // stack: [index] + var start = context.LocalInt; + il.Stloc(start); // start = index + il.Ldc_I4(8); // data length + dict size = 8 + context.AssertLength(); + context.IncreaseIndexBy4(); // index = index + 4 + context.GoToCurrentLocation(); // stack: [&result[index]] + context.LoadObj(); // stack: [&result[index], obj] + il.Ldfld(Type.GetField(PlatformHelpers.HashtableCountFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [&result[index], obj.Count] + il.Dup(); + var count = il.DeclareLocal(typeof(int)); + il.Stloc(count); // count = obj.Count; stack: [&result[index], obj.Count] + il.Stind(typeof(int)); // *(int*)&result[index] = count; stack: [] + context.IncreaseIndexBy4(); // index = index + 4; stack: [] + + var writeDataLengthLabel = il.DefineLabel("writeDataLength"); + il.Ldloc(count); // stack: [count] + il.Brfalse(writeDataLengthLabel); // if(count == 0) goto writeDataLength; stack: [] + + context.LoadObj(); // stack: [obj] + var bucketType = Type.GetNestedType("bucket", BindingFlags.NonPublic); + var buckets = il.DeclareLocal(bucketType.MakeArrayType()); + var bucketsField = Type.GetField(PlatformHelpers.HashtableBucketsFieldName, BindingFlags.Instance | BindingFlags.NonPublic); + il.Ldfld(bucketsField); // stack: [obj.buckets] + il.Stloc(buckets); // buckets = obj.buckets; stack: [] + il.Ldloc(buckets); // stack: [buckets] + il.Ldlen(); // stack: [buckets.Length] + il.Stloc(count); // count = buckets.Length; stack: [] + + var i = il.DeclareLocal(typeof(int)); + il.Ldc_I4(0); // stack: [0] + il.Stloc(i); // i = 0; stack: [] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + il.Ldloc(buckets); // stack: [buckets] + il.Ldloc(i); // stack: [buckets, i] + il.Ldelema(bucketType); // stack: [&buckets[i]] + il.Dup(); // stack: [&buckets[i], &buckets[i]] + var bucket = il.DeclareLocal(bucketType.MakeByRefType()); + il.Stloc(bucket); // bucket = &buckets[i]; stack: [bucket] + il.Ldfld(bucketType.GetField("key")); // stack: [bucket.key] + il.Dup(); // stack: [bucket.key, bucket.key] + var key = il.DeclareLocal(typeof(object)); + il.Stloc(key); // key = bucket.key; stack: [key] + + var nextLabel = il.DefineLabel("next"); + il.Brfalse(nextLabel); // if(bucket.key == null) goto next; stack: [] + il.Ldloc(key); // stack: [key] + context.LoadObj(); // stack: [key, obj] + il.Ldfld(bucketsField); // stack: [key, obj.buckets] + il.Beq(nextLabel); // if(key == obj.buckets) goto next; stack: [] + + il.Ldloc(key); // stack: [obj[i].key] + il.Ldc_I4(1); // stack: [obj[i].key, true] + context.LoadResult(); // stack: [obj[i].key, true, result] + context.LoadIndexByRef(); // stack: [obj[i].key, true, result, ref index] + context.LoadContext(); // stack: [obj[i].key, true, result, ref index, context] + context.CallWriter(typeof(object)); // write(obj[i].key, true, result, ref index, context); stack: [] + + il.Ldloc(bucket); // stack: [bucket] + il.Ldfld(bucketType.GetField("val")); // stack: [bucket.val] + il.Ldc_I4(1); // stack: [obj[i].value, true] + context.LoadResult(); // stack: [obj[i].value, true, result] + context.LoadIndexByRef(); // stack: [obj[i].value, true, result, ref index] + context.LoadContext(); // stack: [obj[i].value, true, result, ref index, context] + context.CallWriter(typeof(object)); // writer(obj[i].value, true, result, ref index, context); stack: [] + + il.MarkLabel(nextLabel); + il.Ldloc(count); // stack: [ count] + il.Ldloc(i); // stack: [count, i] + il.Ldc_I4(1); // stack: [count, i, 1] + il.Add(); // stack: [count, i + 1] + il.Dup(); // stack: [count, i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [count, i] + il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [] + + il.MarkLabel(writeDataLengthLabel); + context.LoadResult(); // stack: [result] + il.Ldloc(start); // stack: [result, start] + il.Add(); // stack: [result + start] + context.LoadIndex(); // stack: [result + start, index] + il.Ldloc(start); // stack: [result + start, index, start] + il.Sub(); // stack: [result + start, index - start] + il.Ldc_I4(4); // stack: [result + start, index - start, 4] + il.Sub(); // stack: [result + start, index - start - 4] + il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 + } + + protected override bool IsReference { get { return true; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/IPAddressWriterBuilder.cs b/GroBuf/Writers/IPAddressWriterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/IPAddressWriterBuilder.cs rename to GroBuf/Writers/IPAddressWriterBuilder.cs index 352380d..449714f 100644 --- a/GroBuf/GroBuf/Writers/IPAddressWriterBuilder.cs +++ b/GroBuf/Writers/IPAddressWriterBuilder.cs @@ -1,33 +1,33 @@ -using System.Net; -using System.Reflection; - -namespace GroBuf.Writers -{ - internal class IPAddressWriterBuilder : WriterBuilderBase - { - public IPAddressWriterBuilder() - : base(typeof(IPAddress)) - { - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.BuildConstants(typeof(byte[])); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - - context.LoadObj(); // stack: [obj] - il.Call(Type.GetMethod("GetAddressBytes", BindingFlags.Instance | BindingFlags.Public)); // stack: [obj.GetAddressBytes()] - context.LoadWriteEmpty(); // stack: [obj.GetAddressBytes(), writeEmpty] - context.LoadResult(); // stack: [obj.GetAddressBytes(), writeEmpty, result] - context.LoadIndexByRef(); // stack: [obj.GetAddressBytes(), writeEmpty, result, ref index] - context.LoadContext(); // stack: [obj.GetAddressBytes(), writeEmpty, result, ref index, context] - context.CallWriter(typeof(byte[])); // writer(obj.GetAddressBytes(), writeEmpty, result, ref index, context) - } - - protected override bool IsReference { get { return false; } } - } +using System.Net; +using System.Reflection; + +namespace GroBuf.Writers +{ + internal class IPAddressWriterBuilder : WriterBuilderBase + { + public IPAddressWriterBuilder() + : base(typeof(IPAddress)) + { + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.BuildConstants(typeof(byte[])); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + + context.LoadObj(); // stack: [obj] + il.Call(Type.GetMethod("GetAddressBytes", BindingFlags.Instance | BindingFlags.Public)); // stack: [obj.GetAddressBytes()] + context.LoadWriteEmpty(); // stack: [obj.GetAddressBytes(), writeEmpty] + context.LoadResult(); // stack: [obj.GetAddressBytes(), writeEmpty, result] + context.LoadIndexByRef(); // stack: [obj.GetAddressBytes(), writeEmpty, result, ref index] + context.LoadContext(); // stack: [obj.GetAddressBytes(), writeEmpty, result, ref index, context] + context.CallWriter(typeof(byte[])); // writer(obj.GetAddressBytes(), writeEmpty, result, ref index, context) + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/IWriterBuilder.cs b/GroBuf/Writers/IWriterBuilder.cs similarity index 96% rename from GroBuf/GroBuf/Writers/IWriterBuilder.cs rename to GroBuf/Writers/IWriterBuilder.cs index 24bc806..17f8803 100644 --- a/GroBuf/GroBuf/Writers/IWriterBuilder.cs +++ b/GroBuf/Writers/IWriterBuilder.cs @@ -1,8 +1,8 @@ -namespace GroBuf.Writers -{ - internal interface IWriterBuilder - { - void BuildWriter(WriterTypeBuilderContext writerTypeBuilderContext); - void BuildConstants(WriterConstantsBuilderContext context); - } +namespace GroBuf.Writers +{ + internal interface IWriterBuilder + { + void BuildWriter(WriterTypeBuilderContext writerTypeBuilderContext); + void BuildConstants(WriterConstantsBuilderContext context); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/IWriterCollection.cs b/GroBuf/Writers/IWriterCollection.cs similarity index 95% rename from GroBuf/GroBuf/Writers/IWriterCollection.cs rename to GroBuf/Writers/IWriterCollection.cs index d94906c..b2e1c9a 100644 --- a/GroBuf/GroBuf/Writers/IWriterCollection.cs +++ b/GroBuf/Writers/IWriterCollection.cs @@ -1,9 +1,9 @@ -using System; - -namespace GroBuf.Writers -{ - internal interface IWriterCollection - { - IWriterBuilder GetWriterBuilder(Type type, bool ignoreCustomSerialization); - } +using System; + +namespace GroBuf.Writers +{ + internal interface IWriterCollection + { + IWriterBuilder GetWriterBuilder(Type type, bool ignoreCustomSerialization); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/LazyWriterBuilder.cs b/GroBuf/Writers/LazyWriterBuilder.cs similarity index 90% rename from GroBuf/GroBuf/Writers/LazyWriterBuilder.cs rename to GroBuf/Writers/LazyWriterBuilder.cs index 9607703..0057db0 100644 --- a/GroBuf/GroBuf/Writers/LazyWriterBuilder.cs +++ b/GroBuf/Writers/LazyWriterBuilder.cs @@ -1,84 +1,83 @@ -using System; -using System.Reflection; - -namespace GroBuf.Writers -{ - internal class LazyWriterBuilder : WriterBuilderBase - { - public LazyWriterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Lazy<>))) - throw new InvalidOperationException("Expected Lazy but was " + Type); - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.BuildConstants(Type.GetGenericArguments()[0]); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - var argument = Type.GetGenericArguments()[0]; - - context.LoadObj(); // stack: [obj] - var factoryField = Type.GetField("m_valueFactory", BindingFlags.Instance | BindingFlags.NonPublic); - il.Ldfld(factoryField); // stack: [obj.m_valueFactory] - var factory = il.DeclareLocal(typeof(Func<>).MakeGenericType(argument)); - il.Dup(); - il.Stloc(factory); // factory = obj.m_valueFactory; stack: [factory] - var writeUsual = il.DefineLabel("writeUsual"); - il.Brfalse(writeUsual); // if(factory == null) goto writeUsual; stack: [] - il.Ldloc(factory); - string targetFieldName = GroBufHelpers.IsMono ? "m_target" : "_target"; - il.Ldfld(typeof(Delegate).GetField(targetFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [factory.target] - var rawData = il.DeclareLocal(typeof(RawData<>).MakeGenericType(Type.GetGenericArguments())); - il.Isinst(rawData.Type); // stack: [factory.target as RawData] - il.Dup(); - il.Stloc(rawData); // rawData = factory.target as RawData; stack: [rawData] - il.Brfalse(writeUsual); // if(!(rawData is RawData)) goto writeUsual; stack: [] - il.Ldloc(rawData); // stack: [rawData] - il.Ldfld(rawData.Type.GetField("serializerId", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [rawData.serializerId] - context.LoadSerializerId(); // stack: [rawData.serializerId, context.serializerId] - il.Bne_Un(writeUsual); // if(rawData.serializerId != context.serializerId) goto writeUsual; stack: [] - - var data = il.DeclareLocal(typeof(byte).MakeByRefType(), true); - var length = il.DeclareLocal(typeof(int)); - il.Ldloc(rawData); // stack: [rawData] - il.Ldfld(rawData.Type.GetField("data", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [rawData.data] - - il.Dup(); // stack: [rawData.data, rawData.data] - il.Ldlen(); // stack: [rawData.data, rawData.data.Length] - il.Stloc(length); // length = rawData.data.Length; stack: [rawData.data] - il.Ldc_I4(0); // stack: [rawData.data, 0] - il.Ldelema(typeof(byte)); // stack: [&rawData.data[0]] - il.Stloc(data); // data = &rawData.data; stack: [] - il.Ldloc(length); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&result[index]] - il.Ldloc(data); // stack: [&result[index], data] - il.Ldloc(length); // stack: [&result[index], data, data.Length] - il.Cpblk(); // result[index] = data; stack: [] - context.LoadIndexByRef(); // stack: [ref index] - context.LoadIndex(); // stack: [ref index, index] - il.Ldloc(length); // stack: [ref index, index, data.Length] - il.Add(); // stack: [ref index, index + data.Length] - il.Stind(typeof(int)); // index = index + data.Length; stack: [] - il.FreePinnedLocal(data); // data = null; stack: [] - il.Ret(); - - il.MarkLabel(writeUsual); - context.LoadObj(); // stack: [obj] - il.Call(Type.GetProperty("Value", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Value] - context.LoadWriteEmpty(); // stack: [obj.Value, writeEmpty] - context.LoadResult(); // stack: [obj.Value, writeEmpty, result] - context.LoadIndexByRef(); // stack: [obj.Value, writeEmpty, result, ref index] - context.LoadContext(); // stack: [obj.Value, writeEmpty, result, ref index, context] - context.CallWriter(argument); // writer(obj.Value, writeEmpty, result, ref index, context) - } - - protected override bool IsReference { get { return false; } } - } +using System; +using System.Reflection; + +namespace GroBuf.Writers +{ + internal class LazyWriterBuilder : WriterBuilderBase + { + public LazyWriterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Lazy<>))) + throw new InvalidOperationException("Expected Lazy but was " + Type); + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.BuildConstants(Type.GetGenericArguments()[0]); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + var argument = Type.GetGenericArguments()[0]; + + context.LoadObj(); // stack: [obj] + var factoryField = Type.GetField(PlatformHelpers.LazyValueFactoryFieldName, BindingFlags.Instance | BindingFlags.NonPublic); + il.Ldfld(factoryField); // stack: [obj.m_valueFactory] + var factory = il.DeclareLocal(typeof(Func<>).MakeGenericType(argument)); + il.Dup(); + il.Stloc(factory); // factory = obj.m_valueFactory; stack: [factory] + var writeUsual = il.DefineLabel("writeUsual"); + il.Brfalse(writeUsual); // if(factory == null) goto writeUsual; stack: [] + il.Ldloc(factory); + il.Ldfld(typeof(Delegate).GetField(PlatformHelpers.DelegateTargetFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [factory.target] + var rawData = il.DeclareLocal(typeof(RawData<>).MakeGenericType(Type.GetGenericArguments())); + il.Isinst(rawData.Type); // stack: [factory.target as RawData] + il.Dup(); + il.Stloc(rawData); // rawData = factory.target as RawData; stack: [rawData] + il.Brfalse(writeUsual); // if(!(rawData is RawData)) goto writeUsual; stack: [] + il.Ldloc(rawData); // stack: [rawData] + il.Ldfld(rawData.Type.GetField("serializerId", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [rawData.serializerId] + context.LoadSerializerId(); // stack: [rawData.serializerId, context.serializerId] + il.Bne_Un(writeUsual); // if(rawData.serializerId != context.serializerId) goto writeUsual; stack: [] + + var data = il.DeclareLocal(typeof(byte).MakeByRefType(), true); + var length = il.DeclareLocal(typeof(int)); + il.Ldloc(rawData); // stack: [rawData] + il.Ldfld(rawData.Type.GetField("data", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [rawData.data] + + il.Dup(); // stack: [rawData.data, rawData.data] + il.Ldlen(); // stack: [rawData.data, rawData.data.Length] + il.Stloc(length); // length = rawData.data.Length; stack: [rawData.data] + il.Ldc_I4(0); // stack: [rawData.data, 0] + il.Ldelema(typeof(byte)); // stack: [&rawData.data[0]] + il.Stloc(data); // data = &rawData.data; stack: [] + il.Ldloc(length); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&result[index]] + il.Ldloc(data); // stack: [&result[index], data] + il.Ldloc(length); // stack: [&result[index], data, data.Length] + il.Cpblk(); // result[index] = data; stack: [] + context.LoadIndexByRef(); // stack: [ref index] + context.LoadIndex(); // stack: [ref index, index] + il.Ldloc(length); // stack: [ref index, index, data.Length] + il.Add(); // stack: [ref index, index + data.Length] + il.Stind(typeof(int)); // index = index + data.Length; stack: [] + il.FreePinnedLocal(data); // data = null; stack: [] + il.Ret(); + + il.MarkLabel(writeUsual); + context.LoadObj(); // stack: [obj] + il.Call(Type.GetProperty("Value", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Value] + context.LoadWriteEmpty(); // stack: [obj.Value, writeEmpty] + context.LoadResult(); // stack: [obj.Value, writeEmpty, result] + context.LoadIndexByRef(); // stack: [obj.Value, writeEmpty, result, ref index] + context.LoadContext(); // stack: [obj.Value, writeEmpty, result, ref index, context] + context.CallWriter(argument); // writer(obj.Value, writeEmpty, result, ref index, context) + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/ListWriterBuilder.cs b/GroBuf/Writers/ListWriterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/ListWriterBuilder.cs rename to GroBuf/Writers/ListWriterBuilder.cs index c7f2e0a..83c6193 100644 --- a/GroBuf/GroBuf/Writers/ListWriterBuilder.cs +++ b/GroBuf/Writers/ListWriterBuilder.cs @@ -1,109 +1,109 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.Writers -{ - internal class ListWriterBuilder : WriterBuilderBase - { - public ListWriterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(List<>))) - throw new InvalidOperationException("Expected list but was '" + Type + "'"); - elementType = Type.GetGenericArguments()[0]; - } - - protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] - context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - context.WriteTypeCode(GroBufTypeCode.Array); - var count = il.DeclareLocal(typeof(int)); - context.LoadObj(); // stack: [obj] - il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] - il.Stloc(count); // count = obj.Count; stack: [] - - var items = il.DeclareLocal(elementType.MakeArrayType()); - context.LoadObj(); // stack: [obj] - il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj._items] - il.Stloc(items); // items = obj._items; stack: [] - context.LoadIndex(); // stack: [index] - var start = context.LocalInt; - il.Stloc(start); // start = index - - il.Ldc_I4(8); - context.AssertLength(); // data length + list size = 8 - - context.IncreaseIndexBy4(); // index = index + 4 - context.GoToCurrentLocation(); // stack: [&result[index]] - il.Ldloc(count); // stack: [&result[index], count] - il.Stind(typeof(int)); // *(int*)&result[index] = count; stack: [] - context.IncreaseIndexBy4(); // index = index + 4 - - var writeDataLengthLabel = il.DefineLabel("writeDataLength"); - il.Ldloc(count); // stack: [length] - il.Brfalse(writeDataLengthLabel); // if(length == 0) goto writeDataLength; stack: [] - - var i = il.DeclareLocal(typeof(int)); - il.Ldc_I4(0); // stack: [0] - il.Stloc(i); // i = 0; stack: [] - var cycleStart = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStart); - - il.Ldloc(items); // stack: [items] - il.Ldloc(i); // stack: [items, i] - il.Ldelem(elementType); - il.Ldc_I4(1); // stack: [obj[i], true] - context.LoadResult(); // stack: [obj[i], true, result] - context.LoadIndexByRef(); // stack: [obj[i], true, result, ref index] - context.LoadContext(); // stack: [obj[i], true, result, ref index, context] - context.CallWriter(elementType); // write(obj[i], true, result, ref index, context); stack: [] - il.Ldloc(count); // stack: [count] - il.Ldloc(i); // stack: [count, i] - il.Ldc_I4(1); // stack: [count, i, 1] - il.Add(); // stack: [count, i + 1] - il.Dup(); // stack: [count, i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [count, i] - il.Bgt(cycleStart, false); // if(count > i) goto cycleStart; stack: [] - - il.MarkLabel(writeDataLengthLabel); - context.LoadResult(); // stack: [result] - il.Ldloc(start); // stack: [result, start] - il.Add(); // stack: [result + start] - context.LoadIndex(); // stack: [result + start, index] - il.Ldloc(start); // stack: [result + start, index, start] - il.Sub(); // stack: [result + start, index - start] - il.Ldc_I4(4); // stack: [result + start, index - start, 4] - il.Sub(); // stack: [result + start, index - start - 4] - il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 - } - - private readonly Type elementType; - } +using System; +using System.Collections.Generic; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.Writers +{ + internal class ListWriterBuilder : WriterBuilderBase + { + public ListWriterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(List<>))) + throw new InvalidOperationException("Expected list but was '" + Type + "'"); + elementType = Type.GetGenericArguments()[0]; + } + + protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] + context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + context.WriteTypeCode(GroBufTypeCode.Array); + var count = il.DeclareLocal(typeof(int)); + context.LoadObj(); // stack: [obj] + il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] + il.Stloc(count); // count = obj.Count; stack: [] + + var items = il.DeclareLocal(elementType.MakeArrayType()); + context.LoadObj(); // stack: [obj] + il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj._items] + il.Stloc(items); // items = obj._items; stack: [] + context.LoadIndex(); // stack: [index] + var start = context.LocalInt; + il.Stloc(start); // start = index + + il.Ldc_I4(8); + context.AssertLength(); // data length + list size = 8 + + context.IncreaseIndexBy4(); // index = index + 4 + context.GoToCurrentLocation(); // stack: [&result[index]] + il.Ldloc(count); // stack: [&result[index], count] + il.Stind(typeof(int)); // *(int*)&result[index] = count; stack: [] + context.IncreaseIndexBy4(); // index = index + 4 + + var writeDataLengthLabel = il.DefineLabel("writeDataLength"); + il.Ldloc(count); // stack: [length] + il.Brfalse(writeDataLengthLabel); // if(length == 0) goto writeDataLength; stack: [] + + var i = il.DeclareLocal(typeof(int)); + il.Ldc_I4(0); // stack: [0] + il.Stloc(i); // i = 0; stack: [] + var cycleStart = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStart); + + il.Ldloc(items); // stack: [items] + il.Ldloc(i); // stack: [items, i] + il.Ldelem(elementType); + il.Ldc_I4(1); // stack: [obj[i], true] + context.LoadResult(); // stack: [obj[i], true, result] + context.LoadIndexByRef(); // stack: [obj[i], true, result, ref index] + context.LoadContext(); // stack: [obj[i], true, result, ref index, context] + context.CallWriter(elementType); // write(obj[i], true, result, ref index, context); stack: [] + il.Ldloc(count); // stack: [count] + il.Ldloc(i); // stack: [count, i] + il.Ldc_I4(1); // stack: [count, i, 1] + il.Add(); // stack: [count, i + 1] + il.Dup(); // stack: [count, i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [count, i] + il.Bgt(cycleStart, false); // if(count > i) goto cycleStart; stack: [] + + il.MarkLabel(writeDataLengthLabel); + context.LoadResult(); // stack: [result] + il.Ldloc(start); // stack: [result, start] + il.Add(); // stack: [result + start] + context.LoadIndex(); // stack: [result + start, index] + il.Ldloc(start); // stack: [result + start, index, start] + il.Sub(); // stack: [result + start, index - start] + il.Ldc_I4(4); // stack: [result + start, index - start, 4] + il.Sub(); // stack: [result + start, index - start - 4] + il.Stind(typeof(int)); // *(int*)(result + start) = index - start - 4 + } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/NullableWriterBuilder.cs b/GroBuf/Writers/NullableWriterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/NullableWriterBuilder.cs rename to GroBuf/Writers/NullableWriterBuilder.cs index ad067b5..0d37021 100644 --- a/GroBuf/GroBuf/Writers/NullableWriterBuilder.cs +++ b/GroBuf/Writers/NullableWriterBuilder.cs @@ -1,44 +1,44 @@ -using System; - -using GrEmit; - -namespace GroBuf.Writers -{ - internal class NullableWriterBuilder : WriterBuilderBase - { - public NullableWriterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Nullable<>))) - throw new InvalidOperationException("Expected nullable but was " + Type); - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.BuildConstants(Type.GetGenericArguments()[0]); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - - context.LoadObjByRef(); // stack: [&obj] - il.Call(Type.GetProperty("Value").GetGetMethod()); // stack: [obj.Value] - context.LoadWriteEmpty(); // stack: [obj.Value, writeEmpty] - context.LoadResult(); // stack: [obj.Value, writeEmpty, result] - context.LoadIndexByRef(); // stack: [obj.Value, writeEmpty, result, ref index] - context.LoadContext(); // stack: [obj.Value, writeEmpty, result, ref index, context] - context.CallWriter(Type.GetGenericArguments()[0]); // writer(obj.Value, writeEmpty, result, ref index, context) - } - - protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObjByRef(); // stack: [&obj] - context.Il.Call(Type.GetProperty("HasValue").GetGetMethod()); // stack: obj.HasValue - context.Il.Brtrue(notEmptyLabel); // if(obj.HasValue) goto notEmpty; - return true; - } - - protected override bool IsReference { get { return false; } } - } +using System; + +using GrEmit; + +namespace GroBuf.Writers +{ + internal class NullableWriterBuilder : WriterBuilderBase + { + public NullableWriterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(Nullable<>))) + throw new InvalidOperationException("Expected nullable but was " + Type); + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.BuildConstants(Type.GetGenericArguments()[0]); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + + context.LoadObjByRef(); // stack: [&obj] + il.Call(Type.GetProperty("Value").GetGetMethod()); // stack: [obj.Value] + context.LoadWriteEmpty(); // stack: [obj.Value, writeEmpty] + context.LoadResult(); // stack: [obj.Value, writeEmpty, result] + context.LoadIndexByRef(); // stack: [obj.Value, writeEmpty, result, ref index] + context.LoadContext(); // stack: [obj.Value, writeEmpty, result, ref index, context] + context.CallWriter(Type.GetGenericArguments()[0]); // writer(obj.Value, writeEmpty, result, ref index, context) + } + + protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObjByRef(); // stack: [&obj] + context.Il.Call(Type.GetProperty("HasValue").GetGetMethod()); // stack: obj.HasValue + context.Il.Brtrue(notEmptyLabel); // if(obj.HasValue) goto notEmpty; + return true; + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/ObjectWriterBuilder.cs b/GroBuf/Writers/ObjectWriterBuilder.cs similarity index 98% rename from GroBuf/GroBuf/Writers/ObjectWriterBuilder.cs rename to GroBuf/Writers/ObjectWriterBuilder.cs index 2b61653..ae6b5d0 100644 --- a/GroBuf/GroBuf/Writers/ObjectWriterBuilder.cs +++ b/GroBuf/Writers/ObjectWriterBuilder.cs @@ -1,126 +1,126 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Reflection.Emit; - -using GrEmit; - -namespace GroBuf.Writers -{ - internal class ObjectWriterBuilder : WriterBuilderBase - { - public ObjectWriterBuilder() - : base(typeof(object)) - { - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.SetFields(Type, new[] - { - new KeyValuePair("writers_" + Type.Name + "_" + Guid.NewGuid(), typeof(IntPtr[])), - new KeyValuePair("delegates_" + Type.Name + "_" + Guid.NewGuid(), typeof(Delegate[])), // This field is needed only to save references to the dynamic methods. Otherwise GC will destroy them - }); - Array.ForEach(GroBufHelpers.LeafTypes.Where(type => type != null).ToArray(), type => context.BuildConstants(type)); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - - var writers = GroBufHelpers.LeafTypes.Select(type1 => type1 == null ? new KeyValuePair(null, IntPtr.Zero) : GetWriter(context, type1)).ToArray(); - var writersField = context.Context.InitConstField(Type, 0, writers.Select(pair => pair.Value).ToArray()); - context.Context.InitConstField(Type, 1, writers.Select(pair => pair.Key).ToArray()); - - il.Ldfld(typeof(GroBufHelpers).GetField("LeafTypeHandles", BindingFlags.Public | BindingFlags.Static)); // stack: [LeafTypeHandles] - context.LoadObj(); // stack: [LeafTypeHandles, obj] - il.Call(getTypeMethod); // stack: [LeafTypeHandles, obj.GetType()] - var type = il.DeclareLocal(typeof(Type)); - il.Dup(); // stack: [LeafTypeHandles, obj.GetType(), obj.GetType()] - il.Stloc(type); // type = obj.GetType(); stack: [LeafTypeHandles, obj.GetType()] - il.Call(typeTypeHandleProperty.GetGetMethod()); // stack: [LeafTypeHandles, obj.GetType().TypeHandle] - var typeHandle = il.DeclareLocal(typeof(RuntimeTypeHandle)); - il.Stloc(typeHandle); // typeHandle = obj.GetType().TypeHandle; stack: [LeafTypeHandles] - il.Ldloca(typeHandle); // stack: [LeafTypeHandles, ref typeHandle] - il.Call(runtimeTypeHandleValueProperty.GetGetMethod(), typeof(RuntimeTypeHandle)); // stack: [LeafTypeHandles, obj.GetType().TypeHandle.Value] - var handle = il.DeclareLocal(typeof(IntPtr)); - il.Dup(); // stack: [LeafTypeHandles, obj.GetType().TypeHandle.Value, obj.GetType().TypeHandle.Value] - il.Stloc(handle); // handle = obj.GetType().TypeHandle.Value; stack: [LeafTypeHandles, handle] - il.Ldc_I4(writers.Length); // stack: [LeafTypeHandles, handle, LeafTypeHandles.Length] - il.Rem(true); // stack: [LeafTypeHandles, handle % LeafTypeHandles.Length] - var index = il.DeclareLocal(typeof(int)); - il.Conv(); // stack: [LeafTypeHandles, (int)(handle % LeafTypeHandles.Length)] - il.Dup(); // stack: [LeafTypeHandles, (int)(handle % LeafTypeHandles.Length), (int)(handle % LeafTypeHandles.Length)] - il.Stloc(index); // index = (int)(handle % LeafTypeHandles.Length); stack: [LeafTypeHandles, index] - il.Ldelem(typeof(IntPtr)); // stack: [LeafTypeHandles[index]] - il.Ldloc(handle); // stack: [LeafTypeHandles[index], handle] - var tryAsArrayLabel = il.DefineLabel("tryAsArray"); - il.Bne_Un(tryAsArrayLabel); // if(LeafTypeHandles[index] != handle) goto tryAsArray; stack: [] - context.LoadObj(); // stack: [obj] - context.LoadWriteEmpty(); // stack: [obj, writeEmpty] - context.LoadResult(); // stack: [obj, writeEmpty, result] - context.LoadIndexByRef(); // stack: [obj, writeEmpty, result, ref index] - context.LoadContext(); // stack: [obj, writeEmpty, result, ref index, context] - context.LoadField(writersField); // stack: [obj, writeEmpty, result, ref index, context, writers] - il.Ldloc(index); // stack: [obj, writeEmpty, result, ref index, context, writers, index] - il.Ldelem(typeof(IntPtr)); // stack: [obj, writeEmpty, result, ref index, context, writers[index]] - var parameterTypes = new[] {typeof(object), typeof(bool), typeof(byte*), typeof(int).MakeByRefType(), typeof(WriterContext)}; - il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // stack: [writers[index](obj, writeEmpty, result, ref index, context)] - il.Ret(); - - il.MarkLabel(tryAsArrayLabel); - il.Ldloc(type); // stack: [obj.GetType()] - il.Call(typeIsArrayProperty.GetGetMethod()); // stack: [obj.GetType().IsArray] - var writeNullLabel = il.DefineLabel("writeNull"); - il.Brfalse(writeNullLabel); - context.LoadObj(); // stack: [obj] - context.LoadWriteEmpty(); // stack: [obj, writeEmpty] - context.LoadResult(); // stack: [obj, writeEmpty, result] - context.LoadIndexByRef(); // stack: [obj, writeEmpty, result, ref index] - context.LoadContext(); // stack: [obj, writeEmpty, result, ref index, context] - context.LoadField(writersField); // stack: [obj, writeEmpty, result, ref index, context, writers] - il.Ldc_I4(Array.IndexOf(GroBufHelpers.LeafTypes, typeof(object[]))); // stack: [obj, writeEmpty, result, ref index, context, writers, index of typeof(object[])] - il.Ldelem(typeof(IntPtr)); // stack: [obj, writeEmpty, result, ref index, context, writers[index of typeof(object[])]] - parameterTypes = new[] {typeof(object), typeof(bool), typeof(byte*), typeof(int).MakeByRefType(), typeof(WriterContext)}; - il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // stack: [writers[index of typeof(object[])](obj, writeEmpty, result, ref index, context)] - il.Ret(); - - il.MarkLabel(writeNullLabel); - context.WriteNull(); - } - - protected override bool IsReference { get { return false; } } - - private static KeyValuePair GetWriter(WriterMethodBuilderContext context, Type type) - { - var method = new DynamicMethod("CastTo_" + type.Name + "_AndWrite_" + Guid.NewGuid(), typeof(void), - new[] - { - typeof(object), typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext) - }, context.Context.Module, true); - using (var il = new GroboIL(method)) - { - il.Ldarg(0); // stack: [obj] - if(type.IsValueType) - il.Unbox_Any(type); // stack: [(type)obj] - else - il.Castclass(type); // stack: [(type)obj] - il.Ldarg(1); // stack: [(type)obj, writeEmpty] - il.Ldarg(2); // stack: [(type)obj, writeEmpty, result] - il.Ldarg(3); // stack: [(type)obj, writeEmpty, result, ref index] - il.Ldarg(4); // stack: [(type)obj, writeEmpty, result, ref index, context] - context.CallWriter(il, type); - il.Ret(); - } - var @delegate = method.CreateDelegate(typeof(WriterDelegate)); - return new KeyValuePair(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)); - } - - private static readonly MethodInfo getTypeMethod = ((MethodCallExpression)((Expression>)(obj => obj.GetType())).Body).Method; - private static readonly PropertyInfo typeTypeHandleProperty = (PropertyInfo)((MemberExpression)((Expression>)(type => type.TypeHandle)).Body).Member; - private static readonly PropertyInfo runtimeTypeHandleValueProperty = (PropertyInfo)((MemberExpression)((Expression>)(handle => handle.Value)).Body).Member; - private static readonly PropertyInfo typeIsArrayProperty = (PropertyInfo)((MemberExpression)((Expression>)(type => type.IsArray)).Body).Member; - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Reflection.Emit; + +using GrEmit; + +namespace GroBuf.Writers +{ + internal class ObjectWriterBuilder : WriterBuilderBase + { + public ObjectWriterBuilder() + : base(typeof(object)) + { + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.SetFields(Type, new[] + { + new KeyValuePair("writers_" + Type.Name + "_" + Guid.NewGuid(), typeof(IntPtr[])), + new KeyValuePair("delegates_" + Type.Name + "_" + Guid.NewGuid(), typeof(Delegate[])), // This field is needed only to save references to the dynamic methods. Otherwise GC will destroy them + }); + Array.ForEach(GroBufHelpers.LeafTypes.Where(type => type != null).ToArray(), type => context.BuildConstants(type)); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + + var writers = GroBufHelpers.LeafTypes.Select(type1 => type1 == null ? new KeyValuePair(null, IntPtr.Zero) : GetWriter(context, type1)).ToArray(); + var writersField = context.Context.InitConstField(Type, 0, writers.Select(pair => pair.Value).ToArray()); + context.Context.InitConstField(Type, 1, writers.Select(pair => pair.Key).ToArray()); + + il.Ldfld(typeof(GroBufHelpers).GetField("LeafTypeHandles", BindingFlags.Public | BindingFlags.Static)); // stack: [LeafTypeHandles] + context.LoadObj(); // stack: [LeafTypeHandles, obj] + il.Call(getTypeMethod); // stack: [LeafTypeHandles, obj.GetType()] + var type = il.DeclareLocal(typeof(Type)); + il.Dup(); // stack: [LeafTypeHandles, obj.GetType(), obj.GetType()] + il.Stloc(type); // type = obj.GetType(); stack: [LeafTypeHandles, obj.GetType()] + il.Call(typeTypeHandleProperty.GetGetMethod()); // stack: [LeafTypeHandles, obj.GetType().TypeHandle] + var typeHandle = il.DeclareLocal(typeof(RuntimeTypeHandle)); + il.Stloc(typeHandle); // typeHandle = obj.GetType().TypeHandle; stack: [LeafTypeHandles] + il.Ldloca(typeHandle); // stack: [LeafTypeHandles, ref typeHandle] + il.Call(runtimeTypeHandleValueProperty.GetGetMethod(), typeof(RuntimeTypeHandle)); // stack: [LeafTypeHandles, obj.GetType().TypeHandle.Value] + var handle = il.DeclareLocal(typeof(IntPtr)); + il.Dup(); // stack: [LeafTypeHandles, obj.GetType().TypeHandle.Value, obj.GetType().TypeHandle.Value] + il.Stloc(handle); // handle = obj.GetType().TypeHandle.Value; stack: [LeafTypeHandles, handle] + il.Ldc_I4(writers.Length); // stack: [LeafTypeHandles, handle, LeafTypeHandles.Length] + il.Rem(true); // stack: [LeafTypeHandles, handle % LeafTypeHandles.Length] + var index = il.DeclareLocal(typeof(int)); + il.Conv(); // stack: [LeafTypeHandles, (int)(handle % LeafTypeHandles.Length)] + il.Dup(); // stack: [LeafTypeHandles, (int)(handle % LeafTypeHandles.Length), (int)(handle % LeafTypeHandles.Length)] + il.Stloc(index); // index = (int)(handle % LeafTypeHandles.Length); stack: [LeafTypeHandles, index] + il.Ldelem(typeof(IntPtr)); // stack: [LeafTypeHandles[index]] + il.Ldloc(handle); // stack: [LeafTypeHandles[index], handle] + var tryAsArrayLabel = il.DefineLabel("tryAsArray"); + il.Bne_Un(tryAsArrayLabel); // if(LeafTypeHandles[index] != handle) goto tryAsArray; stack: [] + context.LoadObj(); // stack: [obj] + context.LoadWriteEmpty(); // stack: [obj, writeEmpty] + context.LoadResult(); // stack: [obj, writeEmpty, result] + context.LoadIndexByRef(); // stack: [obj, writeEmpty, result, ref index] + context.LoadContext(); // stack: [obj, writeEmpty, result, ref index, context] + context.LoadField(writersField); // stack: [obj, writeEmpty, result, ref index, context, writers] + il.Ldloc(index); // stack: [obj, writeEmpty, result, ref index, context, writers, index] + il.Ldelem(typeof(IntPtr)); // stack: [obj, writeEmpty, result, ref index, context, writers[index]] + var parameterTypes = new[] {typeof(object), typeof(bool), typeof(byte*), typeof(int).MakeByRefType(), typeof(WriterContext)}; + il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // stack: [writers[index](obj, writeEmpty, result, ref index, context)] + il.Ret(); + + il.MarkLabel(tryAsArrayLabel); + il.Ldloc(type); // stack: [obj.GetType()] + il.Call(typeIsArrayProperty.GetGetMethod()); // stack: [obj.GetType().IsArray] + var writeNullLabel = il.DefineLabel("writeNull"); + il.Brfalse(writeNullLabel); + context.LoadObj(); // stack: [obj] + context.LoadWriteEmpty(); // stack: [obj, writeEmpty] + context.LoadResult(); // stack: [obj, writeEmpty, result] + context.LoadIndexByRef(); // stack: [obj, writeEmpty, result, ref index] + context.LoadContext(); // stack: [obj, writeEmpty, result, ref index, context] + context.LoadField(writersField); // stack: [obj, writeEmpty, result, ref index, context, writers] + il.Ldc_I4(Array.IndexOf(GroBufHelpers.LeafTypes, typeof(object[]))); // stack: [obj, writeEmpty, result, ref index, context, writers, index of typeof(object[])] + il.Ldelem(typeof(IntPtr)); // stack: [obj, writeEmpty, result, ref index, context, writers[index of typeof(object[])]] + parameterTypes = new[] {typeof(object), typeof(bool), typeof(byte*), typeof(int).MakeByRefType(), typeof(WriterContext)}; + il.Calli(CallingConventions.Standard, typeof(void), parameterTypes); // stack: [writers[index of typeof(object[])](obj, writeEmpty, result, ref index, context)] + il.Ret(); + + il.MarkLabel(writeNullLabel); + context.WriteNull(); + } + + protected override bool IsReference { get { return false; } } + + private static KeyValuePair GetWriter(WriterMethodBuilderContext context, Type type) + { + var method = new DynamicMethod("CastTo_" + type.Name + "_AndWrite_" + Guid.NewGuid(), typeof(void), + new[] + { + typeof(object), typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext) + }, context.Context.Module, true); + using (var il = new GroboIL(method)) + { + il.Ldarg(0); // stack: [obj] + if(type.IsValueType) + il.Unbox_Any(type); // stack: [(type)obj] + else + il.Castclass(type); // stack: [(type)obj] + il.Ldarg(1); // stack: [(type)obj, writeEmpty] + il.Ldarg(2); // stack: [(type)obj, writeEmpty, result] + il.Ldarg(3); // stack: [(type)obj, writeEmpty, result, ref index] + il.Ldarg(4); // stack: [(type)obj, writeEmpty, result, ref index, context] + context.CallWriter(il, type); + il.Ret(); + } + var @delegate = method.CreateDelegate(typeof(WriterDelegate)); + return new KeyValuePair(@delegate, GroBufHelpers.ExtractDynamicMethodPointer(method)); + } + + private static readonly MethodInfo getTypeMethod = ((MethodCallExpression)((Expression>)(obj => obj.GetType())).Body).Method; + private static readonly PropertyInfo typeTypeHandleProperty = (PropertyInfo)((MemberExpression)((Expression>)(type => type.TypeHandle)).Body).Member; + private static readonly PropertyInfo runtimeTypeHandleValueProperty = (PropertyInfo)((MemberExpression)((Expression>)(handle => handle.Value)).Body).Member; + private static readonly PropertyInfo typeIsArrayProperty = (PropertyInfo)((MemberExpression)((Expression>)(type => type.IsArray)).Body).Member; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/PrimitivesArraySegmentWriterBuilder.cs b/GroBuf/Writers/PrimitivesArraySegmentWriterBuilder.cs similarity index 100% rename from GroBuf/GroBuf/Writers/PrimitivesArraySegmentWriterBuilder.cs rename to GroBuf/Writers/PrimitivesArraySegmentWriterBuilder.cs diff --git a/GroBuf/GroBuf/Writers/PrimitivesArrayWriterBuilder.cs b/GroBuf/Writers/PrimitivesArrayWriterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/PrimitivesArrayWriterBuilder.cs rename to GroBuf/Writers/PrimitivesArrayWriterBuilder.cs index 018232e..a3c7125 100644 --- a/GroBuf/GroBuf/Writers/PrimitivesArrayWriterBuilder.cs +++ b/GroBuf/Writers/PrimitivesArrayWriterBuilder.cs @@ -1,125 +1,125 @@ -using System; - -using GrEmit; - -namespace GroBuf.Writers -{ - internal class PrimitivesArrayWriterBuilder : WriterBuilderBase - { - public PrimitivesArrayWriterBuilder(Type type) - : base(type) - { - if(!Type.IsArray) throw new InvalidOperationException("An array expected but was '" + Type + "'"); - if(Type.GetArrayRank() != 1) throw new NotSupportedException("Arrays with rank greater than 1 are not supported"); - elementType = Type.GetElementType(); - if(!elementType.IsPrimitive) throw new NotSupportedException("Array of primitive type expected but was '" + Type + "'"); - } - - protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Ldlen(); // stack: [obj.Length] - context.Il.Brtrue(notEmptyLabel); // if(obj.Length != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override unsafe void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - var typeCode = GroBufTypeCodeMap.GetTypeCode(Type); - context.WriteTypeCode(typeCode); - var size = il.DeclareLocal(typeof(int)); - - il.Ldc_I4(4); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&result[index]] - context.LoadObj(); // stack: [&result[index], obj] - il.Ldlen(); // stack: [&result[index], obj.Length] - CountArraySize(elementType, il); // stack: [&result[index], obj size] - il.Dup(); // stack: [&result[index], obj size, obj size] - il.Stloc(size); // size = obj size; stack: [&result[index], obj size] - il.Stind(typeof(int)); // result[index] = size; stack: [] - context.IncreaseIndexBy4(); // index = index + 4; stack: [] - - var doneLabel = il.DefineLabel("done"); - il.Ldloc(size); // stack: [size] - il.Brfalse(doneLabel); // if(size == 0) goto done; stack: [] - - il.Ldloc(size); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&result[index]] - context.LoadObj(); // stack: [&result[index], obj] - il.Ldc_I4(0); // stack: [&result[index], obj, 0] - il.Ldelema(elementType); // stack: [&result[index], &obj[0]] - var arr = il.DeclareLocal(elementType.MakeByRefType(), true); - il.Stloc(arr); // arr = &obj[0]; stack: [&result[index]] - il.Ldloc(arr); // stack: [&result[index], arr] - il.Ldloc(size); // stack: [&result[index], arr, size] - il.Cpblk(); // &result[index] = arr - il.FreePinnedLocal(arr); // arr = null; stack: [] - context.LoadIndexByRef(); // stack: [ref index] - context.LoadIndex(); // stack: [ref index, index] - il.Ldloc(size); // stack: [ref index, index, size] - il.Add(); // stack: [ref index, index + size] - il.Stind(typeof(int)); // index = index + size - il.MarkLabel(doneLabel); - } - - private static void CountArraySize(Type elementType, GroboIL il) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(1); - il.Shl(); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(3); - il.Shl(); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(3); - il.Shl(); - break; - default: - throw new NotSupportedException("Type '" + elementType + "' is not supported"); - } - } - - private readonly Type elementType; - } +using System; + +using GrEmit; + +namespace GroBuf.Writers +{ + internal class PrimitivesArrayWriterBuilder : WriterBuilderBase + { + public PrimitivesArrayWriterBuilder(Type type) + : base(type) + { + if(!Type.IsArray) throw new InvalidOperationException("An array expected but was '" + Type + "'"); + if(Type.GetArrayRank() != 1) throw new NotSupportedException("Arrays with rank greater than 1 are not supported"); + elementType = Type.GetElementType(); + if(!elementType.IsPrimitive) throw new NotSupportedException("Array of primitive type expected but was '" + Type + "'"); + } + + protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Ldlen(); // stack: [obj.Length] + context.Il.Brtrue(notEmptyLabel); // if(obj.Length != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override unsafe void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + var typeCode = GroBufTypeCodeMap.GetTypeCode(Type); + context.WriteTypeCode(typeCode); + var size = il.DeclareLocal(typeof(int)); + + il.Ldc_I4(4); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&result[index]] + context.LoadObj(); // stack: [&result[index], obj] + il.Ldlen(); // stack: [&result[index], obj.Length] + CountArraySize(elementType, il); // stack: [&result[index], obj size] + il.Dup(); // stack: [&result[index], obj size, obj size] + il.Stloc(size); // size = obj size; stack: [&result[index], obj size] + il.Stind(typeof(int)); // result[index] = size; stack: [] + context.IncreaseIndexBy4(); // index = index + 4; stack: [] + + var doneLabel = il.DefineLabel("done"); + il.Ldloc(size); // stack: [size] + il.Brfalse(doneLabel); // if(size == 0) goto done; stack: [] + + il.Ldloc(size); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&result[index]] + context.LoadObj(); // stack: [&result[index], obj] + il.Ldc_I4(0); // stack: [&result[index], obj, 0] + il.Ldelema(elementType); // stack: [&result[index], &obj[0]] + var arr = il.DeclareLocal(elementType.MakeByRefType(), true); + il.Stloc(arr); // arr = &obj[0]; stack: [&result[index]] + il.Ldloc(arr); // stack: [&result[index], arr] + il.Ldloc(size); // stack: [&result[index], arr, size] + il.Cpblk(); // &result[index] = arr + il.FreePinnedLocal(arr); // arr = null; stack: [] + context.LoadIndexByRef(); // stack: [ref index] + context.LoadIndex(); // stack: [ref index, index] + il.Ldloc(size); // stack: [ref index, index, size] + il.Add(); // stack: [ref index, index + size] + il.Stind(typeof(int)); // index = index + size + il.MarkLabel(doneLabel); + } + + private static void CountArraySize(Type elementType, GroboIL il) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(1); + il.Shl(); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(3); + il.Shl(); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(3); + il.Shl(); + break; + default: + throw new NotSupportedException("Type '" + elementType + "' is not supported"); + } + } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/PrimitivesHashSetWriterBuilder.cs b/GroBuf/Writers/PrimitivesHashSetWriterBuilder.cs similarity index 95% rename from GroBuf/GroBuf/Writers/PrimitivesHashSetWriterBuilder.cs rename to GroBuf/Writers/PrimitivesHashSetWriterBuilder.cs index 38f6932..4d8de03 100644 --- a/GroBuf/GroBuf/Writers/PrimitivesHashSetWriterBuilder.cs +++ b/GroBuf/Writers/PrimitivesHashSetWriterBuilder.cs @@ -1,191 +1,191 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.Writers -{ - internal class PrimitivesHashSetWriterBuilder : WriterBuilderBase - { - public PrimitivesHashSetWriterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(HashSet<>))) - throw new InvalidOperationException("HashSet expected but was '" + Type + "'"); - elementType = Type.GetGenericArguments()[0]; - if(!elementType.IsPrimitive) - throw new NotSupportedException("HashSet of primitive type expected but was '" + Type + "'"); - } - - protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Count] - context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - - context.WriteTypeCode(GroBufTypeCodeMap.GetTypeCode(elementType.MakeArrayType())); - var size = il.DeclareLocal(typeof(int)); - il.Ldc_I4(4); - context.AssertLength(); - context.LoadObj(); // stack: [obj] - il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Count] - CountArraySize(elementType, il); // stack: [obj size] - il.Stloc(size); // size = obj size; stack: [] - context.GoToCurrentLocation(); // stack: [&result[index]] - il.Ldloc(size); // stack: [&result[index], size] - il.Stind(typeof(int)); // result[index] = size; stack: [] - context.IncreaseIndexBy4(); // index = index + 4; stack: [] - - il.Ldloc(size); - context.AssertLength(); - - context.LoadObj(); // stack: [obj] - var slotType = Type.GetNestedType("Slot", BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); - var slots = il.DeclareLocal(slotType.MakeArrayType()); - il.Ldfld(Type.GetField("m_slots", BindingFlags.Instance | BindingFlags.NonPublic)); - il.Stloc(slots); - - context.LoadObj(); // stack: [obj] - il.Ldfld(Type.GetField("m_lastIndex", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.m_lastIndex] - il.Dup(); - var count = context.LocalInt; - il.Stloc(count); // count = obj.m_lastIndex; stack: [count] - var writeDataLengthLabel = il.DefineLabel("writeDataLength"); - il.Brfalse(writeDataLengthLabel); - - var i = il.DeclareLocal(typeof(int)); - il.Ldc_I4(0); // stack: [0] - il.Stloc(i); // i = 0; stack: [] - context.GoToCurrentLocation(); // stack: [&result[index]] - var cycleStartLabel = il.DefineLabel("cycleStart"); - il.MarkLabel(cycleStartLabel); - il.Ldloc(slots); // stack: [current, slots] - il.Ldloc(i); // stack: [current, slots, i] - il.Ldelema(slotType); // stack: [current, &slots[i]] - il.Dup(); // stack: [current, &slots[i], &slots[i]] - var slot = il.DeclareLocal(slotType.MakeByRefType()); - il.Stloc(slot); // slot = &slots[i]; stack: [current, slot] - il.Ldfld(slotType.GetField("hashCode", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [current, slot.hashCode] - il.Ldc_I4(0); // stack: [current, slot.hashCode, 0] - var nextLabel = il.DefineLabel("next"); - il.Blt(nextLabel, false); // if(slot.hashCode < 0) goto next; stack: [current] - il.Dup(); // stack: [current, current] - il.Ldloc(slot); // stack: [current, current, slot] - il.Ldfld(slotType.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [current, current, slot.value] - il.Stind(elementType); // *current = slot.value; stack: [current] - LoadItemSize(elementType, il); // stack: [current, item size] - il.Add(); // stack: [current + item size] - il.MarkLabel(nextLabel); - il.Ldloc(count); // stack: [current, count] - il.Ldloc(i); // stack: [current, count, i] - il.Ldc_I4(1); // stack: [current, count, i, 1] - il.Add(); // stack: [current, count, i + 1] - il.Dup(); // stack: [current, count, i + 1, i + 1] - il.Stloc(i); // i = i + 1; stack: [current, count, i] - il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [current] - il.Pop(); // stack: [] - - il.MarkLabel(writeDataLengthLabel); - context.LoadIndexByRef(); // stack: [ref index] - context.LoadIndex(); // stack: [ref index, index] - il.Ldloc(size); // stack: [ref index, index, size] - il.Add(); // stack: [ref index, index + size] - il.Stind(typeof(int)); // index = index + size - } - - private static void CountArraySize(Type elementType, GroboIL il) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(1); - il.Shl(); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(3); - il.Shl(); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(3); - il.Shl(); - break; - default: - throw new NotSupportedException("Type '" + elementType + "' is not supported"); - } - } - - private static void LoadItemSize(Type elementType, GroboIL il) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - il.Ldc_I4(1); - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(2); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(4); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(8); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(4); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(8); - break; - default: - throw new NotSupportedException("Type '" + elementType + "' is not supported"); - } - } - - private readonly Type elementType; - } +using System; +using System.Collections.Generic; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.Writers +{ + internal class PrimitivesHashSetWriterBuilder : WriterBuilderBase + { + public PrimitivesHashSetWriterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(HashSet<>))) + throw new InvalidOperationException("HashSet expected but was '" + Type + "'"); + elementType = Type.GetGenericArguments()[0]; + if(!elementType.IsPrimitive) + throw new NotSupportedException("HashSet of primitive type expected but was '" + Type + "'"); + } + + protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Count] + context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + + context.WriteTypeCode(GroBufTypeCodeMap.GetTypeCode(elementType.MakeArrayType())); + var size = il.DeclareLocal(typeof(int)); + il.Ldc_I4(4); + context.AssertLength(); + context.LoadObj(); // stack: [obj] + il.Call(Type.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public).GetGetMethod()); // stack: [obj.Count] + CountArraySize(elementType, il); // stack: [obj size] + il.Stloc(size); // size = obj size; stack: [] + context.GoToCurrentLocation(); // stack: [&result[index]] + il.Ldloc(size); // stack: [&result[index], size] + il.Stind(typeof(int)); // result[index] = size; stack: [] + context.IncreaseIndexBy4(); // index = index + 4; stack: [] + + il.Ldloc(size); + context.AssertLength(); + + context.LoadObj(); // stack: [obj] + var slotType = Type.GetNestedType("Slot", BindingFlags.NonPublic).MakeGenericType(Type.GetGenericArguments()); + var slots = il.DeclareLocal(slotType.MakeArrayType()); + il.Ldfld(Type.GetField(PlatformHelpers.HashSetSlotsFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); + il.Stloc(slots); + + context.LoadObj(); // stack: [obj] + il.Ldfld(Type.GetField(PlatformHelpers.HashSetLastIndexFieldName, BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.m_lastIndex] + il.Dup(); + var count = context.LocalInt; + il.Stloc(count); // count = obj.m_lastIndex; stack: [count] + var writeDataLengthLabel = il.DefineLabel("writeDataLength"); + il.Brfalse(writeDataLengthLabel); + + var i = il.DeclareLocal(typeof(int)); + il.Ldc_I4(0); // stack: [0] + il.Stloc(i); // i = 0; stack: [] + context.GoToCurrentLocation(); // stack: [&result[index]] + var cycleStartLabel = il.DefineLabel("cycleStart"); + il.MarkLabel(cycleStartLabel); + il.Ldloc(slots); // stack: [current, slots] + il.Ldloc(i); // stack: [current, slots, i] + il.Ldelema(slotType); // stack: [current, &slots[i]] + il.Dup(); // stack: [current, &slots[i], &slots[i]] + var slot = il.DeclareLocal(slotType.MakeByRefType()); + il.Stloc(slot); // slot = &slots[i]; stack: [current, slot] + il.Ldfld(slotType.GetField("hashCode", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [current, slot.hashCode] + il.Ldc_I4(0); // stack: [current, slot.hashCode, 0] + var nextLabel = il.DefineLabel("next"); + il.Blt(nextLabel, false); // if(slot.hashCode < 0) goto next; stack: [current] + il.Dup(); // stack: [current, current] + il.Ldloc(slot); // stack: [current, current, slot] + il.Ldfld(slotType.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [current, current, slot.value] + il.Stind(elementType); // *current = slot.value; stack: [current] + LoadItemSize(elementType, il); // stack: [current, item size] + il.Add(); // stack: [current + item size] + il.MarkLabel(nextLabel); + il.Ldloc(count); // stack: [current, count] + il.Ldloc(i); // stack: [current, count, i] + il.Ldc_I4(1); // stack: [current, count, i, 1] + il.Add(); // stack: [current, count, i + 1] + il.Dup(); // stack: [current, count, i + 1, i + 1] + il.Stloc(i); // i = i + 1; stack: [current, count, i] + il.Bgt(cycleStartLabel, false); // if(count > i) goto cycleStart; stack: [current] + il.Pop(); // stack: [] + + il.MarkLabel(writeDataLengthLabel); + context.LoadIndexByRef(); // stack: [ref index] + context.LoadIndex(); // stack: [ref index, index] + il.Ldloc(size); // stack: [ref index, index, size] + il.Add(); // stack: [ref index, index + size] + il.Stind(typeof(int)); // index = index + size + } + + private static void CountArraySize(Type elementType, GroboIL il) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(1); + il.Shl(); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(3); + il.Shl(); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(3); + il.Shl(); + break; + default: + throw new NotSupportedException("Type '" + elementType + "' is not supported"); + } + } + + private static void LoadItemSize(Type elementType, GroboIL il) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + il.Ldc_I4(1); + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(2); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(4); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(8); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(4); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(8); + break; + default: + throw new NotSupportedException("Type '" + elementType + "' is not supported"); + } + } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/PrimitivesListWriterBuilder.cs b/GroBuf/Writers/PrimitivesListWriterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/PrimitivesListWriterBuilder.cs rename to GroBuf/Writers/PrimitivesListWriterBuilder.cs index 42a2c40..6a41b43 100644 --- a/GroBuf/GroBuf/Writers/PrimitivesListWriterBuilder.cs +++ b/GroBuf/Writers/PrimitivesListWriterBuilder.cs @@ -1,127 +1,127 @@ -using System; -using System.Collections.Generic; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.Writers -{ - internal class PrimitivesListWriterBuilder : WriterBuilderBase - { - public PrimitivesListWriterBuilder(Type type) - : base(type) - { - if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(List<>))) - throw new InvalidOperationException("Expected list but was '" + Type + "'"); - elementType = Type.GetGenericArguments()[0]; - if(!elementType.IsPrimitive) - throw new NotSupportedException("List of primitive type expected but was '" + Type + "'"); - } - - protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - context.LoadObj(); // stack: [obj] - if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - else - { - var emptyLabel = context.Il.DefineLabel("empty"); - context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; - context.LoadObj(); // stack: [obj] - context.Il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] - context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; - context.Il.MarkLabel(emptyLabel); - } - return true; - } - - protected override bool IsReference { get { return true; } } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.BuildConstants(elementType); - } - - protected override unsafe void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - context.WriteTypeCode(GroBufTypeCodeMap.GetTypeCode(elementType.MakeArrayType())); - il.Ldc_I4(4); - context.AssertLength(); - var size = il.DeclareLocal(typeof(int)); - context.GoToCurrentLocation(); // stack: [&result[index]] - context.LoadObj(); // stack: [&result[index], obj] - il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [&result[index], obj.Count] - CountArraySize(elementType, il); // stack: [&result[index], obj size] - il.Dup(); // stack: [&result[index], obj size, obj size] - il.Stloc(size); // size = obj size; stack: [&result[index], obj size] - il.Stind(typeof(int)); // result[index] = size; stack: [] - context.IncreaseIndexBy4(); // index = index + 4; stack: [] - - il.Ldloc(size); // stack: [size] - var doneLabel = il.DefineLabel("done"); - il.Brfalse(doneLabel); // if(size == 0) goto done; stack: [] - - il.Ldloc(size); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&result[index]] - context.LoadObj(); // stack: [&result[index], obj] - il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [&result[index], obj._items] - il.Ldc_I4(0); // stack: [&result[index], obj._items, 0] - il.Ldelema(elementType); // stack: [&result[index], &obj._items[0]] - var arr = il.DeclareLocal(elementType.MakeByRefType(), true); - il.Stloc(arr); // arr = &obj._items[0]; stack: [&result[index]] - il.Ldloc(arr); // stack: [&result[index], arr] - il.Ldloc(size); // stack: [&result[index], arr, size] - il.Cpblk(); // &result[index] = arr - il.FreePinnedLocal(arr); // arr = null; stack: [] - context.LoadIndexByRef(); // stack: [ref index] - context.LoadIndex(); // stack: [ref index, index] - il.Ldloc(size); // stack: [ref index, index, size] - il.Add(); // stack: [ref index, index + size] - il.Stind(typeof(int)); // index = index + size - - il.MarkLabel(doneLabel); - } - - private static void CountArraySize(Type elementType, GroboIL il) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(1); - il.Shl(); - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(3); - il.Shl(); - break; - case GroBufTypeCode.Single: - il.Ldc_I4(2); - il.Shl(); - break; - case GroBufTypeCode.Double: - il.Ldc_I4(3); - il.Shl(); - break; - default: - throw new NotSupportedException("Type '" + elementType + "' is not supported"); - } - } - - private readonly Type elementType; - } +using System; +using System.Collections.Generic; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.Writers +{ + internal class PrimitivesListWriterBuilder : WriterBuilderBase + { + public PrimitivesListWriterBuilder(Type type) + : base(type) + { + if(!(Type.IsGenericType && Type.GetGenericTypeDefinition() == typeof(List<>))) + throw new InvalidOperationException("Expected list but was '" + Type + "'"); + elementType = Type.GetGenericArguments()[0]; + if(!elementType.IsPrimitive) + throw new NotSupportedException("List of primitive type expected but was '" + Type + "'"); + } + + protected override bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + context.LoadObj(); // stack: [obj] + if(context.Context.GroBufWriter.Options.HasFlag(GroBufOptions.WriteEmptyObjects)) + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + else + { + var emptyLabel = context.Il.DefineLabel("empty"); + context.Il.Brfalse(emptyLabel); // if(obj == null) goto empty; + context.LoadObj(); // stack: [obj] + context.Il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj.Count] + context.Il.Brtrue(notEmptyLabel); // if(obj.Count != 0) goto notEmpty; + context.Il.MarkLabel(emptyLabel); + } + return true; + } + + protected override bool IsReference { get { return true; } } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.BuildConstants(elementType); + } + + protected override unsafe void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + context.WriteTypeCode(GroBufTypeCodeMap.GetTypeCode(elementType.MakeArrayType())); + il.Ldc_I4(4); + context.AssertLength(); + var size = il.DeclareLocal(typeof(int)); + context.GoToCurrentLocation(); // stack: [&result[index]] + context.LoadObj(); // stack: [&result[index], obj] + il.Ldfld(Type.GetField("_size", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [&result[index], obj.Count] + CountArraySize(elementType, il); // stack: [&result[index], obj size] + il.Dup(); // stack: [&result[index], obj size, obj size] + il.Stloc(size); // size = obj size; stack: [&result[index], obj size] + il.Stind(typeof(int)); // result[index] = size; stack: [] + context.IncreaseIndexBy4(); // index = index + 4; stack: [] + + il.Ldloc(size); // stack: [size] + var doneLabel = il.DefineLabel("done"); + il.Brfalse(doneLabel); // if(size == 0) goto done; stack: [] + + il.Ldloc(size); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&result[index]] + context.LoadObj(); // stack: [&result[index], obj] + il.Ldfld(Type.GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [&result[index], obj._items] + il.Ldc_I4(0); // stack: [&result[index], obj._items, 0] + il.Ldelema(elementType); // stack: [&result[index], &obj._items[0]] + var arr = il.DeclareLocal(elementType.MakeByRefType(), true); + il.Stloc(arr); // arr = &obj._items[0]; stack: [&result[index]] + il.Ldloc(arr); // stack: [&result[index], arr] + il.Ldloc(size); // stack: [&result[index], arr, size] + il.Cpblk(); // &result[index] = arr + il.FreePinnedLocal(arr); // arr = null; stack: [] + context.LoadIndexByRef(); // stack: [ref index] + context.LoadIndex(); // stack: [ref index, index] + il.Ldloc(size); // stack: [ref index, index, size] + il.Add(); // stack: [ref index, index + size] + il.Stind(typeof(int)); // index = index + size + + il.MarkLabel(doneLabel); + } + + private static void CountArraySize(Type elementType, GroboIL il) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(elementType); + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(1); + il.Shl(); + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(3); + il.Shl(); + break; + case GroBufTypeCode.Single: + il.Ldc_I4(2); + il.Shl(); + break; + case GroBufTypeCode.Double: + il.Ldc_I4(3); + il.Shl(); + break; + default: + throw new NotSupportedException("Type '" + elementType + "' is not supported"); + } + } + + private readonly Type elementType; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/PrimitivesWriterBuilder.cs b/GroBuf/Writers/PrimitivesWriterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/PrimitivesWriterBuilder.cs rename to GroBuf/Writers/PrimitivesWriterBuilder.cs index 916765a..e6036de 100644 --- a/GroBuf/GroBuf/Writers/PrimitivesWriterBuilder.cs +++ b/GroBuf/Writers/PrimitivesWriterBuilder.cs @@ -1,94 +1,94 @@ -using System; - -namespace GroBuf.Writers -{ - internal class PrimitivesWriterBuilder : WriterBuilderBase - { - public PrimitivesWriterBuilder(Type type) - : base(type) - { - if(!Type.IsPrimitive && Type != typeof(decimal)) throw new InvalidOperationException("Expected primitive type but was " + Type); - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var typeCode = GroBufTypeCodeMap.GetTypeCode(Type); - context.WriteTypeCode(typeCode); - context.GoToCurrentLocation(); // stack: [&result[index]] - var il = context.Il; - switch(typeCode) - { - case GroBufTypeCode.Int8: - case GroBufTypeCode.UInt8: - case GroBufTypeCode.Boolean: - il.Ldc_I4(1); - context.AssertLength(); - context.LoadObj(); // stack: [&result[index], obj] - il.Stind(typeof(byte)); // result[index] = obj - context.IncreaseIndexBy1(); // index = index + 1 - break; - case GroBufTypeCode.Int16: - case GroBufTypeCode.UInt16: - il.Ldc_I4(2); - context.AssertLength(); - context.LoadObj(); // stack: [&result[index], obj] - il.Stind(typeof(short)); // result[index] = obj - context.IncreaseIndexBy2(); // index = index + 2 - break; - case GroBufTypeCode.Int32: - case GroBufTypeCode.UInt32: - il.Ldc_I4(4); - context.AssertLength(); - context.LoadObj(); // stack: [&result[index], obj] - il.Stind(typeof(int)); // result[index] = obj - context.IncreaseIndexBy4(); // index = index + 4 - break; - case GroBufTypeCode.Int64: - case GroBufTypeCode.UInt64: - il.Ldc_I4(8); - context.AssertLength(); - context.LoadObj(); // stack: [&result[index], obj] - il.Stind(typeof(long)); // result[index] = obj - context.IncreaseIndexBy8(); // index = index + 8 - break; - case GroBufTypeCode.Single: - il.Ldc_I4(4); - context.AssertLength(); - context.LoadObj(); // stack: [&result[index], obj] - il.Stind(typeof(float)); // result[index] = obj - context.IncreaseIndexBy4(); // index = index + 4 - break; - case GroBufTypeCode.Double: - il.Ldc_I4(8); - context.AssertLength(); - context.LoadObj(); // stack: [&result[index], obj] - il.Stind(typeof(double)); // result[index] = obj - context.IncreaseIndexBy8(); // index = index + 8 - break; - case GroBufTypeCode.Decimal: - il.Ldc_I4(16); - context.AssertLength(); - context.LoadObjByRef(); // stack: [&result[index], &obj] - il.Ldind(typeof(long)); // stack: [&result[index], (int64)*obj] - il.Stind(typeof(long)); // result[index] = (int64)*obj - context.IncreaseIndexBy8(); // index = index + 8 - context.GoToCurrentLocation(); // stack: [&result[index]] - context.LoadObjByRef(); // stack: [&result[index], &obj] - il.Ldc_I4(8); // stack: [&result[index], &obj, 8] - il.Add(); // stack: [&result[index], &obj + 8] - il.Ldind(typeof(long)); // stack: [&result[index], *(&obj+8)] - il.Stind(typeof(long)); // result[index] = (int64)*(obj + 8) - context.IncreaseIndexBy8(); // index = index + 8 - break; - default: - throw new NotSupportedException(); - } - } - - protected override bool IsReference { get { return false; } } - } +using System; + +namespace GroBuf.Writers +{ + internal class PrimitivesWriterBuilder : WriterBuilderBase + { + public PrimitivesWriterBuilder(Type type) + : base(type) + { + if(!Type.IsPrimitive && Type != typeof(decimal)) throw new InvalidOperationException("Expected primitive type but was " + Type); + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var typeCode = GroBufTypeCodeMap.GetTypeCode(Type); + context.WriteTypeCode(typeCode); + context.GoToCurrentLocation(); // stack: [&result[index]] + var il = context.Il; + switch(typeCode) + { + case GroBufTypeCode.Int8: + case GroBufTypeCode.UInt8: + case GroBufTypeCode.Boolean: + il.Ldc_I4(1); + context.AssertLength(); + context.LoadObj(); // stack: [&result[index], obj] + il.Stind(typeof(byte)); // result[index] = obj + context.IncreaseIndexBy1(); // index = index + 1 + break; + case GroBufTypeCode.Int16: + case GroBufTypeCode.UInt16: + il.Ldc_I4(2); + context.AssertLength(); + context.LoadObj(); // stack: [&result[index], obj] + il.Stind(typeof(short)); // result[index] = obj + context.IncreaseIndexBy2(); // index = index + 2 + break; + case GroBufTypeCode.Int32: + case GroBufTypeCode.UInt32: + il.Ldc_I4(4); + context.AssertLength(); + context.LoadObj(); // stack: [&result[index], obj] + il.Stind(typeof(int)); // result[index] = obj + context.IncreaseIndexBy4(); // index = index + 4 + break; + case GroBufTypeCode.Int64: + case GroBufTypeCode.UInt64: + il.Ldc_I4(8); + context.AssertLength(); + context.LoadObj(); // stack: [&result[index], obj] + il.Stind(typeof(long)); // result[index] = obj + context.IncreaseIndexBy8(); // index = index + 8 + break; + case GroBufTypeCode.Single: + il.Ldc_I4(4); + context.AssertLength(); + context.LoadObj(); // stack: [&result[index], obj] + il.Stind(typeof(float)); // result[index] = obj + context.IncreaseIndexBy4(); // index = index + 4 + break; + case GroBufTypeCode.Double: + il.Ldc_I4(8); + context.AssertLength(); + context.LoadObj(); // stack: [&result[index], obj] + il.Stind(typeof(double)); // result[index] = obj + context.IncreaseIndexBy8(); // index = index + 8 + break; + case GroBufTypeCode.Decimal: + il.Ldc_I4(16); + context.AssertLength(); + context.LoadObjByRef(); // stack: [&result[index], &obj] + il.Ldind(typeof(long)); // stack: [&result[index], (int64)*obj] + il.Stind(typeof(long)); // result[index] = (int64)*obj + context.IncreaseIndexBy8(); // index = index + 8 + context.GoToCurrentLocation(); // stack: [&result[index]] + context.LoadObjByRef(); // stack: [&result[index], &obj] + il.Ldc_I4(8); // stack: [&result[index], &obj, 8] + il.Add(); // stack: [&result[index], &obj + 8] + il.Ldind(typeof(long)); // stack: [&result[index], *(&obj+8)] + il.Stind(typeof(long)); // result[index] = (int64)*(obj + 8) + context.IncreaseIndexBy8(); // index = index + 8 + break; + default: + throw new NotSupportedException(); + } + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/StringWriterBuilder.cs b/GroBuf/Writers/StringWriterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/StringWriterBuilder.cs rename to GroBuf/Writers/StringWriterBuilder.cs index f115ae4..b1a9d9f 100644 --- a/GroBuf/GroBuf/Writers/StringWriterBuilder.cs +++ b/GroBuf/Writers/StringWriterBuilder.cs @@ -1,68 +1,68 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace GroBuf.Writers -{ - internal class StringWriterBuilder : WriterBuilderBase - { - public StringWriterBuilder() - : base(typeof(string)) - { - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - } - - protected override unsafe void WriteNotEmpty(WriterMethodBuilderContext context) - { - var length = context.LocalInt; - context.LoadObj(); // stack: [obj] - var il = context.Il; - il.Call(lengthPropertyGetter); // stack: [obj.Length] - il.Ldc_I4(1); // stack: [obj.Length, 1] - il.Shl(); // stack: [obj.Length << 1] - il.Stloc(length); // length = obj.Length << 1 - context.WriteTypeCode(GroBufTypeCode.String); - il.Ldc_I4(4); - context.AssertLength(); - context.GoToCurrentLocation(); // stack: [&result[index]] - il.Ldloc(length); // stack: [&result[index], length] - il.Stind(typeof(int)); // result[index] = length - context.IncreaseIndexBy4(); // index = index + 4 - - var doneLabel = il.DefineLabel("done"); - il.Ldloc(length); // stack: [length] - il.Brfalse(doneLabel); - - il.Ldloc(length); - context.AssertLength(); - - context.GoToCurrentLocation(); // stack: [&result[index]] - var str = il.DeclareLocal(typeof(string), true); - context.LoadObj(); // stack: [&result[index], obj] - il.Stloc(str); // str = obj - il.Ldloc(str); // stack: [&result[index], str] - il.Conv(); // stack: [&result[index], (IntPtr)str] - il.Ldc_I4(RuntimeHelpers.OffsetToStringData); // stack: [&result[index], (IntPtr)str, offset] - il.Add(); // stack: [&result[index], (IntPtr)str + offset] - il.Ldloc(length); // stack: [&result[index], (IntPtr)str + offset, length] - il.Cpblk(); // &result[index] = str - il.FreePinnedLocal(str); // str = null; stack: [] - - context.LoadIndexByRef(); // stack: [ref index] - context.LoadIndex(); // stack: [ref index, index] - il.Ldloc(length); // stack: [ref index, index, length] - il.Add(); // stack: [ref index, index + length] - il.Stind(typeof(int)); // index = index + length - - il.MarkLabel(doneLabel); - } - - protected override bool IsReference { get { return true; } } - - private static readonly MethodInfo lengthPropertyGetter = ((PropertyInfo)((MemberExpression)((Expression>)(s => s.Length)).Body).Member).GetGetMethod(); - } +using System; +using System.Linq.Expressions; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace GroBuf.Writers +{ + internal class StringWriterBuilder : WriterBuilderBase + { + public StringWriterBuilder() + : base(typeof(string)) + { + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + } + + protected override unsafe void WriteNotEmpty(WriterMethodBuilderContext context) + { + var length = context.LocalInt; + context.LoadObj(); // stack: [obj] + var il = context.Il; + il.Call(lengthPropertyGetter); // stack: [obj.Length] + il.Ldc_I4(1); // stack: [obj.Length, 1] + il.Shl(); // stack: [obj.Length << 1] + il.Stloc(length); // length = obj.Length << 1 + context.WriteTypeCode(GroBufTypeCode.String); + il.Ldc_I4(4); + context.AssertLength(); + context.GoToCurrentLocation(); // stack: [&result[index]] + il.Ldloc(length); // stack: [&result[index], length] + il.Stind(typeof(int)); // result[index] = length + context.IncreaseIndexBy4(); // index = index + 4 + + var doneLabel = il.DefineLabel("done"); + il.Ldloc(length); // stack: [length] + il.Brfalse(doneLabel); + + il.Ldloc(length); + context.AssertLength(); + + context.GoToCurrentLocation(); // stack: [&result[index]] + var str = il.DeclareLocal(typeof(string), true); + context.LoadObj(); // stack: [&result[index], obj] + il.Stloc(str); // str = obj + il.Ldloc(str); // stack: [&result[index], str] + il.Conv(); // stack: [&result[index], (IntPtr)str] + il.Ldc_I4(RuntimeHelpers.OffsetToStringData); // stack: [&result[index], (IntPtr)str, offset] + il.Add(); // stack: [&result[index], (IntPtr)str + offset] + il.Ldloc(length); // stack: [&result[index], (IntPtr)str + offset, length] + il.Cpblk(); // &result[index] = str + il.FreePinnedLocal(str); // str = null; stack: [] + + context.LoadIndexByRef(); // stack: [ref index] + context.LoadIndex(); // stack: [ref index, index] + il.Ldloc(length); // stack: [ref index, index, length] + il.Add(); // stack: [ref index, index + length] + il.Stind(typeof(int)); // index = index + length + + il.MarkLabel(doneLabel); + } + + protected override bool IsReference { get { return true; } } + + private static readonly MethodInfo lengthPropertyGetter = ((PropertyInfo)((MemberExpression)((Expression>)(s => s.Length)).Body).Member).GetGetMethod(); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/TimeSpanWriterBuilder.cs b/GroBuf/Writers/TimeSpanWriterBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/TimeSpanWriterBuilder.cs rename to GroBuf/Writers/TimeSpanWriterBuilder.cs index 6c98530..7aa9905 100644 --- a/GroBuf/GroBuf/Writers/TimeSpanWriterBuilder.cs +++ b/GroBuf/Writers/TimeSpanWriterBuilder.cs @@ -1,33 +1,33 @@ -using System; -using System.Reflection; - -namespace GroBuf.Writers -{ - internal class TimeSpanWriterBuilder : WriterBuilderBase - { - public TimeSpanWriterBuilder() - : base(typeof(TimeSpan)) - { - } - - protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) - { - context.BuildConstants(typeof(long)); - } - - protected override void WriteNotEmpty(WriterMethodBuilderContext context) - { - var il = context.Il; - - context.LoadObjByRef(); // stack: [obj] - il.Ldfld(Type.GetField("_ticks", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj._ticks] - context.LoadWriteEmpty(); // stack: [obj._ticks, writeEmpty] - context.LoadResult(); // stack: [obj._ticks, writeEmpty, result] - context.LoadIndexByRef(); // stack: [obj._ticks, writeEmpty, result, ref index] - context.LoadContext(); // stack: [obj._ticks, writeEmpty, result, ref index, context] - context.CallWriter(typeof(long)); // writer(obj._ticks, writeEmpty, result, ref index, context) - } - - protected override bool IsReference { get { return false; } } - } +using System; +using System.Reflection; + +namespace GroBuf.Writers +{ + internal class TimeSpanWriterBuilder : WriterBuilderBase + { + public TimeSpanWriterBuilder() + : base(typeof(TimeSpan)) + { + } + + protected override void BuildConstantsInternal(WriterConstantsBuilderContext context) + { + context.BuildConstants(typeof(long)); + } + + protected override void WriteNotEmpty(WriterMethodBuilderContext context) + { + var il = context.Il; + + context.LoadObjByRef(); // stack: [obj] + il.Ldfld(Type.GetField("_ticks", BindingFlags.Instance | BindingFlags.NonPublic)); // stack: [obj._ticks] + context.LoadWriteEmpty(); // stack: [obj._ticks, writeEmpty] + context.LoadResult(); // stack: [obj._ticks, writeEmpty, result] + context.LoadIndexByRef(); // stack: [obj._ticks, writeEmpty, result, ref index] + context.LoadContext(); // stack: [obj._ticks, writeEmpty, result, ref index, context] + context.CallWriter(typeof(long)); // writer(obj._ticks, writeEmpty, result, ref index, context) + } + + protected override bool IsReference { get { return false; } } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/TupleWriterBuilder.cs b/GroBuf/Writers/TupleWriterBuilder.cs similarity index 100% rename from GroBuf/GroBuf/Writers/TupleWriterBuilder.cs rename to GroBuf/Writers/TupleWriterBuilder.cs diff --git a/GroBuf/GroBuf/Writers/WriterBuilderBase.cs b/GroBuf/Writers/WriterBuilderBase.cs similarity index 98% rename from GroBuf/GroBuf/Writers/WriterBuilderBase.cs rename to GroBuf/Writers/WriterBuilderBase.cs index ce0f91c..67045ab 100644 --- a/GroBuf/GroBuf/Writers/WriterBuilderBase.cs +++ b/GroBuf/Writers/WriterBuilderBase.cs @@ -1,116 +1,116 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Reflection.Emit; - -using GrEmit; -using GrEmit.Utils; - -namespace GroBuf.Writers -{ - internal abstract class WriterBuilderBase : IWriterBuilder - { - protected WriterBuilderBase(Type type) - { - Type = type; - } - - public void BuildWriter(WriterTypeBuilderContext writerTypeBuilderContext) - { - var method = new DynamicMethod("Write_" + Type.Name + "_" + Guid.NewGuid(), typeof(void), - new[] - { - Type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext) - }, writerTypeBuilderContext.Module, true); - writerTypeBuilderContext.SetWriterMethod(Type, method); - using (var il = new GroboIL(method)) - { - var context = new WriterMethodBuilderContext(writerTypeBuilderContext, il); - - var notEmptyLabel = il.DefineLabel("notEmpty"); - if(CheckEmpty(context, notEmptyLabel)) // Check if obj is empty - context.WriteNull(); // Write null & return - il.MarkLabel(notEmptyLabel); // Now we know that obj is not empty - - if(!Type.IsValueType && IsReference && writerTypeBuilderContext.GroBufWriter.Options.HasFlag(GroBufOptions.PackReferences)) - { - // Pack reference - var index = il.DeclareLocal(typeof(int)); - context.LoadIndex(); // stack: [external index] - context.LoadContext(); // stack: [external index, context] - il.Ldfld(WriterContext.StartField); // stack: [external index, context.start] - il.Sub(); // stack: [external index - context.start] - il.Stloc(index); // index = external index - context.start; stack: [] - context.LoadContext(); // stack: [context] - il.Ldfld(typeof(WriterContext).GetField("objects", BindingFlags.Public | BindingFlags.Instance)); // stack: [context.objects] - context.LoadObj(); // stack: [context.objects, obj] - var reference = il.DeclareLocal(typeof(int)); - il.Ldloca(reference); // stack: [context.objects, obj, ref reference] - int dummy; - il.Call(HackHelpers.GetMethodDefinition>(dict => dict.TryGetValue(null, out dummy))); // stack: [context.object.TryGetValue(obj, out reference)] - var storeLocationLabel = il.DefineLabel("storeLocation"); - il.Brfalse(storeLocationLabel); - // Current object is in dict - il.Ldloc(index); - il.Ldloc(reference); // stack: [index, reference] - var skipSelfLabel = il.DefineLabel("skipSelf"); - il.Beq(skipSelfLabel); // if(index == reference) goto skipSelf; stack: [] - il.Ldloc(index); // stack: [index] - il.Ldloc(reference); // stack: [index, reference] - var badReferenceLabel = il.DefineLabel("badReference"); - il.Blt(badReferenceLabel, false); // if(index < reference) goto badReference; stack: [] - context.WriteTypeCode(GroBufTypeCode.Reference); // result[index++] = GroBufTypeCode.Reference - context.GoToCurrentLocation(); // stack: [&result[index]] - il.Ldloc(reference); // stack: [&result[index], reference] - il.Stind(typeof(int)); // *(int *)&result[index] = reference - context.IncreaseIndexBy4(); // index += 4 - il.Ret(); - il.MarkLabel(badReferenceLabel); - il.Ldstr("Bad reference"); - il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] {typeof(string)})); - il.Throw(); - il.MarkLabel(storeLocationLabel); - context.LoadContext(); // stack: [context] - il.Ldfld(typeof(WriterContext).GetField("objects", BindingFlags.Public | BindingFlags.Instance)); // stack: [context.objects] - context.LoadObj(); // stack: [context.objects, obj] - il.Ldloc(index); // stack: [context.objects, obj, index] - il.Call(HackHelpers.GetMethodDefinition>(dict => dict.Add(null, 0))); // context.objects.Add(obj, index); - il.MarkLabel(skipSelfLabel); - } - - WriteNotEmpty(context); // Write obj - il.Ret(); - } - var @delegate = method.CreateDelegate(typeof(WriterDelegate<>).MakeGenericType(Type)); - var pointer = GroBufHelpers.ExtractDynamicMethodPointer(method); - writerTypeBuilderContext.SetWriterPointer(Type, pointer, @delegate); - } - - public void BuildConstants(WriterConstantsBuilderContext context) - { - context.SetFields(Type, new KeyValuePair[0]); - BuildConstantsInternal(context); - } - - protected abstract void BuildConstantsInternal(WriterConstantsBuilderContext context); - protected abstract void WriteNotEmpty(WriterMethodBuilderContext context); - - /// - /// Checks whether obj is empty - /// - /// Current context - /// Label where to go if obj is not empty - /// true if obj can be empty - protected virtual bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) - { - if(Type.IsValueType) return false; - context.LoadObj(); // stack: [obj] - context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; - return true; - } - - protected abstract bool IsReference { get; } - - protected Type Type { get; private set; } - } +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; + +using GrEmit; +using GrEmit.Utils; + +namespace GroBuf.Writers +{ + internal abstract class WriterBuilderBase : IWriterBuilder + { + protected WriterBuilderBase(Type type) + { + Type = type; + } + + public void BuildWriter(WriterTypeBuilderContext writerTypeBuilderContext) + { + var method = new DynamicMethod("Write_" + Type.Name + "_" + Guid.NewGuid(), typeof(void), + new[] + { + Type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext) + }, writerTypeBuilderContext.Module, true); + writerTypeBuilderContext.SetWriterMethod(Type, method); + using (var il = new GroboIL(method)) + { + var context = new WriterMethodBuilderContext(writerTypeBuilderContext, il); + + var notEmptyLabel = il.DefineLabel("notEmpty"); + if(CheckEmpty(context, notEmptyLabel)) // Check if obj is empty + context.WriteNull(); // Write null & return + il.MarkLabel(notEmptyLabel); // Now we know that obj is not empty + + if(!Type.IsValueType && IsReference && writerTypeBuilderContext.GroBufWriter.Options.HasFlag(GroBufOptions.PackReferences)) + { + // Pack reference + var index = il.DeclareLocal(typeof(int)); + context.LoadIndex(); // stack: [external index] + context.LoadContext(); // stack: [external index, context] + il.Ldfld(WriterContext.StartField); // stack: [external index, context.start] + il.Sub(); // stack: [external index - context.start] + il.Stloc(index); // index = external index - context.start; stack: [] + context.LoadContext(); // stack: [context] + il.Ldfld(typeof(WriterContext).GetField("objects", BindingFlags.Public | BindingFlags.Instance)); // stack: [context.objects] + context.LoadObj(); // stack: [context.objects, obj] + var reference = il.DeclareLocal(typeof(int)); + il.Ldloca(reference); // stack: [context.objects, obj, ref reference] + int dummy; + il.Call(HackHelpers.GetMethodDefinition>(dict => dict.TryGetValue(null, out dummy))); // stack: [context.object.TryGetValue(obj, out reference)] + var storeLocationLabel = il.DefineLabel("storeLocation"); + il.Brfalse(storeLocationLabel); + // Current object is in dict + il.Ldloc(index); + il.Ldloc(reference); // stack: [index, reference] + var skipSelfLabel = il.DefineLabel("skipSelf"); + il.Beq(skipSelfLabel); // if(index == reference) goto skipSelf; stack: [] + il.Ldloc(index); // stack: [index] + il.Ldloc(reference); // stack: [index, reference] + var badReferenceLabel = il.DefineLabel("badReference"); + il.Blt(badReferenceLabel, false); // if(index < reference) goto badReference; stack: [] + context.WriteTypeCode(GroBufTypeCode.Reference); // result[index++] = GroBufTypeCode.Reference + context.GoToCurrentLocation(); // stack: [&result[index]] + il.Ldloc(reference); // stack: [&result[index], reference] + il.Stind(typeof(int)); // *(int *)&result[index] = reference + context.IncreaseIndexBy4(); // index += 4 + il.Ret(); + il.MarkLabel(badReferenceLabel); + il.Ldstr("Bad reference"); + il.Newobj(typeof(DataCorruptedException).GetConstructor(new[] {typeof(string)})); + il.Throw(); + il.MarkLabel(storeLocationLabel); + context.LoadContext(); // stack: [context] + il.Ldfld(typeof(WriterContext).GetField("objects", BindingFlags.Public | BindingFlags.Instance)); // stack: [context.objects] + context.LoadObj(); // stack: [context.objects, obj] + il.Ldloc(index); // stack: [context.objects, obj, index] + il.Call(HackHelpers.GetMethodDefinition>(dict => dict.Add(null, 0))); // context.objects.Add(obj, index); + il.MarkLabel(skipSelfLabel); + } + + WriteNotEmpty(context); // Write obj + il.Ret(); + } + var @delegate = method.CreateDelegate(typeof(WriterDelegate<>).MakeGenericType(Type)); + var pointer = GroBufHelpers.ExtractDynamicMethodPointer(method); + writerTypeBuilderContext.SetWriterPointer(Type, pointer, @delegate); + } + + public void BuildConstants(WriterConstantsBuilderContext context) + { + context.SetFields(Type, new KeyValuePair[0]); + BuildConstantsInternal(context); + } + + protected abstract void BuildConstantsInternal(WriterConstantsBuilderContext context); + protected abstract void WriteNotEmpty(WriterMethodBuilderContext context); + + /// + /// Checks whether obj is empty + /// + /// Current context + /// Label where to go if obj is not empty + /// true if obj can be empty + protected virtual bool CheckEmpty(WriterMethodBuilderContext context, GroboIL.Label notEmptyLabel) + { + if(Type.IsValueType) return false; + context.LoadObj(); // stack: [obj] + context.Il.Brtrue(notEmptyLabel); // if(obj != null) goto notEmpty; + return true; + } + + protected abstract bool IsReference { get; } + + protected Type Type { get; private set; } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/WriterCollection.cs b/GroBuf/Writers/WriterCollection.cs similarity index 98% rename from GroBuf/GroBuf/Writers/WriterCollection.cs rename to GroBuf/Writers/WriterCollection.cs index 8a5bf7b..3492acd 100644 --- a/GroBuf/GroBuf/Writers/WriterCollection.cs +++ b/GroBuf/Writers/WriterCollection.cs @@ -1,92 +1,92 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Net; - -namespace GroBuf.Writers -{ - internal class WriterCollection : IWriterCollection - { - public WriterCollection(IGroBufCustomSerializerCollection customSerializerCollection, Func factory, Func baseFactory) - { - this.customSerializerCollection = customSerializerCollection; - this.factory = factory; - this.baseFactory = baseFactory; - } - - public IWriterBuilder GetWriterBuilder(Type type, bool ignoreCustomSerialization) - { - var key = new KeyValuePair(type, ignoreCustomSerialization); - var writerBuilder = (IWriterBuilder)writerBuilders[key]; - if(writerBuilder == null) - { - lock(writerBuildersLock) - { - writerBuilder = (IWriterBuilder)writerBuilders[key]; - if(writerBuilder == null) - { - writerBuilder = GetWriterBuilderInternal(type, ignoreCustomSerialization); - writerBuilders[key] = writerBuilder; - } - } - } - return writerBuilder; - } - - private IWriterBuilder GetWriterBuilderInternal(Type type, bool ignoreCustomSerialization) - { - IWriterBuilder writerBuilder; - IGroBufCustomSerializer customSerializer = null; - if(!ignoreCustomSerialization) - customSerializer = customSerializerCollection.Get(type, factory, baseFactory(type)); - if(customSerializer != null) - writerBuilder = new CustomWriterBuilder(type, customSerializer); - else if(type == typeof(string)) - writerBuilder = new StringWriterBuilder(); - else if(type == typeof(DateTime)) - writerBuilder = new DateTimeWriterBuilder(); - else if(type == typeof(Guid)) - writerBuilder = new GuidWriterBuilder(); - else if(type == typeof(IPAddress)) - writerBuilder = new IPAddressWriterBuilder(); - else if(type == typeof(TimeSpan)) - writerBuilder = new TimeSpanWriterBuilder(); - else if(type == typeof(DateTimeOffset)) - writerBuilder = new DateTimeOffsetWriterBuilder(); - else if(type.IsEnum) - writerBuilder = new EnumWriterBuilder(type); - else if(type.IsPrimitive || type == typeof(decimal)) - writerBuilder = new PrimitivesWriterBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) - writerBuilder = new NullableWriterBuilder(type); - else if(type.IsArray) - writerBuilder = type.GetElementType().IsPrimitive ? (IWriterBuilder)new PrimitivesArrayWriterBuilder(type) : new ArrayWriterBuilder(type); - else if(type == typeof(Hashtable)) - writerBuilder = new HashtableWriterBuilder(); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) - writerBuilder = new DictionaryWriterBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ArraySegment<>)) - writerBuilder = type.GetGenericArguments()[0].IsPrimitive ? (IWriterBuilder)new PrimitivesArraySegmentWriterBuilder(type) : new ArraySegmentWriterBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>)) - writerBuilder = type.GetGenericArguments()[0].IsPrimitive ? (IWriterBuilder)new PrimitivesHashSetWriterBuilder(type) : new HashSetWriterBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) - writerBuilder = type.GetGenericArguments()[0].IsPrimitive ? (IWriterBuilder)new PrimitivesListWriterBuilder(type) : new ListWriterBuilder(type); - else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Lazy<>)) - writerBuilder = new LazyWriterBuilder(type); - else if(type.IsTuple()) - writerBuilder = new TupleWriterBuilder(type); - else if(type == typeof(object)) - writerBuilder = new ObjectWriterBuilder(); - else - writerBuilder = new ClassWriterBuilder(type); - return writerBuilder; - } - - private readonly IGroBufCustomSerializerCollection customSerializerCollection; - private readonly Func factory; - private readonly Func baseFactory; - - private readonly Hashtable writerBuilders = new Hashtable(); - private readonly object writerBuildersLock = new object(); - } +using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; + +namespace GroBuf.Writers +{ + internal class WriterCollection : IWriterCollection + { + public WriterCollection(IGroBufCustomSerializerCollection customSerializerCollection, Func factory, Func baseFactory) + { + this.customSerializerCollection = customSerializerCollection; + this.factory = factory; + this.baseFactory = baseFactory; + } + + public IWriterBuilder GetWriterBuilder(Type type, bool ignoreCustomSerialization) + { + var key = new KeyValuePair(type, ignoreCustomSerialization); + var writerBuilder = (IWriterBuilder)writerBuilders[key]; + if(writerBuilder == null) + { + lock(writerBuildersLock) + { + writerBuilder = (IWriterBuilder)writerBuilders[key]; + if(writerBuilder == null) + { + writerBuilder = GetWriterBuilderInternal(type, ignoreCustomSerialization); + writerBuilders[key] = writerBuilder; + } + } + } + return writerBuilder; + } + + private IWriterBuilder GetWriterBuilderInternal(Type type, bool ignoreCustomSerialization) + { + IWriterBuilder writerBuilder; + IGroBufCustomSerializer customSerializer = null; + if(!ignoreCustomSerialization) + customSerializer = customSerializerCollection.Get(type, factory, baseFactory(type)); + if(customSerializer != null) + writerBuilder = new CustomWriterBuilder(type, customSerializer); + else if(type == typeof(string)) + writerBuilder = new StringWriterBuilder(); + else if(type == typeof(DateTime)) + writerBuilder = new DateTimeWriterBuilder(); + else if(type == typeof(Guid)) + writerBuilder = new GuidWriterBuilder(); + else if(type == typeof(IPAddress)) + writerBuilder = new IPAddressWriterBuilder(); + else if(type == typeof(TimeSpan)) + writerBuilder = new TimeSpanWriterBuilder(); + else if(type == typeof(DateTimeOffset)) + writerBuilder = new DateTimeOffsetWriterBuilder(); + else if(type.IsEnum) + writerBuilder = new EnumWriterBuilder(type); + else if(type.IsPrimitive || type == typeof(decimal)) + writerBuilder = new PrimitivesWriterBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + writerBuilder = new NullableWriterBuilder(type); + else if(type.IsArray) + writerBuilder = type.GetElementType().IsPrimitive ? (IWriterBuilder)new PrimitivesArrayWriterBuilder(type) : new ArrayWriterBuilder(type); + else if(type == typeof(Hashtable)) + writerBuilder = new HashtableWriterBuilder(); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + writerBuilder = new DictionaryWriterBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ArraySegment<>)) + writerBuilder = type.GetGenericArguments()[0].IsPrimitive ? (IWriterBuilder)new PrimitivesArraySegmentWriterBuilder(type) : new ArraySegmentWriterBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>)) + writerBuilder = type.GetGenericArguments()[0].IsPrimitive ? (IWriterBuilder)new PrimitivesHashSetWriterBuilder(type) : new HashSetWriterBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) + writerBuilder = type.GetGenericArguments()[0].IsPrimitive ? (IWriterBuilder)new PrimitivesListWriterBuilder(type) : new ListWriterBuilder(type); + else if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Lazy<>)) + writerBuilder = new LazyWriterBuilder(type); + else if(type.IsTuple()) + writerBuilder = new TupleWriterBuilder(type); + else if(type == typeof(object)) + writerBuilder = new ObjectWriterBuilder(); + else + writerBuilder = new ClassWriterBuilder(type); + return writerBuilder; + } + + private readonly IGroBufCustomSerializerCollection customSerializerCollection; + private readonly Func factory; + private readonly Func baseFactory; + + private readonly Hashtable writerBuilders = new Hashtable(); + private readonly object writerBuildersLock = new object(); + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/WriterConstantsBuilderContext.cs b/GroBuf/Writers/WriterConstantsBuilderContext.cs similarity index 97% rename from GroBuf/GroBuf/Writers/WriterConstantsBuilderContext.cs rename to GroBuf/Writers/WriterConstantsBuilderContext.cs index c6e9e3c..34f7692 100644 --- a/GroBuf/GroBuf/Writers/WriterConstantsBuilderContext.cs +++ b/GroBuf/Writers/WriterConstantsBuilderContext.cs @@ -1,56 +1,56 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -using GroBuf.DataMembersExtracters; - -namespace GroBuf.Writers -{ - internal class WriterConstantsBuilderContext - { - public WriterConstantsBuilderContext(GroBufWriter groBufWriter, TypeBuilder constantsBuilder, IWriterCollection writerCollection, IDataMembersExtractor dataMembersExtractor) - { - GroBufWriter = groBufWriter; - ConstantsBuilder = constantsBuilder; - this.writerCollection = writerCollection; - this.dataMembersExtractor = dataMembersExtractor; - } - - public IDataMember[] GetDataMembers(Type type) - { - return dataMembersExtractor.GetMembers(type); - } - - public void SetFields(Type type, KeyValuePair[] fields) - { - hashtable[type] = fields; - foreach(var field in fields) - ConstantsBuilder.DefineField(field.Key, field.Value, FieldAttributes.Public | FieldAttributes.Static); - } - - public void BuildConstants(Type type, bool isRoot = false, bool ignoreCustomSerialization = false) - { - if(isRoot || GroBufWriter.writersWithCustomSerialization[type] == null) - { - if(hashtable[type] == null) - writerCollection.GetWriterBuilder(type, ignoreCustomSerialization).BuildConstants(this); - } - } - - public Dictionary GetFields() - { - return hashtable.Cast().ToDictionary(entry => (Type)entry.Key, entry => ((KeyValuePair[])entry.Value).Select(pair => pair.Key).ToArray()); - } - - public GroBufWriter GroBufWriter { get; private set; } - public TypeBuilder ConstantsBuilder { get; private set; } - - private readonly Hashtable hashtable = new Hashtable(); - - private readonly IWriterCollection writerCollection; - private readonly IDataMembersExtractor dataMembersExtractor; - } +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; + +using GroBuf.DataMembersExtracters; + +namespace GroBuf.Writers +{ + internal class WriterConstantsBuilderContext + { + public WriterConstantsBuilderContext(GroBufWriter groBufWriter, TypeBuilder constantsBuilder, IWriterCollection writerCollection, IDataMembersExtractor dataMembersExtractor) + { + GroBufWriter = groBufWriter; + ConstantsBuilder = constantsBuilder; + this.writerCollection = writerCollection; + this.dataMembersExtractor = dataMembersExtractor; + } + + public IDataMember[] GetDataMembers(Type type) + { + return dataMembersExtractor.GetMembers(type); + } + + public void SetFields(Type type, KeyValuePair[] fields) + { + hashtable[type] = fields; + foreach(var field in fields) + ConstantsBuilder.DefineField(field.Key, field.Value, FieldAttributes.Public | FieldAttributes.Static); + } + + public void BuildConstants(Type type, bool isRoot = false, bool ignoreCustomSerialization = false) + { + if(isRoot || GroBufWriter.writersWithCustomSerialization[type] == null) + { + if(hashtable[type] == null) + writerCollection.GetWriterBuilder(type, ignoreCustomSerialization).BuildConstants(this); + } + } + + public Dictionary GetFields() + { + return hashtable.Cast().ToDictionary(entry => (Type)entry.Key, entry => ((KeyValuePair[])entry.Value).Select(pair => pair.Key).ToArray()); + } + + public GroBufWriter GroBufWriter { get; private set; } + public TypeBuilder ConstantsBuilder { get; private set; } + + private readonly Hashtable hashtable = new Hashtable(); + + private readonly IWriterCollection writerCollection; + private readonly IDataMembersExtractor dataMembersExtractor; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/WriterMethodBuilderContext.cs b/GroBuf/Writers/WriterMethodBuilderContext.cs similarity index 97% rename from GroBuf/GroBuf/Writers/WriterMethodBuilderContext.cs rename to GroBuf/Writers/WriterMethodBuilderContext.cs index 3210f6d..b4eb776 100644 --- a/GroBuf/GroBuf/Writers/WriterMethodBuilderContext.cs +++ b/GroBuf/Writers/WriterMethodBuilderContext.cs @@ -1,230 +1,230 @@ -using System; -using System.Reflection; - -using GrEmit; - -namespace GroBuf.Writers -{ - internal class WriterMethodBuilderContext - { - public WriterMethodBuilderContext(WriterTypeBuilderContext context, GroboIL il) - { - Context = context; - Il = il; - LocalInt = il.DeclareLocal(typeof(int)); - } - - /// - /// Loads obj onto the evaluation stack - /// - public void LoadObj() - { - Il.Ldarg(0); - } - - /// - /// Loads ref obj onto the evaluation stack - /// - public void LoadObjByRef() - { - Il.Ldarga(0); - } - - /// - /// Loads writeEmpty onto the evaluation stack - /// - public void LoadWriteEmpty() - { - Il.Ldarg(1); - } - - /// - /// Loads result onto the evaluation stack - /// - public void LoadResult() - { - Il.Ldarg(2); - } - - /// - /// Loads ref index onto the evaluation stack - /// - public void LoadIndexByRef() - { - Il.Ldarg(3); - } - - /// - /// Loads index onto the evaluation stack - /// - public void LoadIndex() - { - Il.Ldarg(3); - Il.Ldind(typeof(int)); - } - - /// - /// Loads context onto the evaluation stack - /// - public void LoadContext() - { - Il.Ldarg(4); - } - - /// - /// Loads length onto the evaluation stack - /// - public void LoadResultLength() - { - LoadContext(); - Il.Ldfld(WriterContext.LengthField); - } - - /// - /// Loads context.serializerId onto the evaluation stack - /// - public void LoadSerializerId() - { - LoadContext(); - Il.Ldfld(WriterContext.SerializerIdField); - } - - /// - /// Loads the specified field onto the evaluation stack - /// - /// Field to load - public void LoadField(FieldInfo field) - { - Il.Ldfld(field); - } - - /// - /// Increases index by 1 - /// - public void IncreaseIndexBy1() - { - LoadIndexByRef(); // stack: [ref index] - LoadIndex(); // stack: [ref index, index] - Il.Ldc_I4(1); // stack: [ref index, index, 1] - Il.Add(); // stack: [ref index, index + 1] - Il.Stind(typeof(int)); // index = index + 1 - } - - /// - /// Increases index by 2 - /// - public void IncreaseIndexBy2() - { - LoadIndexByRef(); // stack: [ref index] - LoadIndex(); // stack: [ref index, index] - Il.Ldc_I4(2); // stack: [ref index, index, 2] - Il.Add(); // stack: [ref index, index + 2] - Il.Stind(typeof(int)); // index = index + 2 - } - - /// - /// Increases index by 4 - /// - public void IncreaseIndexBy4() - { - LoadIndexByRef(); // stack: [ref index] - LoadIndex(); // stack: [ref index, index] - Il.Ldc_I4(4); // stack: [ref index, index, 4] - Il.Add(); // stack: [ref index, index + 4] - Il.Stind(typeof(int)); // index = index + 4 - } - - /// - /// Increases index by 8 - /// - public void IncreaseIndexBy8() - { - LoadIndexByRef(); // stack: [ref index] - LoadIndex(); // stack: [ref index, index] - Il.Ldc_I4(8); // stack: [ref index, index, 8] - Il.Add(); // stack: [ref index, index + 8] - Il.Stind(typeof(int)); // index = index + 8 - } - - /// - /// Loads &result[index] onto the evaluation stack - /// - public void GoToCurrentLocation() - { - LoadResult(); // stack: [result] - LoadIndex(); // stack: [result, index] - Il.Add(); // stack: [result + index] - } - - /// - /// Puts TypeCode.Empty in result if writeEmpty = true and returns - /// - public void WriteNull() - { - var retLabel = Il.DefineLabel("return"); - LoadWriteEmpty(); // stack: [writeEmpty] - Il.Brfalse(retLabel); // if(!writeEmpty) goto ret; - WriteTypeCode(GroBufTypeCode.Empty); - Il.MarkLabel(retLabel); - Il.Ret(); - } - - /// - /// Asserts that the specified number of bytes can be written to result starting at index - /// - /// The number of bytes must be pushed onto the evaluation stack - /// - public void AssertLength() - { - LoadIndex(); // stack: [length, index] - Il.Add(); // stack: [length + index] - LoadResultLength(); // stack: [length + index, resultLength] - var bigEnoughLabel = Il.DefineLabel("bigEnough"); - Il.Ble(bigEnoughLabel, true); - Il.Ldstr("Seems like the object being serialized has been changed during serialization"); - var constructor = typeof(InvalidOperationException).GetConstructor(new[] {typeof(string)}); - if(constructor == null) - throw new MissingConstructorException(typeof(InvalidOperationException), typeof(string)); - Il.Newobj(constructor); - Il.Throw(); - Il.MarkLabel(bigEnoughLabel); - } - - /// - /// Puts the specified type code at result[index] - /// - /// Type code to put - public void WriteTypeCode(GroBufTypeCode typeCode) - { - Il.Ldc_I4(1); - AssertLength(); - GoToCurrentLocation(); // stack: [&result[index]] - Il.Ldc_I4((int)typeCode); // stack: [&result[index], typeCode] - Il.Stind(typeof(byte)); // result[index] = typeCode - IncreaseIndexBy1(); // index = index + 1 - } - - public void CallWriter(GroboIL il, Type type) - { - var counter = Context.GetWriter(type); - if(counter.Pointer != IntPtr.Zero) - il.Ldc_IntPtr(counter.Pointer); - else - { - il.Ldfld(Context.ConstantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic)); - il.Ldc_I4(counter.Index); - il.Ldelem(typeof(IntPtr)); - } - il.Calli(CallingConventions.Standard, typeof(void), new[] {type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext)}); - } - - public void CallWriter(Type type) - { - CallWriter(Il, type); - } - - public WriterTypeBuilderContext Context { get; private set; } - public GroboIL Il { get; private set; } - public GroboIL.Local LocalInt { get; private set; } - } +using System; +using System.Reflection; + +using GrEmit; + +namespace GroBuf.Writers +{ + internal class WriterMethodBuilderContext + { + public WriterMethodBuilderContext(WriterTypeBuilderContext context, GroboIL il) + { + Context = context; + Il = il; + LocalInt = il.DeclareLocal(typeof(int)); + } + + /// + /// Loads obj onto the evaluation stack + /// + public void LoadObj() + { + Il.Ldarg(0); + } + + /// + /// Loads ref obj onto the evaluation stack + /// + public void LoadObjByRef() + { + Il.Ldarga(0); + } + + /// + /// Loads writeEmpty onto the evaluation stack + /// + public void LoadWriteEmpty() + { + Il.Ldarg(1); + } + + /// + /// Loads result onto the evaluation stack + /// + public void LoadResult() + { + Il.Ldarg(2); + } + + /// + /// Loads ref index onto the evaluation stack + /// + public void LoadIndexByRef() + { + Il.Ldarg(3); + } + + /// + /// Loads index onto the evaluation stack + /// + public void LoadIndex() + { + Il.Ldarg(3); + Il.Ldind(typeof(int)); + } + + /// + /// Loads context onto the evaluation stack + /// + public void LoadContext() + { + Il.Ldarg(4); + } + + /// + /// Loads length onto the evaluation stack + /// + public void LoadResultLength() + { + LoadContext(); + Il.Ldfld(WriterContext.LengthField); + } + + /// + /// Loads context.serializerId onto the evaluation stack + /// + public void LoadSerializerId() + { + LoadContext(); + Il.Ldfld(WriterContext.SerializerIdField); + } + + /// + /// Loads the specified field onto the evaluation stack + /// + /// Field to load + public void LoadField(FieldInfo field) + { + Il.Ldfld(field); + } + + /// + /// Increases index by 1 + /// + public void IncreaseIndexBy1() + { + LoadIndexByRef(); // stack: [ref index] + LoadIndex(); // stack: [ref index, index] + Il.Ldc_I4(1); // stack: [ref index, index, 1] + Il.Add(); // stack: [ref index, index + 1] + Il.Stind(typeof(int)); // index = index + 1 + } + + /// + /// Increases index by 2 + /// + public void IncreaseIndexBy2() + { + LoadIndexByRef(); // stack: [ref index] + LoadIndex(); // stack: [ref index, index] + Il.Ldc_I4(2); // stack: [ref index, index, 2] + Il.Add(); // stack: [ref index, index + 2] + Il.Stind(typeof(int)); // index = index + 2 + } + + /// + /// Increases index by 4 + /// + public void IncreaseIndexBy4() + { + LoadIndexByRef(); // stack: [ref index] + LoadIndex(); // stack: [ref index, index] + Il.Ldc_I4(4); // stack: [ref index, index, 4] + Il.Add(); // stack: [ref index, index + 4] + Il.Stind(typeof(int)); // index = index + 4 + } + + /// + /// Increases index by 8 + /// + public void IncreaseIndexBy8() + { + LoadIndexByRef(); // stack: [ref index] + LoadIndex(); // stack: [ref index, index] + Il.Ldc_I4(8); // stack: [ref index, index, 8] + Il.Add(); // stack: [ref index, index + 8] + Il.Stind(typeof(int)); // index = index + 8 + } + + /// + /// Loads &result[index] onto the evaluation stack + /// + public void GoToCurrentLocation() + { + LoadResult(); // stack: [result] + LoadIndex(); // stack: [result, index] + Il.Add(); // stack: [result + index] + } + + /// + /// Puts TypeCode.Empty in result if writeEmpty = true and returns + /// + public void WriteNull() + { + var retLabel = Il.DefineLabel("return"); + LoadWriteEmpty(); // stack: [writeEmpty] + Il.Brfalse(retLabel); // if(!writeEmpty) goto ret; + WriteTypeCode(GroBufTypeCode.Empty); + Il.MarkLabel(retLabel); + Il.Ret(); + } + + /// + /// Asserts that the specified number of bytes can be written to result starting at index + /// + /// The number of bytes must be pushed onto the evaluation stack + /// + public void AssertLength() + { + LoadIndex(); // stack: [length, index] + Il.Add(); // stack: [length + index] + LoadResultLength(); // stack: [length + index, resultLength] + var bigEnoughLabel = Il.DefineLabel("bigEnough"); + Il.Ble(bigEnoughLabel, true); + Il.Ldstr("Seems like the object being serialized has been changed during serialization"); + var constructor = typeof(InvalidOperationException).GetConstructor(new[] {typeof(string)}); + if(constructor == null) + throw new MissingConstructorException(typeof(InvalidOperationException), typeof(string)); + Il.Newobj(constructor); + Il.Throw(); + Il.MarkLabel(bigEnoughLabel); + } + + /// + /// Puts the specified type code at result[index] + /// + /// Type code to put + public void WriteTypeCode(GroBufTypeCode typeCode) + { + Il.Ldc_I4(1); + AssertLength(); + GoToCurrentLocation(); // stack: [&result[index]] + Il.Ldc_I4((int)typeCode); // stack: [&result[index], typeCode] + Il.Stind(typeof(byte)); // result[index] = typeCode + IncreaseIndexBy1(); // index = index + 1 + } + + public void CallWriter(GroboIL il, Type type) + { + var counter = Context.GetWriter(type); + if(counter.Pointer != IntPtr.Zero) + il.Ldc_IntPtr(counter.Pointer); + else + { + il.Ldfld(Context.ConstantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic)); + il.Ldc_I4(counter.Index); + il.Ldelem(typeof(IntPtr)); + } + il.Calli(CallingConventions.Standard, typeof(void), new[] {type, typeof(bool), typeof(IntPtr), typeof(int).MakeByRefType(), typeof(WriterContext)}); + } + + public void CallWriter(Type type) + { + CallWriter(Il, type); + } + + public WriterTypeBuilderContext Context { get; private set; } + public GroboIL Il { get; private set; } + public GroboIL.Local LocalInt { get; private set; } + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/WriterTypeBuilder.cs b/GroBuf/Writers/WriterTypeBuilder.cs similarity index 97% rename from GroBuf/GroBuf/Writers/WriterTypeBuilder.cs rename to GroBuf/Writers/WriterTypeBuilder.cs index 0565718..6999433 100644 --- a/GroBuf/GroBuf/Writers/WriterTypeBuilder.cs +++ b/GroBuf/Writers/WriterTypeBuilder.cs @@ -1,89 +1,89 @@ -using System; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -using GroBuf.DataMembersExtracters; - -namespace GroBuf.Writers -{ - internal class WriterTypeBuilder - { - public WriterTypeBuilder(GroBufWriter groBufWriter, ModuleBuilder module, IWriterCollection writerCollection, IDataMembersExtractor dataMembersExtractor) - { - this.groBufWriter = groBufWriter; - this.module = module; - this.writerCollection = writerCollection; - this.dataMembersExtractor = dataMembersExtractor; - } - - public IntPtr BuildWriter(Type type, bool ignoreCustomSerialization) - { - var constantsBuilder = module.DefineType(type.Name + "_GroBufWriter_" + Guid.NewGuid(), TypeAttributes.Class | TypeAttributes.Public); - constantsBuilder.DefineField("pointers", typeof(IntPtr[]), FieldAttributes.Private | FieldAttributes.Static); - constantsBuilder.DefineField("delegates", typeof(Delegate[]), FieldAttributes.Private | FieldAttributes.Static); - var constantsBuilderContext = new WriterConstantsBuilderContext(groBufWriter, constantsBuilder, writerCollection, dataMembersExtractor); - constantsBuilderContext.BuildConstants(type, true, ignoreCustomSerialization); - var constantsType = constantsBuilder.CreateType(); - var fields = constantsBuilderContext.GetFields().ToDictionary(pair => pair.Key, pair => pair.Value.Select(constantsType.GetField).ToArray()); - var context = new WriterTypeBuilderContext(groBufWriter, module, constantsType, fields, writerCollection, dataMembersExtractor); - var writer = context.GetWriter(type, true, ignoreCustomSerialization); - - var initializer = BuildInitializer(constantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic), constantsType.GetField("delegates", BindingFlags.Static | BindingFlags.NonPublic)); - - var compiledDynamicMethods = context.GetMethods(); - var pointers = new IntPtr[compiledDynamicMethods.Length]; - var delegates = new Delegate[compiledDynamicMethods.Length]; - foreach(var pair in compiledDynamicMethods) - { - var compiledDynamicMethod = pair.Value; - var index = compiledDynamicMethod.Index; - pointers[index] = compiledDynamicMethod.Pointer; - delegates[index] = compiledDynamicMethod.Delegate; - if (compiledDynamicMethod.Pointer != writer.Pointer) - groBufWriter.writersWithCustomSerialization[pair.Key] = (IntPtr?)compiledDynamicMethod.Pointer; - } - initializer(pointers, delegates, context.GetFieldInitializers()); - return writer.Pointer; - } - - private Action BuildInitializer(FieldInfo pointersField, FieldInfo delegatesField) - { - var initializer = new DynamicMethod("Init", typeof(void), new[] {typeof(IntPtr[]), typeof(Delegate[]), typeof(Action[])}, module, true); - var il = initializer.GetILGenerator(); - var retLabel = il.DefineLabel(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Stsfld, pointersField); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Stsfld, delegatesField); - il.Emit(OpCodes.Ldarg_2); // stack: [initializers] - il.Emit(OpCodes.Brfalse, retLabel); // if(initializers == null) goto ret; - il.Emit(OpCodes.Ldarg_2); // stack: [initializers] - il.Emit(OpCodes.Ldlen); // stack: [initializers.Length] - il.Emit(OpCodes.Dup); // stack: [initializers.Length, initializers.Length] - var index = il.DeclareLocal(typeof(int)); - il.Emit(OpCodes.Stloc, index); // index = initializers.Length; stack: [initializers.Length] - il.Emit(OpCodes.Brfalse, retLabel); // if(initializers.Length == 0) goto ret; - var cycleStart = il.DefineLabel(); - il.MarkLabel(cycleStart); - il.Emit(OpCodes.Ldarg_2); // stack: [initializers] - il.Emit(OpCodes.Ldloc, index); // stack: [initializers, index] - il.Emit(OpCodes.Ldc_I4_1); // stack: [initializers, index, 1] - il.Emit(OpCodes.Sub); // stack: [initializers, index - 1] - il.Emit(OpCodes.Dup); // stack: [initializers, index - 1, index - 1] - il.Emit(OpCodes.Stloc, index); // index = index - 1; // stack: [initializers, index] - il.Emit(OpCodes.Ldelem_Ref); // stack: [initializers[index]] - il.Emit(OpCodes.Call, typeof(Action).GetMethod("Invoke")); // intializers[index]() - il.Emit(OpCodes.Ldloc, index); - il.Emit(OpCodes.Brtrue, cycleStart); - il.MarkLabel(retLabel); - il.Emit(OpCodes.Ret); - return (Action)initializer.CreateDelegate(typeof(Action)); - } - - private readonly GroBufWriter groBufWriter; - private readonly ModuleBuilder module; - private readonly IWriterCollection writerCollection; - private readonly IDataMembersExtractor dataMembersExtractor; - } +using System; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; + +using GroBuf.DataMembersExtracters; + +namespace GroBuf.Writers +{ + internal class WriterTypeBuilder + { + public WriterTypeBuilder(GroBufWriter groBufWriter, ModuleBuilder module, IWriterCollection writerCollection, IDataMembersExtractor dataMembersExtractor) + { + this.groBufWriter = groBufWriter; + this.module = module; + this.writerCollection = writerCollection; + this.dataMembersExtractor = dataMembersExtractor; + } + + public IntPtr BuildWriter(Type type, bool ignoreCustomSerialization) + { + var constantsBuilder = module.DefineType(type.Name + "_GroBufWriter_" + Guid.NewGuid(), TypeAttributes.Class | TypeAttributes.Public); + constantsBuilder.DefineField("pointers", typeof(IntPtr[]), FieldAttributes.Private | FieldAttributes.Static); + constantsBuilder.DefineField("delegates", typeof(Delegate[]), FieldAttributes.Private | FieldAttributes.Static); + var constantsBuilderContext = new WriterConstantsBuilderContext(groBufWriter, constantsBuilder, writerCollection, dataMembersExtractor); + constantsBuilderContext.BuildConstants(type, true, ignoreCustomSerialization); + var constantsType = constantsBuilder.CreateTypeInfo(); + var fields = constantsBuilderContext.GetFields().ToDictionary(pair => pair.Key, pair => pair.Value.Select(constantsType.GetField).ToArray()); + var context = new WriterTypeBuilderContext(groBufWriter, module, constantsType, fields, writerCollection, dataMembersExtractor); + var writer = context.GetWriter(type, true, ignoreCustomSerialization); + + var initializer = BuildInitializer(constantsType.GetField("pointers", BindingFlags.Static | BindingFlags.NonPublic), constantsType.GetField("delegates", BindingFlags.Static | BindingFlags.NonPublic)); + + var compiledDynamicMethods = context.GetMethods(); + var pointers = new IntPtr[compiledDynamicMethods.Length]; + var delegates = new Delegate[compiledDynamicMethods.Length]; + foreach(var pair in compiledDynamicMethods) + { + var compiledDynamicMethod = pair.Value; + var index = compiledDynamicMethod.Index; + pointers[index] = compiledDynamicMethod.Pointer; + delegates[index] = compiledDynamicMethod.Delegate; + if (compiledDynamicMethod.Pointer != writer.Pointer) + groBufWriter.writersWithCustomSerialization[pair.Key] = (IntPtr?)compiledDynamicMethod.Pointer; + } + initializer(pointers, delegates, context.GetFieldInitializers()); + return writer.Pointer; + } + + private Action BuildInitializer(FieldInfo pointersField, FieldInfo delegatesField) + { + var initializer = new DynamicMethod("Init", typeof(void), new[] {typeof(IntPtr[]), typeof(Delegate[]), typeof(Action[])}, module, true); + var il = initializer.GetILGenerator(); + var retLabel = il.DefineLabel(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Stsfld, pointersField); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Stsfld, delegatesField); + il.Emit(OpCodes.Ldarg_2); // stack: [initializers] + il.Emit(OpCodes.Brfalse, retLabel); // if(initializers == null) goto ret; + il.Emit(OpCodes.Ldarg_2); // stack: [initializers] + il.Emit(OpCodes.Ldlen); // stack: [initializers.Length] + il.Emit(OpCodes.Dup); // stack: [initializers.Length, initializers.Length] + var index = il.DeclareLocal(typeof(int)); + il.Emit(OpCodes.Stloc, index); // index = initializers.Length; stack: [initializers.Length] + il.Emit(OpCodes.Brfalse, retLabel); // if(initializers.Length == 0) goto ret; + var cycleStart = il.DefineLabel(); + il.MarkLabel(cycleStart); + il.Emit(OpCodes.Ldarg_2); // stack: [initializers] + il.Emit(OpCodes.Ldloc, index); // stack: [initializers, index] + il.Emit(OpCodes.Ldc_I4_1); // stack: [initializers, index, 1] + il.Emit(OpCodes.Sub); // stack: [initializers, index - 1] + il.Emit(OpCodes.Dup); // stack: [initializers, index - 1, index - 1] + il.Emit(OpCodes.Stloc, index); // index = index - 1; // stack: [initializers, index] + il.Emit(OpCodes.Ldelem_Ref); // stack: [initializers[index]] + il.Emit(OpCodes.Call, typeof(Action).GetMethod("Invoke")); // intializers[index]() + il.Emit(OpCodes.Ldloc, index); + il.Emit(OpCodes.Brtrue, cycleStart); + il.MarkLabel(retLabel); + il.Emit(OpCodes.Ret); + return (Action)initializer.CreateDelegate(typeof(Action)); + } + + private readonly GroBufWriter groBufWriter; + private readonly ModuleBuilder module; + private readonly IWriterCollection writerCollection; + private readonly IDataMembersExtractor dataMembersExtractor; + } } \ No newline at end of file diff --git a/GroBuf/GroBuf/Writers/WriterTypeBuilderContext.cs b/GroBuf/Writers/WriterTypeBuilderContext.cs similarity index 97% rename from GroBuf/GroBuf/Writers/WriterTypeBuilderContext.cs rename to GroBuf/Writers/WriterTypeBuilderContext.cs index e9d2bd9..119027b 100644 --- a/GroBuf/GroBuf/Writers/WriterTypeBuilderContext.cs +++ b/GroBuf/Writers/WriterTypeBuilderContext.cs @@ -1,107 +1,107 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -using GrEmit; - -using GroBuf.DataMembersExtracters; - -namespace GroBuf.Writers -{ - internal class WriterTypeBuilderContext - { - public WriterTypeBuilderContext(GroBufWriter groBufWriter, ModuleBuilder module, Type constantsType, Dictionary fields, IWriterCollection writerCollection, IDataMembersExtractor dataMembersExtractor) - { - GroBufWriter = groBufWriter; - Module = module; - ConstantsType = constantsType; - this.fields = fields; - this.writerCollection = writerCollection; - this.dataMembersExtractor = dataMembersExtractor; - } - - public IDataMember[] GetDataMembers(Type type) - { - return dataMembersExtractor.GetMembers(type); - } - - public FieldInfo InitConstField(Type type, int index, T value) - { - var field = fields[type][index]; - initializers.Add(field.Name, ((Func)(f => BuildFieldInitializer(f, value)))(field)); - return field; - } - - public Action[] GetFieldInitializers() - { - return (from object value in initializers.Values select ((Action)value)).ToArray(); - } - - public KeyValuePair[] GetMethods() - { - return writers.Cast().Select(entry => new KeyValuePair((Type)entry.Key, (CompiledDynamicMethod)entry.Value)).ToArray(); - } - - public void SetWriterMethod(Type type, DynamicMethod method) - { - if(writers[type] != null) - throw new InvalidOperationException(); - writers[type] = new CompiledDynamicMethod {Method = method, Index = writers.Count}; - } - - public void SetWriterPointer(Type type, IntPtr writerPointer, Delegate writer) - { - if(writers[type] == null) - throw new InvalidOperationException(); - var compiledDynamicMethod = (CompiledDynamicMethod)writers[type]; - compiledDynamicMethod.Pointer = writerPointer; - compiledDynamicMethod.Delegate = writer; - } - - public CompiledDynamicMethod GetWriter(Type type, bool isRoot = false, bool ignoreCustomSerialization = false) - { - var writer = (CompiledDynamicMethod)writers[type]; - if(writer == null) - { - if (!isRoot) - { - var pointer = (IntPtr?)GroBufWriter.writersWithCustomSerialization[type]; - if (pointer != null) - return new CompiledDynamicMethod { Pointer = pointer.Value }; - } - writerCollection.GetWriterBuilder(type, ignoreCustomSerialization).BuildWriter(this); - writer = (CompiledDynamicMethod)writers[type]; - if(writer == null) - throw new InvalidOperationException(); - } - return writer; - } - - public GroBufWriter GroBufWriter { get; private set; } - public ModuleBuilder Module { get; private set; } - public Type ConstantsType { get; private set; } - - private Action BuildFieldInitializer(FieldInfo field, T value) - { - var method = new DynamicMethod(field.Name + "_Init_" + Guid.NewGuid(), typeof(void), new[] {typeof(T)}, Module); - using (var il = new GroboIL(method)) - { - il.Ldarg(0); - il.Stfld(field); - il.Ret(); - } - var action = (Action)method.CreateDelegate(typeof(Action)); - return () => action(value); - } - - private readonly IWriterCollection writerCollection; - private readonly IDataMembersExtractor dataMembersExtractor; - private readonly Dictionary fields; - - private readonly Hashtable writers = new Hashtable(); - private readonly Hashtable initializers = new Hashtable(); - } +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; + +using GrEmit; + +using GroBuf.DataMembersExtracters; + +namespace GroBuf.Writers +{ + internal class WriterTypeBuilderContext + { + public WriterTypeBuilderContext(GroBufWriter groBufWriter, ModuleBuilder module, Type constantsType, Dictionary fields, IWriterCollection writerCollection, IDataMembersExtractor dataMembersExtractor) + { + GroBufWriter = groBufWriter; + Module = module; + ConstantsType = constantsType; + this.fields = fields; + this.writerCollection = writerCollection; + this.dataMembersExtractor = dataMembersExtractor; + } + + public IDataMember[] GetDataMembers(Type type) + { + return dataMembersExtractor.GetMembers(type); + } + + public FieldInfo InitConstField(Type type, int index, T value) + { + var field = fields[type][index]; + initializers.Add(field.Name, ((Func)(f => BuildFieldInitializer(f, value)))(field)); + return field; + } + + public Action[] GetFieldInitializers() + { + return (from object value in initializers.Values select ((Action)value)).ToArray(); + } + + public KeyValuePair[] GetMethods() + { + return writers.Cast().Select(entry => new KeyValuePair((Type)entry.Key, (CompiledDynamicMethod)entry.Value)).ToArray(); + } + + public void SetWriterMethod(Type type, DynamicMethod method) + { + if(writers[type] != null) + throw new InvalidOperationException(); + writers[type] = new CompiledDynamicMethod {Method = method, Index = writers.Count}; + } + + public void SetWriterPointer(Type type, IntPtr writerPointer, Delegate writer) + { + if(writers[type] == null) + throw new InvalidOperationException(); + var compiledDynamicMethod = (CompiledDynamicMethod)writers[type]; + compiledDynamicMethod.Pointer = writerPointer; + compiledDynamicMethod.Delegate = writer; + } + + public CompiledDynamicMethod GetWriter(Type type, bool isRoot = false, bool ignoreCustomSerialization = false) + { + var writer = (CompiledDynamicMethod)writers[type]; + if(writer == null) + { + if (!isRoot) + { + var pointer = (IntPtr?)GroBufWriter.writersWithCustomSerialization[type]; + if (pointer != null) + return new CompiledDynamicMethod { Pointer = pointer.Value }; + } + writerCollection.GetWriterBuilder(type, ignoreCustomSerialization).BuildWriter(this); + writer = (CompiledDynamicMethod)writers[type]; + if(writer == null) + throw new InvalidOperationException(); + } + return writer; + } + + public GroBufWriter GroBufWriter { get; private set; } + public ModuleBuilder Module { get; private set; } + public Type ConstantsType { get; private set; } + + private Action BuildFieldInitializer(FieldInfo field, T value) + { + var method = new DynamicMethod(field.Name + "_Init_" + Guid.NewGuid(), typeof(void), new[] {typeof(T)}, Module); + using (var il = new GroboIL(method)) + { + il.Ldarg(0); + il.Stfld(field); + il.Ret(); + } + var action = (Action)method.CreateDelegate(typeof(Action)); + return () => action(value); + } + + private readonly IWriterCollection writerCollection; + private readonly IDataMembersExtractor dataMembersExtractor; + private readonly Dictionary fields; + + private readonly Hashtable writers = new Hashtable(); + private readonly Hashtable initializers = new Hashtable(); + } } \ No newline at end of file diff --git a/README.markdown b/README.markdown index 7a1b70a..436a7e4 100644 --- a/README.markdown +++ b/README.markdown @@ -1,4 +1,6 @@ # GroBuf +[![Build Status](https://travis-ci.org/skbkontur/GroBuf.svg?branch=dotnetcore)](https://travis-ci.org/skbkontur/GroBuf) +[![Build status](https://ci.appveyor.com/api/projects/status/xbq92fnsfbo8946k?svg=true)](https://ci.appveyor.com/project/vostok/grobuf) GroBuf is a fast binary serializer for .NET. diff --git a/appveyor.yml b/appveyor.yml index 316427c..388223d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,11 +1,17 @@ -version: 1.0.{build} image: Visual Studio 2017 -configuration: Release -branches: - only: - - master + +before_build: + - cmd: dotnet --info + - cmd: dotnet restore ./GroBuf.sln --verbosity m + build_script: -- ps: '& { ./build.ps1 -Script build.cake -Target Build-And-Merge -Configuration Release }' -after_build: -- nuget pack GroBuf.nuspec -- ps: Get-ChildItem .\GroBuf.*.nupkg | % { Push-AppveyorArtifact $_ -FileName $_.FullName } + - cmd: dotnet build --configuration Release ./GroBuf.sln + +test_script: + - cmd: dotnet test --no-build --configuration Release --filter TestCategory!=LongRunning ./GroBuf.Tests/GroBuf.Tests.csproj --logger "trx;LogFileName=test-results.trx" + +after_test: + - ps: | + $wc = New-Object 'System.Net.WebClient' + $url = "https://ci.appveyor.com/api/testresults/mstest/$($env:APPVEYOR_JOB_ID)"; + $wc.UploadFile($url, (Resolve-Path './GroBuf.Tests/TestResults/test-results.trx')) diff --git a/build.cake b/build.cake deleted file mode 100644 index ece5da0..0000000 --- a/build.cake +++ /dev/null @@ -1,91 +0,0 @@ -#tool "nuget:?package=NUnit.Runners&version=2.6.4" -#tool "nuget:?package=ilmerge" - -var target = Argument("target", "Default"); -var configuration = Argument("configuration", "Debug"); -var slnPath = "./GroBuf/GroBuf.sln"; - -Task("Default") - .Does(() => -{ - Information(@"Supported cake targets: - Restore-NuGet-Packages : Runs NuGet to restore all required packages. - Rebuild : Rebuild grobuf to ./Assemblies/ - Build-And-Merge : Rebuild and il-merge all required assemblies to ./Output/GroBuf.dll - Run-Unit-Tests : Rebuild and run unit tests excluding 'LongRunning' category. - Run-All-Tests : Rebuild and run all unit tests. - "); -}); - -Task("Restore-NuGet-Packages") - .Does(() => -{ - var solutions = GetFiles("./GroBuf/**/*.sln"); - foreach(var solution in solutions) - { - Information("Restoring {0}", solution); - NuGetRestore(solution); - } -}); - -Task("Rebuild") - .IsDependentOn("Restore-NuGet-Packages") - .Does(() => -{ - Information("Cleaning output directory."); - CleanDirectory("./Output/"); - - Information(@"Rebuilding grobuf solution. Configuration : {0}", configuration); - MSBuild(slnPath, settings => settings.WithTarget("Rebuild") - .SetVerbosity(Verbosity.Minimal) - .SetConfiguration(configuration) - .UseToolVersion(MSBuildToolVersion.VS2017)); - - Information("Copying build results to output directory"); - EnsureDirectoryExists("./Output/bin/"); - CopyDirectory($"./GroBuf/GroBuf/bin/{configuration}/", "./Output/bin/"); -}); - -Task("Run-Unit-Tests") - .IsDependentOn("Rebuild") - .Does(() => -{ - Information("Running unit tests excluding 'LongRunning' category."); - RunTests(excludeLongRunning : true); -}); - -Task("Run-All-Tests") - .IsDependentOn("Rebuild") - .Does(() => -{ - Information("Running all unit tests."); - RunTests(excludeLongRunning : false); -}); - -Task("Build-And-Merge") - .IsDependentOn("Rebuild") - .IsDependentOn("Run-Unit-Tests") - .Does(() => -{ - var assembliesToMerge = GetFiles("./Output/bin/*.dll").Where(file => file.GetFilename().ToString() != "GroBuf.dll"); - Information("Merging {0} into the GroBuf.dll", string.Join(", ", assembliesToMerge.Select(x => x.GetFilename()))); - ILMerge( - "./Output/GroBuf.dll", - "./Output/bin/GroBuf.dll", - assembliesToMerge, - new ILMergeSettings { Internalize = true }); -}); - -RunTarget(target); - -private void RunTests(bool excludeLongRunning){ - EnsureDirectoryExists("./Output/test/"); - var settings = new NUnitSettings - { - NoResults = true, - OutputFile = "./Output/test/tests-output.txt" - }; - if(excludeLongRunning) - settings.Exclude = "LongRunning"; - NUnit("./GroBuf/Tests/**/bin/" + configuration + "/*.Tests.dll", settings); -} \ No newline at end of file diff --git a/build.ps1 b/build.ps1 deleted file mode 100644 index 054535b..0000000 --- a/build.ps1 +++ /dev/null @@ -1,237 +0,0 @@ -########################################################################## -# This is the Cake bootstrapper script for PowerShell. -# This file was downloaded from https://github.com/cake-build/resources -# Feel free to change this file to fit your needs. -########################################################################## - -<# - -.SYNOPSIS -This is a Powershell script to bootstrap a Cake build. - -.DESCRIPTION -This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) -and execute your Cake build script with the parameters you provide. - -.PARAMETER Script -The build script to execute. -.PARAMETER Target -The build script target to run. -.PARAMETER Configuration -The build configuration to use. -.PARAMETER Verbosity -Specifies the amount of information to be displayed. -.PARAMETER ShowDescription -Shows description about tasks. -.PARAMETER DryRun -Performs a dry run. -.PARAMETER Experimental -Uses the nightly builds of the Roslyn script engine. -.PARAMETER Mono -Uses the Mono Compiler rather than the Roslyn script engine. -.PARAMETER SkipToolPackageRestore -Skips restoring of packages. -.PARAMETER ScriptArgs -Remaining arguments are added here. - -.LINK -https://cakebuild.net - -#> - -[CmdletBinding()] -Param( - [string]$Script = "build.cake", - [string]$Target, - [string]$Configuration, - [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] - [string]$Verbosity, - [switch]$ShowDescription, - [Alias("WhatIf", "Noop")] - [switch]$DryRun, - [switch]$Experimental, - [switch]$Mono, - [switch]$SkipToolPackageRestore, - [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] - [string[]]$ScriptArgs -) - -[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null -function MD5HashFile([string] $filePath) -{ - if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) - { - return $null - } - - [System.IO.Stream] $file = $null; - [System.Security.Cryptography.MD5] $md5 = $null; - try - { - $md5 = [System.Security.Cryptography.MD5]::Create() - $file = [System.IO.File]::OpenRead($filePath) - return [System.BitConverter]::ToString($md5.ComputeHash($file)) - } - finally - { - if ($file -ne $null) - { - $file.Dispose() - } - } -} - -function GetProxyEnabledWebClient -{ - $wc = New-Object System.Net.WebClient - $proxy = [System.Net.WebRequest]::GetSystemWebProxy() - $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials - $wc.Proxy = $proxy - return $wc -} - -Write-Host "Preparing to run build script..." - -if(!$PSScriptRoot){ - $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent -} - -$TOOLS_DIR = Join-Path $PSScriptRoot ".cake" -$ADDINS_DIR = Join-Path $TOOLS_DIR "Addins" -$MODULES_DIR = Join-Path $TOOLS_DIR "Modules" -$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" -$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" -$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" -$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" -$ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config" -$MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config" - -# Make sure tools folder exists -if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { - Write-Verbose -Message "Creating tools directory..." - New-Item -Path $TOOLS_DIR -Type directory | out-null -} - -# Make sure that packages.config exist. -if (!(Test-Path $PACKAGES_CONFIG)) { - Write-Verbose -Message "Downloading packages.config..." - try { - $wc = GetProxyEnabledWebClient - $wc.DownloadFile("https://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { - Throw "Could not download packages.config." - } -} - -# Try find NuGet.exe in path if not exists -if (!(Test-Path $NUGET_EXE)) { - Write-Verbose -Message "Trying to find nuget.exe in PATH..." - $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) } - $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 - if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { - Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." - $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName - } -} - -# Try download NuGet.exe if not exists -if (!(Test-Path $NUGET_EXE)) { - Write-Verbose -Message "Downloading NuGet.exe..." - try { - $wc = GetProxyEnabledWebClient - $wc.DownloadFile($NUGET_URL, $NUGET_EXE) - } catch { - Throw "Could not download NuGet.exe." - } -} - -# Save nuget.exe path to environment to be available to child processed -$ENV:NUGET_EXE = $NUGET_EXE - -# Save tools directory to environment -$ENV:CAKE_PATHS_TOOLS = $TOOLS_DIR - -# Restore tools from NuGet? -if(-Not $SkipToolPackageRestore.IsPresent) { - Push-Location - Set-Location $TOOLS_DIR - - # Check for changes in packages.config and remove installed tools if true. - [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) - if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or - ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { - Write-Verbose -Message "Missing or changed package.config hash..." - Remove-Item * -Recurse -Exclude packages.config,nuget.exe - } - - Write-Verbose -Message "Restoring tools from NuGet..." - $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`"" - - if ($LASTEXITCODE -ne 0) { - Throw "An error occured while restoring NuGet tools." - } - else - { - $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" - } - Write-Verbose -Message ($NuGetOutput | out-string) - - Pop-Location -} - -# Restore addins from NuGet -if (Test-Path $ADDINS_PACKAGES_CONFIG) { - Push-Location - Set-Location $ADDINS_DIR - - Write-Verbose -Message "Restoring addins from NuGet..." - $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`"" - - if ($LASTEXITCODE -ne 0) { - Throw "An error occured while restoring NuGet addins." - } - - Write-Verbose -Message ($NuGetOutput | out-string) - - Pop-Location -} - -# Restore modules from NuGet -if (Test-Path $MODULES_PACKAGES_CONFIG) { - Push-Location - Set-Location $MODULES_DIR - - Write-Verbose -Message "Restoring modules from NuGet..." - $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`"" - - if ($LASTEXITCODE -ne 0) { - Throw "An error occured while restoring NuGet modules." - } - - Write-Verbose -Message ($NuGetOutput | out-string) - - Pop-Location -} - -# Make sure that Cake has been installed. -if (!(Test-Path $CAKE_EXE)) { - Throw "Could not find Cake.exe at $CAKE_EXE" -} - - - -# Build Cake arguments -$cakeArguments = @("$Script"); -if ($Target) { $cakeArguments += "-target=$Target" } -if ($Configuration) { $cakeArguments += "-configuration=$Configuration" } -if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" } -if ($ShowDescription) { $cakeArguments += "-showdescription" } -if ($DryRun) { $cakeArguments += "-dryrun" } -if ($Experimental) { $cakeArguments += "-experimental" } -if ($Mono) { $cakeArguments += "-mono" } -$cakeArguments += $ScriptArgs - -# Start Cake -Write-Host "Running build script..." -&$CAKE_EXE $cakeArguments -exit $LASTEXITCODE diff --git a/module.yaml b/module.yaml deleted file mode 100644 index f6d530c..0000000 --- a/module.yaml +++ /dev/null @@ -1,10 +0,0 @@ - -full-build: - deps: - - build: - target: GroBuf\GroBuf.sln - configuration: Release - - install: - - Assemblies\GroBuf.dll