diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..53a1987 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,144 @@ +# examples are here: http://editorconfig.org/ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +charset = utf-8 + +[*.{yml,yaml,csproj}] +indent_size = 2 + +[*.cs] +# .NET Code Style Settings +## Use this or not +dotnet_style_qualification_for_field = false:error +dotnet_style_qualification_for_property = false:error +dotnet_style_qualification_for_method = false:error +dotnet_style_qualification_for_event = false:error + +## use int or Int32 +dotnet_style_predefined_type_for_locals_parameters_members = true:error +dotnet_style_predefined_type_for_member_access = true:error + +## Modifier preferences +dotnet_style_require_accessibility_modifiers = always:error +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:error +dotnet_style_readonly_field = true:error + +## use of object initializers, collection initializers, explicit tuple names +dotnet_style_object_initializer = true:error +dotnet_style_collection_initializer = true:error +dotnet_style_explicit_tuple_names = true:error +dotnet_prefer_inferred_tuple_names = true:error +dotnet_prefer_inferred_anonymous_type_member_names = true:error + +## "Null" checking preferences +dotnet_style_coalesce_expression = true:error +dotnet_style_null_propagation = true:error + +## to var or not to var +csharp_style_var_for_built_in_types = true:error +csharp_style_var_when_type_is_apparent = true:error +csharp_style_var_elsewhere = true:error + +## => for bodies or not +csharp_style_expression_bodied_methods = when_on_single_line:error +csharp_style_expression_bodied_constructors = when_on_single_line:error +csharp_style_expression_bodied_operators = when_on_single_line:error +csharp_style_expression_bodied_properties = when_on_single_line:error +csharp_style_expression_bodied_indexers = when_on_single_line:error +csharp_style_expression_bodied_accessors = when_on_single_line:error + +## pattern matching +csharp_style_pattern_matching_over_is_with_cast_check = true:error +csharp_style_pattern_matching_over_as_with_null_check = true:error +csharp_style_inlined_variable_declaration = true:error + +## default expressions, deconstructed variables, and local functions over anonymous functions. +csharp_prefer_simple_default_expression = true:error +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion + +## null check +csharp_style_throw_expression = true:error +csharp_style_conditional_delegate_call = true:error + +## braces around one liner +csharp_prefer_braces = false:suggestion + +# .NET formatting settings +## Organize usings +dotnet_sort_system_directives_first = true + +## Newline Options +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +## Indentation options +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = one_less_than_current + +## Spacing Options +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_parentheses = false + +## Wrapping options + +csharp_preserve_single_line_statements = true +csharp_preserve_single_line_blocks = true + +# Naming style + +## Source: https://github.com/kentcb/EditorConfigReference/blob/master/.editorconfig +dotnet_naming_symbols.private_field_symbol.applicable_kinds = field +dotnet_naming_symbols.private_field_symbol.applicable_accessibilities = private +dotnet_naming_style.private_field_style.required_prefix = _ +dotnet_naming_style.private_field_style.capitalization = camel_case +dotnet_naming_rule.private_fields_are_camel_case.severity = error +dotnet_naming_rule.private_fields_are_camel_case.symbols = private_field_symbol +dotnet_naming_rule.private_fields_are_camel_case.style = private_field_style + +dotnet_naming_symbols.non_private_field_symbol.applicable_kinds = field +dotnet_naming_symbols.non_private_field_symbol.applicable_accessibilities = public,internal,friend,protected,protected_internal,protected_friend +dotnet_naming_style.non_private_field_style.capitalization = pascal_case +dotnet_naming_rule.non_private_fields_are_pascal_case.severity = error +dotnet_naming_rule.non_private_fields_are_pascal_case.symbols = non_private_field_symbol +dotnet_naming_rule.non_private_fields_are_pascal_case.style = non_private_field_style + +dotnet_naming_symbols.parameter_symbol.applicable_kinds = parameter +dotnet_naming_style.parameter_style.capitalization = camel_case +dotnet_naming_rule.parameters_are_camel_case.severity = error +dotnet_naming_rule.parameters_are_camel_case.symbols = parameter_symbol +dotnet_naming_rule.parameters_are_camel_case.style = parameter_style + +dotnet_naming_symbols.non_interface_type_symbol.applicable_kinds = class,struct,enum,delegate +dotnet_naming_style.non_interface_type_style.capitalization = pascal_case +dotnet_naming_rule.non_interface_types_are_pascal_case.severity = error +dotnet_naming_rule.non_interface_types_are_pascal_case.symbols = non_interface_type_symbol +dotnet_naming_rule.non_interface_types_are_pascal_case.style = non_interface_type_style + +dotnet_naming_symbols.interface_type_symbol.applicable_kinds = interface +dotnet_naming_style.interface_type_style.capitalization = pascal_case +dotnet_naming_style.interface_type_style.required_prefix = I +dotnet_naming_rule.interface_types_must_be_prefixed_with_I.severity = error +dotnet_naming_rule.interface_types_must_be_prefixed_with_I.symbols = interface_type_symbol +dotnet_naming_rule.interface_types_must_be_prefixed_with_I.style = interface_type_style + +dotnet_naming_symbols.member_symbol.applicable_kinds = method,property,event +dotnet_naming_style.member_style.capitalization = pascal_case +dotnet_naming_rule.members_are_pascal_case.severity = error +dotnet_naming_rule.members_are_pascal_case.symbols = member_symbol +dotnet_naming_rule.members_are_pascal_case.style = member_style diff --git a/.gitignore b/.gitignore index 3653bb7..8aa62b5 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ Release bin obj /.vs + +**/BenchmarkDotNet.Artifacts/ diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 27ffa11..49c59ce 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,47 +1,13 @@ -jobs: -- job: macOs - pool: - name: Hosted macOS - steps: - - template: .azure/tests.yml - -- job: linux - pool: - name: Hosted Ubuntu 1604 - steps: - - script: curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin -channel 1.1 - displayName: Installing .netcore 1.1 - - template: .azure/tests.yml - parameters: - netcore1Global: false - -- job: win - dependsOn: - - macOs - - linux - pool: - name: Hosted VS2017 - steps: - - template: .azure/tests.yml +variables: + sln: msgpack.sln + tests: tests/msgpack.light.tests/msgpack.light.tests.csproj - - task: PowerShell@2 - displayName: pack nuget package - inputs: - targetType: inline - script: | - $version = $(git describe --tags | %{$_ -replace '-([^g])', '.$1'}) - dotnet pack --no-build -v minimal -c Release /property:Version=$version /property:PackageOutputPath=$(Build.ArtifactStagingDirectory) +resources: + repositories: + - repository: templates + type: github + name: progaudi/azure-pipelines + endpoint: progaudi - - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - - task: NuGetCommand@2 - displayName: push nuget packages - inputs: - command: push - packagesToPush: '$(Build.ArtifactStagingDirectory)/*.nupkg' - nuGetFeedType: external - publishFeedCredentials: api.nuget.org - - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: '$(Build.ArtifactStagingDirectory)' - artifactName: .nupkgs +jobs: +- template: library/nuget.yml@templates diff --git a/msgpack.sln b/msgpack.sln index 31ffd25..fb1734c 100644 --- a/msgpack.sln +++ b/msgpack.sln @@ -1,4 +1,4 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 +Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26730.10 MinimumVisualStudioVersion = 10.0.40219.1 @@ -12,8 +12,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "msgpack.light", "src\msgpac EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "msgpack.light.tests", "tests\msgpack.light.tests\msgpack.light.tests.csproj", "{4DD9051D-548F-4E11-86EA-746F443CEA67}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "msgpack.light.benchmark", "src\msgpack.light.benchmark\msgpack.light.benchmark.csproj", "{62C5CC43-A029-4529-BBCA-6D8CC69E6B11}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -28,10 +26,6 @@ Global {4DD9051D-548F-4E11-86EA-746F443CEA67}.Debug|Any CPU.Build.0 = Debug|Any CPU {4DD9051D-548F-4E11-86EA-746F443CEA67}.Release|Any CPU.ActiveCfg = Release|Any CPU {4DD9051D-548F-4E11-86EA-746F443CEA67}.Release|Any CPU.Build.0 = Release|Any CPU - {62C5CC43-A029-4529-BBCA-6D8CC69E6B11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {62C5CC43-A029-4529-BBCA-6D8CC69E6B11}.Debug|Any CPU.Build.0 = Debug|Any CPU - {62C5CC43-A029-4529-BBCA-6D8CC69E6B11}.Release|Any CPU.ActiveCfg = Release|Any CPU - {62C5CC43-A029-4529-BBCA-6D8CC69E6B11}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/msgpack.sln.DotSettings b/msgpack.sln.DotSettings index 1a1f4e0..3117fce 100644 --- a/msgpack.sln.DotSettings +++ b/msgpack.sln.DotSettings @@ -68,6 +68,7 @@ True True True + True True True True diff --git a/src/msgpack.light.benchmark/BeerDeserializeBenchmark.cs b/src/msgpack.light.benchmark/BeerDeserializeBenchmark.cs index 6dcb7e4..658b230 100644 --- a/src/msgpack.light.benchmark/BeerDeserializeBenchmark.cs +++ b/src/msgpack.light.benchmark/BeerDeserializeBenchmark.cs @@ -41,91 +41,70 @@ private MemoryStream PrepareJson(BeerSerializeBenchmark serializer) } [Benchmark] - public void JsonNet() + public object JsonNet() { _json.Seek(0, SeekOrigin.Begin); using (var reader = new StreamReader(_json, Encoding.UTF8, false, 1024, true)) { - var beer = Serializers.Newtonsoft.Deserialize(reader, typeof(Beer)); + return Serializers.Newtonsoft.Deserialize(reader, typeof(Beer)); } } - + [Benchmark(Baseline = true)] - public void MPCli_Stream() + public Beer MPCli_Stream() { _msgPack.Seek(0, SeekOrigin.Begin); - var beer = Serializers.MsgPack.GetSerializer().Unpack(_msgPack); + return Serializers.MsgPack.GetSerializer().Unpack(_msgPack); } [Benchmark] - public void MPCli_Array() + public Beer MPCli_Array() { - var beer = Serializers.MsgPack.GetSerializer().UnpackSingleObject(_msgPackArray); + return Serializers.MsgPack.GetSerializer().UnpackSingleObject(_msgPackArray); } [Benchmark] - public void MPSharp_Stream() + public Beer MPSharp_Stream() { _msgPack.Seek(0, SeekOrigin.Begin); - var beer = MessagePackSerializer.Deserialize(_msgPack); - } - - [Benchmark] - public void MPSharp_Array() - { - var beer = MessagePackSerializer.Deserialize(_msgPackArray); + return MessagePackSerializer.Deserialize(_msgPack); } [Benchmark] - public void MPLight_Stream() + public Beer MPSharp_Array() { - _msgPack.Seek(0, SeekOrigin.Begin); - var beer = MsgPackSerializer.Deserialize(_msgPack, Serializers.MsgPackLight); + return MessagePackSerializer.Deserialize(_msgPackArray); } [Benchmark] - public void MPLight_Array() + public Beer MPLight_Array() { - var beer = MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLight); + return MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLight); } [Benchmark] - public void MPCliH_Stream() + public Beer MPCliH_Stream() { _msgPack.Seek(0, SeekOrigin.Begin); - var beer = Serializers.MsgPackHardcore.GetSerializer().Unpack(_msgPack); + return Serializers.MsgPackHardcore.GetSerializer().Unpack(_msgPack); } [Benchmark] - public void MPCliH_Array() + public Beer MPCliH_Array() { - var beer = Serializers.MsgPackHardcore.GetSerializer().UnpackSingleObject(_msgPackArray); + return Serializers.MsgPackHardcore.GetSerializer().UnpackSingleObject(_msgPackArray); } [Benchmark] - public void MPLightH_Stream() + public Beer MPLightH_Array() { - _msgPack.Seek(0, SeekOrigin.Begin); - var beer = MsgPackSerializer.Deserialize(_msgPack, Serializers.MsgPackLightHardcore); + return MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLightHardcore, out _); } - [Benchmark] - public void MPLightH_Array() - { - var beer = MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLightHardcore); - } - - [Benchmark] - public void MPLightH_Stream_AutoMap() - { - _msgPack.Seek(0, SeekOrigin.Begin); - var beer = MsgPackSerializer.Deserialize(_msgPack, Serializers.MsgPackLightMapAutoGeneration); - } - - [Benchmark] - public void MPLightH_Array_AutoMap() - { - var beer = MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLightMapAutoGeneration); - } +// [Benchmark] +// public void MPLightH_Array_AutoMap() +// { +// var beer = MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLightMapAutoGeneration); +// } } -} \ No newline at end of file +} diff --git a/src/msgpack.light.benchmark/BeerListDeserializeBenchmark.cs b/src/msgpack.light.benchmark/BeerListDeserializeBenchmark.cs index d34d032..44251c1 100644 --- a/src/msgpack.light.benchmark/BeerListDeserializeBenchmark.cs +++ b/src/msgpack.light.benchmark/BeerListDeserializeBenchmark.cs @@ -31,13 +31,6 @@ private MemoryStream PrepareMsgPack(BeerListSerializeBenchmark serializer) return memoryStream; } - private MemoryStream PrepareMsgPackLight(BeerListSerializeBenchmark serializer) - { - var memoryStream = new MemoryStream(); - serializer.MsgPackLightSerialize(memoryStream); - return memoryStream; - } - private MemoryStream PrepareJson(BeerListSerializeBenchmark serializer) { var memoryStream = new MemoryStream(); @@ -46,78 +39,57 @@ private MemoryStream PrepareJson(BeerListSerializeBenchmark serializer) } [Benchmark] - public void JsonNet() + public object JsonNet() { _json.Seek(0, SeekOrigin.Begin); using (var reader = new StreamReader(_json, Encoding.UTF8, false, 1024, true)) { - var beer = Serializers.Newtonsoft.Deserialize(reader, typeof(Beer[])); + return Serializers.Newtonsoft.Deserialize(reader, typeof(Beer[])); } } - - [Benchmark(Baseline = true)] - public void MPCli_Stream() - { - _msgPack.Seek(0, SeekOrigin.Begin); - var beer = Serializers.MsgPack.GetSerializer().Unpack(_msgPack); - } - - [Benchmark] - public void MPCli_Array() - { - var beer = Serializers.MsgPack.GetSerializer().UnpackSingleObject(_msgPackArray); - } - [Benchmark] - public void MPLight_Stream() + [Benchmark(Baseline = true)] + public Beer[] MPCli_Stream() { _msgPack.Seek(0, SeekOrigin.Begin); - var beer = MsgPackSerializer.Deserialize(_msgPack, Serializers.MsgPackLight); - } - - [Benchmark] - public void MPLight_Array() - { - var beer = MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLight); + return Serializers.MsgPack.GetSerializer().Unpack(_msgPack); } [Benchmark] - public void MPCliH_Stream() + public Beer[] MPCli_Array() { - _msgPack.Seek(0, SeekOrigin.Begin); - var beer = Serializers.MsgPackHardcore.GetSerializer().Unpack(_msgPack); + return Serializers.MsgPack.GetSerializer().UnpackSingleObject(_msgPackArray); } [Benchmark] - public void MPCliH_Array() + public Beer[] MPLight_Array() { - var beer = Serializers.MsgPackHardcore.GetSerializer().UnpackSingleObject(_msgPackArray); + return MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLight); } [Benchmark] - public void MPLightH_Stream() + public Beer[] MPCliH_Stream() { _msgPack.Seek(0, SeekOrigin.Begin); - var beer = MsgPackSerializer.Deserialize(_msgPack, Serializers.MsgPackLightHardcore); + return Serializers.MsgPackHardcore.GetSerializer().Unpack(_msgPack); } [Benchmark] - public void MPLightH_Array() + public Beer[] MPCliH_Array() { - var beer = MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLightHardcore); + return Serializers.MsgPackHardcore.GetSerializer().UnpackSingleObject(_msgPackArray); } [Benchmark] - public void MPLightH_Stream_AutoMap() + public Beer[] MPLightH_Array() { - _msgPack.Seek(0, SeekOrigin.Begin); - var beer = MsgPackSerializer.Deserialize(_msgPack, Serializers.MsgPackLightMapAutoGeneration); + return MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLightHardcore); } - [Benchmark] - public void MPLightH_Array_AutoMap() - { - var beer = MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLightMapAutoGeneration); - } +// [Benchmark] +// public void MPLightH_Array_AutoMap() +// { +// var beer = MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLightMapAutoGeneration); +// } } -} \ No newline at end of file +} diff --git a/src/msgpack.light.benchmark/BeerListSerializeBenchmark.cs b/src/msgpack.light.benchmark/BeerListSerializeBenchmark.cs index a663b9e..78d1dfa 100644 --- a/src/msgpack.light.benchmark/BeerListSerializeBenchmark.cs +++ b/src/msgpack.light.benchmark/BeerListSerializeBenchmark.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.Buffers; +using System.IO; using System.Text; using BenchmarkDotNet.Attributes; @@ -10,11 +11,16 @@ namespace ProGaudi.MsgPack.Light.Benchmark [Config(typeof(BenchmarkConfig))] public class BeerListSerializeBenchmark { + private readonly MemoryStream _memoryStream = Serializers.CreateStream(); + + private readonly IMemoryOwner _buffer = MsgPackSerializer.Serialize(BenchmarkData.Belgium, Serializers.MsgPackLight, out _); + [Benchmark] - public void JsonNet() + public long JsonNet() { - var memoryStream = new MemoryStream(); - JsonSerialize(memoryStream); + _memoryStream.Seek(0, SeekOrigin.Begin); + JsonSerialize(_memoryStream); + return _memoryStream.Position; } internal void JsonSerialize(MemoryStream memoryStream) @@ -25,12 +31,13 @@ internal void JsonSerialize(MemoryStream memoryStream) writer.Flush(); } } - + [Benchmark(Baseline = true)] - public void MPCli_Stream() + public long MPCli_Stream() { - var memoryStream = new MemoryStream(); - MsgPackSerialize(memoryStream); + _memoryStream.Seek(0, SeekOrigin.Begin); + MsgPackSerialize(_memoryStream); + return _memoryStream.Position; } internal void MsgPackSerialize(MemoryStream memoryStream) @@ -39,66 +46,41 @@ internal void MsgPackSerialize(MemoryStream memoryStream) } [Benchmark] - public void MPCli_Array() - { - var bytes = Serializers.MsgPack.GetSerializer().PackSingleObject(BenchmarkData.Belgium); - } - - [Benchmark] - public void MPLight_Stream() - { - var memoryStream = new MemoryStream(); - MsgPackLightSerialize(memoryStream); - } - - internal void MsgPackLightSerialize(MemoryStream memoryStream) - { - MsgPackSerializer.Serialize(BenchmarkData.Belgium, memoryStream, Serializers.MsgPackLight); - } - - [Benchmark] - public void MPLight_Array() - { - var bytes = MsgPackSerializer.Serialize(BenchmarkData.Belgium, Serializers.MsgPackLight); - } - - [Benchmark] - public void MPCliH_Stream() - { - var memoryStream = new MemoryStream(); - Serializers.MsgPackHardcore.GetSerializer().Pack(memoryStream, BenchmarkData.Belgium); - } - - [Benchmark] - public void MPCliH_Array() + public byte[] MPCli_Array() { - var bytes = Serializers.MsgPackHardcore.GetSerializer().PackSingleObject(BenchmarkData.Belgium); + return Serializers.MsgPack.GetSerializer().PackSingleObject(BenchmarkData.Belgium); } [Benchmark] - public void MPLightH_Stream() + public int MPLight_Array() { - var memoryStream = new MemoryStream(); - MsgPackSerializer.Serialize(BenchmarkData.Belgium, memoryStream, Serializers.MsgPackLightHardcore); + return MsgPackSerializer.Serialize(BenchmarkData.Belgium, _buffer.Memory.Span, Serializers.MsgPackLight); } [Benchmark] - public void MPLightH_Array() + public long MPCliH_Stream() { - var bytes = MsgPackSerializer.Serialize(BenchmarkData.Belgium, Serializers.MsgPackLightHardcore); + _memoryStream.Seek(0, SeekOrigin.Begin); + Serializers.MsgPackHardcore.GetSerializer().Pack(_memoryStream, BenchmarkData.Belgium); + return _memoryStream.Position; } [Benchmark] - public void MPLightH_Stream_AutoMap() + public byte[] MPCliH_Array() { - var memoryStream = new MemoryStream(); - MsgPackSerializer.Serialize(BenchmarkData.Belgium, memoryStream, Serializers.MsgPackLightMapAutoGeneration); + return Serializers.MsgPackHardcore.GetSerializer().PackSingleObject(BenchmarkData.Belgium); } [Benchmark] - public void MPLightH_Array_AutoMap() + public int MPLightH_Array() { - var bytes = MsgPackSerializer.Serialize(BenchmarkData.Belgium, Serializers.MsgPackLightMapAutoGeneration); + return MsgPackSerializer.Serialize(BenchmarkData.Belgium, _buffer.Memory.Span, Serializers.MsgPackLightHardcore); } +// +// [Benchmark] +// public void MPLightH_Array_AutoMap() +// { +// var bytes = MsgPackSerializer.Serialize(BenchmarkData.Belgium, Serializers.MsgPackLightMapAutoGeneration); +// } } } diff --git a/src/msgpack.light.benchmark/BeerSerializeBenchmark.cs b/src/msgpack.light.benchmark/BeerSerializeBenchmark.cs index cf1d64f..53d271e 100644 --- a/src/msgpack.light.benchmark/BeerSerializeBenchmark.cs +++ b/src/msgpack.light.benchmark/BeerSerializeBenchmark.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Buffers; +using System.Collections.Generic; using System.IO; using System.Text; @@ -15,6 +17,10 @@ public class BeerSerializeBenchmark { private readonly Beer _testBeer; + private readonly MemoryStream _memoryStream = new MemoryStream(); + + private readonly IMemoryOwner _buffer; + public BeerSerializeBenchmark() { _testBeer = new Beer @@ -24,13 +30,15 @@ public BeerSerializeBenchmark() Brewery = "Sint-Sixtusabdij van Westvleteren", Sort = new List {"trappist"} }; + _buffer = MsgPackSerializer.Serialize(_testBeer, Serializers.MsgPackLightHardcore, out _); } [Benchmark] - public void JsonNet() + public long JsonNet() { - var memoryStream = new MemoryStream(); - JsonSerialize(memoryStream); + _memoryStream.Seek(0, SeekOrigin.Begin); + JsonSerialize(_memoryStream); + return _memoryStream.Position; } internal void JsonSerialize(MemoryStream memoryStream) @@ -41,12 +49,13 @@ internal void JsonSerialize(MemoryStream memoryStream) writer.Flush(); } } - + [Benchmark(Baseline = true)] - public void MPCli_Stream() + public long MPCli_Stream() { - var memoryStream = new MemoryStream(); - MsgPackSerialize(memoryStream); + _memoryStream.Seek(0, SeekOrigin.Begin); + MsgPackSerialize(_memoryStream); + return _memoryStream.Position; } internal void MsgPackSerialize(MemoryStream memoryStream) @@ -55,93 +64,67 @@ internal void MsgPackSerialize(MemoryStream memoryStream) } [Benchmark] - public void MPSharp_Stream() - { - var stream = new MemoryStream(); - MessagePackSerializer.Serialize(stream, _testBeer); - } - - [Benchmark] - public void MPSharp_Array() - { - MessagePackSerializer.Serialize(_testBeer); - } - - [Benchmark] - public void MPSharp_Array_Unsafe() - { - MessagePackSerializer.SerializeUnsafe(_testBeer); - } - - [Benchmark] - public void MPCli_Array() + public long MPSharp_Stream() { - var bytes = Serializers.MsgPack.GetSerializer().PackSingleObject(_testBeer); + _memoryStream.Seek(0, SeekOrigin.Begin); + MessagePackSerializer.Serialize(_memoryStream, _testBeer); + return _memoryStream.Position; } [Benchmark] - public void MPLight_Stream() + public byte[] MPSharp_Array() { - var memoryStream = new MemoryStream(); - MsgPackSerializer.Serialize(_testBeer, memoryStream, Serializers.MsgPackLight); + return MessagePackSerializer.Serialize(_testBeer); } [Benchmark] - public void MPLight_Array() + public ArraySegment MPSharp_Array_Unsafe() { - var bytes = MsgPackSerializer.Serialize(_testBeer, Serializers.MsgPackLight); + return MessagePackSerializer.SerializeUnsafe(_testBeer); } [Benchmark] - public void MPCliH_Stream() + public byte[] MPCli_Array() { - var memoryStream = new MemoryStream(); - Serializers.MsgPackHardcore.GetSerializer().Pack(memoryStream, _testBeer); + return Serializers.MsgPack.GetSerializer().PackSingleObject(_testBeer); } [Benchmark] - public void MPCliH_Array() + public int MPLight_Array() { - var bytes = Serializers.MsgPackHardcore.GetSerializer().PackSingleObject(_testBeer); + return MsgPackSerializer.Serialize(_testBeer, _buffer.Memory.Span, Serializers.MsgPackLight); } [Benchmark] - public void MPLightH_Stream() + public long MPCliH_Stream() { - var memoryStream = new MemoryStream(); - MsgPackSerializer.Serialize(_testBeer, memoryStream, Serializers.MsgPackLightHardcore); + _memoryStream.Seek(0, SeekOrigin.Begin); + Serializers.MsgPackHardcore.GetSerializer().Pack(_memoryStream, _testBeer); + return _memoryStream.Position; } [Benchmark] - public void MPLightH_Array() + public byte[] MPCliH_Array() { - var bytes = MsgPackSerializer.Serialize(_testBeer, Serializers.MsgPackLightHardcore); + return Serializers.MsgPackHardcore.GetSerializer().PackSingleObject(_testBeer); } [Benchmark] - public void MPLightH_Stream_AutoMap() - { - var memoryStream = new MemoryStream(); - MsgPackSerializer.Serialize(_testBeer, memoryStream, Serializers.MsgPackLightMapAutoGeneration); - } - - [Benchmark] - public void MPLightH_Array_AutoMap() - { - var bytes = MsgPackSerializer.Serialize(_testBeer, Serializers.MsgPackLightMapAutoGeneration); - } - - [Benchmark] - public void MPLightH_Stream_AutoArray() - { - var memoryStream = new MemoryStream(); - MsgPackSerializer.Serialize(_testBeer, memoryStream, Serializers.MsgPackLightArrayAutoGeneration); - } - - [Benchmark] - public void MPLightH_Array_AutoArray() - { - var bytes = MsgPackSerializer.Serialize(_testBeer, Serializers.MsgPackLightArrayAutoGeneration); - } + public int MPLightH_Array() + { + return MsgPackSerializer.Serialize(_testBeer, _buffer.Memory.Span, Serializers.MsgPackLightHardcore); + } + +// [Benchmark] +// public void MPLightH_Array_AutoMap() +// { +// var bytes = MsgPackSerializer.Serialize(_testBeer, Serializers.MsgPackLightMapAutoGeneration); +// } +// +// [Benchmark] +// public void MPLightH_Array_AutoArray() +// { +// var bytes = MsgPackSerializer.Serialize(_testBeer, Serializers.MsgPackLightArrayAutoGeneration); +// } } } diff --git a/src/msgpack.light.benchmark/BeerSkip.cs b/src/msgpack.light.benchmark/BeerSkip.cs index 75cc241..e219546 100644 --- a/src/msgpack.light.benchmark/BeerSkip.cs +++ b/src/msgpack.light.benchmark/BeerSkip.cs @@ -21,43 +21,29 @@ public class BeerSkip public BeerSkip() { - var serialize = new BeerSerializeBenchmark(); - _inputStream = PrepareMsgPack(serialize); + _inputStream = Serializers.CreateStream(); + new BeerSerializeBenchmark().MsgPackSerialize(_inputStream); _inputBytes = _inputStream.ToArray(); _unpacker = Unpacker.Create(_inputStream); _msgPackContext = new MsgPackContext(); - _msgPackContext.RegisterConverter(new SkipConverter()); + _msgPackContext.RegisterParser(_ => new SkipConverter()); } - private MemoryStream PrepareMsgPack(BeerSerializeBenchmark serializer) - { - var memoryStream = new MemoryStream(); - serializer.MsgPackSerialize(memoryStream); - return memoryStream; - } - [Benchmark(Baseline = true)] - public void MPackCli_Skip() - { - _inputStream.Position = 0; - var result = _unpacker.Skip(); - } - - [Benchmark] - public void MsgPackLight_Skip_Stream() + public long? MPackCli_Skip() { _inputStream.Position = 0; - var beer = MsgPackSerializer.Deserialize(_inputStream, _msgPackContext); + return _unpacker.Skip(); } [Benchmark] - public void MsgPackLight_Skip_Array() + public Beer MsgPackLight_Skip_Array() { _inputStream.Position = 0; - var beer = MsgPackSerializer.Deserialize(_inputBytes, _msgPackContext); + return MsgPackSerializer.Deserialize(_inputBytes, _msgPackContext, out _); } } -} \ No newline at end of file +} diff --git a/src/msgpack.light.benchmark/BeerSkipList.cs b/src/msgpack.light.benchmark/BeerSkipList.cs index a53e1c5..01da2d8 100644 --- a/src/msgpack.light.benchmark/BeerSkipList.cs +++ b/src/msgpack.light.benchmark/BeerSkipList.cs @@ -21,43 +21,28 @@ public class BeerSkipList public BeerSkipList() { - var serialize = new BeerListSerializeBenchmark(); - _inputStream = PrepareMsgPack(serialize); + _inputStream = Serializers.CreateStream(); + new BeerListSerializeBenchmark().MsgPackSerialize(_inputStream); _inputBytes = _inputStream.ToArray(); _unpacker = Unpacker.Create(_inputStream); _msgPackContext = new MsgPackContext(); - _msgPackContext.RegisterConverter(new SkipConverter()); - - } - - private MemoryStream PrepareMsgPack(BeerListSerializeBenchmark serializer) - { - var memoryStream = new MemoryStream(); - serializer.MsgPackSerialize(memoryStream); - return memoryStream; + _msgPackContext.RegisterParser(new SkipConverter()); } [Benchmark(Baseline = true)] - public void MPackCli_Skip() - { - _inputStream.Position = 0; - var result = _unpacker.Skip(); - } - - [Benchmark] - public void MsgPackLight_Skip_Stream() + public long? MPackCli_Skip() { _inputStream.Position = 0; - var beer = MsgPackSerializer.Deserialize(_inputStream, _msgPackContext); + return _unpacker.Skip(); } [Benchmark] - public void MsgPackLight_Skip_Array() + public Beer MsgPackLight_Skip_Array() { _inputStream.Position = 0; - var beer = MsgPackSerializer.Deserialize(_inputBytes, _msgPackContext); + return MsgPackSerializer.Deserialize(_inputBytes, _msgPackContext, out _); } } -} \ No newline at end of file +} diff --git a/src/msgpack.light.benchmark/BenchmarkConfig.cs b/src/msgpack.light.benchmark/BenchmarkConfig.cs index 0ba1a50..17d270d 100644 --- a/src/msgpack.light.benchmark/BenchmarkConfig.cs +++ b/src/msgpack.light.benchmark/BenchmarkConfig.cs @@ -5,8 +5,6 @@ using BenchmarkDotNet.Exporters; using BenchmarkDotNet.Exporters.Csv; using BenchmarkDotNet.Jobs; -using BenchmarkDotNet.Order; -using BenchmarkDotNet.Reports; using BenchmarkDotNet.Toolchains.CsProj; namespace ProGaudi.MsgPack.Light.Benchmark @@ -25,14 +23,13 @@ public BenchmarkConfig() //Add(Job.ShortRun.With(Jit.RyuJit).With(Platform.X64).With(Runtime.Clr)); - // RyuJit for .NET Core 1.1 - Add(Job.Default.With(Jit.RyuJit).With(Platform.X64).With(Runtime.Core).With(CsProjCoreToolchain.NetCoreApp11).WithId("netcore1.1")); - // RyuJit for .NET Core 2.0 Add(Job.Default.With(Jit.RyuJit).With(Platform.X64).With(Runtime.Core).With(CsProjCoreToolchain.NetCoreApp20).WithId("netcore2.0")); + Add(Job.Default.With(Jit.RyuJit).With(Platform.X64).With(Runtime.Core).With(CsProjCoreToolchain.NetCoreApp21).WithId("netcore2.1")); + Add(Job.Default.With(Jit.RyuJit).With(Platform.X64).With(Runtime.Core).With(CsProjCoreToolchain.NetCoreApp22).WithId("netcore2.2")); Add(MarkdownExporter.GitHub); Add(CsvMeasurementsExporter.Default); } } -} \ No newline at end of file +} diff --git a/src/msgpack.light.benchmark/Data/Beer.cs b/src/msgpack.light.benchmark/Data/Beer.cs index ce79be6..38f6c01 100644 --- a/src/msgpack.light.benchmark/Data/Beer.cs +++ b/src/msgpack.light.benchmark/Data/Beer.cs @@ -5,7 +5,7 @@ namespace ProGaudi.MsgPack.Light.Benchmark.Data { [MessagePackObject(true)] - public class Beer + public sealed class Beer { [MsgPackMapElement(nameof(Brand))] [MsgPackArrayElement(0)] @@ -23,4 +23,4 @@ public class Beer [MsgPackArrayElement(3)] public string Brewery { get; set; } } -} \ No newline at end of file +} diff --git a/src/msgpack.light.benchmark/Data/BeerConverter.cs b/src/msgpack.light.benchmark/Data/BeerConverter.cs index 859bff1..b85e7aa 100644 --- a/src/msgpack.light.benchmark/Data/BeerConverter.cs +++ b/src/msgpack.light.benchmark/Data/BeerConverter.cs @@ -1,70 +1,92 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Runtime.Serialization; namespace ProGaudi.MsgPack.Light.Benchmark.Data { - internal class BeerConverter : IMsgPackConverter + internal sealed class BeerConverter : IMsgPackFormatter, IMsgPackParser { - private IMsgPackConverter _stringConverter; + private readonly IMsgPackFormatter _stringFormatter; + private readonly IMsgPackFormatter> _listStringFormatter; + private readonly IMsgPackFormatter _floatFormatter; - private IMsgPackConverter> _listStringConverter; + private readonly IMsgPackParser _stringParser; + private readonly IMsgPackParser> _listStringParser; + private readonly IMsgPackParser _floatParser; - private IMsgPackConverter _floatConverter; + public BeerConverter(MsgPackContext context) + { + _stringFormatter = context.GetRequiredFormatter(); + _listStringFormatter = context.GetRequiredFormatter>(); + _floatFormatter = context.GetRequiredFormatter(); + + _stringParser = context.GetRequiredParser(); + _listStringParser = context.GetRequiredParser>(); + _floatParser = context.GetRequiredParser(); + } + + public int GetBufferSize(Beer value) => value == null + ? DataLengths.Nil + : _stringFormatter.GetBufferSize(value.Brand) + + _stringFormatter.GetBufferSize(value.Brewery) + + _listStringFormatter.GetBufferSize(value.Sort) + + _floatFormatter.GetBufferSize(value.Alcohol) + + 27; - private MsgPackContext _context; + public bool HasConstantSize => false; - public void Write(Beer value, IMsgPackWriter writer) + public int Format(Span destination, Beer value) { - if (value == null) - { - _context.NullConverter.Write(null, writer); - return; - } + if (value == null) return MsgPackSpec.WriteNil(destination); + + var result = MsgPackSpec.WriteMapHeader(destination, 4); + result += _stringFormatter.Format(destination.Slice(result), nameof(value.Brand)); + result += _stringFormatter.Format(destination.Slice(result), value.Brand); - writer.WriteMapHeader(4); - _stringConverter.Write(nameof(value.Brand), writer); - _stringConverter.Write(value.Brand, writer); + result += _stringFormatter.Format(destination.Slice(result), nameof(value.Sort)); + result += _listStringFormatter.Format(destination.Slice(result), value.Sort); - _stringConverter.Write(nameof(value.Sort), writer); - _listStringConverter.Write(value.Sort, writer); + result += _stringFormatter.Format(destination.Slice(result), nameof(value.Alcohol)); + result += _floatFormatter.Format(destination.Slice(result), value.Alcohol); - _stringConverter.Write(nameof(value.Alcohol), writer); - _floatConverter.Write(value.Alcohol, writer); + result += _stringFormatter.Format(destination.Slice(result), nameof(value.Brewery)); + result += _stringFormatter.Format(destination.Slice(result), value.Brewery); - _stringConverter.Write(nameof(value.Brewery), writer); - _stringConverter.Write(value.Brewery, writer); + return result; } - public Beer Read(IMsgPackReader reader) + public Beer Parse(ReadOnlySpan source, out int readSize) { - var length = reader.ReadMapLength(); - if (length == null) - { - return null; - } + if (MsgPackSpec.TryReadNil(source, out readSize)) return null; + var length = MsgPackSpec.ReadMapHeader(source, out readSize); if (length != 4) { throw new SerializationException("Bad format"); } var result = new Beer(); - for (var i = 0; i < length.Value; i++) + for (var i = 0; i < length; i++) { - var propertyName = _stringConverter.Read(reader); + var propertyName = _stringParser.Parse(source, out var temp); + readSize += temp; switch (propertyName) { case nameof(result.Brand): - result.Brand = _stringConverter.Read(reader); + result.Brand = _stringParser.Parse(source, out temp); + readSize += temp; break; case nameof(result.Sort): - result.Sort = _listStringConverter.Read(reader); + result.Sort = _listStringParser.Parse(source, out temp); + readSize += temp; break; case nameof(result.Alcohol): - result.Alcohol = _floatConverter.Read(reader); + result.Alcohol = _floatParser.Parse(source, out temp); + readSize += temp; break; case nameof(result.Brewery): - result.Brewery = _stringConverter.Read(reader); + result.Brewery = _stringParser.Parse(source, out temp); + readSize += temp; break; default: throw new SerializationException("Bad format"); @@ -73,13 +95,5 @@ public Beer Read(IMsgPackReader reader) return result; } - - public void Initialize(MsgPackContext context) - { - _stringConverter = context.GetConverter(); - _listStringConverter = context.GetConverter>(); - _floatConverter = context.GetConverter(); - _context = context; - } } -} \ No newline at end of file +} diff --git a/src/msgpack.light.benchmark/Data/BeerConverterHardcore.cs b/src/msgpack.light.benchmark/Data/BeerConverterHardcore.cs index ab938f0..a44c652 100644 --- a/src/msgpack.light.benchmark/Data/BeerConverterHardcore.cs +++ b/src/msgpack.light.benchmark/Data/BeerConverterHardcore.cs @@ -1,78 +1,114 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Runtime.Serialization; namespace ProGaudi.MsgPack.Light.Benchmark.Data { - internal class BeerConverterHardCore : IMsgPackConverter + internal sealed class BeerConverterHardCore : IMsgPackFormatter, IMsgPackParser { - private IMsgPackConverter _stringConverter; + private static readonly byte[] Brand; + private static readonly byte[] Alcohol; + private static readonly byte[] Sort; + private static readonly byte[] Brewery; - private IMsgPackConverter> _listStringConverter; + private readonly IMsgPackFormatter _stringFormatter; + private readonly IMsgPackFormatter> _listStringFormatter; + private readonly IMsgPackFormatter _floatFormatter; - private IMsgPackConverter _floatConverter; + private readonly IMsgPackParser _stringParser; + private readonly IMsgPackParser> _listStringParser; + private readonly IMsgPackParser _floatParser; - private MsgPackContext _context; + static BeerConverterHardCore() + { + Brand = new byte[6]; + MsgPackSpec.WriteFixString(Brand, nameof(Beer.Brand).AsSpan()); + Alcohol = new byte[8]; + MsgPackSpec.WriteFixString(Alcohol, nameof(Beer.Alcohol).AsSpan()); + Sort = new byte[5]; + MsgPackSpec.WriteFixString(Sort, nameof(Beer.Sort).AsSpan()); + Brewery = new byte[8]; + MsgPackSpec.WriteFixString(Brewery, nameof(Beer.Brewery).AsSpan()); + } - private byte[] _brand; + public BeerConverterHardCore(MsgPackContext context) + { + _stringFormatter = context.GetRequiredFormatter(); + _listStringFormatter = context.GetRequiredFormatter>(); + _floatFormatter = context.GetRequiredFormatter(); - private byte[] _alcohol; + _stringParser = context.GetRequiredParser(); + _listStringParser = context.GetRequiredParser>(); + _floatParser = context.GetRequiredParser(); + } - private byte[] _sort; + public int GetBufferSize(Beer value) => value == null + ? DataLengths.Nil + : _stringFormatter.GetBufferSize(value.Brand) + + _stringFormatter.GetBufferSize(value.Brewery) + + _listStringFormatter.GetBufferSize(value.Sort) + + _floatFormatter.GetBufferSize(value.Alcohol) + + 27; - private byte[] _brewery; + public bool HasConstantSize => false; - public void Write(Beer value, IMsgPackWriter writer) + public int Format(Span destination, Beer value) { - if (value == null) - { - _context.NullConverter.Write(null, writer); - return; - } + if (value == null) return MsgPackSpec.WriteNil(destination); + + var result = MsgPackSpec.WriteMapHeader(destination, 4); - writer.WriteMapHeader(4); - writer.Write(_brand); - _stringConverter.Write(value.Brand, writer); + Brand.CopyTo(destination.Slice(result)); + result += Brand.Length; + result += _stringFormatter.Format(destination, value.Brand); - writer.Write(_sort); - _listStringConverter.Write(value.Sort, writer); + Sort.CopyTo(destination.Slice(result)); + result += Sort.Length; + result += _listStringFormatter.Format(destination, value.Sort); - writer.Write(_alcohol); - _floatConverter.Write(value.Alcohol, writer); + Alcohol.CopyTo(destination.Slice(result)); + result += Alcohol.Length; + result += _floatFormatter.Format(destination, value.Alcohol); - writer.Write(_brewery); - _stringConverter.Write(value.Brewery, writer); + Brewery.CopyTo(destination.Slice(result)); + result += Brewery.Length; + result += _stringFormatter.Format(destination, value.Brewery); + + return result; } - public Beer Read(IMsgPackReader reader) + public Beer Parse(ReadOnlySpan source, out int readSize) { - var length = reader.ReadMapLength(); - if (length == null) - { - return null; - } + if (MsgPackSpec.TryReadNil(source, out readSize)) return null; + var length = MsgPackSpec.ReadMapHeader(source, out readSize); if (length != 4) { throw new SerializationException("Bad format"); } var result = new Beer(); - for (var i = 0; i < length.Value; i++) + for (var i = 0; i < length; i++) { - var propertyName = _stringConverter.Read(reader); + var propertyName = _stringParser.Parse(source, out var temp); + readSize += temp; switch (propertyName) { case nameof(result.Brand): - result.Brand = _stringConverter.Read(reader); + result.Brand = _stringParser.Parse(source, out temp); + readSize += temp; break; case nameof(result.Sort): - result.Sort = _listStringConverter.Read(reader); + result.Sort = _listStringParser.Parse(source, out temp); + readSize += temp; break; case nameof(result.Alcohol): - result.Alcohol = _floatConverter.Read(reader); + result.Alcohol = _floatParser.Parse(source, out temp); + readSize += temp; break; case nameof(result.Brewery): - result.Brewery = _stringConverter.Read(reader); + result.Brewery = _stringParser.Parse(source, out temp); + readSize += temp; break; default: throw new SerializationException("Bad format"); @@ -81,17 +117,5 @@ public Beer Read(IMsgPackReader reader) return result; } - - public void Initialize(MsgPackContext context) - { - _stringConverter = context.GetConverter(); - _listStringConverter = context.GetConverter>(); - _floatConverter = context.GetConverter(); - _brand = MsgPackSerializer.Serialize(nameof(Beer.Brand)); - _alcohol = MsgPackSerializer.Serialize(nameof(Beer.Alcohol)); - _sort = MsgPackSerializer.Serialize(nameof(Beer.Sort)); - _brewery = MsgPackSerializer.Serialize(nameof(Beer.Brewery)); - _context = context; - } } -} \ No newline at end of file +} diff --git a/src/msgpack.light.benchmark/Data/BeerType.cs b/src/msgpack.light.benchmark/Data/BeerType.cs index a3898d6..d1bfc9a 100644 --- a/src/msgpack.light.benchmark/Data/BeerType.cs +++ b/src/msgpack.light.benchmark/Data/BeerType.cs @@ -2,10 +2,10 @@ { public enum BeerType { - Ale, - Lager, - Stout, - Porter, - Malt + Ale = 0, + Lager = 1, + Stout = 2, + Porter = 3, + Malt = 4 } -} \ No newline at end of file +} diff --git a/src/msgpack.light.benchmark/Data/BeerTypeConverter.cs b/src/msgpack.light.benchmark/Data/BeerTypeConverter.cs index 1844ee5..a501eef 100644 --- a/src/msgpack.light.benchmark/Data/BeerTypeConverter.cs +++ b/src/msgpack.light.benchmark/Data/BeerTypeConverter.cs @@ -2,23 +2,14 @@ namespace ProGaudi.MsgPack.Light.Benchmark.Data { - public class BeerTypeConverter : IMsgPackConverter + public class BeerTypeConverter : IMsgPackFormatter, IMsgPackParser { - private Lazy> _intConverter; + public int GetBufferSize(BeerType value) => DataLengths.PositiveFixInt; - public void Initialize(MsgPackContext context) - { - _intConverter = new Lazy>(context.GetConverter); - } + public bool HasConstantSize => true; - public void Write(BeerType value, IMsgPackWriter writer) - { - _intConverter.Value.Write((int)value, writer); - } + public int Format(Span destination, BeerType value) => MsgPackSpec.WritePositiveFixInt(destination, (byte)value); - public BeerType Read(IMsgPackReader reader) - { - return (BeerType)_intConverter.Value.Read(reader); - } + public BeerType Parse(ReadOnlySpan source, out int readSize) => (BeerType) MsgPackSpec.ReadPositiveFixInt(source, out readSize); } -} \ No newline at end of file +} diff --git a/src/msgpack.light.benchmark/EnumGeneratedDeserializeBenchmark.cs b/src/msgpack.light.benchmark/EnumGeneratedDeserializeBenchmark.cs deleted file mode 100644 index 9ddc9d6..0000000 --- a/src/msgpack.light.benchmark/EnumGeneratedDeserializeBenchmark.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.IO; - -using BenchmarkDotNet.Attributes; - -using ProGaudi.MsgPack.Light.Benchmark.Data; - -namespace ProGaudi.MsgPack.Light.Benchmark -{ - [Config(typeof(BenchmarkConfig))] - public class EnumGeneratedDeserializeBenchmark - { - private readonly byte[] _msgPackForInt; - - private readonly byte[] _msgPackArray; - - public EnumGeneratedDeserializeBenchmark() - { - var beerType = BeerType.Lager; - _msgPackArray = PrepareMsgPack(beerType).ToArray(); - _msgPackForInt = PrepareMsgPack((int)beerType).ToArray(); - } - - private MemoryStream PrepareMsgPack(T item) - { - var memoryStream = new MemoryStream(); - MsgPackSerializer.Serialize(item, memoryStream, Serializers.MsgPackLight); - return memoryStream; - } - - [Benchmark] - public void MPLight_AutoEnum() - { - var beerType = MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLight); - } - - [Benchmark(Baseline = true)] - public void MPLight_IntEnum() - { - var beerType = MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLightIntEnum); - } - - [Benchmark] - public void MPLight_Int() - { - var beerType = MsgPackSerializer.Deserialize(_msgPackForInt, Serializers.MsgPackLight); - } - } -} \ No newline at end of file diff --git a/src/msgpack.light.benchmark/EnumGeneratedSerializeBenchmark.cs b/src/msgpack.light.benchmark/EnumGeneratedSerializeBenchmark.cs deleted file mode 100644 index 2dc7b6e..0000000 --- a/src/msgpack.light.benchmark/EnumGeneratedSerializeBenchmark.cs +++ /dev/null @@ -1,38 +0,0 @@ -using BenchmarkDotNet.Attributes; - -using ProGaudi.MsgPack.Light.Benchmark.Data; - -namespace ProGaudi.MsgPack.Light.Benchmark -{ - [Config(typeof(BenchmarkConfig))] - public class EnumGeneratedSerializeBenchmark - { - private readonly BeerType _beerType; - - private readonly int _beerTypeIntRepresentation; - - public EnumGeneratedSerializeBenchmark() - { - _beerType = BeerType.Malt; - _beerTypeIntRepresentation = (int) _beerType; - } - - [Benchmark(Baseline = true)] - public void MPLight_IntEnum() - { - var bytes = MsgPackSerializer.Serialize(_beerType, Serializers.MsgPackLightIntEnum); - } - - [Benchmark] - public void MPLight_AutoEnum() - { - var bytes = MsgPackSerializer.Serialize(_beerType, Serializers.MsgPackLight); - } - - [Benchmark] - public void MPLight_Int() - { - var bytes = MsgPackSerializer.Serialize(_beerTypeIntRepresentation, Serializers.MsgPackLight); - } - } -} diff --git a/src/msgpack.light.benchmark/MapGeneratedDeserializeBenchmark.cs b/src/msgpack.light.benchmark/MapGeneratedDeserializeBenchmark.cs deleted file mode 100644 index bc41ba2..0000000 --- a/src/msgpack.light.benchmark/MapGeneratedDeserializeBenchmark.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System.IO; -using System.Text; - -using BenchmarkDotNet.Attributes; - -using ProGaudi.MsgPack.Light.Benchmark.Data; - -namespace ProGaudi.MsgPack.Light.Benchmark -{ - [Config(typeof(BenchmarkConfig))] - public class MapGeneratedDeserializeBenchmark - { - private readonly MemoryStream _json; - - private readonly MemoryStream _msgPack; - - private readonly byte[] _msgPackArray; - - public MapGeneratedDeserializeBenchmark() - { - var serializer = new BeerSerializeBenchmark(); - _json = PrepareJson(serializer); - _msgPack = PrepareMsgPack(serializer); - _msgPackArray = _msgPack.ToArray(); - } - - private MemoryStream PrepareMsgPack(BeerSerializeBenchmark serializer) - { - var memoryStream = new MemoryStream(); - serializer.MsgPackSerialize(memoryStream); - return memoryStream; - } - - private MemoryStream PrepareJson(BeerSerializeBenchmark serializer) - { - var memoryStream = new MemoryStream(); - serializer.JsonSerialize(memoryStream); - return memoryStream; - } - - [Benchmark] - public void JsonNet() - { - _json.Seek(0, SeekOrigin.Begin); - using (var reader = new StreamReader(_json, Encoding.UTF8, false, 1024, true)) - { - var beer = Serializers.Newtonsoft.Deserialize(reader, typeof(Beer)); - } - } - - [Benchmark(Baseline = true)] - public void MPCli_Array() - { - var beer = Serializers.MsgPack.GetSerializer().UnpackSingleObject(_msgPackArray); - } - - [Benchmark] - public void MPLight_Array() - { - var beer = MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLight); - } - - [Benchmark] - public void MPLight_Array_AutoMap() - { - var beer = MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLightMapAutoGeneration); - } - - [Benchmark] - public void MPLight_Array_AutoArray() - { - var beer = MsgPackSerializer.Deserialize(_msgPackArray, Serializers.MsgPackLightArrayAutoGeneration); - } - } -} \ No newline at end of file diff --git a/src/msgpack.light.benchmark/MapGeneratedSerializeBenchmark.cs b/src/msgpack.light.benchmark/MapGeneratedSerializeBenchmark.cs deleted file mode 100644 index 0b6ecb4..0000000 --- a/src/msgpack.light.benchmark/MapGeneratedSerializeBenchmark.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Text; - -using BenchmarkDotNet.Attributes; - -using ProGaudi.MsgPack.Light.Benchmark.Data; - -namespace ProGaudi.MsgPack.Light.Benchmark -{ - [Config(typeof(BenchmarkConfig))] - public class MapGeneratedSerializeBenchmark - { - private readonly Beer _testBeer; - - public MapGeneratedSerializeBenchmark() - { - _testBeer = new Beer - { - Brand = "Westvleteren Zes", - Alcohol = 6.2F, - Brewery = "Sint-Sixtusabdij van Westvleteren", - Sort = new List {"trappist"} - }; - } - - [Benchmark] - public void JsonNet() - { - var memoryStream = new MemoryStream(); - using (var writer = new StreamWriter(memoryStream, Encoding.UTF8, 1024, true)) - { - Serializers.Newtonsoft.Serialize(writer, _testBeer); - writer.Flush(); - } - } - - [Benchmark(Baseline = true)] - public void MPCli_Array() - { - var bytes = Serializers.MsgPack.GetSerializer().PackSingleObject(_testBeer); - } - - [Benchmark] - public void MPLight_Array() - { - var bytes = MsgPackSerializer.Serialize(_testBeer, Serializers.MsgPackLight); - } - - [Benchmark] - public void MPLight_Array_AutoMap() - { - var bytes = MsgPackSerializer.Serialize(_testBeer, Serializers.MsgPackLightMapAutoGeneration); - } - - [Benchmark] - public void MPLight_Array_AutoArray() - { - var bytes = MsgPackSerializer.Serialize(_testBeer, Serializers.MsgPackLightArrayAutoGeneration); - } - } -} diff --git a/src/msgpack.light.benchmark/NumberDeserialize.cs b/src/msgpack.light.benchmark/NumberDeserialize.cs index 6904bc5..a6b881b 100644 --- a/src/msgpack.light.benchmark/NumberDeserialize.cs +++ b/src/msgpack.light.benchmark/NumberDeserialize.cs @@ -15,7 +15,7 @@ public abstract class NumberDeserialize private readonly MemoryStream _stream; - private readonly MsgPackContext _mplightContext; + private readonly MsgPackContext _mpLightContext; protected abstract T[] Numbers { get; } @@ -24,33 +24,26 @@ protected NumberDeserialize() _messagePackSerializer = SerializationContext.Default.GetSerializer(); _bytes = _messagePackSerializer.PackSingleObject(Numbers); _stream = new MemoryStream(_bytes); - _mplightContext = new MsgPackContext(); + _mpLightContext = new MsgPackContext(); } [Benchmark] - public void MPCli_Array() + public T[] MPCli_Array() { - var data = _messagePackSerializer.UnpackSingleObject(_bytes); + return _messagePackSerializer.UnpackSingleObject(_bytes); } [Benchmark(Baseline = true)] - public void MPCli_Stream() + public T[] MPCli_Stream() { _stream.Seek(0, SeekOrigin.Begin); - var data = _messagePackSerializer.Unpack(_stream); + return _messagePackSerializer.Unpack(_stream); } [Benchmark] - public void MPLight_Array() + public T[] MPLight_Array() { - var data = MsgPackSerializer.Deserialize(_bytes, _mplightContext); - } - - [Benchmark] - public void MPLight_Stream() - { - _stream.Seek(0, SeekOrigin.Begin); - var data = MsgPackSerializer.Deserialize(_stream, _mplightContext); + return MsgPackSerializer.Deserialize(_bytes, _mpLightContext, out _); } } } diff --git a/src/msgpack.light.benchmark/NumberSerialize.cs b/src/msgpack.light.benchmark/NumberSerialize.cs index 91ce90f..bace8a0 100644 --- a/src/msgpack.light.benchmark/NumberSerialize.cs +++ b/src/msgpack.light.benchmark/NumberSerialize.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.Buffers; +using System.IO; using BenchmarkDotNet.Attributes; @@ -11,40 +12,39 @@ public abstract class NumberSerialize { private readonly MessagePackSerializer _messagePackSerializer; - private readonly MsgPackContext _mplightContext; + private readonly MsgPackContext _mpLightContext; + + private readonly MemoryStream _stream = Serializers.CreateStream(); + + private readonly IMemoryOwner _buffer; protected abstract T[] Numbers { get; } protected NumberSerialize() { _messagePackSerializer = SerializationContext.Default.GetSerializer(); - _mplightContext = new MsgPackContext(); + _mpLightContext = new MsgPackContext(); + _buffer = MsgPackSerializer.Serialize(Numbers, _mpLightContext, out _); } [Benchmark] - public void MPCli_Array() + public byte[] MPCli_Array() { - var bytes = _messagePackSerializer.PackSingleObject(Numbers); + return _messagePackSerializer.PackSingleObject(Numbers); } [Benchmark(Baseline = true)] - public void MPCli_Stream() - { - var stream = new MemoryStream(); - _messagePackSerializer.Pack(stream, Numbers); - } - - [Benchmark] - public void MPLight_Array() + public long MPCli_Stream() { - var bytes = MsgPackSerializer.Serialize(Numbers, _mplightContext); + _stream.Seek(0, SeekOrigin.Begin); + _messagePackSerializer.Pack(_stream, Numbers); + return _stream.Position; } [Benchmark] - public void MPLight_Stream() + public int MPLight_Array() { - var stream = new MemoryStream(); - MsgPackSerializer.Serialize(Numbers, stream, _mplightContext); + return MsgPackSerializer.Serialize(Numbers, _buffer.Memory.Span, _mpLightContext); } } } diff --git a/src/msgpack.light.benchmark/Program.cs b/src/msgpack.light.benchmark/Program.cs index 679f7be..26f57e6 100644 --- a/src/msgpack.light.benchmark/Program.cs +++ b/src/msgpack.light.benchmark/Program.cs @@ -9,8 +9,8 @@ public static void Main(string[] args) var switcher = new BenchmarkSwitcher( new[] { - typeof (MapGeneratedSerializeBenchmark), - typeof (MapGeneratedDeserializeBenchmark), +// typeof (MapGeneratedSerializeBenchmark), +// typeof (MapGeneratedDeserializeBenchmark), typeof (BeerSerializeBenchmark), typeof (BeerDeserializeBenchmark), typeof (BeerListSerializeBenchmark), @@ -21,8 +21,8 @@ public static void Main(string[] args) typeof (DoubleSerialize), typeof (BeerSkip), typeof (BeerSkipList), - typeof (EnumGeneratedDeserializeBenchmark), - typeof (EnumGeneratedSerializeBenchmark) +// typeof (EnumGeneratedDeserializeBenchmark), +// typeof (EnumGeneratedSerializeBenchmark) }); switcher.Run(args); } diff --git a/src/msgpack.light.benchmark/Serializers.cs b/src/msgpack.light.benchmark/Serializers.cs index ef8b25c..7cc77cb 100644 --- a/src/msgpack.light.benchmark/Serializers.cs +++ b/src/msgpack.light.benchmark/Serializers.cs @@ -1,4 +1,6 @@ -using MsgPack.Serialization; +using System.IO; + +using MsgPack.Serialization; using ProGaudi.MsgPack.Light.Benchmark.Data; @@ -11,21 +13,21 @@ public static class Serializers public static readonly JsonSerializer Newtonsoft = new JsonSerializer(); public static readonly SerializationContext MsgPack = new SerializationContext(); public static readonly SerializationContext MsgPackHardcore = new SerializationContext(); - public static readonly MsgPackContext MsgPackLight = new MsgPackContext(convertEnumsAsStrings: false); + public static readonly MsgPackContext MsgPackLight = new MsgPackContext(); public static readonly MsgPackContext MsgPackLightHardcore = new MsgPackContext(); - public static readonly MsgPackContext MsgPackLightMapAutoGeneration = new MsgPackContext(); - public static readonly MsgPackContext MsgPackLightArrayAutoGeneration = new MsgPackContext(); - public static readonly MsgPackContext MsgPackLightIntEnum = new MsgPackContext(); static Serializers() { - MsgPackLight.RegisterConverter(new BeerConverter()); - MsgPackLightHardcore.RegisterConverter(new BeerConverterHardCore()); + MsgPackLight.RegisterFormatter(x => new BeerConverter(x)); + MsgPackLight.RegisterParser(x => new BeerConverter(x)); + + MsgPackLightHardcore.RegisterFormatter(x => new BeerConverterHardCore(x)); + MsgPackLightHardcore.RegisterParser(x => new BeerConverterHardCore(x)); + MsgPack.Serializers.Register(new BeerSerializer(MsgPack)); MsgPackHardcore.Serializers.Register(new BeerSerializer(MsgPackHardcore)); - MsgPackLightMapAutoGeneration.GenerateAndRegisterMapConverter(); - MsgPackLightArrayAutoGeneration.GenerateAndRegisterArrayConverter(); - MsgPackLightIntEnum.RegisterConverter(new BeerTypeConverter()); } + + public static MemoryStream CreateStream() => new MemoryStream(1_000_000); } -} \ No newline at end of file +} diff --git a/src/msgpack.light.benchmark/SkipConverter.cs b/src/msgpack.light.benchmark/SkipConverter.cs index 70099bd..baf66e9 100644 --- a/src/msgpack.light.benchmark/SkipConverter.cs +++ b/src/msgpack.light.benchmark/SkipConverter.cs @@ -1,21 +1,14 @@ -namespace ProGaudi.MsgPack.Light.Benchmark +using System; + +namespace ProGaudi.MsgPack.Light.Benchmark { - public class SkipConverter :IMsgPackConverter + public class SkipConverter : IMsgPackParser { - public void Initialize(MsgPackContext context) - { - - } - - public void Write(T value, IMsgPackWriter writer) - { - throw new System.NotImplementedException(); - } - - public T Read(IMsgPackReader reader) + public T Parse(ReadOnlySpan source, out int readSize) { - reader.SkipToken(); - return default(T); + var token = MsgPackSpec.ReadToken(source); + readSize = token.Length; + return default; } } -} \ No newline at end of file +} diff --git a/src/msgpack.light.benchmark/msgpack.light.benchmark.csproj b/src/msgpack.light.benchmark/msgpack.light.benchmark.csproj index 4fd5cf0..ee65332 100644 --- a/src/msgpack.light.benchmark/msgpack.light.benchmark.csproj +++ b/src/msgpack.light.benchmark/msgpack.light.benchmark.csproj @@ -3,7 +3,7 @@ msgpack.light.benchmark Console Application aensidhe - netcoreapp1.1;netcoreapp2.0 + netcoreapp2.0;netcoreapp2.1 msgpack.light.benchmark ProGaudi.MsgPack.Light.Benchmark Exe @@ -18,13 +18,14 @@ false false + latest - - - - + + + + diff --git a/src/msgpack.light/BadCodeConstraintException.cs b/src/msgpack.light/BadCodeConstraintException.cs new file mode 100644 index 0000000..1148ab8 --- /dev/null +++ b/src/msgpack.light/BadCodeConstraintException.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ProGaudi.MsgPack +{ + [Serializable] + public class BadCodeConstraintException : ConstraintViolationException + { + public byte DataCode { get; } + + public HashSet AllowedCodes { get; } + + public BadCodeConstraintException(byte dataCode, HashSet allowedCodes, Exception innerException = null) + : base($"{dataCode:x2} should be one of ({string.Join(", ", allowedCodes.Select(x => $"{x:x2}"))}), but it doesn't.", innerException) + { + DataCode = dataCode; + AllowedCodes = allowedCodes; + } + } +} diff --git a/src/msgpack.light/BadSizeConstraintException.cs b/src/msgpack.light/BadSizeConstraintException.cs new file mode 100644 index 0000000..a610c50 --- /dev/null +++ b/src/msgpack.light/BadSizeConstraintException.cs @@ -0,0 +1,28 @@ +using System; + +namespace ProGaudi.MsgPack +{ + [Serializable] + public class BadSizeConstraintException : ConstraintViolationException + { + public DataFamily DataFamily { get; } + + public byte DataCode { get; } + + public int RequestedSize { get; } + + public BadSizeConstraintException(DataFamily dataFamily, byte dataCode, int requestedSize, Exception innerException = null) + : base(M(dataFamily, dataCode, requestedSize), innerException) + { + DataFamily = dataFamily; + DataCode = dataCode; + RequestedSize = requestedSize; + } + + private static string M(DataFamily dataFamily, byte dataCode, int requestedSize) + { + var (min, max) = DataLengths.GetMinAndMaxLength(dataCode); + return $"Length of {dataCode} of {dataFamily} should belong to [{min}, {max}]. {requestedSize} doesn't"; + } + } +} \ No newline at end of file diff --git a/src/msgpack.light/BaseMsgPackReader.cs b/src/msgpack.light/BaseMsgPackReader.cs deleted file mode 100644 index 1823685..0000000 --- a/src/msgpack.light/BaseMsgPackReader.cs +++ /dev/null @@ -1,211 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -using ProGaudi.MsgPack.Light.Converters; - -namespace ProGaudi.MsgPack.Light -{ - internal abstract class BaseMsgPackReader : IMsgPackReader - { - public abstract byte ReadByte(); - - public abstract ArraySegment ReadBytes(uint length); - - public abstract void Seek(long offset, SeekOrigin origin); - - public uint? ReadArrayLength() - { - var type = ReadDataType(); - switch (type) - { - case DataTypes.Null: - return null; - case DataTypes.Array16: - return NumberConverter.ReadUInt16(this); - - case DataTypes.Array32: - return NumberConverter.ReadUInt32(this); - } - - var length = TryGetLengthFromFixArray(type); - - if (length.HasValue) - { - return length; - } - - throw ExceptionUtils.BadTypeException(type, DataTypes.Array16, DataTypes.Array32, DataTypes.FixArray, DataTypes.Null); - } - - public uint? ReadMapLength() - { - var type = ReadDataType(); - - switch (type) - { - case DataTypes.Null: - return null; - case DataTypes.Map16: - return NumberConverter.ReadUInt16(this); - - case DataTypes.Map32: - return NumberConverter.ReadUInt32(this); - } - - var length = TryGetLengthFromFixMap(type); - if (length.HasValue) - return length.Value; - - throw ExceptionUtils.BadTypeException(type, DataTypes.Map16, DataTypes.Map32, DataTypes.FixMap, DataTypes.Null); - } - - public virtual DataTypes ReadDataType() - { - return (DataTypes)ReadByte(); - } - - public void SkipToken() - { - var dataType = ReadDataType(); - - switch (dataType) - { - case DataTypes.Null: - case DataTypes.False: - case DataTypes.True: - return; - case DataTypes.UInt8: - case DataTypes.Int8: - SkipBytes(1); - return; - case DataTypes.UInt16: - case DataTypes.Int16: - SkipBytes(2); - return; - case DataTypes.UInt32: - case DataTypes.Int32: - case DataTypes.Single: - SkipBytes(4); - return; - case DataTypes.UInt64: - case DataTypes.Int64: - case DataTypes.Double: - SkipBytes(8); - return; - case DataTypes.Array16: - SkipArrayItems(NumberConverter.ReadUInt16(this)); - return; - case DataTypes.Array32: - SkipArrayItems(NumberConverter.ReadUInt32(this)); - return; - case DataTypes.Map16: - SkipMapItems(NumberConverter.ReadUInt16(this)); - return; - case DataTypes.Map32: - SkipMapItems(NumberConverter.ReadUInt32(this)); - return; - case DataTypes.Str8: - SkipBytes(NumberConverter.ReadUInt8(this)); - return; - case DataTypes.Str16: - SkipBytes(NumberConverter.ReadUInt16(this)); - return; - case DataTypes.Str32: - SkipBytes(NumberConverter.ReadUInt32(this)); - return; - case DataTypes.Bin8: - SkipBytes(NumberConverter.ReadUInt8(this)); - return; - case DataTypes.Bin16: - SkipBytes(NumberConverter.ReadUInt16(this)); - return; - case DataTypes.Bin32: - SkipBytes(NumberConverter.ReadUInt32(this)); - return; - } - - if (dataType.GetHighBits(1) == DataTypes.PositiveFixNum.GetHighBits(1) || - dataType.GetHighBits(3) == DataTypes.NegativeFixNum.GetHighBits(3)) - { - return; - } - - var arrayLength = TryGetLengthFromFixArray(dataType); - if (arrayLength.HasValue) - { - SkipArrayItems(arrayLength.Value); - return; - } - - var mapLength = TryGetLengthFromFixMap(dataType); - if (mapLength.HasValue) - { - SkipMapItems(mapLength.Value); - return; - } - - var stringLength = TryGetLengthFromFixStr(dataType); - if (stringLength.HasValue) - { - SkipBytes(stringLength.Value); - return; - } - - throw new ArgumentOutOfRangeException(); - } - - private void SkipMapItems(uint count) - { - for (var i = 0; i < count; i++) - { - SkipToken(); - SkipToken(); - } - } - - private void SkipArrayItems(uint count) - { - for (var i = 0; i < count; i++) - { - SkipToken(); - } - } - - private void SkipBytes(uint bytesCount) - { - Seek(bytesCount, SeekOrigin.Current); - } - - private static uint? TryGetLengthFromFixStr(DataTypes type) - { - var length = type - DataTypes.FixStr; - return type.GetHighBits(3) == DataTypes.FixStr.GetHighBits(3) ? length : (uint?)null; - } - - protected static uint? TryGetLengthFromFixArray(DataTypes type) - { - var length = type - DataTypes.FixArray; - return type.GetHighBits(4) == DataTypes.FixArray.GetHighBits(4) ? length : (uint?)null; - } - - protected static uint? TryGetLengthFromFixMap(DataTypes type) - { - var length = type - DataTypes.FixMap; - return type.GetHighBits(4) == DataTypes.FixMap.GetHighBits(4) ? length : (uint?)null; - } - - public byte[] ReadToken() - { - StartTokenGathering(); - SkipToken(); - var gatheredBytes = StopTokenGathering(); - return gatheredBytes.ToArray(); - } - - protected abstract IList StopTokenGathering(); - - protected abstract void StartTokenGathering(); - } -} \ No newline at end of file diff --git a/src/msgpack.light/CodeDoesntBelongFamilyException.cs b/src/msgpack.light/CodeDoesntBelongFamilyException.cs new file mode 100644 index 0000000..e274018 --- /dev/null +++ b/src/msgpack.light/CodeDoesntBelongFamilyException.cs @@ -0,0 +1,19 @@ +using System; + +namespace ProGaudi.MsgPack +{ + [Serializable] + public class CodeDoesntBelongFamilyException : ConstraintViolationException + { + public byte DataCode { get; } + + public DataFamily Binary { get; } + + public CodeDoesntBelongFamilyException(byte dataCode, DataFamily binary, Exception innerException = null) + : base($"We expect {binary} data family, but we have {dataCode}, it belongs to {MsgPackSpec.GetDataFamily(dataCode)}.", innerException) + { + DataCode = dataCode; + Binary = binary; + } + } +} \ No newline at end of file diff --git a/src/msgpack.light/CompiledLambdaActivatorFactory.cs b/src/msgpack.light/CompiledLambdaActivatorFactory.cs index 7a072e2..e6bd764 100644 --- a/src/msgpack.light/CompiledLambdaActivatorFactory.cs +++ b/src/msgpack.light/CompiledLambdaActivatorFactory.cs @@ -1,26 +1,65 @@ using System; +using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; -namespace ProGaudi.MsgPack.Light +namespace ProGaudi.MsgPack { public static class CompiledLambdaActivatorFactory { - public static Func GetActivator(this Type type) + private static readonly ConcurrentDictionary> DefaultConstructorCache = new ConcurrentDictionary>(); + + private static readonly ConcurrentDictionary> SingleConstructorCache = new ConcurrentDictionary>(); + + public static Func GetDefaultActivator(this Type type) + { + return DefaultConstructorCache.GetOrAdd(type, x => CreateActivator()); + + Func CreateActivator() + { + var ctor = type + .GetTypeInfo() + .DeclaredConstructors + .FirstOrDefault(x => x.GetParameters().Length == 0 && !x.IsStatic); + + if (ctor == null) + { + return default; + } + + var newExp = Expression.New(ctor); + + var lambda = Expression.Lambda(typeof(Func), newExp); + + return (Func) lambda.Compile(); + } + } + + public static Func GetContextActivator(this Type type) { - var ctor = type.GetTypeInfo().DeclaredConstructors.First(x => x.GetParameters().Length == 0 && !x.IsStatic); + return SingleConstructorCache.GetOrAdd(type, x => CreateActivator()); + + Func CreateActivator() + { + var ctor = type + .GetTypeInfo() + .DeclaredConstructors + .FirstOrDefault(x => x.GetParameters().Length == 1 && x.GetParameters()[0].ParameterType == typeof(MsgPackContext) && !x.IsStatic); + + if (ctor == null) + { + return default; + } - //make a NewExpression that calls the - //ctor with the args we just created - var newExp = Expression.New(ctor); + var parameter = Expression.Parameter(typeof(MsgPackContext), "context"); + var newExp = Expression.New(ctor, parameter); - //create a lambda with the New - //Expression as body and our param object[] as arg - var lambda = Expression.Lambda(typeof(Func), newExp); + var lambda = Expression.Lambda(typeof(Func), newExp, parameter); - //compile it - return (Func)lambda.Compile(); + return (Func) lambda.Compile(); + } } } } diff --git a/src/msgpack.light/ConstraintViolationException.cs b/src/msgpack.light/ConstraintViolationException.cs new file mode 100644 index 0000000..d7ed1e2 --- /dev/null +++ b/src/msgpack.light/ConstraintViolationException.cs @@ -0,0 +1,14 @@ +using System; +using System.Runtime.Serialization; + +namespace ProGaudi.MsgPack +{ + [Serializable] + public abstract class ConstraintViolationException : SerializationException + { + protected ConstraintViolationException(string message, Exception innerException = null) + : base(message, innerException) + { + } + } +} \ No newline at end of file diff --git a/src/msgpack.light/ConverterNotFoundException.cs b/src/msgpack.light/ConverterNotFoundException.cs deleted file mode 100644 index 129052d..0000000 --- a/src/msgpack.light/ConverterNotFoundException.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace ProGaudi.MsgPack.Light -{ - public class ConverterNotFoundException : Exception - { - public ConverterNotFoundException(Type type) - : base($"Converter not found for type {type.FullName}") - { - ObjectType = type; - } - - public Type ObjectType { get; } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/Array/ConstrainedFormatter.cs b/src/msgpack.light/Converters/Array/ConstrainedFormatter.cs new file mode 100644 index 0000000..6075ecf --- /dev/null +++ b/src/msgpack.light/Converters/Array/ConstrainedFormatter.cs @@ -0,0 +1,80 @@ +using System; + +namespace ProGaudi.MsgPack.Converters.Array +{ + public sealed class ConstrainedFormatter : IMsgPackFormatter + { + public byte? Code { get; } + + public int? MinSize { get; } + + public int? MaxSize { get; } + + public bool Nullable { get; } + + private readonly IMsgPackFormatter _elementFormatter; + + public ConstrainedFormatter(MsgPackContext context, byte? code = null, int? minSize = null, int? maxSize = null, bool nullable = true) + { + Code = code; + MinSize = minSize; + MaxSize = maxSize; + Nullable = nullable; + + _elementFormatter = context.GetRequiredFormatter(); + + if (minSize.HasValue && maxSize.HasValue && minSize > maxSize) + { + throw ExceptionUtils.MinimumShouldBeLessThanOrEqualToMaximum(minSize.Value, maxSize.Value); + } + + if (code == null) return; + + var codeValue = code.Value; + + if (MsgPackSpec.GetDataFamily(codeValue) != DataFamily.Array) + throw ExceptionUtils.BadCodeConstraint(codeValue, DataFamily.Array); + + (MinSize, MaxSize) = Converters.Extensions.ValidateMinMaxCode(code.Value, minSize, maxSize); + } + + public int GetBufferSize(TElement[] value) => value == null + ? DataLengths.Nil + : ((ReadOnlyMemory) value).GetBufferSize(_elementFormatter); + + public bool HasConstantSize => !Nullable && _elementFormatter.HasConstantSize && MinSize.HasValue && MinSize == MaxSize; + + public int Format(Span destination, TElement[] value) + { + if (value == null) return MsgPackSpec.WriteNil(destination); + + var span = value.AsSpan(); + var length = span.Length; + Converters.Extensions.CheckMinMax(length, MinSize, MaxSize); + + var result = WriteHeader(destination); + + for (var i = 0; i < length; i++) + { + result += _elementFormatter.Format(destination.Slice(result), span[i]); + } + + return result; + + int WriteHeader(Span buffer) + { + switch (Code) + { + case null: + return MsgPackSpec.WriteArrayHeader(buffer, length); + case DataCodes.Array16: + return MsgPackSpec.WriteArray16Header(buffer, (ushort) length); + case DataCodes.Array32: + return MsgPackSpec.WriteArray32Header(buffer, (uint) length); + default: + return MsgPackSpec.WriteFixArrayHeader(buffer, (byte) length); + } + } + } + } +} diff --git a/src/msgpack.light/Converters/Array/Extensions.cs b/src/msgpack.light/Converters/Array/Extensions.cs new file mode 100644 index 0000000..f02f306 --- /dev/null +++ b/src/msgpack.light/Converters/Array/Extensions.cs @@ -0,0 +1,25 @@ +using System; + +namespace ProGaudi.MsgPack.Converters.Array +{ + internal static class Extensions + { + public static int GetBufferSize(this ReadOnlyMemory value, IMsgPackFormatter elementFormatter) + { + var span = value.Span; + if (span.Length == 0) + return DataLengths.FixArrayHeader; + + if (elementFormatter.HasConstantSize) + return span.Length * elementFormatter.GetBufferSize(span[0]) + DataLengths.GetArrayHeaderLength(span.Length); + + var result = DataLengths.Array32Header; + for (var i = 0; i < span.Length; i++) + { + result += elementFormatter.GetBufferSize(span[i]); + } + + return result; + } + } +} diff --git a/src/msgpack.light/Converters/Array/Parser.cs b/src/msgpack.light/Converters/Array/Parser.cs new file mode 100644 index 0000000..f8f9524 --- /dev/null +++ b/src/msgpack.light/Converters/Array/Parser.cs @@ -0,0 +1,50 @@ +using System; +using System.Buffers; +using System.Runtime.CompilerServices; + +using ProGaudi.Buffers; + +namespace ProGaudi.MsgPack.Converters.Array +{ + public sealed class Parser : IMsgPackParser>, IMsgPackParser + { + private readonly IMsgPackParser _elementParser; + + public Parser(MsgPackContext context) + { + _elementParser = context.GetRequiredParser(); + } + + IMemoryOwner IMsgPackParser>.Parse(ReadOnlySpan source, out int readSize) + { + if (MsgPackSpec.TryReadNil(source, out readSize)) return null; + + var length = MsgPackSpec.ReadArrayHeader(source, out readSize); + var result = FixedLengthMemoryPool.Shared.Rent(length); + Read(source, result.Memory.Span, ref readSize); + + return result; + } + + TElement[] IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) + { + if (MsgPackSpec.TryReadNil(source, out readSize)) return null; + + var length = MsgPackSpec.ReadArrayHeader(source, out readSize); + var array = new TElement[length]; + Read(source, array, ref readSize); + + return array; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Read(ReadOnlySpan source, Span array, ref int readSize) + { + for (var i = 0; i < array.Length; i++) + { + array[i] = _elementParser.Parse(source.Slice(readSize), out var temp); + readSize += temp; + } + } + } +} diff --git a/src/msgpack.light/Converters/Array/SequenceParser.cs b/src/msgpack.light/Converters/Array/SequenceParser.cs new file mode 100644 index 0000000..b4f77c3 --- /dev/null +++ b/src/msgpack.light/Converters/Array/SequenceParser.cs @@ -0,0 +1,50 @@ +using System; +using System.Buffers; +using System.Runtime.CompilerServices; + +using ProGaudi.Buffers; + +namespace ProGaudi.MsgPack.Converters.Array +{ + public sealed class SequenceParser : IMsgPackSequenceParser>, IMsgPackSequenceParser + { + private readonly IMsgPackSequenceParser _elementSequenceParser; + + public SequenceParser(MsgPackContext context) + { + _elementSequenceParser = context.GetRequiredSequenceParser(); + } + + IMemoryOwner IMsgPackSequenceParser>.Parse(ReadOnlySequence source, out int readSize) + { + if (MsgPackSpec.TryReadNil(source, out readSize)) return null; + + var length = MsgPackSpec.ReadArrayHeader(source, out readSize); + var result = FixedLengthMemoryPool.Shared.Rent(length); + Read(source, result.Memory.Span, ref readSize); + + return result; + } + + TElement[] IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) + { + if (MsgPackSpec.TryReadNil(source, out readSize)) return null; + + var length = MsgPackSpec.ReadArrayHeader(source, out readSize); + var array = new TElement[length]; + Read(source, array, ref readSize); + + return array; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Read(ReadOnlySequence source, Span array, ref int readSize) + { + for (var i = 0; i < array.Length; i++) + { + array[i] = _elementSequenceParser.Parse(source.Slice(readSize), out var temp); + readSize += temp; + } + } + } +} diff --git a/src/msgpack.light/Converters/Array/UsualFormatter.cs b/src/msgpack.light/Converters/Array/UsualFormatter.cs new file mode 100644 index 0000000..6799a89 --- /dev/null +++ b/src/msgpack.light/Converters/Array/UsualFormatter.cs @@ -0,0 +1,38 @@ +using System; + +namespace ProGaudi.MsgPack.Converters.Array +{ + public sealed class UsualFormatter : IMsgPackFormatter>, IMsgPackFormatter + { + private readonly IMsgPackFormatter _elementFormatter; + + public UsualFormatter(MsgPackContext context) + { + _elementFormatter = context.GetRequiredFormatter(); + } + + public int GetBufferSize(ReadOnlyMemory value) => value.GetBufferSize(_elementFormatter); + + public int GetBufferSize(TElement[] value) => value == null + ? DataLengths.Nil + : GetBufferSize((ReadOnlyMemory)value); + + public bool HasConstantSize => false; + + public int Format(Span destination, TElement[] value) => value == null + ? MsgPackSpec.WriteNil(destination) + : Format(destination, (ReadOnlyMemory)value); + + public int Format(Span destination, ReadOnlyMemory value) + { + var span = value.Span; + var result = MsgPackSpec.WriteArrayHeader(destination, span.Length); + for (var i = 0; i < span.Length; i++) + { + result += _elementFormatter.Format(destination.Slice(result), span[i]); + } + + return result; + } + } +} diff --git a/src/msgpack.light/Converters/ArrayConverter.cs b/src/msgpack.light/Converters/ArrayConverter.cs deleted file mode 100644 index 0069ee8..0000000 --- a/src/msgpack.light/Converters/ArrayConverter.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Collections.Generic; - -namespace ProGaudi.MsgPack.Light.Converters -{ - internal class ArrayConverter : ArrayConverterBase - where TArray : IList - { - private static readonly bool IsSingleDimensionArray; - - static ArrayConverter() - { - var type = typeof(TArray); - IsSingleDimensionArray = type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof(TElement); - } - - public override void Write(TArray value, IMsgPackWriter writer) - { - if (value == null) - { - Context.NullConverter.Write(value, writer); - return; - } - - writer.WriteArrayHeader((uint) value.Count); - - foreach (var element in value) - { - ElementConverter.Write(element, writer); - } - } - - public override TArray Read(IMsgPackReader reader) - { - var length = reader.ReadArrayLength(); - return length.HasValue ? ReadArray(reader, length.Value) : default(TArray); - } - - private TArray ReadArray(IMsgPackReader reader, uint length) - { - if (!IsSingleDimensionArray) - return ReadList(reader, length); - - // ReSharper disable once RedundantCast - var result = (TArray)(object)new TElement[length]; - - for (var i = 0; i < length; i++) - { - result[i] = ElementConverter.Read(reader); - } - - return result; - } - - private TArray ReadList(IMsgPackReader reader, uint length) - { - var array = (TArray)Context.GetObjectActivator(typeof (TArray))(); - - for (var i = 0u; i < length; i++) - { - array.Add(ElementConverter.Read(reader)); - } - - return array; - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/ArrayConverterBase.cs b/src/msgpack.light/Converters/ArrayConverterBase.cs deleted file mode 100644 index 337ed1e..0000000 --- a/src/msgpack.light/Converters/ArrayConverterBase.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace ProGaudi.MsgPack.Light.Converters -{ - public abstract class ArrayConverterBase : IMsgPackConverter - { - public abstract void Write(TArray value, IMsgPackWriter writer); - - public abstract TArray Read(IMsgPackReader reader); - - public void Initialize(MsgPackContext context) - { - var elementConverter = context.GetConverter(); - if (elementConverter == null) - { - throw ExceptionUtils.NoConverterForCollectionElement(typeof(TElement), "element"); - } - ElementConverter = elementConverter; - Context = context; - } - - protected IMsgPackConverter ElementConverter { get; private set; } - - protected MsgPackContext Context { get; private set; } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/Binary/CompatibilitySpec.cs b/src/msgpack.light/Converters/Binary/CompatibilitySpec.cs new file mode 100644 index 0000000..3218ac3 --- /dev/null +++ b/src/msgpack.light/Converters/Binary/CompatibilitySpec.cs @@ -0,0 +1,117 @@ +using System; +using System.Buffers; +using System.Collections.Generic; + +using ProGaudi.Buffers; + +namespace ProGaudi.MsgPack.Converters.Binary +{ + internal sealed class CompatibilitySpec : Converter + { + public override int GetBufferSize(ReadOnlyMemory value) + { + var length = value.Length; + return length + DataLengths.GetCompatibilityBinaryHeaderLength(length); + } + + public override bool HasConstantSize => false; + + public override int Format(Span destination, ReadOnlyMemory value) + { + var span = value.Span; + var wroteSize = WriteStringHeaderAndLength(destination, span.Length); + span.CopyTo(destination.Slice(wroteSize)); + return wroteSize + span.Length; + + int WriteStringHeaderAndLength(Span buffer, int length) + { + if (length <= 31) + { + return MsgPackSpec.WriteFixStringHeader(buffer, (byte) length); + } + + return length <= ushort.MaxValue + ? MsgPackSpec.WriteString16Header(buffer, (ushort) length) + : MsgPackSpec.WriteString32Header(buffer, (uint) length); + } + } + + public static readonly HashSet AllowedCodes = new HashSet + { + DataCodes.Binary8, + DataCodes.Binary16, + DataCodes.Binary32, + DataCodes.String8, + DataCodes.String16, + DataCodes.String32 + }; + + public override IMemoryOwner Parse(ReadOnlySpan source, out int readSize) + { + if (MsgPackSpec.TryReadNil(source, out readSize)) return null; + var code = source[0]; + switch (code) + { + case DataCodes.Binary8: + case DataCodes.Binary16: + case DataCodes.Binary32: + return MsgPackSpec.ReadBinary(source, out readSize); + + case DataCodes.String8: + case DataCodes.String16: + case DataCodes.String32: + return ReadBinaryFromString(source, out readSize); + } + + if (DataCodes.FixStringMin <= code && code <= DataCodes.FixStringMax) + { + return ReadBinaryFromString(source, out readSize); + } + + throw ExceptionUtils.BadBinaryCompatibilityCode(code, AllowedCodes); + + IMemoryOwner ReadBinaryFromString(ReadOnlySpan buffer, out int r) + { + var length = MsgPackSpec.ReadStringHeader(buffer, out r); + var result = FixedLengthMemoryPool.Shared.Rent(length); + buffer.Slice(r).CopyTo(result.Memory.Span); + r += length; + return result; + } + } + + public override IMemoryOwner Parse(ReadOnlySequence source, out int readSize) + { + if (MsgPackSpec.TryReadNil(source, out readSize)) return null; + var code = source.GetFirst(); + switch (code) + { + case DataCodes.Binary8: + case DataCodes.Binary16: + case DataCodes.Binary32: + return MsgPackSpec.ReadBinary(source, out readSize); + + case DataCodes.String8: + case DataCodes.String16: + case DataCodes.String32: + return ReadBinaryFromString(source, out readSize); + } + + if (DataCodes.FixStringMin <= code && code <= DataCodes.FixStringMax) + { + return ReadBinaryFromString(source, out readSize); + } + + throw ExceptionUtils.BadBinaryCompatibilityCode(code, AllowedCodes); + + IMemoryOwner ReadBinaryFromString(ReadOnlySequence buffer, out int r) + { + var length = MsgPackSpec.ReadStringHeader(buffer, out r); + var result = FixedLengthMemoryPool.Shared.Rent(length); + buffer.Slice(r).CopyTo(result.Memory.Span); + r += length; + return result; + } + } + } +} diff --git a/src/msgpack.light/Converters/Binary/Constrained.cs b/src/msgpack.light/Converters/Binary/Constrained.cs new file mode 100644 index 0000000..b7f7e9d --- /dev/null +++ b/src/msgpack.light/Converters/Binary/Constrained.cs @@ -0,0 +1,72 @@ +using System; +using System.Buffers; + +namespace ProGaudi.MsgPack.Converters.Binary +{ + public sealed class Constrained : IMsgPackFormatter?>, IMsgPackParser> + { + private readonly Converter _serializer; + + public bool CompatibilityMode { get; } + + public int? MinSize { get; } + + public int? MaxSize { get; } + + public bool Nullable { get; } + + public byte? DataCodeRestriction { get; } + + public Constrained( + bool compatibilityMode, + int? minSize = null, + int? maxSize = null, + bool nullable = true, + byte? dataCodeRestriction = null) + { + CompatibilityMode = compatibilityMode; + MinSize = minSize; + MaxSize = maxSize; + Nullable = nullable; + DataCodeRestriction = dataCodeRestriction; + + if (minSize.HasValue && maxSize.HasValue && minSize > maxSize) + throw ExceptionUtils.MinimumShouldBeLessThanOrEqualToMaximum(minSize.Value, maxSize.Value); + + _serializer = compatibilityMode ? Converter.Compatibility : Converter.Current; + + if (dataCodeRestriction == null) return; + var dataCode = dataCodeRestriction.Value; + _serializer = new DataCodeRestricted(dataCode, compatibilityMode); + (MinSize, MaxSize) = Extensions.ValidateMinMaxCode(dataCode, minSize, maxSize); + } + + // We will have problem with binary blobs greater than int.MaxValue bytes. + public int GetBufferSize(ReadOnlyMemory? value) + { + if (value == null) + return DataLengths.Nil; + + return HasConstantSize + // ReSharper disable once PossibleInvalidOperationException because HasConstantSize will check for it + ? DataLengths.GetBinaryHeaderLength(MinSize.Value) + MinSize.Value + : _serializer.GetBufferSize(value.Value); + } + + public bool HasConstantSize => !Nullable && MinSize.HasValue && MinSize == MaxSize; + + public int Format(Span destination, ReadOnlyMemory? value) + { + if (value == null) + { + return Extensions.WriteNil(destination, Nullable); + } + + Extensions.CheckMinMax(value.Value.Length, MinSize, MaxSize); + + return _serializer.Format(destination, value.Value); + } + + public IMemoryOwner Parse(ReadOnlySpan source, out int readSize) => _serializer.Parse(source, out readSize); + } +} diff --git a/src/msgpack.light/Converters/Binary/Converter.cs b/src/msgpack.light/Converters/Binary/Converter.cs new file mode 100644 index 0000000..b3f3fca --- /dev/null +++ b/src/msgpack.light/Converters/Binary/Converter.cs @@ -0,0 +1,52 @@ +using System; +using System.Buffers; + +namespace ProGaudi.MsgPack.Converters.Binary +{ + public abstract class Converter : + IMsgPackFormatter, + IMsgPackFormatter>, + IMsgPackParser, + IMsgPackParser>, + IMsgPackSequenceParser, + IMsgPackSequenceParser> + { + public static readonly Converter Current = new CurrentSpec(); + + public static readonly Converter Compatibility = new CompatibilitySpec(); + + public int GetBufferSize(byte[] value) => value == null + ? DataLengths.Nil + : GetBufferSize((ReadOnlyMemory)value); + + public abstract int GetBufferSize(ReadOnlyMemory value); + + public abstract bool HasConstantSize { get; } + + public abstract int Format(Span destination, ReadOnlyMemory value); + + public int Format(Span destination, byte[] value) => value == null + ? MsgPackSpec.WriteNil(destination) + : Format(destination, (ReadOnlyMemory)value); + + public abstract IMemoryOwner Parse(ReadOnlySpan source, out int readSize); + + byte[] IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) + { + using (var owner = Parse(source, out readSize)) + { + return owner?.Memory.ToArray(); + } + } + + public abstract IMemoryOwner Parse(ReadOnlySequence source, out int readSize); + + byte[] IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) + { + using (var owner = Parse(source, out readSize)) + { + return owner?.Memory.ToArray(); + } + } + } +} diff --git a/src/msgpack.light/Converters/Binary/CurrentSpec.cs b/src/msgpack.light/Converters/Binary/CurrentSpec.cs new file mode 100644 index 0000000..6318401 --- /dev/null +++ b/src/msgpack.light/Converters/Binary/CurrentSpec.cs @@ -0,0 +1,44 @@ +using System; +using System.Buffers; + +namespace ProGaudi.MsgPack.Converters.Binary +{ + internal sealed class CurrentSpec : Converter + { + public override int GetBufferSize(ReadOnlyMemory value) + { + var length = value.Length; + return DataLengths.GetBinaryHeaderLength(length) + length; + } + + public override bool HasConstantSize => false; + + public override int Format(Span destination, ReadOnlyMemory value) + { + var span = value.Span; + return MsgPackSpec.WriteBinary(destination, span); + } + + public override IMemoryOwner Parse(ReadOnlySpan source, out int readSize) + { + if (source[0] == DataCodes.Nil) + { + readSize = DataLengths.Nil; + return null; + } + + return MsgPackSpec.ReadBinary(source, out readSize); + } + + public override IMemoryOwner Parse(ReadOnlySequence source, out int readSize) + { + if (source.GetFirst() == DataCodes.Nil) + { + readSize = DataLengths.Nil; + return null; + } + + return MsgPackSpec.ReadBinary(source, out readSize); + } + } +} diff --git a/src/msgpack.light/Converters/Binary/DataCodeRestricted.cs b/src/msgpack.light/Converters/Binary/DataCodeRestricted.cs new file mode 100644 index 0000000..07a7f40 --- /dev/null +++ b/src/msgpack.light/Converters/Binary/DataCodeRestricted.cs @@ -0,0 +1,103 @@ +using System; +using System.Buffers; + +namespace ProGaudi.MsgPack.Converters.Binary +{ + public sealed class DataCodeRestricted : Converter + { + private readonly byte _code; + + private readonly Converter _reader; + + public DataCodeRestricted(byte code, bool compatibilityMode) + { + _code = code; + var (min, max) = DataLengths.GetMinAndMaxLength(code); + HasConstantSize = min == max; + if (compatibilityMode) + { + if (!CompatibilitySpec.AllowedCodes.Contains(code) + && !(DataCodes.FixStringMin <= code && code <= DataCodes.FixStringMax)) + throw ExceptionUtils.BadBinaryCompatibilityCode(code, CompatibilitySpec.AllowedCodes); + _reader = Compatibility; + } + else + { + if (MsgPackSpec.GetDataFamily(code) != DataFamily.Binary) + throw ExceptionUtils.BadCodeConstraint(code, DataFamily.Binary); + _reader = Current; + } + } + + public override int GetBufferSize(ReadOnlyMemory value) + { + switch (_code) + { + case DataCodes.Binary8: + return DataLengths.Binary8Header + value.Length; + case DataCodes.Binary16: + return DataLengths.Binary16Header + value.Length; + case DataCodes.Binary32: + return DataLengths.Binary32Header + value.Length; + + case DataCodes.String8: + return DataLengths.String8Header + value.Length; + case DataCodes.String16: + return DataLengths.String16Header + value.Length; + case DataCodes.String32: + return DataLengths.String32Header + value.Length; + + default: + if (DataCodes.FixStringMin <= _code && _code <= DataCodes.FixStringMax) + return DataLengths.FixStringHeader + (_code - DataCodes.FixStringMin); + throw ExceptionUtils.UnexpectedCode(_code); + } + } + + public override bool HasConstantSize { get; } + + public override int Format(Span destination, ReadOnlyMemory value) + { + int wroteSize; + + switch (_code) + { + case DataCodes.Binary8: + wroteSize = MsgPackSpec.WriteBinary8Header(destination, (byte) value.Length); + break; + case DataCodes.Binary16: + wroteSize = MsgPackSpec.WriteBinary16Header(destination, (ushort) value.Length); + break; + case DataCodes.Binary32: + wroteSize = MsgPackSpec.WriteBinary32Header(destination, (uint) value.Length); + break; + + case DataCodes.String8: + wroteSize = MsgPackSpec.WriteString8Header(destination, (byte) value.Length); + break; + case DataCodes.String16: + wroteSize = MsgPackSpec.WriteString16Header(destination, (ushort) value.Length); + break; + case DataCodes.String32: + wroteSize = MsgPackSpec.WriteString32Header(destination, (uint) value.Length); + break; + + default: + if (DataCodes.FixStringMin <= _code && _code <= DataCodes.FixStringMax) + { + wroteSize = MsgPackSpec.WriteFixStringHeader(destination, (byte) value.Length); + break; + } + + throw ExceptionUtils.UnexpectedCode(_code); + } + + value.Span.CopyTo(destination.Slice(wroteSize)); + return wroteSize + value.Length; + } + + public override IMemoryOwner Parse(ReadOnlySpan source, out int readSize) => _reader.Parse(source, out readSize); + + public override IMemoryOwner Parse(ReadOnlySequence source, out int readSize) => _reader.Parse(source, out readSize); + } +} diff --git a/src/msgpack.light/Converters/BinaryConverter.cs b/src/msgpack.light/Converters/BinaryConverter.cs deleted file mode 100644 index 98b490e..0000000 --- a/src/msgpack.light/Converters/BinaryConverter.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; - -namespace ProGaudi.MsgPack.Light.Converters -{ - internal class BinaryConverter : IMsgPackConverter - { - private readonly bool _compatibilityMode; - - private MsgPackContext _context; - - public BinaryConverter(bool compatibilityMode) - { - _compatibilityMode = compatibilityMode; - } - - public void Initialize(MsgPackContext context) - { - _context = context; - } - - public void Write(byte[] value, IMsgPackWriter writer) - { - if (value == null) - { - _context.NullConverter.Write(value, writer); - return; - } - - var valueLength = (uint) value.Length; - if (_compatibilityMode) - { - WriteStringHeaderAndLength(valueLength, writer); - } - else - { - WriteBinaryHeaderAndLength(valueLength, writer); - } - - writer.Write(value); - } - - // We will have problem with binary blobs greater than int.MaxValue bytes. - public byte[] Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); - - uint length; - switch (type) - { - case DataTypes.Null: - return null; - - case DataTypes.Bin8: - length = NumberConverter.ReadUInt8(reader); - break; - - case DataTypes.Bin16: - length = NumberConverter.ReadUInt16(reader); - break; - - case DataTypes.Bin32: - length = NumberConverter.ReadUInt32(reader); - break; - - case DataTypes.Str8: - if (_compatibilityMode) - length = NumberConverter.ReadUInt8(reader); - else - throw ExceptionUtils.CantReadStringAsBinary(); - break; - - case DataTypes.Str16: - if (_compatibilityMode) - length = NumberConverter.ReadUInt16(reader); - else - throw ExceptionUtils.CantReadStringAsBinary(); - break; - - case DataTypes.Str32: - if (_compatibilityMode) - length = NumberConverter.ReadUInt32(reader); - else - throw ExceptionUtils.CantReadStringAsBinary(); - break; - - default: - if ((type & DataTypes.FixStr) == DataTypes.FixStr) - { - if (_compatibilityMode) - length = (uint)(type & ~DataTypes.FixStr); - else - throw ExceptionUtils.CantReadStringAsBinary(); - } - else - { - throw ExceptionUtils.BadTypeException(type, DataTypes.Bin8, DataTypes.Bin16, DataTypes.Bin32, DataTypes.Null); - } - break; - } - - var segment = reader.ReadBytes(length); - var array = new byte[segment.Count]; - Array.Copy(segment.Array, segment.Offset, array, 0, segment.Count); - return array; - } - - private void WriteBinaryHeaderAndLength(uint length, IMsgPackWriter writer) - { - if (length <= byte.MaxValue) - { - writer.Write(DataTypes.Bin8); - NumberConverter.WriteByteValue((byte) length, writer); - } - else if (length <= ushort.MaxValue) - { - writer.Write(DataTypes.Bin16); - NumberConverter.WriteUShortValue((ushort) length, writer); - } - else - { - writer.Write(DataTypes.Bin32); - NumberConverter.WriteUIntValue(length, writer); - } - } - - private void WriteStringHeaderAndLength(uint length, IMsgPackWriter writer) - { - if (length <= 31) - { - writer.Write((byte)(((byte)DataTypes.FixStr + length) % 256)); - return; - } - - if (length <= ushort.MaxValue) - { - writer.Write(DataTypes.Str16); - NumberConverter.WriteUShortValue((ushort)length, writer); - } - else - { - writer.Write(DataTypes.Str32); - NumberConverter.WriteUIntValue((uint)length, writer); - } - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/BoolConverter.cs b/src/msgpack.light/Converters/BoolConverter.cs index 81cda15..41b845b 100644 --- a/src/msgpack.light/Converters/BoolConverter.cs +++ b/src/msgpack.light/Converters/BoolConverter.cs @@ -1,31 +1,20 @@ -namespace ProGaudi.MsgPack.Light.Converters +using System; +using System.Buffers; + +namespace ProGaudi.MsgPack.Converters { - internal class BoolConverter : IMsgPackConverter + internal sealed class BoolConverter : IMsgPackFormatter, IMsgPackParser, IMsgPackSequenceParser { - public void Initialize(MsgPackContext context) - { - } + public static BoolConverter Instance = new BoolConverter(); - public void Write(bool value, IMsgPackWriter writer) - { - writer.Write(value ? DataTypes.True : DataTypes.False); - } + public int GetBufferSize(bool value) => DataLengths.Boolean; - public bool Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); + public bool HasConstantSize => true; - switch (type) - { - case DataTypes.True: - return true; + public int Format(Span destination, bool value) => MsgPackSpec.WriteBoolean(destination, value); - case DataTypes.False: - return false; + public bool Parse(ReadOnlySpan source, out int readSize) => MsgPackSpec.ReadBoolean(source, out readSize); - default: - throw ExceptionUtils.BadTypeException(type, DataTypes.True, DataTypes.False); - } - } + public bool Parse(ReadOnlySequence source, out int readSize) => MsgPackSpec.ReadBoolean(source, out readSize); } -} \ No newline at end of file +} diff --git a/src/msgpack.light/Converters/Collection/ConstrainedFormatter.cs b/src/msgpack.light/Converters/Collection/ConstrainedFormatter.cs new file mode 100644 index 0000000..300783d --- /dev/null +++ b/src/msgpack.light/Converters/Collection/ConstrainedFormatter.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.Collection +{ + public sealed class ConstrainedFormatter : IMsgPackFormatter + where TCollection : ICollection + { + public byte? Code { get; } + + public int? MinSize { get; } + + public int? MaxSize { get; } + + public bool Nullable { get; } + + private readonly IMsgPackFormatter _elementFormatter; + + public ConstrainedFormatter( + MsgPackContext context, + byte? code = null, + int? minSize = null, + int? maxSize = null, + bool nullable = true) + { + Code = code; + MinSize = minSize; + MaxSize = maxSize; + Nullable = nullable; + + _elementFormatter = context.GetRequiredFormatter(); + + if (minSize.HasValue && maxSize.HasValue && minSize > maxSize) + { + throw ExceptionUtils.MinimumShouldBeLessThanOrEqualToMaximum(minSize.Value, maxSize.Value); + } + + if (code == null) return; + + var codeValue = code.Value; + + if (MsgPackSpec.GetDataFamily(codeValue) != DataFamily.Array) + throw ExceptionUtils.BadCodeConstraint(codeValue, DataFamily.Array); + + (MinSize, MaxSize) = Converters.Extensions.ValidateMinMaxCode(code.Value, minSize, maxSize); + } + + int IMsgPackFormatter.GetBufferSize(TCollection value) => value.GetBufferSize(_elementFormatter); + + public bool HasConstantSize => !Nullable && _elementFormatter.HasConstantSize && MinSize.HasValue && MinSize == MaxSize; + + int IMsgPackFormatter.Format(Span destination, TCollection value) + { + if (value == null) return MsgPackSpec.WriteNil(destination); + + var span = value; + var length = span.Count; + Converters.Extensions.CheckMinMax(length, MinSize, MaxSize); + + var result = WriteHeader(destination, length); + foreach (var element in value) + { + result += _elementFormatter.Format(destination.Slice(result), element); + } + + return result; + } + + private int WriteHeader(Span buffer, int length) + { + switch (Code) + { + case null: + return MsgPackSpec.WriteArrayHeader(buffer, length); + case DataCodes.Array16: + return MsgPackSpec.WriteArray16Header(buffer, (ushort) length); + case DataCodes.Array32: + return MsgPackSpec.WriteArray32Header(buffer, (uint) length); + default: + return MsgPackSpec.WriteFixArrayHeader(buffer, (byte) length); + } + } + } +} diff --git a/src/msgpack.light/Converters/Collection/Extensions.cs b/src/msgpack.light/Converters/Collection/Extensions.cs new file mode 100644 index 0000000..82d5c36 --- /dev/null +++ b/src/msgpack.light/Converters/Collection/Extensions.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Linq; + +namespace ProGaudi.MsgPack.Converters.Collection +{ + internal static class Extensions + { + public static int GetBufferSize(this TCollection value, IMsgPackFormatter elementFormatter) + where TCollection : ICollection + { + if (value == null) + return DataLengths.Nil; + + if (value.Count == 0) + return DataLengths.FixArrayHeader; + + if (elementFormatter.HasConstantSize) + return value.Count * elementFormatter.GetBufferSize(value.First()) + DataLengths.GetArrayHeaderLength(value.Count); + + var result = DataLengths.Array32Header; + foreach (var element in value) + { + result += elementFormatter.GetBufferSize(element); + } + + return result; + } + } +} diff --git a/src/msgpack.light/Converters/Collection/Parser.cs b/src/msgpack.light/Converters/Collection/Parser.cs new file mode 100644 index 0000000..1960502 --- /dev/null +++ b/src/msgpack.light/Converters/Collection/Parser.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace ProGaudi.MsgPack.Converters.Collection +{ + public sealed class Parser : IMsgPackParser + where TCollection : ICollection, new() + { + private readonly IMsgPackParser _elementParser; + + public Parser(MsgPackContext context) + { + _elementParser = context.GetRequiredParser(); + } + + public TCollection Parse(ReadOnlySpan source, out int readSize) + { + return MsgPackSpec.TryReadNil(source, out readSize) ? default : Read(source, out readSize); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private TCollection Read(ReadOnlySpan source, out int readSize) + { + var length = MsgPackSpec.ReadArrayHeader(source, out readSize); + var array = new TCollection(); + for (var i = 0; i < length; i++) + { + array.Add(_elementParser.Parse(source.Slice(readSize), out var temp)); + readSize += temp; + } + + return array; + } + } +} diff --git a/src/msgpack.light/Converters/Collection/SequenceParser.cs b/src/msgpack.light/Converters/Collection/SequenceParser.cs new file mode 100644 index 0000000..73b1e04 --- /dev/null +++ b/src/msgpack.light/Converters/Collection/SequenceParser.cs @@ -0,0 +1,36 @@ +using System.Buffers; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace ProGaudi.MsgPack.Converters.Collection +{ + public sealed class SequenceParser : IMsgPackSequenceParser + where TCollection : ICollection, new() + { + private readonly IMsgPackSequenceParser _elementSequenceParser; + + public SequenceParser(MsgPackContext context) + { + _elementSequenceParser = context.GetRequiredSequenceParser(); + } + + public TCollection Parse(ReadOnlySequence source, out int readSize) + { + return MsgPackSpec.TryReadNil(source, out readSize) ? default : Read(source, out readSize); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private TCollection Read(ReadOnlySequence source, out int readSize) + { + var length = MsgPackSpec.ReadArrayHeader(source, out readSize); + var array = new TCollection(); + for (var i = 0; i < length; i++) + { + array.Add(_elementSequenceParser.Parse(source.Slice(readSize), out var temp)); + readSize += temp; + } + + return array; + } + } +} diff --git a/src/msgpack.light/Converters/Collection/UsualFormatter.cs b/src/msgpack.light/Converters/Collection/UsualFormatter.cs new file mode 100644 index 0000000..69cb7b5 --- /dev/null +++ b/src/msgpack.light/Converters/Collection/UsualFormatter.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.Collection +{ + public sealed class UsualFormatter : IMsgPackFormatter + where TCollection : ICollection + { + private readonly IMsgPackFormatter _elementFormatter; + + public UsualFormatter(MsgPackContext context) + { + _elementFormatter = context.GetRequiredFormatter(); + } + + int IMsgPackFormatter.GetBufferSize(TCollection value) => value.GetBufferSize(_elementFormatter); + + public bool HasConstantSize => false; + + int IMsgPackFormatter.Format(Span destination, TCollection value) + { + if (value == null) return MsgPackSpec.WriteNil(destination); + + var result = MsgPackSpec.WriteArrayHeader(destination, value.Count); + foreach (var element in value) + { + result += _elementFormatter.Format(destination.Slice(result), element); + } + + return result; + } + } +} diff --git a/src/msgpack.light/Converters/Date/Ticks.cs b/src/msgpack.light/Converters/Date/Ticks.cs new file mode 100644 index 0000000..f362ec6 --- /dev/null +++ b/src/msgpack.light/Converters/Date/Ticks.cs @@ -0,0 +1,56 @@ +using System; +using System.Buffers; + +namespace ProGaudi.MsgPack.Converters.Date +{ + public class Ticks : IMsgPackFormatter, IMsgPackFormatter, IMsgPackFormatter, + IMsgPackParser, IMsgPackParser, IMsgPackParser, + IMsgPackSequenceParser, IMsgPackSequenceParser, IMsgPackSequenceParser + { + private static readonly int BufferSize = DataLengths.GetMinAndMaxLength(DataCodes.Int64).max; + + private static readonly DateTime UnixEpochUtc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + public static readonly Ticks Instance = new Ticks(); + + public bool HasConstantSize => false; + + int IMsgPackFormatter.GetBufferSize(DateTime value) => BufferSize; + + int IMsgPackFormatter.GetBufferSize(DateTimeOffset value) => BufferSize; + + int IMsgPackFormatter.GetBufferSize(TimeSpan value) => BufferSize; + + int IMsgPackFormatter.Format(Span destination, DateTimeOffset value) => MsgPackSpec.WriteInt64(destination, value.ToUniversalTime().Subtract(UnixEpochUtc).Ticks); + + int IMsgPackFormatter.Format(Span destination, DateTime value) => MsgPackSpec.WriteInt64(destination, value.ToUniversalTime().Subtract(UnixEpochUtc).Ticks); + + int IMsgPackFormatter.Format(Span destination, TimeSpan value) => MsgPackSpec.WriteInt64(destination, value.Ticks); + + DateTime IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) => UnixEpochUtc.AddTicks(ReadTicks(source, out readSize)); + + DateTimeOffset IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) => UnixEpochUtc.AddTicks(ReadTicks(source, out readSize)); + + TimeSpan IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) => new TimeSpan(ReadTicks(source, out readSize)); + + DateTime IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) => UnixEpochUtc.AddTicks(ReadTicks(source, out readSize)); + + DateTimeOffset IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) => UnixEpochUtc.AddTicks(ReadTicks(source, out readSize)); + + TimeSpan IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) => new TimeSpan(ReadTicks(source, out readSize)); + + private static long ReadTicks(ReadOnlySpan source, out int readSize) + { + return MsgPackSpec.TryReadInt64(source, out var value, out readSize) + ? value + : (long)MsgPackSpec.ReadUInt64(source, out readSize); + } + + private static long ReadTicks(ReadOnlySequence source, out int readSize) + { + return MsgPackSpec.TryReadInt64(source, out var value, out readSize) + ? value + : (long)MsgPackSpec.ReadUInt64(source, out readSize); + } + } +} diff --git a/src/msgpack.light/Converters/DateTimeConverter.cs b/src/msgpack.light/Converters/DateTimeConverter.cs deleted file mode 100644 index 139cfec..0000000 --- a/src/msgpack.light/Converters/DateTimeConverter.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; - -namespace ProGaudi.MsgPack.Light.Converters -{ - public class DateTimeConverter : IMsgPackConverter, IMsgPackConverter - { - private Lazy> _ulongConverter; - private Lazy> _longConverter; - - public void Initialize(MsgPackContext context) - { - _ulongConverter = new Lazy>(context.GetConverter); - _longConverter = new Lazy>(context.GetConverter); - } - - public void Write(DateTime value, IMsgPackWriter writer) - { - var longValue = DateTimeUtils.FromDateTime(value); - - _longConverter.Value.Write(longValue, writer); - } - - DateTime IMsgPackConverter.Read(IMsgPackReader reader) - { - var ulongValue = _ulongConverter.Value.Read(reader); - return DateTimeUtils.ToDateTime((long)ulongValue); - } - - public void Write(DateTimeOffset value, IMsgPackWriter writer) - { - var longValue = DateTimeUtils.FromDateTimeOffset(value); - - _longConverter.Value.Write(longValue, writer); - } - - DateTimeOffset IMsgPackConverter.Read(IMsgPackReader reader) - { - var ulongValue = _ulongConverter.Value.Read(reader); - return DateTimeUtils.ToDateTimeOffset((long)ulongValue); - } - } -} diff --git a/src/msgpack.light/Converters/Enum/String.cs b/src/msgpack.light/Converters/Enum/String.cs new file mode 100644 index 0000000..968e95d --- /dev/null +++ b/src/msgpack.light/Converters/Enum/String.cs @@ -0,0 +1,79 @@ +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace ProGaudi.MsgPack.Converters.Enum +{ + internal class String : IMsgPackFormatter, IMsgPackParser, IMsgPackSequenceParser + where T : struct + { + private static readonly Dictionary ValueToLabel; + + private static readonly Dictionary LabelToValue; + + private static readonly Dictionary ValueToLength; + + static String() + { + if (!typeof(T).GetTypeInfo().IsEnum) + { + throw new ArgumentException($"{typeof(T)} is not an enum."); + } + + var values = System.Enum.GetValues(typeof(T)).Cast().Distinct().ToArray(); + ValueToLabel = values.ToDictionary(x => x, x => + { + var name = System.Enum.GetName(typeof(T), x); + return (name.Length, MsgPackSpec.DefaultEncoding.GetBytes(name)); + }); + LabelToValue = values.ToDictionary(x => System.Enum.GetName(typeof(T), x)); + ValueToLength = LabelToValue.ToDictionary( + x => x.Value, + x => + { + var length = MsgPackSpec.DefaultEncoding.GetByteCount(x.Key); + return length + DataLengths.GetStringHeaderLengthByBytesCount(length); + }); + } + + public int GetBufferSize(T value) => ValueToLength.TryGetValue(value, out var x ) ? x : MsgPackSpec.DefaultEncoding.GetByteCount(value.ToString()); + + public bool HasConstantSize => false; + + public int Format(Span destination, T value) + { + if (ValueToLabel.TryGetValue(value, out var x)) + { + var result = MsgPackSpec.WriteStringHeader(destination, x.length); + x.blob.CopyTo(destination.Slice(result)); + return result + x.blob.Length; + } + + return MsgPackSpec.WriteString(destination, value.ToString().AsSpan()); + } + + public T Parse(ReadOnlySpan source, out int readSize) + { + var value = MsgPackSpec.ReadString(source, out readSize); + return LabelToValue.TryGetValue(value, out var x) + ? x + : (T)System.Enum.Parse( + typeof(T), + value, + true); + } + + public T Parse(ReadOnlySequence source, out int readSize) + { + var value = MsgPackSpec.ReadString(source, out readSize); + return LabelToValue.TryGetValue(value, out var x) + ? x + : (T)System.Enum.Parse( + typeof(T), + value, + true); + } + } +} diff --git a/src/msgpack.light/Converters/EnumStringConverter.cs b/src/msgpack.light/Converters/EnumStringConverter.cs deleted file mode 100644 index b821733..0000000 --- a/src/msgpack.light/Converters/EnumStringConverter.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace ProGaudi.MsgPack.Light.Converters -{ - internal class EnumStringConverter : IMsgPackConverter - { - private Lazy> _stringConverter; - - public void Initialize(MsgPackContext context) - { - _stringConverter = new Lazy>(context.GetConverter); - } - - public void Write(T value, IMsgPackWriter writer) - { - _stringConverter.Value.Write(value.ToString(), writer); - } - - public T Read(IMsgPackReader reader) - { - return (T)Enum.Parse(typeof(T), _stringConverter.Value.Read(reader)); - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/Enumerable/ConstrainedFormatter.cs b/src/msgpack.light/Converters/Enumerable/ConstrainedFormatter.cs new file mode 100644 index 0000000..a7d34df --- /dev/null +++ b/src/msgpack.light/Converters/Enumerable/ConstrainedFormatter.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.Enumerable +{ + public sealed class ConstrainedFormatter : IMsgPackFormatter + where TEnumerable : IEnumerable + { + public byte Code { get; } + + public int? MinSize { get; } + + public int? MaxSize { get; } + + public bool Nullable { get; } + + private readonly IMsgPackFormatter _elementFormatter; + + public ConstrainedFormatter( + MsgPackContext context, + byte? code = null, + int? minSize = null, + int? maxSize = null, + bool nullable = true) + { + Code = code ?? DataCodes.Array32; + MinSize = minSize; + MaxSize = maxSize; + Nullable = nullable; + + _elementFormatter = context.GetRequiredFormatter(); + + if (minSize.HasValue && maxSize.HasValue && minSize > maxSize) + { + throw ExceptionUtils.MinimumShouldBeLessThanOrEqualToMaximum(minSize.Value, maxSize.Value); + } + + if (MsgPackSpec.GetDataFamily(Code) != DataFamily.Array) + throw ExceptionUtils.BadCodeConstraint(Code, DataFamily.Array); + + (MinSize, MaxSize) = Converters.Extensions.ValidateMinMaxCode(Code, minSize, maxSize); + } + + int IMsgPackFormatter.GetBufferSize(TEnumerable value) => value.GetBufferSize(_elementFormatter); + + public bool HasConstantSize => !Nullable && _elementFormatter.HasConstantSize && MinSize.HasValue && MinSize == MaxSize; + + int IMsgPackFormatter.Format(Span destination, TEnumerable value) + { + if (value == null) return MsgPackSpec.WriteNil(destination); + + var span = destination.Slice(DataLengths.GetHeaderLength(Code)); + var length = 0; + var result = 0; + foreach (var element in value) + { + result += _elementFormatter.Format(span.Slice(result), element); + length += 1; + } + Converters.Extensions.CheckMinMax(length, MinSize, MaxSize); + result += WriteHeader(destination, length); + + return result; + } + + private int WriteHeader(Span buffer, int length) + { + switch (Code) + { + case DataCodes.Array16: + return MsgPackSpec.WriteArray16Header(buffer, (ushort) length); + case DataCodes.Array32: + return MsgPackSpec.WriteArray32Header(buffer, (uint) length); + default: + return MsgPackSpec.WriteFixArrayHeader(buffer, (byte) length); + } + } + } +} diff --git a/src/msgpack.light/Converters/Enumerable/Extensions.cs b/src/msgpack.light/Converters/Enumerable/Extensions.cs new file mode 100644 index 0000000..f84969f --- /dev/null +++ b/src/msgpack.light/Converters/Enumerable/Extensions.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.Enumerable +{ + internal static class Extensions + { + public static int GetBufferSize(this TEnumerable value, IMsgPackFormatter elementFormatter) + where TEnumerable : IEnumerable + { + if (value == null) + return DataLengths.Nil; + + var result = DataLengths.Array32Header; + foreach (var element in value) + { + result += elementFormatter.GetBufferSize(element); + } + + return result; + } + } +} diff --git a/src/msgpack.light/Converters/Enumerable/UsualFormatter.cs b/src/msgpack.light/Converters/Enumerable/UsualFormatter.cs new file mode 100644 index 0000000..18d2d84 --- /dev/null +++ b/src/msgpack.light/Converters/Enumerable/UsualFormatter.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.Enumerable +{ + public sealed class UsualFormatter : IMsgPackFormatter + where TEnumerable : IEnumerable + { + private readonly IMsgPackFormatter _impl; + + public UsualFormatter(MsgPackContext context) + { + _impl = new ConstrainedFormatter(context, DataCodes.Array32); + } + + public int GetBufferSize(TEnumerable value) => _impl.GetBufferSize(value); + + public bool HasConstantSize => _impl.HasConstantSize; + + public int Format(Span destination, TEnumerable value) => _impl.Format(destination, value); + } +} \ No newline at end of file diff --git a/src/msgpack.light/Converters/Extensions.cs b/src/msgpack.light/Converters/Extensions.cs new file mode 100644 index 0000000..4c47cb2 --- /dev/null +++ b/src/msgpack.light/Converters/Extensions.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; + +using JetBrains.Annotations; + +namespace ProGaudi.MsgPack.Converters +{ + internal static class Extensions + { + internal static (int? minSize, int? maxSize) ValidateMinMaxCode(byte code, int? minSize, int? maxSize) + { + var (minLengthByCode, maxLengthByCode) = DataLengths.GetMinAndMaxLength(code); + if (minSize.HasValue) + { + if (maxLengthByCode < minSize) + throw ExceptionUtils.MinSizeIsTooBigForDataCode(DataFamily.Binary, code, minSize.Value); + if (minSize < minLengthByCode) + throw ExceptionUtils.MinSizeIsTooSmallForDataCode(DataFamily.Binary, code, minSize.Value); + } + else + { + minSize = minLengthByCode; + } + + if (maxSize.HasValue) + { + if (maxLengthByCode < maxSize) + throw ExceptionUtils.MaxSizeIsTooBigForDataCode(DataFamily.Binary, code, maxSize.Value); + if (maxSize < maxLengthByCode) + throw ExceptionUtils.MaxSizeIsTooSmallForDataCode(DataFamily.Binary, code, maxSize.Value); + } + else + { + maxSize = maxLengthByCode; + } + + return (minSize, maxSize); + } + + internal static int WriteNil(Span destination, bool nullable) + { + if (nullable) + return MsgPackSpec.WriteNil(destination); + + throw ExceptionUtils.NonNullableConstraintIsViolated(); + } + + internal static void CheckMinMax(int length, int? minSize, int? maxSize) + { + if (minSize.HasValue) + { + if (length < minSize.Value) + throw ExceptionUtils.MinimumLengthConstraintIsViolated(minSize.Value, length); + } + + if (maxSize.HasValue) + { + if (length > maxSize.Value) + throw ExceptionUtils.MaximumLengthConstraintIsViolated(maxSize.Value, length); + } + } + + internal static int GetMapBufferSize([NotNull]this IEnumerable> value, int count, IMsgPackFormatter keyFormatter, IMsgPackFormatter valueFormatter) + { + var sum = DataLengths.GetMapHeaderLength(count); + foreach (var pair in value) + { + sum += keyFormatter.GetBufferSize(pair.Key); + sum += valueFormatter.GetBufferSize(pair.Value); + } + + return sum; + } + + internal static int FormatTo([NotNull]this IEnumerable> value, Span destination, int count, IMsgPackFormatter keyFormatter, IMsgPackFormatter valueFormatter) + { + var sum = MsgPackSpec.WriteMapHeader(destination, count); + foreach (var pair in value) + { + sum += keyFormatter.Format(destination.Slice(sum), pair.Key); + sum += valueFormatter.Format(destination.Slice(sum), pair.Value); + } + + return sum; + } + } +} diff --git a/src/msgpack.light/Converters/Generation/ArrayConverterGenerator.cs b/src/msgpack.light/Converters/Generation/ArrayConverterGenerator.cs deleted file mode 100644 index 0ef7013..0000000 --- a/src/msgpack.light/Converters/Generation/ArrayConverterGenerator.cs +++ /dev/null @@ -1,223 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -namespace ProGaudi.MsgPack.Light.Converters.Generation -{ - public class ArrayConverterGenerator : ConverterGeneratorBase - { - public ArrayConverterGenerator(ModuleBuilder moduleBuilder, string namespaceToPlace) - : base(moduleBuilder, namespaceToPlace, "ArrayConverter") - { - } - - protected override IEnumerable FilterProperties(Type typeToWrap, ImmutableArray allProperties) - { - var properties = allProperties - .Where(x => x.GetCustomAttribute() != null) - .GroupBy(x => x.GetArrayElementOrder()) - .OrderBy(x => x.Key) - .ToDictionary(x => x.Key, x => x.ToArray()); - - foreach (var pair in properties) - { - if (pair.Value.Length > 1) - { - throw ExceptionUtils.DuplicateArrayElement(typeToWrap, pair); - } - - yield return pair.Value[0]; - } - } - - protected override MethodBuilder EmitReadImplMethod( - TypeBuilder typeBuilder, - Type typeToInstantinate, - ImmutableArray propsToWrap, - ImmutableDictionary converters) - { - var mb = typeBuilder.DefineMethod( - $"{nameof(IMsgPackConverter.Read)}Impl", - MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig, - CallingConventions.HasThis); - mb.SetReturnType(typeToInstantinate); - mb.SetParameters(typeof(IMsgPackReader)); - - var generator = mb.GetILGenerator(); - - var instance = generator.DeclareLocal(typeToInstantinate); - var length = generator.DeclareLocal(typeof(uint?)); - var index = generator.DeclareLocal(typeof(int)); - - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Callvirt, typeof(IMsgPackReader).GetTypeInfo().GetMethod(nameof(IMsgPackReader.ReadArrayLength))); - generator.Emit(OpCodes.Stloc, length); - - var nonNullLabel = generator.DefineLabel(); - generator.Emit(OpCodes.Ldloca, length); - generator.Emit(OpCodes.Call, typeof(uint?).GetTypeInfo().GetProperty(nameof(Nullable.HasValue)).GetMethod); - generator.Emit(OpCodes.Brtrue, nonNullLabel); - generator.Emit(OpCodes.Ldnull); - generator.Emit(OpCodes.Ret); - - generator.MarkLabel(nonNullLabel); - generator.Emit(OpCodes.Newobj, typeToInstantinate.GetTypeInfo().GetDefaultConstructor()); - generator.Emit(OpCodes.Stloc, instance); - - var beginOfIteration = generator.DefineLabel(); - var conditionLabel = generator.DefineLabel(); - var incrementLabel = generator.DefineLabel(); - generator.Emit(OpCodes.Ldc_I4_0); - generator.Emit(OpCodes.Stloc, index); - generator.Emit(OpCodes.Br, conditionLabel); - - void EmitRead(Type type) - { - var converter = converters[type]; - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, converter); - generator.Emit(OpCodes.Callvirt, converter.FieldType.GetTypeInfo().GetProperty(nameof(Lazy.Value)).GetMethod); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit( - OpCodes.Callvirt, - converter.FieldType.GenericTypeArguments[0].GetTypeInfo().GetMethod(nameof(IMsgPackConverter.Read), new[] { typeof(IMsgPackReader) })); - } - - generator.MarkLabel(beginOfIteration); - - var next = default(Label?); - foreach (var property in propsToWrap) - { - if (next.HasValue) - { - generator.MarkLabel(next.Value); - } - - next = generator.DefineLabel(); - - generator.Emit(OpCodes.Ldloc, index); - generator.Emit(OpCodes.Ldc_I4, property.GetArrayElementOrder()); - generator.Emit(OpCodes.Ceq); - generator.Emit(OpCodes.Brfalse, next.Value); - - generator.Emit(OpCodes.Ldloc, instance); - EmitRead(property.PropertyType); - generator.Emit(OpCodes.Callvirt, GetPropertySetter(typeToInstantinate, property)); - - generator.Emit(OpCodes.Br, incrementLabel); - } - - if (next.HasValue) - { - generator.MarkLabel(next.Value); - } - - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Callvirt, typeof(IMsgPackReader).GetTypeInfo().GetMethod(nameof(IMsgPackReader.SkipToken))); - - generator.MarkLabel(incrementLabel); - generator.Emit(OpCodes.Ldloc, index); - generator.Emit(OpCodes.Ldc_I4_1); - generator.Emit(OpCodes.Add); - generator.Emit(OpCodes.Stloc, index); - - generator.MarkLabel(conditionLabel); - generator.Emit(OpCodes.Ldloc, index); - generator.Emit(OpCodes.Conv_I8); - generator.Emit(OpCodes.Ldloca, length); - generator.Emit(OpCodes.Call, length.LocalType.GetTypeInfo().GetProperty(nameof(Nullable.Value)).GetMethod); - generator.Emit(OpCodes.Conv_U8); - generator.Emit(OpCodes.Blt, beginOfIteration); - - generator.Emit(OpCodes.Ldloc, instance); - generator.Emit(OpCodes.Ret); - - return mb; - } - - protected override MethodBuilder EmitWriteImplMethod( - TypeBuilder typeBuilder, - Type typeToWrap, - ImmutableArray propsToWrap, - ImmutableDictionary converters) - { - var mb = typeBuilder.DefineMethod( - $"{nameof(IMsgPackConverter.Write)}Impl", - MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig, - CallingConventions.HasThis); - mb.SetReturnType(typeof(void)); - mb.SetParameters(typeToWrap, typeof(IMsgPackWriter)); - - var generator = mb.GetILGenerator(); - - var notNullCode = generator.DefineLabel(); - var value = OpCodes.Ldarg_1; - generator.Emit(value); - generator.Emit(OpCodes.Brtrue, notNullCode); - - // emit null version - var writer = OpCodes.Ldarg_2; - generator.Emit(writer); - generator.Emit(OpCodes.Ldc_I4, (int)DataTypes.Null); - generator.Emit( - OpCodes.Callvirt, - typeof(IMsgPackWriter).GetTypeInfo().GetMethod(nameof(IMsgPackWriter.Write), new[] { typeof(DataTypes) })); - generator.Emit(OpCodes.Ret); - - // emit not-null version - generator.MarkLabel(notNullCode); - generator.Emit(writer); - - var propsWithIndex = propsToWrap - .GroupBy(p => p.GetArrayElementOrder()) - .ToDictionary(x => x.Key, x => x.Single()); - - var maxIndex = propsWithIndex.Max(t => t.Key); - - generator.Emit(OpCodes.Ldc_I4, maxIndex + 1); - generator.Emit(OpCodes.Callvirt, typeof(IMsgPackWriter).GetTypeInfo().GetMethod(nameof(IMsgPackWriter.WriteArrayHeader))); - - void EmitWrite(Type type, Action valueLoader) - { - var converter = converters[type]; - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, converter); - generator.Emit(OpCodes.Callvirt, converter.FieldType.GetTypeInfo().GetProperty(nameof(Lazy.Value)).GetMethod); - valueLoader(generator); - generator.Emit(writer); - generator.Emit( - OpCodes.Callvirt, - converter.FieldType.GenericTypeArguments[0].GetTypeInfo().GetMethod(nameof(IMsgPackConverter.Write), new[] { type, typeof(IMsgPackWriter) })); - } - - for (var index = 0; index < maxIndex + 1; index++) - { - if (propsWithIndex.TryGetValue(index, out var property)) - { - EmitWrite( - property.PropertyType, - x => - { - x.Emit(OpCodes.Ldarg_1); - x.Emit(OpCodes.Callvirt, property.GetMethod); - }); - } - else - { - generator.Emit(writer); - generator.Emit(OpCodes.Ldc_I4, (int)DataTypes.Null); - generator.Emit( - OpCodes.Callvirt, - typeof(IMsgPackWriter).GetTypeInfo().GetMethod(nameof(IMsgPackWriter.Write), new[] { typeof(DataTypes) })); - } - } - - generator.Emit(OpCodes.Ret); - - return mb; - } - } -} diff --git a/src/msgpack.light/Converters/Generation/ConverterGenerationContext.cs b/src/msgpack.light/Converters/Generation/ConverterGenerationContext.cs deleted file mode 100644 index f388a63..0000000 --- a/src/msgpack.light/Converters/Generation/ConverterGenerationContext.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Reflection; -using System.Reflection.Emit; - -namespace ProGaudi.MsgPack.Light.Converters.Generation -{ - internal class ConverterGenerationContext - { - private readonly AssemblyBuilder _asmBuilder; - - private readonly string _name; - - private readonly string _namespace = "ProGaudi.MsgPack.Light.Generated"; - - private readonly MapConverterGenerator _mapGenerator; - - private readonly ArrayConverterGenerator _arrayGenerator; - - private readonly EnumConverterGenerator _enumConverterGenerator; - - private readonly InterfaceStubGenerator _interfaceStubGenerator; - - private readonly ConcurrentDictionary _implementationCaches = new ConcurrentDictionary(); - - private readonly ConcurrentDictionary<(Type, Type), Type> _converterCaches = new ConcurrentDictionary<(Type, Type), Type>(); - - public ConverterGenerationContext() - { - _name = Guid.NewGuid().ToString("N"); -#if NET46 || NET45 - _asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(_name), AssemblyBuilderAccess.RunAndSave); - var moduleBuilder = _asmBuilder.DefineDynamicModule("main", $"{_name}.dll"); -#else - _asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(_name), AssemblyBuilderAccess.RunAndCollect); - var moduleBuilder = _asmBuilder.DefineDynamicModule("main"); -#endif - _mapGenerator = new MapConverterGenerator(moduleBuilder, _namespace); - _arrayGenerator = new ArrayConverterGenerator(moduleBuilder, _namespace); - _enumConverterGenerator = new EnumConverterGenerator(moduleBuilder, _namespace); - - _interfaceStubGenerator = new InterfaceStubGenerator(moduleBuilder, _namespace); - } - - public IMsgPackConverter GenerateMapConverter(Type type) - { - return GenerateMapConverter(type, DetectImplementation(type)); - } - - public IMsgPackConverter GenerateMapConverter(Type @interface, Type implementation) - { - var generatorType = _converterCaches.GetOrAdd((@interface, implementation), x => _mapGenerator.Generate(x.Item1, x.Item2)); - return (IMsgPackConverter) generatorType.GetActivator()(); - } - - public IMsgPackConverter GenerateArrayConverter(Type type) - { - return GenerateArrayConverter(type, DetectImplementation(type)); - } - - public IMsgPackConverter GenerateArrayConverter(Type @interface, Type implementation) - { - var generatorType = _converterCaches.GetOrAdd((@interface, implementation), x => _arrayGenerator.Generate(x.Item1, x.Item2)); - return (IMsgPackConverter)generatorType.GetActivator()(); - } - - public IMsgPackConverter GenerateEnumConverter(Type type, bool convertEnumsAsStrings) - { - if (convertEnumsAsStrings) - { - return new EnumStringConverter(); - } - - var generatorType = _converterCaches.GetOrAdd((type, type), x => _enumConverterGenerator.Generate(x.Item1)); - return (IMsgPackConverter)generatorType.GetActivator()(); - } - - private Type DetectImplementation(Type @interface) - { - return _implementationCaches.GetOrAdd(@interface, GenerateInterfaceImplementation); - } - - private Type GenerateInterfaceImplementation(Type type) - { - var typeInfo = type.GetTypeInfo(); - var isInterface = typeInfo.IsInterface; - if (!isInterface) - { - if (typeInfo.IsAbstract) - { - throw new NotImplementedException("Can't generate child type for abstract class"); - } - - if (typeInfo.GetDefaultConstructor() == null) - { - throw new NotImplementedException("Can't generate child type for type without default ctor"); - } - } - - if (typeInfo.IsGenericTypeDefinition) - { - throw new NotImplementedException("Can't generate generic implementors."); - } - - return typeInfo.IsInterface - ? _interfaceStubGenerator.GenerateTypeToInstantinate(type, x => $"{x}Implementation") - : type; - } - - public void Dump() - { -#if NET46 || NET45 - _asmBuilder.Save($"{_name}.dll"); -#else - throw new NotSupportedException(); -#endif - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/Generation/ConverterGeneratorBase.cs b/src/msgpack.light/Converters/Generation/ConverterGeneratorBase.cs deleted file mode 100644 index 7692451..0000000 --- a/src/msgpack.light/Converters/Generation/ConverterGeneratorBase.cs +++ /dev/null @@ -1,189 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -using ProGaudi.MsgPack.Light.Converters.Generation.Exceptions; - -namespace ProGaudi.MsgPack.Light.Converters.Generation -{ - public abstract class ConverterGeneratorBase - { - private readonly ModuleBuilder _moduleBuilder; - - private readonly string _namespaceToPlace; - - private readonly PropertyProvider _propertyProvider = new PropertyProvider(); - - private readonly string _converterNameSuffix; - - protected ConverterGeneratorBase(ModuleBuilder moduleBuilder, string namespaceToPlace, string converterNameSuffix) - { - _moduleBuilder = moduleBuilder; - _namespaceToPlace = namespaceToPlace; - _converterNameSuffix = converterNameSuffix; - } - - public Type Generate(Type typeToWrap, Type typeToInstantinate) - { - var propsToWrap = GetDistinctProperties(typeToWrap).ToImmutableArray(); - - var interfaces = typeToInstantinate == typeToWrap - ? new[] {typeof(IMsgPackConverter<>).MakeGenericType(typeToWrap)} - : new[] - { - typeof(IMsgPackConverter<>).MakeGenericType(typeToWrap), - typeof(IMsgPackConverter<>).MakeGenericType(typeToInstantinate) - }; - - var typeBuilder = _moduleBuilder.DefineType( - $"{_namespaceToPlace}.{typeToWrap.GetNormalizedName()}_{typeToInstantinate.GetNormalizedName()}_{_converterNameSuffix}", - TypeAttributes.Public, - typeof(object), - interfaces); - - var converters = propsToWrap - .Select(x => x.PropertyType) - .Distinct() - .Union(new[] {typeof(string)}) - .Select>( - x => (x, typeBuilder.DefineField( - $"_{x.Name}_Converter", - typeof(Lazy<>).MakeGenericType(typeof(IMsgPackConverter<>).MakeGenericType(x)), - FieldAttributes.Private))) - .ToImmutableDictionary( - x => x.Item1, - x => x.Item2 - ); - - EmitInitializeMethod(typeBuilder, converters); - var writeImpl = EmitWriteImplMethod(typeBuilder, typeToWrap, propsToWrap, converters); - var readImpl = EmitReadImplMethod(typeBuilder, typeToInstantinate, propsToWrap, converters); - - foreach (var @interface in interfaces) - { - EmitWriteMethod(typeBuilder, @interface, writeImpl); - EmitReadMethod(typeBuilder, @interface, readImpl); - } - - return typeBuilder.ToType(); - } - - protected MethodInfo GetPropertySetter(Type typeToInstantinate, PropertyInfo property) - { - // if property has setter, we will call it. Otherwise we'll try to find it on implementation. - if (property.SetMethod != null) return property.SetMethod; - - var implementationProperty = _propertyProvider.GetPropertyByName(typeToInstantinate, property.Name); - - return implementationProperty != null - ? implementationProperty.SetMethod - : throw new GeneratorException($"Can't find setter for property {property.PropertyType.Name} {property.Name}"); - } - - protected abstract IEnumerable FilterProperties(Type typeToWrap, ImmutableArray properties); - - protected abstract MethodBuilder EmitReadImplMethod( - TypeBuilder typeBuilder, - Type typeToInstantinate, - ImmutableArray propsToWrap, - ImmutableDictionary converters); - - protected abstract MethodBuilder EmitWriteImplMethod( - TypeBuilder typeBuilder, - Type typeToWrap, - ImmutableArray propsToWrap, - ImmutableDictionary converters); - - private IEnumerable GetDistinctProperties(Type typeToWrap) - { - var allProperties = _propertyProvider.GetProperties(typeToWrap); - - return FilterProperties(typeToWrap, allProperties); - } - - private void EmitReadMethod(TypeBuilder typeBuilder, Type @interface, MethodBuilder readImpl) - { - var mb = typeBuilder.DefineMethod( - $"{nameof(IMsgPackConverter.Read)}", - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, - CallingConventions.HasThis); - mb.SetReturnType(@interface.GenericTypeArguments[0]); - mb.SetParameters(typeof(IMsgPackReader)); - - var generator = mb.GetILGenerator(); - - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Call, readImpl); - generator.Emit(OpCodes.Ret); - } - - private void EmitWriteMethod(TypeBuilder typeBuilder, Type @interface, MethodBuilder writeImpl) - { - var mb = typeBuilder.DefineMethod( - $"{nameof(IMsgPackConverter.Write)}", - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, - CallingConventions.HasThis); - mb.SetReturnType(typeof(void)); - mb.SetParameters(@interface.GenericTypeArguments[0], typeof(IMsgPackWriter)); - - var generator = mb.GetILGenerator(); - - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldarg_2); - generator.Emit(OpCodes.Call, writeImpl); - generator.Emit(OpCodes.Ret); - } - - [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] - private void EmitInitializeMethod( - TypeBuilder typeBuilder, - ImmutableDictionary converters) - { - var mb = typeBuilder.DefineMethod( - nameof(IMsgPackConverter.Initialize), - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, - CallingConventions.HasThis); - mb.SetReturnType(typeof(void)); - mb.SetParameters(typeof(MsgPackContext)); - - var generator = mb.GetILGenerator(); - - foreach (var converter in converters) - { - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit( - OpCodes.Ldftn, - typeof(MsgPackContext).GetTypeInfo().GetMethod(nameof(MsgPackContext.GetConverter)) - .MakeGenericMethod(converter.Key)); - - var converterType = converter.Value.FieldType.GenericTypeArguments[0]; - generator.Emit( - OpCodes.Newobj, - typeof(Func<>) - .MakeGenericType(converterType) - .GetTypeInfo() - .GetConstructor(new[] {typeof(object), typeof(IntPtr)})); - generator.Emit( - OpCodes.Newobj, - typeof(Lazy<>) - .MakeGenericType(converterType) - .GetTypeInfo() - .GetConstructor( - new[] - { - typeof(Func<>).MakeGenericType(converterType) - })); - generator.Emit(OpCodes.Stfld, converter.Value); - } - - generator.Emit(OpCodes.Ret); - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/Generation/EnumConverterGenerator.cs b/src/msgpack.light/Converters/Generation/EnumConverterGenerator.cs deleted file mode 100644 index d45567e..0000000 --- a/src/msgpack.light/Converters/Generation/EnumConverterGenerator.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Reflection; -using System.Reflection.Emit; - -namespace ProGaudi.MsgPack.Light.Converters.Generation -{ - internal class EnumConverterGenerator - { - private readonly ModuleBuilder _moduleBuilder; - private readonly string _namespaceToPlace; - - public EnumConverterGenerator(ModuleBuilder moduleBuilder, string namespaceToPlace) - { - _moduleBuilder = moduleBuilder; - _namespaceToPlace = namespaceToPlace; - } - - public Type Generate(Type typeToWrap) - { - var interfaceToImplement = typeof(IMsgPackConverter<>).MakeGenericType(typeToWrap); - - var typeBuilder = _moduleBuilder.DefineType( - $"{_namespaceToPlace}.{typeToWrap.GetNormalizedName()}_EnumConverter", - TypeAttributes.Public, - typeof(object), - new[] { interfaceToImplement }); - - var underlyingType = Enum.GetUnderlyingType(typeToWrap); - - var underlyingTypeConverter = typeBuilder.DefineField( - $"_{underlyingType.Name}_Converter", - typeof(Lazy<>).MakeGenericType(typeof(IMsgPackConverter<>).MakeGenericType(underlyingType)), - FieldAttributes.Private); - - EmitInitializeMethod(typeBuilder, underlyingType, underlyingTypeConverter); - EmitWriteMethod(typeBuilder, typeToWrap, underlyingType, underlyingTypeConverter); - EmitReadMethod(typeBuilder, typeToWrap, underlyingTypeConverter); - - return typeBuilder.ToType(); - } - - private static void EmitReadMethod( - TypeBuilder typeBuilder, - Type typeToWrap, - FieldBuilder underlyingTypeConverter) - { - var mb = typeBuilder.DefineMethod( - $"{nameof(IMsgPackConverter.Read)}", - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, - CallingConventions.HasThis); - mb.SetReturnType(typeToWrap); - mb.SetParameters(typeof(IMsgPackReader)); - - var generator = mb.GetILGenerator(); - generator.DeclareLocal(typeToWrap); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, underlyingTypeConverter); - generator.Emit(OpCodes.Callvirt, underlyingTypeConverter.FieldType.GetTypeInfo().GetProperty(nameof(Lazy.Value)).GetMethod); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit( - OpCodes.Callvirt, - underlyingTypeConverter.FieldType.GenericTypeArguments[0].GetTypeInfo().GetMethod(nameof(IMsgPackConverter.Read), new[] { typeof(IMsgPackReader) })); - - generator.Emit(OpCodes.Stloc_0); - generator.Emit(OpCodes.Ldloc_0); - - generator.Emit(OpCodes.Ret); - } - - private static void EmitWriteMethod( - TypeBuilder typeBuilder, - Type type, - Type underlyingType, - FieldBuilder underlyingTypeConverter) - { - var mb = typeBuilder.DefineMethod( - $"{nameof(IMsgPackConverter.Write)}", - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, - CallingConventions.HasThis); - mb.SetReturnType(typeof(void)); - mb.SetParameters(type, typeof(IMsgPackWriter)); - - var generator = mb.GetILGenerator(); - - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, underlyingTypeConverter); - generator.Emit(OpCodes.Callvirt, underlyingTypeConverter.FieldType.GetTypeInfo().GetProperty(nameof(Lazy.Value)).GetMethod); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Ldarg_2); - generator.Emit( - OpCodes.Callvirt, - underlyingTypeConverter.FieldType.GenericTypeArguments[0].GetTypeInfo().GetMethod(nameof(IMsgPackConverter.Write), new[] { underlyingType, typeof(IMsgPackWriter) })); - - generator.Emit(OpCodes.Ret); - } - - [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")] - private static void EmitInitializeMethod( - TypeBuilder typeBuilder, - Type underlyingType, - FieldBuilder underlyingTypeConverter) - { - var mb = typeBuilder.DefineMethod( - nameof(IMsgPackConverter.Initialize), - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, - CallingConventions.HasThis); - mb.SetReturnType(typeof(void)); - mb.SetParameters(typeof(MsgPackContext)); - - var generator = mb.GetILGenerator(); - - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit( - OpCodes.Ldftn, - typeof(MsgPackContext).GetTypeInfo().GetMethod(nameof(MsgPackContext.GetConverter)) - .MakeGenericMethod(underlyingType)); - - var converterType = underlyingTypeConverter.FieldType.GenericTypeArguments[0]; - generator.Emit( - OpCodes.Newobj, - typeof(Func<>) - .MakeGenericType(converterType) - .GetTypeInfo() - .GetConstructor(new[] { typeof(object), typeof(IntPtr) })); - generator.Emit( - OpCodes.Newobj, - typeof(Lazy<>) - .MakeGenericType(converterType) - .GetTypeInfo() - .GetConstructor( - new[] - { - typeof(Func<>).MakeGenericType(converterType) - })); - generator.Emit(OpCodes.Stfld, underlyingTypeConverter); - - generator.Emit(OpCodes.Ret); - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/Generation/Exceptions/DuplicateArrayElementException.cs b/src/msgpack.light/Converters/Generation/Exceptions/DuplicateArrayElementException.cs deleted file mode 100644 index 3c38929..0000000 --- a/src/msgpack.light/Converters/Generation/Exceptions/DuplicateArrayElementException.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; - -namespace ProGaudi.MsgPack.Light.Converters.Generation.Exceptions -{ - public class DuplicateArrayElementException : GeneratorException - { - public DuplicateArrayElementException(Type type, int order, PropertyInfo[] properties) - : base($"Duplicate order '{order}' in type '{type}'. Properties: {string.Join(", ", properties.Select(x => $"{x.DeclaringType.Name}.{x.Name}"))}.") - { - Type = type; - Order = order; - Properties = properties; - } - - public Type Type { get; } - - public int Order { get; } - - public PropertyInfo[] Properties { get; } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/Generation/Exceptions/DuplicateMapElementException.cs b/src/msgpack.light/Converters/Generation/Exceptions/DuplicateMapElementException.cs deleted file mode 100644 index aa8663c..0000000 --- a/src/msgpack.light/Converters/Generation/Exceptions/DuplicateMapElementException.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; - -namespace ProGaudi.MsgPack.Light.Converters.Generation.Exceptions -{ - public class DuplicateMapElementException : GeneratorException - { - public DuplicateMapElementException(Type type, string key, PropertyInfo[] properties) - : base($"Duplicate key '{key}' in type '{type}'. Properties: {string.Join(", ", properties.Select(x => $"{x.DeclaringType.Name}.{x.Name}"))}.") - { - Type = type; - Key = key; - Properties = properties; - } - - public Type Type { get; } - - public string Key { get; } - - public PropertyInfo[] Properties { get; } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/Generation/Exceptions/GeneratorException.cs b/src/msgpack.light/Converters/Generation/Exceptions/GeneratorException.cs deleted file mode 100644 index 4e3ad6f..0000000 --- a/src/msgpack.light/Converters/Generation/Exceptions/GeneratorException.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.Serialization; - -namespace ProGaudi.MsgPack.Light.Converters.Generation.Exceptions -{ - public class GeneratorException : SerializationException - { - public GeneratorException(string message) - : base(message) - { - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/Generation/Extensions.cs b/src/msgpack.light/Converters/Generation/Extensions.cs deleted file mode 100644 index cff7061..0000000 --- a/src/msgpack.light/Converters/Generation/Extensions.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -namespace ProGaudi.MsgPack.Light.Converters.Generation -{ - public static class Extensions - { - public static Type ToType(this TypeBuilder typeBuilder) - { -#if NET46 - return typeBuilder.CreateType(); -#else - return typeBuilder.CreateTypeInfo().AsType(); -#endif - } - - public static string GetNormalizedName(this Type type) - { - return type.GetTypeInfo().IsInterface && type.Name.StartsWith("I") ? type.Name.Substring(1) : type.Name; - } - - public static IEnumerable GetMembersFromInterface(this Type typeToWrap, Func> getter) - { - foreach (var member in getter(typeToWrap)) - { - yield return member; - } - - foreach (var @interface in typeToWrap.GetTypeInfo().ImplementedInterfaces) - { - foreach (var member in GetMembersFromInterface(@interface, getter)) - { - yield return member; - } - } - } - - public static ConstructorInfo GetDefaultConstructor(this TypeInfo type) - { - return type.GetConstructor(new Type[0]); - } - - public static string GetMapElementName(this PropertyInfo info) - { - return info.GetCustomAttribute().Name; - } - - public static int GetArrayElementOrder(this PropertyInfo info) - { - return info.GetCustomAttribute().Order; - } - - public static MethodInfo GetGenericMethod(this TypeInfo type, string name, byte number) - { - return type.DeclaredMethods.SingleOrDefault(x => x.Name == name && x.GetGenericArguments().Length == number); - } - -#if NETSTANDARD1_1 - public static ConstructorInfo GetConstructor(this TypeInfo type, Type[] parameters) - { - foreach (var constructor in type.DeclaredConstructors) - { - var declaredParameters = constructor.GetParameters(); - if (ParameterMatch(declaredParameters, parameters)) - return constructor; - } - - return null; - } - - public static PropertyInfo GetProperty(this TypeInfo type, string name) - { - return type.DeclaredProperties.SingleOrDefault(x => x.Name == name); - } - - public static MethodInfo GetMethod(this TypeInfo type, string name) - { - return type.DeclaredMethods.SingleOrDefault(x => x.Name == name); - } - - public static MethodInfo GetMethod(this TypeInfo type, string name, Type[] parameters) - { - foreach (var method in type.DeclaredMethods.Where(x => x.Name == name)) - { - var declaredParameters = method.GetParameters(); - if (ParameterMatch(declaredParameters, parameters)) - return method; - } - - return null; - } - - private static bool ParameterMatch(IReadOnlyList parameters, IReadOnlyList types) - { - if (parameters.Count != types.Count) - { - return false; - } - - for (var i = 0; i < parameters.Count; i++) - { - if (parameters[i].ParameterType != types[i]) - { - return false; - } - } - - return true; - } -#endif - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/Generation/InterfaceStubGenerator.cs b/src/msgpack.light/Converters/Generation/InterfaceStubGenerator.cs deleted file mode 100644 index be2077a..0000000 --- a/src/msgpack.light/Converters/Generation/InterfaceStubGenerator.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -namespace ProGaudi.MsgPack.Light.Converters.Generation -{ - public class InterfaceStubGenerator - { - private readonly ModuleBuilder _moduleBuilder; - - private readonly string _namespaceToPlace; - - private readonly PropertyProvider _propertyProvider = new PropertyProvider(); - - public InterfaceStubGenerator(ModuleBuilder moduleBuilder, string namespaceToPlace) - { - _moduleBuilder = moduleBuilder; - _namespaceToPlace = namespaceToPlace; - } - - public Type GenerateTypeToInstantinate(Type typeToWrap, Func nameMangler) - { - var typeInfo = typeToWrap.GetTypeInfo(); - var isInterface = typeInfo.IsInterface; - if (!isInterface) - { - throw new ArgumentException($"{typeToWrap.Name} should be interface", nameof(typeToWrap)); - } - - if (typeInfo.IsGenericTypeDefinition) - { - throw new NotImplementedException("Can't generate generic implementors."); - } - - var typeBuilder = _moduleBuilder.DefineType( - $"{_namespaceToPlace}.{nameMangler(typeToWrap.GetNormalizedName())}", - TypeAttributes.Public, - typeof(object)); - - typeBuilder.AddInterfaceImplementation(typeToWrap); - - var methodToSkip = new HashSet(); - var properties = _propertyProvider.GetProperties(typeToWrap); - foreach (var info in properties) - { - GenerateProperty(info, typeBuilder); - if (info.GetMethod != null) - methodToSkip.Add(info.GetMethod); - - if (info.SetMethod != null) - methodToSkip.Add(info.SetMethod); - } - - foreach (var method in typeToWrap.GetMembersFromInterface(x => x.GetTypeInfo().DeclaredMethods).Where(x => !methodToSkip.Contains(x))) - { - GenerateNotImplementedMethod(method, typeBuilder); - } - - return typeBuilder.ToType(); - } - - private static void GenerateNotImplementedMethod(MethodInfo method, TypeBuilder typeBuilder) - { - var mb = typeBuilder.DefineMethod( - method.Name, - MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, - CallingConventions.HasThis); - mb.SetReturnType(method.ReturnType); - mb.SetParameters(method.GetParameters().Select(x => x.ParameterType).ToArray()); - if (method.ContainsGenericParameters) - { - throw new NotImplementedException("Can't generate generic methods"); - } - - var generator = mb.GetILGenerator(); - - // ReSharper disable once AssignNullToNotNullAttribute - generator.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetTypeInfo().DeclaredConstructors.First(x => x.GetParameters().Length == 0)); - generator.Emit(OpCodes.Throw); - generator.Emit(OpCodes.Ret); - } - - private static void GenerateProperty(PropertyInfo info, TypeBuilder typeBuilder) - { - var propertyType = info.PropertyType; - - var field = typeBuilder.DefineField( - $"_{info.Name.Substring(0, 1).ToLowerInvariant()}{info.Name.Substring(1)}", - propertyType, - FieldAttributes.Private); - - var property = typeBuilder.DefineProperty(info.Name, PropertyAttributes.None, propertyType, new Type[0]); - property.SetGetMethod(GenerateGetter(info, typeBuilder, field)); - property.SetSetMethod(GenerateSetter(info, typeBuilder, field)); - } - - private static MethodBuilder GenerateSetter(PropertyInfo info, TypeBuilder typeBuilder, FieldInfo field) - { - var setter = typeBuilder.DefineMethod( - $"set_{info.Name}", - MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Public | - MethodAttributes.Virtual, - CallingConventions.HasThis); - - setter.SetReturnType(typeof(void)); - setter.SetParameters(field.FieldType); - var generator = setter.GetILGenerator(); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Stfld, field); - generator.Emit(OpCodes.Ret); - - return setter; - } - - private static MethodBuilder GenerateGetter(PropertyInfo info, TypeBuilder typeBuilder, FieldBuilder field) - { - var getter = typeBuilder.DefineMethod( - $"get_{info.Name}", - MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Public | - MethodAttributes.Virtual, - CallingConventions.HasThis); - - getter.SetReturnType(field.FieldType); - var generator = getter.GetILGenerator(); - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, field); - generator.Emit(OpCodes.Ret); - - return getter; - } - } -} diff --git a/src/msgpack.light/Converters/Generation/MapConverterGenerator.cs b/src/msgpack.light/Converters/Generation/MapConverterGenerator.cs deleted file mode 100644 index a582be0..0000000 --- a/src/msgpack.light/Converters/Generation/MapConverterGenerator.cs +++ /dev/null @@ -1,215 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; - -namespace ProGaudi.MsgPack.Light.Converters.Generation -{ - public class MapConverterGenerator : ConverterGeneratorBase - { - public MapConverterGenerator(ModuleBuilder moduleBuilder, string namespaceToPlace) - : base(moduleBuilder, namespaceToPlace, "MapConverter") - { - } - - protected override IEnumerable FilterProperties(Type typeToWrap, ImmutableArray allProperties) - { - var properties = allProperties - .Where(x => x.GetCustomAttribute() != null) - .GroupBy(x => x.GetMapElementName()) - .ToDictionary(x => x.Key, x => x.ToArray()); - - foreach (var pair in properties) - { - if (pair.Value.Length > 1) - { - throw ExceptionUtils.DuplicateMapElement(typeToWrap, pair); - } - - yield return pair.Value[0]; - } - } - - protected override MethodBuilder EmitReadImplMethod( - TypeBuilder typeBuilder, - Type typeToInstantinate, - ImmutableArray propsToWrap, - ImmutableDictionary converters) - { - var mb = typeBuilder.DefineMethod( - $"{nameof(IMsgPackConverter.Read)}Impl", - MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig, - CallingConventions.HasThis); - mb.SetReturnType(typeToInstantinate); - mb.SetParameters(typeof(IMsgPackReader)); - - var generator = mb.GetILGenerator(); - - var instance = generator.DeclareLocal(typeToInstantinate); - var length = generator.DeclareLocal(typeof(uint?)); - var propertyName = generator.DeclareLocal(typeof(string)); - var index = generator.DeclareLocal(typeof(int)); - - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Callvirt, typeof(IMsgPackReader).GetTypeInfo().GetMethod(nameof(IMsgPackReader.ReadMapLength))); - generator.Emit(OpCodes.Stloc, length); - - var nonNullLabel = generator.DefineLabel(); - generator.Emit(OpCodes.Ldloca, length); - generator.Emit(OpCodes.Call, typeof(uint?).GetTypeInfo().GetProperty(nameof(Nullable.HasValue)).GetMethod); - generator.Emit(OpCodes.Brtrue, nonNullLabel); - generator.Emit(OpCodes.Ldnull); - generator.Emit(OpCodes.Ret); - - generator.MarkLabel(nonNullLabel); - generator.Emit(OpCodes.Newobj, typeToInstantinate.GetTypeInfo().GetDefaultConstructor()); - generator.Emit(OpCodes.Stloc, instance); - - var beginOfIteration = generator.DefineLabel(); - var conditionLabel = generator.DefineLabel(); - var incrementLabel = generator.DefineLabel(); - generator.Emit(OpCodes.Ldc_I4_0); - generator.Emit(OpCodes.Stloc, index); - generator.Emit(OpCodes.Br, conditionLabel); - - void EmitRead(Type type) - { - var converter = converters[type]; - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, converter); - generator.Emit(OpCodes.Callvirt, converter.FieldType.GetTypeInfo().GetProperty(nameof(Lazy.Value)).GetMethod); - generator.Emit(OpCodes.Ldarg_1); - generator.Emit( - OpCodes.Callvirt, - converter.FieldType.GenericTypeArguments[0].GetTypeInfo().GetMethod(nameof(IMsgPackConverter.Read), new[] {typeof(IMsgPackReader)})); - } - - generator.MarkLabel(beginOfIteration); - EmitRead(typeof(string)); - generator.Emit(OpCodes.Stloc, propertyName); - - var next = default(Label?); - foreach (var property in propsToWrap) - { - if (next.HasValue) - { - generator.MarkLabel(next.Value); - } - - next = generator.DefineLabel(); - generator.Emit(OpCodes.Ldloc, propertyName); - generator.Emit(OpCodes.Ldstr, property.GetMapElementName()); - generator.Emit(OpCodes.Ldc_I4, (int) StringComparison.OrdinalIgnoreCase); - generator.Emit( - OpCodes.Call, - typeof(string).GetTypeInfo().GetMethod( - nameof(string.Equals), - new[] {typeof(string), typeof(string), typeof(StringComparison)})); - generator.Emit(OpCodes.Brfalse, next.Value); - - generator.Emit(OpCodes.Ldloc, instance); - EmitRead(property.PropertyType); - // if property has setter, we will call it. Otherwise we'll try to find it on implementation. - generator.Emit(OpCodes.Callvirt, GetPropertySetter(typeToInstantinate, property)); - - generator.Emit(OpCodes.Br, incrementLabel); - } - - if (next.HasValue) - { - generator.MarkLabel(next.Value); - } - - generator.Emit(OpCodes.Ldarg_1); - generator.Emit(OpCodes.Callvirt, typeof(IMsgPackReader).GetTypeInfo().GetMethod(nameof(IMsgPackReader.SkipToken))); - - generator.MarkLabel(incrementLabel); - generator.Emit(OpCodes.Ldloc, index); - generator.Emit(OpCodes.Ldc_I4_1); - generator.Emit(OpCodes.Add); - generator.Emit(OpCodes.Stloc, index); - - generator.MarkLabel(conditionLabel); - generator.Emit(OpCodes.Ldloc, index); - generator.Emit(OpCodes.Conv_I8); - generator.Emit(OpCodes.Ldloca, length); - generator.Emit(OpCodes.Call, length.LocalType.GetTypeInfo().GetProperty(nameof(Nullable.Value)).GetMethod); - generator.Emit(OpCodes.Conv_U8); - generator.Emit(OpCodes.Blt, beginOfIteration); - - generator.Emit(OpCodes.Ldloc, instance); - generator.Emit(OpCodes.Ret); - - return mb; - } - - protected override MethodBuilder EmitWriteImplMethod( - TypeBuilder typeBuilder, - Type typeToWrap, - ImmutableArray propsToWrap, - ImmutableDictionary converters) - { - var mb = typeBuilder.DefineMethod( - $"{nameof(IMsgPackConverter.Write)}Impl", - MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig, - CallingConventions.HasThis); - mb.SetReturnType(typeof(void)); - mb.SetParameters(typeToWrap, typeof(IMsgPackWriter)); - - var generator = mb.GetILGenerator(); - - var notNullCode = generator.DefineLabel(); - var value = OpCodes.Ldarg_1; - generator.Emit(value); - generator.Emit(OpCodes.Brtrue, notNullCode); - - // emit null version - var writer = OpCodes.Ldarg_2; - generator.Emit(writer); - generator.Emit(OpCodes.Ldc_I4, (int) DataTypes.Null); - generator.Emit( - OpCodes.Callvirt, - typeof(IMsgPackWriter).GetTypeInfo().GetMethod(nameof(IMsgPackWriter.Write), new[] {typeof(DataTypes)})); - generator.Emit(OpCodes.Ret); - - // emit not-null version - generator.MarkLabel(notNullCode); - generator.Emit(writer); - generator.Emit(OpCodes.Ldc_I4, propsToWrap.Length); - generator.Emit(OpCodes.Callvirt, typeof(IMsgPackWriter).GetTypeInfo().GetMethod(nameof(IMsgPackWriter.WriteMapHeader))); - - void EmitWrite(Type type, Action valueLoader) - { - var converter = converters[type]; - generator.Emit(OpCodes.Ldarg_0); - generator.Emit(OpCodes.Ldfld, converter); - generator.Emit(OpCodes.Callvirt, converter.FieldType.GetTypeInfo().GetProperty(nameof(Lazy.Value)).GetMethod); - valueLoader(generator); - generator.Emit(writer); - generator.Emit( - OpCodes.Callvirt, - converter.FieldType.GenericTypeArguments[0].GetTypeInfo().GetMethod(nameof(IMsgPackConverter.Write), new[] {type, typeof(IMsgPackWriter)})); - } - - foreach (var property in propsToWrap) - { - EmitWrite( - typeof(string), - x => x.Emit(OpCodes.Ldstr, property.GetMapElementName())); - EmitWrite( - property.PropertyType, - x => - { - x.Emit(OpCodes.Ldarg_1); - x.Emit(OpCodes.Callvirt, property.GetMethod); - }); - } - - generator.Emit(OpCodes.Ret); - - return mb; - } - } -} diff --git a/src/msgpack.light/Converters/Generation/PropertyProvider.cs b/src/msgpack.light/Converters/Generation/PropertyProvider.cs deleted file mode 100644 index 280020d..0000000 --- a/src/msgpack.light/Converters/Generation/PropertyProvider.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Reflection; - -namespace ProGaudi.MsgPack.Light.Converters.Generation -{ - public class PropertyProvider - { - private readonly ConcurrentDictionary> _cacheByName = new ConcurrentDictionary>(); - private readonly ConcurrentDictionary> _cacheByOrder = new ConcurrentDictionary>(); - - public ImmutableArray GetProperties(Type type) - { - return GetPropertiesFromCache(type, _cacheByOrder); - } - - public PropertyInfo GetPropertyByName(Type type, string name) - { - var cache = GetPropertiesFromCache(type, _cacheByName); - return cache.TryGetValue(name, out var r) ? r : null; - } - - private T GetPropertiesFromCache(Type type, ConcurrentDictionary cache) - { - if (cache.TryGetValue(type, out var r)) - return r; - - Discover(type); - - return cache[type]; - } - - private void Discover(Type type) - { - var cacheByName = new Dictionary(); - var cacheByOrder = new List(); - foreach (var info in DiscoverProperties(type)) - { - if (cacheByName.ContainsKey(info.Name)) continue; - cacheByName[info.Name] = info; - cacheByOrder.Add(info); - } - - _cacheByName[type] = cacheByName.ToImmutableDictionary(x => x.Key, x => x.Value); - _cacheByOrder[type] = cacheByOrder.ToImmutableArray(); - } - - private IEnumerable DiscoverProperties(Type type) - { - if (type == null) - yield break; - - var typeInfo = type.GetTypeInfo(); - foreach (var property in typeInfo.DeclaredProperties) - { - yield return property; - } - - if (typeInfo.IsInterface) - { - foreach (var property in typeInfo.ImplementedInterfaces.SelectMany(DiscoverProperties)) - { - yield return property; - } - } - else - { - foreach (var property in DiscoverProperties(typeInfo.BaseType)) - { - yield return property; - } - } - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/List/ConstrainedFormatter.cs b/src/msgpack.light/Converters/List/ConstrainedFormatter.cs new file mode 100644 index 0000000..627f26a --- /dev/null +++ b/src/msgpack.light/Converters/List/ConstrainedFormatter.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.List +{ + public sealed class ConstrainedFormatter : IMsgPackFormatter + where TList : IList + { + public byte? Code { get; } + + public int? MinSize { get; } + + public int? MaxSize { get; } + + public bool Nullable { get; } + + private readonly IMsgPackFormatter _elementFormatter; + + public ConstrainedFormatter( + MsgPackContext context, + byte? code = null, + int? minSize = null, + int? maxSize = null, + bool nullable = true) + { + Code = code; + MinSize = minSize; + MaxSize = maxSize; + Nullable = nullable; + + _elementFormatter = context.GetRequiredFormatter(); + + if (minSize.HasValue && maxSize.HasValue && minSize > maxSize) + { + throw ExceptionUtils.MinimumShouldBeLessThanOrEqualToMaximum(minSize.Value, maxSize.Value); + } + + if (code == null) return; + + var codeValue = code.Value; + + if (MsgPackSpec.GetDataFamily(codeValue) != DataFamily.Array) + throw ExceptionUtils.BadCodeConstraint(codeValue, DataFamily.Array); + + (MinSize, MaxSize) = Converters.Extensions.ValidateMinMaxCode(code.Value, minSize, maxSize); + } + + int IMsgPackFormatter.GetBufferSize(TList value) => value.GetBufferSize(_elementFormatter); + + public bool HasConstantSize => !Nullable && _elementFormatter.HasConstantSize && MinSize.HasValue && MinSize == MaxSize; + + int IMsgPackFormatter.Format(Span destination, TList value) + { + if (value == null) return MsgPackSpec.WriteNil(destination); + + var span = value; + var length = span.Count; + Converters.Extensions.CheckMinMax(length, MinSize, MaxSize); + + var result = WriteHeader(destination, length); + + for (var i = 0; i < length; i++) + { + result += _elementFormatter.Format(destination.Slice(result), span[i]); + } + + return result; + } + + private int WriteHeader(Span buffer, int length) + { + switch (Code) + { + case null: + return MsgPackSpec.WriteArrayHeader(buffer, length); + case DataCodes.Array16: + return MsgPackSpec.WriteArray16Header(buffer, (ushort)length); + case DataCodes.Array32: + return MsgPackSpec.WriteArray32Header(buffer, (uint)length); + default: + return MsgPackSpec.WriteFixArrayHeader(buffer, (byte)length); + } + } + } +} diff --git a/src/msgpack.light/Converters/List/Extensions.cs b/src/msgpack.light/Converters/List/Extensions.cs new file mode 100644 index 0000000..e7ebc82 --- /dev/null +++ b/src/msgpack.light/Converters/List/Extensions.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.List +{ + internal static class Extensions + { + public static int GetBufferSize(this TList value, IMsgPackFormatter elementFormatter) + where TList : IList + { + if (value == null) + return DataLengths.Nil; + + if (value.Count == 0) + return DataLengths.FixArrayHeader; + + if (elementFormatter.HasConstantSize) + return value.Count * elementFormatter.GetBufferSize(value[0]) + DataLengths.GetArrayHeaderLength(value.Count); + + var result = DataLengths.Array32Header; + for (var i = 0; i < value.Count; i++) + { + result += elementFormatter.GetBufferSize(value[i]); + } + + return result; + } + } +} diff --git a/src/msgpack.light/Converters/List/Parser.cs b/src/msgpack.light/Converters/List/Parser.cs new file mode 100644 index 0000000..e84df74 --- /dev/null +++ b/src/msgpack.light/Converters/List/Parser.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace ProGaudi.MsgPack.Converters.List +{ + public sealed class Parser : IMsgPackParser + where TList : IList, new() + { + private readonly IMsgPackParser _elementParser; + + public Parser(MsgPackContext context) + { + _elementParser = context.GetRequiredParser(); + } + + public TList Parse(ReadOnlySpan source, out int readSize) + { + return MsgPackSpec.TryReadNil(source, out readSize) ? default : Read(source, out readSize); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private TList Read(ReadOnlySpan source, out int readSize) + { + var length = MsgPackSpec.ReadArrayHeader(source, out readSize); + var array = new TList(); + for (var i = 0; i < length; i++) + { + array.Add(_elementParser.Parse(source.Slice(readSize), out var temp)); + readSize += temp; + } + + return array; + } + } +} diff --git a/src/msgpack.light/Converters/List/SequenceParser.cs b/src/msgpack.light/Converters/List/SequenceParser.cs new file mode 100644 index 0000000..4cb0c78 --- /dev/null +++ b/src/msgpack.light/Converters/List/SequenceParser.cs @@ -0,0 +1,37 @@ +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace ProGaudi.MsgPack.Converters.List +{ + public sealed class SequenceParser : IMsgPackSequenceParser + where TList : IList, new() + { + private readonly IMsgPackSequenceParser _elementSequenceParser; + + public SequenceParser(MsgPackContext context) + { + _elementSequenceParser = context.GetRequiredSequenceParser(); + } + + public TList Parse(ReadOnlySequence source, out int readSize) + { + return MsgPackSpec.TryReadNil(source, out readSize) ? default : Read(source, out readSize); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private TList Read(ReadOnlySequence source, out int readSize) + { + var length = MsgPackSpec.ReadArrayHeader(source, out readSize); + var array = new TList(); + for (var i = 0; i < length; i++) + { + array.Add(_elementSequenceParser.Parse(source.Slice(readSize), out var temp)); + readSize += temp; + } + + return array; + } + } +} diff --git a/src/msgpack.light/Converters/List/UsualFormatter.cs b/src/msgpack.light/Converters/List/UsualFormatter.cs new file mode 100644 index 0000000..3315ff3 --- /dev/null +++ b/src/msgpack.light/Converters/List/UsualFormatter.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.List +{ + public sealed class UsualFormatter : IMsgPackFormatter + where TList : IList + { + private readonly IMsgPackFormatter _elementFormatter; + + public UsualFormatter(MsgPackContext context) + { + _elementFormatter = context.GetRequiredFormatter(); + } + + int IMsgPackFormatter.GetBufferSize(TList value) => value.GetBufferSize(_elementFormatter); + + public bool HasConstantSize => false; + + int IMsgPackFormatter.Format(Span destination, TList value) + { + if (value == null) return MsgPackSpec.WriteNil(destination); + + var result = MsgPackSpec.WriteArrayHeader(destination, value.Count); + for (var i = 0; i < value.Count; i++) + { + result += _elementFormatter.Format(destination.Slice(result), value[i]); + } + + return result; + } + } +} diff --git a/src/msgpack.light/Converters/Map/Parser.cs b/src/msgpack.light/Converters/Map/Parser.cs new file mode 100644 index 0000000..bbb8c42 --- /dev/null +++ b/src/msgpack.light/Converters/Map/Parser.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.Map +{ + public sealed class Parser : IMsgPackParser + where TMap : IDictionary, new() + { + private readonly IMsgPackParser _keyParser; + private readonly IMsgPackParser _valueParser; + + public Parser(MsgPackContext context) + { + _keyParser = context.GetRequiredParser(); + _valueParser = context.GetRequiredParser(); + } + + public TMap Parse(ReadOnlySpan source, out int readSize) + { + if (MsgPackSpec.TryReadNil(source, out readSize)) return default; + + var count = MsgPackSpec.ReadMapHeader(source, out readSize); + var result = new TMap(); + + for (var i = 0; i < count; i++) + { + var key = _keyParser.Parse(source.Slice(readSize), out var read); + readSize += read; + var value = _valueParser.Parse(source.Slice(readSize), out read); + readSize += read; + result[key] = value; + } + + return result; + } + } +} diff --git a/src/msgpack.light/Converters/Map/SequenceParser.cs b/src/msgpack.light/Converters/Map/SequenceParser.cs new file mode 100644 index 0000000..a36dbcd --- /dev/null +++ b/src/msgpack.light/Converters/Map/SequenceParser.cs @@ -0,0 +1,38 @@ +using System; +using System.Buffers; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.Map +{ + public sealed class SequenceParser : IMsgPackSequenceParser + where TMap : IDictionary, new() + { + private readonly IMsgPackSequenceParser _keySequenceParser; + private readonly IMsgPackSequenceParser _valueSequenceParser; + + public SequenceParser(MsgPackContext context) + { + _keySequenceParser = context.GetRequiredSequenceParser(); + _valueSequenceParser = context.GetRequiredSequenceParser(); + } + + public TMap Parse(ReadOnlySequence source, out int readSize) + { + if (MsgPackSpec.TryReadNil(source, out readSize)) return default; + + var count = MsgPackSpec.ReadMapHeader(source, out readSize); + var result = new TMap(); + + for (var i = 0; i < count; i++) + { + var key = _keySequenceParser.Parse(source.Slice(readSize), out var read); + readSize += read; + var value = _valueSequenceParser.Parse(source.Slice(readSize), out read); + readSize += read; + result[key] = value; + } + + return result; + } + } +} diff --git a/src/msgpack.light/Converters/Map/UsualFormatter.cs b/src/msgpack.light/Converters/Map/UsualFormatter.cs new file mode 100644 index 0000000..661379e --- /dev/null +++ b/src/msgpack.light/Converters/Map/UsualFormatter.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.Map +{ + public sealed class UsualFormatter : IMsgPackFormatter + where TMap : IDictionary + { + private readonly IMsgPackFormatter _keyFormatter; + private readonly IMsgPackFormatter _valueFormatter; + + public UsualFormatter(MsgPackContext context) + { + _keyFormatter = context.GetRequiredFormatter(); + _valueFormatter = context.GetRequiredFormatter(); + } + + public int GetBufferSize(TMap value) => value == null + ? DataLengths.Nil + : value.GetMapBufferSize(value.Count, _keyFormatter, _valueFormatter); + + public bool HasConstantSize => false; + + public int Format(Span destination, TMap value) => value == null + ? MsgPackSpec.WriteNil(destination) + : value.FormatTo(destination, value.Count, _keyFormatter, _valueFormatter); + } +} diff --git a/src/msgpack.light/Converters/MapConverter.cs b/src/msgpack.light/Converters/MapConverter.cs deleted file mode 100644 index 136f39b..0000000 --- a/src/msgpack.light/Converters/MapConverter.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Collections.Generic; - -namespace ProGaudi.MsgPack.Light.Converters -{ - internal class MapConverter : MapConverterBase - where TMap : IDictionary - { - public override void Write(TMap value, IMsgPackWriter writer) - { - if (value == null) - { - Context.NullConverter.Write(value, writer); - return; - } - - writer.WriteMapHeader((uint) value.Count); - - foreach (var element in value) - { - KeyConverter.Write(element.Key, writer); - ValueConverter.Write(element.Value, writer); - } - } - - public override TMap Read(IMsgPackReader reader) - { - var length = reader.ReadMapLength(); - return length.HasValue ? ReadMap(reader, length.Value) : default(TMap); - } - - private TMap ReadMap(IMsgPackReader reader, uint length) - { - var map = (TMap) Context.GetObjectActivator(typeof(TMap))(); - - for (var i = 0u; i < length; i++) - { - var key = KeyConverter.Read(reader); - var value = ValueConverter.Read(reader); - - map[key] = value; - } - - return map; - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/MapConverterBase.cs b/src/msgpack.light/Converters/MapConverterBase.cs deleted file mode 100644 index c0e5d8c..0000000 --- a/src/msgpack.light/Converters/MapConverterBase.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace ProGaudi.MsgPack.Light.Converters -{ - public abstract class MapConverterBase : IMsgPackConverter - { - public void Initialize(MsgPackContext context) - { - var keyConverter = context.GetConverter(); - var valueConverter = context.GetConverter(); - if (keyConverter == null) - { - throw ExceptionUtils.NoConverterForCollectionElement(typeof(TKey), "key"); - } - - if (valueConverter == null) - { - throw ExceptionUtils.NoConverterForCollectionElement(typeof(TValue), "value"); - } - - KeyConverter = keyConverter; - ValueConverter = valueConverter; - Context = context; - } - - public abstract void Write(TMap value, IMsgPackWriter writer); - - public abstract TMap Read(IMsgPackReader reader); - - protected MsgPackContext Context { get; private set; } - - protected IMsgPackConverter ValueConverter { get; private set; } - - protected IMsgPackConverter KeyConverter { get; private set; } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/MsgPackTokenConverter.cs b/src/msgpack.light/Converters/MsgPackTokenConverter.cs deleted file mode 100644 index 85d0919..0000000 --- a/src/msgpack.light/Converters/MsgPackTokenConverter.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace ProGaudi.MsgPack.Light.Converters -{ - public class MsgPackTokenConverter : IMsgPackConverter - { - private MsgPackContext _context; - - public void Initialize(MsgPackContext context) - { - _context = context; - } - - public void Write(MsgPackToken value, IMsgPackWriter writer) - { - writer.Write(value.RawBytes); - } - - public MsgPackToken Read(IMsgPackReader reader) - { - var rawBytes = reader.ReadToken(); - return new MsgPackToken(_context, rawBytes); - } - } -} diff --git a/src/msgpack.light/Converters/NullConverter.cs b/src/msgpack.light/Converters/NullConverter.cs deleted file mode 100644 index 90b6561..0000000 --- a/src/msgpack.light/Converters/NullConverter.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace ProGaudi.MsgPack.Light.Converters -{ - internal class NullConverter : IMsgPackConverter - { - public void Initialize(MsgPackContext context) - { - } - - public void Write(object value, IMsgPackWriter writer) - { - writer.Write(DataTypes.Null); - } - - public object Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); - if (type == DataTypes.Null) - return null; - - throw ExceptionUtils.BadTypeException(type, DataTypes.Null); - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/NullableConverter.cs b/src/msgpack.light/Converters/NullableConverter.cs index 89a6e5d..d7f9e67 100644 --- a/src/msgpack.light/Converters/NullableConverter.cs +++ b/src/msgpack.light/Converters/NullableConverter.cs @@ -1,42 +1,38 @@ -using System.IO; +using System; +using System.Buffers; -namespace ProGaudi.MsgPack.Light.Converters +namespace ProGaudi.MsgPack.Converters { - public class NullableConverter : IMsgPackConverter + public class NullableConverter : IMsgPackFormatter, IMsgPackParser, IMsgPackSequenceParser where T : struct { - private MsgPackContext _context; + private readonly IMsgPackFormatter _formatter; - private IMsgPackConverter _converter; + private readonly IMsgPackParser _parser; - public T? Read(IMsgPackReader reader) + private readonly IMsgPackSequenceParser _sequenceParser; + + public NullableConverter(MsgPackContext context) { - var type = reader.ReadDataType(); + _formatter = context.GetRequiredFormatter(); + _parser = context.GetRequiredParser(); + _sequenceParser = context.GetRequiredSequenceParser(); + } - if (type == DataTypes.Null) - return null; + public int GetBufferSize(T? value) => value.HasValue ? _formatter.GetBufferSize(value.Value) : DataLengths.Nil; - reader.Seek(-1, SeekOrigin.Current); + public bool HasConstantSize => _formatter.HasConstantSize && _formatter.GetBufferSize(default) == DataLengths.Nil; - return _converter.Read(reader); - } + public int Format(Span destination, T? value) => value.HasValue + ? _formatter.Format(destination, value.Value) + : MsgPackSpec.WriteNil(destination); - public void Write(T? value, IMsgPackWriter writer) - { - if (value.HasValue) - { - _converter.Write(value.Value, writer); - } - else - { - _context.NullConverter.Write(null, writer); - } - } + public T? Parse(ReadOnlySpan source, out int readSize) => MsgPackSpec.TryReadNil(source, out readSize) + ? default(T?) + : _parser.Parse(source, out readSize); - public void Initialize(MsgPackContext context) - { - _context = context; - _converter = context.GetConverter(); - } + public T? Parse(ReadOnlySequence source, out int readSize) => MsgPackSpec.TryReadNil(source, out readSize) + ? default(T?) + : _sequenceParser.Parse(source, out readSize); } } diff --git a/src/msgpack.light/Converters/Number/Parser.cs b/src/msgpack.light/Converters/Number/Parser.cs new file mode 100644 index 0000000..5d7a35e --- /dev/null +++ b/src/msgpack.light/Converters/Number/Parser.cs @@ -0,0 +1,43 @@ +using System; + +namespace ProGaudi.MsgPack.Converters.Number +{ + public sealed class Parser : + IMsgPackParser, + IMsgPackParser, + IMsgPackParser, + IMsgPackParser, + IMsgPackParser, + IMsgPackParser, + IMsgPackParser, + IMsgPackParser, + IMsgPackParser, + IMsgPackParser + { + public static Parser Instance = new Parser(); + + byte IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) => MsgPackSpec.ReadUInt8(source, out readSize); + + sbyte IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) => MsgPackSpec.ReadInt8(source, out readSize); + + short IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) => MsgPackSpec.ReadInt16(source, out readSize); + + ushort IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) => MsgPackSpec.ReadUInt16(source, out readSize); + + int IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) => MsgPackSpec.ReadInt32(source, out readSize); + + uint IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) => MsgPackSpec.ReadUInt32(source, out readSize); + + long IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) => MsgPackSpec.ReadInt64(source, out readSize); + + ulong IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) => MsgPackSpec.ReadUInt64(source, out readSize); + + float IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) => MsgPackSpec.TryReadFloat(source, out var result, out readSize) + ? result + : MsgPackSpec.ReadInt32(source, out readSize); + + double IMsgPackParser.Parse(ReadOnlySpan source, out int readSize) => MsgPackSpec.TryReadDouble(source, out var result, out readSize) + ? result + : MsgPackSpec.ReadInt64(source, out readSize); + } +} diff --git a/src/msgpack.light/Converters/Number/SequenceParser.cs b/src/msgpack.light/Converters/Number/SequenceParser.cs new file mode 100644 index 0000000..fc493e0 --- /dev/null +++ b/src/msgpack.light/Converters/Number/SequenceParser.cs @@ -0,0 +1,44 @@ +using System; +using System.Buffers; + +namespace ProGaudi.MsgPack.Converters.Number +{ + public sealed class SequenceParser : + IMsgPackSequenceParser, + IMsgPackSequenceParser, + IMsgPackSequenceParser, + IMsgPackSequenceParser, + IMsgPackSequenceParser, + IMsgPackSequenceParser, + IMsgPackSequenceParser, + IMsgPackSequenceParser, + IMsgPackSequenceParser, + IMsgPackSequenceParser + { + public static SequenceParser Instance = new SequenceParser(); + + byte IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) => MsgPackSpec.ReadUInt8(source, out readSize); + + sbyte IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) => MsgPackSpec.ReadInt8(source, out readSize); + + short IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) => MsgPackSpec.ReadInt16(source, out readSize); + + ushort IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) => MsgPackSpec.ReadUInt16(source, out readSize); + + int IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) => MsgPackSpec.ReadInt32(source, out readSize); + + uint IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) => MsgPackSpec.ReadUInt32(source, out readSize); + + long IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) => MsgPackSpec.ReadInt64(source, out readSize); + + ulong IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) => MsgPackSpec.ReadUInt64(source, out readSize); + + float IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) => MsgPackSpec.TryReadFloat(source, out var result, out readSize) + ? result + : MsgPackSpec.ReadInt32(source, out readSize); + + double IMsgPackSequenceParser.Parse(ReadOnlySequence source, out int readSize) => MsgPackSpec.TryReadDouble(source, out var result, out readSize) + ? result + : MsgPackSpec.ReadInt64(source, out readSize); + } +} diff --git a/src/msgpack.light/Converters/Number/UsualFormatter.cs b/src/msgpack.light/Converters/Number/UsualFormatter.cs new file mode 100644 index 0000000..37085f9 --- /dev/null +++ b/src/msgpack.light/Converters/Number/UsualFormatter.cs @@ -0,0 +1,72 @@ +using System; + +namespace ProGaudi.MsgPack.Converters.Number +{ + public sealed class UsualFormatter : + IMsgPackFormatter, + IMsgPackFormatter, + IMsgPackFormatter, + IMsgPackFormatter, + IMsgPackFormatter, + IMsgPackFormatter, + IMsgPackFormatter, + IMsgPackFormatter, + IMsgPackFormatter, + IMsgPackFormatter + { + private static readonly int ByteLength = DataLengths.GetHeaderLength(DataCodes.UInt8); + private static readonly int SByteLength = DataLengths.GetHeaderLength(DataCodes.Int8); + private static readonly int ShortLength = DataLengths.GetHeaderLength(DataCodes.Int16); + private static readonly int UShortLength = DataLengths.GetHeaderLength(DataCodes.UInt16); + private static readonly int IntLength = DataLengths.GetHeaderLength(DataCodes.Int32); + private static readonly int UIntLength = DataLengths.GetHeaderLength(DataCodes.UInt32); + private static readonly int LongLength = DataLengths.GetHeaderLength(DataCodes.Int64); + private static readonly int ULongLength = DataLengths.GetHeaderLength(DataCodes.UInt64); + private static readonly int FloatLength = DataLengths.GetHeaderLength(DataCodes.Float32); + private static readonly int DoubleLength = DataLengths.GetHeaderLength(DataCodes.Float64); + + public static UsualFormatter Instance = new UsualFormatter(); + + int IMsgPackFormatter.GetBufferSize(byte value) => ByteLength; + + int IMsgPackFormatter.GetBufferSize(sbyte value) => SByteLength; + + int IMsgPackFormatter.GetBufferSize(short value) => ShortLength; + + int IMsgPackFormatter.GetBufferSize(ushort value) => UShortLength; + + int IMsgPackFormatter.GetBufferSize(int value) => IntLength; + + int IMsgPackFormatter.GetBufferSize(uint value) => UIntLength; + + int IMsgPackFormatter.GetBufferSize(long value) => LongLength; + + int IMsgPackFormatter.GetBufferSize(ulong value) => ULongLength; + + int IMsgPackFormatter.GetBufferSize(float value) => FloatLength; + + int IMsgPackFormatter.GetBufferSize(double value) => DoubleLength; + + public bool HasConstantSize => true; + + int IMsgPackFormatter.Format(Span destination, double value) => MsgPackSpec.WriteDouble(destination, value); + + int IMsgPackFormatter.Format(Span destination, float value) => MsgPackSpec.WriteFloat(destination, value); + + int IMsgPackFormatter.Format(Span destination, ulong value) => MsgPackSpec.WriteUInt64(destination, value); + + int IMsgPackFormatter.Format(Span destination, long value) => MsgPackSpec.WriteInt64(destination, value); + + int IMsgPackFormatter.Format(Span destination, uint value) => MsgPackSpec.WriteUInt32(destination, value); + + int IMsgPackFormatter.Format(Span destination, int value) => MsgPackSpec.WriteInt32(destination, value); + + int IMsgPackFormatter.Format(Span destination, ushort value) => MsgPackSpec.WriteUInt16(destination, value); + + int IMsgPackFormatter.Format(Span destination, short value) => MsgPackSpec.WriteInt16(destination, value); + + int IMsgPackFormatter.Format(Span destination, sbyte value) => MsgPackSpec.WriteInt8(destination, value); + + int IMsgPackFormatter.Format(Span destination, byte value) => MsgPackSpec.WriteUInt8(destination, value); + } +} diff --git a/src/msgpack.light/Converters/NumberConverter.cs b/src/msgpack.light/Converters/NumberConverter.cs deleted file mode 100644 index f1a9391..0000000 --- a/src/msgpack.light/Converters/NumberConverter.cs +++ /dev/null @@ -1,986 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace ProGaudi.MsgPack.Light.Converters -{ - internal class NumberConverter : - IMsgPackConverter, - IMsgPackConverter, - IMsgPackConverter, - IMsgPackConverter, - IMsgPackConverter, - IMsgPackConverter, - IMsgPackConverter, - IMsgPackConverter, - IMsgPackConverter, - IMsgPackConverter - { - private readonly bool _strictParseOfFloat; - - public NumberConverter(bool strictParseOfFloat) - { - _strictParseOfFloat = strictParseOfFloat; - } - - public static void WriteByteValue(byte value, IMsgPackWriter writer) - { - writer.Write(value); - } - - public static void WriteUShortValue(ushort value, IMsgPackWriter writer) - { - unchecked - { - writer.Write((byte)((value >> 8) & 0xff)); - writer.Write((byte)(value & 0xff)); - } - } - - public static void WriteUIntValue(uint value, IMsgPackWriter writer) - { - unchecked - { - writer.Write((byte)((value >> 24) & 0xff)); - writer.Write((byte)((value >> 16) & 0xff)); - writer.Write((byte)((value >> 8) & 0xff)); - writer.Write((byte)(value & 0xff)); - } - } - - public void Initialize(MsgPackContext context) - { - } - - public void Write(double value, IMsgPackWriter writer) - { - var binary = new DoubleBinary(value); - byte[] bytes; - if (BitConverter.IsLittleEndian) - { - bytes = new[] - { - (byte) DataTypes.Double, - binary.byte7, - binary.byte6, - binary.byte5, - binary.byte4, - binary.byte3, - binary.byte2, - binary.byte1, - binary.byte0 - }; - } - else - { - bytes = new[] - { - (byte) DataTypes.Double, - binary.byte0, - binary.byte1, - binary.byte2, - binary.byte3, - binary.byte4, - binary.byte5, - binary.byte6, - binary.byte7 - }; - } - - writer.Write(bytes); - } - - double IMsgPackConverter.Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); - - if (type != DataTypes.Single && type != DataTypes.Double) - { - if (_strictParseOfFloat) - throw ExceptionUtils.BadTypeException(type, DataTypes.Single, DataTypes.Double); - - return TryGetInt64(type, reader) ?? throw ExceptionUtils.BadTypeException(type, DataTypes.Single, DataTypes.Double); - } - - if (type == DataTypes.Single) - { - return ReadFloat(reader); - } - - var bytes = ReadBytes(reader, 8); - - return new DoubleBinary(bytes).value; - } - - public void Write(float value, IMsgPackWriter writer) - { - var binary = new FloatBinary(value); - byte[] bytes; - if (BitConverter.IsLittleEndian) - { - bytes = new[] - { - (byte) DataTypes.Single, - binary.byte3, - binary.byte2, - binary.byte1, - binary.byte0 - }; - } - else - { - bytes = new[] - { - (byte) DataTypes.Single, - binary.byte0, - binary.byte1, - binary.byte2, - binary.byte3 - }; - } - - writer.Write(bytes); - } - - float IMsgPackConverter.Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); - - if (type == DataTypes.Single) - { - return ReadFloat(reader); - } - - if (_strictParseOfFloat) - { - throw ExceptionUtils.BadTypeException(type, DataTypes.Single); - } - - return TryGetInt32(type, reader) ?? throw ExceptionUtils.BadTypeException(type, DataTypes.Single); - } - - public void Write(byte value, IMsgPackWriter writer) - { - // positive fixnum - if (value < 128L) - { - writer.Write(value); - } - else - { - writer.Write(DataTypes.UInt8); - WriteByteValue(value, writer); - } - } - - byte IMsgPackConverter.Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); - - if (TryGetFixPositiveNumber(type, out byte temp)) - { - return temp; - } - - if (TryGetNegativeNumber(type, out sbyte tempInt8)) - { - return (byte)tempInt8; - } - - switch (type) - { - case DataTypes.UInt8: - return ReadUInt8(reader); - - case DataTypes.Int8: - return (byte)ReadInt8(reader); - - default: - throw ExceptionUtils.IntDeserializationFailure(type); - } - } - - public void Write(sbyte value, IMsgPackWriter writer) - { - WriteInteger(value, writer); - } - - sbyte IMsgPackConverter.Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); - - if (TryGetFixPositiveNumber(type, out byte temp)) - { - return (sbyte)temp; - } - - if (TryGetNegativeNumber(type, out sbyte tempInt8)) - { - return tempInt8; - } - - if (type == DataTypes.Int8) - { - return ReadInt8(reader); - } - - throw ExceptionUtils.IntDeserializationFailure(type); - } - - public void Write(short value, IMsgPackWriter writer) - { - WriteInteger(value, writer); - } - - short IMsgPackConverter.Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); - - if (TryGetFixPositiveNumber(type, out byte temp)) - { - return temp; - } - - if (TryGetNegativeNumber(type, out sbyte tempInt8)) - { - return tempInt8; - } - - switch (type) - { - case DataTypes.UInt8: - return ReadUInt8(reader); - - case DataTypes.UInt16: - var ushortValue = ReadUInt16(reader); - if (ushortValue <= short.MaxValue) - { - return (short)ushortValue; - } - - throw ExceptionUtils.IntDeserializationFailure(type); - - case DataTypes.Int8: - return ReadInt8(reader); - - case DataTypes.Int16: - return ReadInt16(reader); - - default: - throw ExceptionUtils.IntDeserializationFailure(type); - } - } - - public void Write(ushort value, IMsgPackWriter writer) - { - WriteNonNegativeInteger(value, writer); - } - - public ushort Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); - - if (TryGetFixPositiveNumber(type, out byte temp)) - { - return temp; - } - - if (TryGetNegativeNumber(type, out sbyte tempInt8)) - { - return (ushort)tempInt8; - } - - switch (type) - { - case DataTypes.UInt8: - return ReadUInt8(reader); - - case DataTypes.UInt16: - return ReadUInt16(reader); - - case DataTypes.Int8: - return (ushort)ReadInt8(reader); - - case DataTypes.Int16: - return (ushort)ReadInt16(reader); - - default: - throw ExceptionUtils.IntDeserializationFailure(type); - } - } - - public void Write(int value, IMsgPackWriter writer) - { - WriteInteger(value, writer); - } - - int IMsgPackConverter.Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); - - return TryGetInt32(type, reader) ?? throw ExceptionUtils.IntDeserializationFailure(type); - } - - public void Write(uint value, IMsgPackWriter writer) - { - WriteNonNegativeInteger(value, writer); - } - - uint IMsgPackConverter.Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); - - if (TryGetFixPositiveNumber(type, out byte temp)) - { - return temp; - } - - if (TryGetNegativeNumber(type, out sbyte tempInt8)) - { - return (uint)tempInt8; - } - - switch (type) - { - case DataTypes.UInt8: - return ReadUInt8(reader); - - case DataTypes.UInt16: - return ReadUInt16(reader); - - case DataTypes.UInt32: - return ReadUInt32(reader); - - case DataTypes.Int8: - return (uint)ReadInt8(reader); - - case DataTypes.Int16: - return (uint)ReadInt16(reader); - - case DataTypes.Int32: - return (uint)ReadInt32(reader); - - default: - throw ExceptionUtils.IntDeserializationFailure(type); - } - } - - public void Write(long value, IMsgPackWriter writer) - { - WriteInteger(value, writer); - } - - long IMsgPackConverter.Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); - - return TryGetInt64(type, reader) ?? throw ExceptionUtils.IntDeserializationFailure(type); - } - - public void Write(ulong value, IMsgPackWriter writer) - { - WriteNonNegativeInteger(value, writer); - } - - ulong IMsgPackConverter.Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); - - if (TryGetFixPositiveNumber(type, out byte temp)) - { - return temp; - } - - if (TryGetNegativeNumber(type, out sbyte tempInt8)) - { - return (ulong)tempInt8; - } - - switch (type) - { - case DataTypes.UInt8: - return ReadUInt8(reader); - - case DataTypes.UInt16: - return ReadUInt16(reader); - - case DataTypes.UInt32: - return ReadUInt32(reader); - - case DataTypes.UInt64: - return ReadUInt64(reader); - - case DataTypes.Int8: - return (ulong)ReadInt8(reader); - - case DataTypes.Int16: - return (ulong)ReadInt16(reader); - - case DataTypes.Int32: - return (ulong)ReadInt32(reader); - - case DataTypes.Int64: - return (ulong)ReadInt64(reader); - - default: - throw ExceptionUtils.IntDeserializationFailure(type); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static sbyte ReadInt8(IMsgPackReader reader) - { - var temp = reader.ReadByte(); - if (temp <= sbyte.MaxValue) - return (sbyte)temp; - - return (sbyte)(temp - byte.MaxValue - 1); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static byte ReadUInt8(IMsgPackReader reader) - { - return reader.ReadByte(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static ushort ReadUInt16(IMsgPackReader reader) - { - return (ushort)((reader.ReadByte() << 8) + reader.ReadByte()); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static short ReadInt16(IMsgPackReader reader) - { - var temp = ReadUInt16(reader); - if (temp <= short.MaxValue) - return (short)temp; - - return (short)(temp - 1 - ushort.MaxValue); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int ReadInt32(IMsgPackReader reader) - { - var temp = ReadUInt32(reader); - if (temp <= int.MaxValue) - return (int)temp; - - return (int)(temp - 1 - uint.MaxValue); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static uint ReadUInt32(IMsgPackReader reader) - { - var temp = (uint)(reader.ReadByte() << 24); - temp += (uint)reader.ReadByte() << 16; - temp += (uint)reader.ReadByte() << 8; - temp += reader.ReadByte(); - - return temp; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong ReadUInt64(IMsgPackReader reader) - { - var temp = (ulong)reader.ReadByte() << 56; - temp += (ulong)reader.ReadByte() << 48; - temp += (ulong)reader.ReadByte() << 40; - temp += (ulong)reader.ReadByte() << 32; - temp += (ulong)reader.ReadByte() << 24; - temp += (ulong)reader.ReadByte() << 16; - temp += (ulong)reader.ReadByte() << 8; - temp += reader.ReadByte(); - - return temp; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static long ReadInt64(IMsgPackReader reader) - { - var temp = ReadUInt64(reader); - if (temp <= long.MaxValue) - return (long)temp; - - return (long)(temp - 1 - ulong.MaxValue); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryWriteSignedFixNum(long value, IMsgPackWriter writer) - { - // positive fixnum - if (value >= 0 && value < 128L) - { - writer.Write(unchecked((byte)value)); - return true; - } - - // negative fixnum - if (value >= -32L && value <= -1L) - { - writer.Write(unchecked((byte)value)); - return true; - } - - return false; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryWriteUnsignedFixNum(ulong value, IMsgPackWriter writer) - { - // positive fixnum - if (value < 128L) - { - writer.Write(unchecked((byte)value)); - return true; - } - - return false; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryWriteInt8(long value, IMsgPackWriter writer) - { - if (value > sbyte.MaxValue || value < sbyte.MinValue) - { - return false; - } - - writer.Write(DataTypes.Int8); - WriteSByteValue((sbyte)value, writer); - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryGetFixPositiveNumber(DataTypes type, out byte temp) - { - temp = (byte)type; - return type.GetHighBits(1) == DataTypes.PositiveFixNum.GetHighBits(1); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryGetNegativeNumber(DataTypes type, out sbyte temp) - { - temp = (sbyte)((byte)type - 1 - byte.MaxValue); - - return type.GetHighBits(3) == DataTypes.NegativeFixNum.GetHighBits(3); - } - - private static int? TryGetInt32(DataTypes type, IMsgPackReader reader) - { - if (TryGetFixPositiveNumber(type, out byte temp)) - { - return temp; - } - - if (TryGetNegativeNumber(type, out sbyte tempInt8)) - { - return tempInt8; - } - - switch (type) - { - case DataTypes.UInt8: - return ReadUInt8(reader); - - case DataTypes.UInt16: - return ReadUInt16(reader); - - case DataTypes.UInt32: - var uintValue = ReadUInt32(reader); - if (uintValue <= int.MaxValue) - { - return (int) uintValue; - } - return null; - - case DataTypes.Int8: - return ReadInt8(reader); - - case DataTypes.Int16: - return ReadInt16(reader); - - case DataTypes.Int32: - return ReadInt32(reader); - - default: - return null; - } - } - - private static long? TryGetInt64(DataTypes type, IMsgPackReader reader) - { - if (TryGetFixPositiveNumber(type, out byte tempUInt8)) - { - return tempUInt8; - } - - if (TryGetNegativeNumber(type, out sbyte tempInt8)) - { - return tempInt8; - } - - switch (type) - { - case DataTypes.UInt8: - return ReadUInt8(reader); - - case DataTypes.UInt16: - return ReadUInt16(reader); - - case DataTypes.UInt32: - return ReadUInt32(reader); - - case DataTypes.UInt64: - var ulongValue = ReadUInt64(reader); - if (ulongValue <= long.MaxValue) - { - return (long) ulongValue; - } - return null; - - case DataTypes.Int8: - return ReadInt8(reader); - - case DataTypes.Int16: - return ReadInt16(reader); - - case DataTypes.Int32: - return ReadInt32(reader); - - case DataTypes.Int64: - return ReadInt64(reader); - - default: - return null; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WriteSByteValue(sbyte value, IMsgPackWriter writer) - { - writer.Write((byte)value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryWriteUInt8(ulong value, IMsgPackWriter writer) - { - if (value > byte.MaxValue) - { - return false; - } - - writer.Write(DataTypes.UInt8); - WriteByteValue((byte)value, writer); - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryWriteInt16(long value, IMsgPackWriter writer) - { - if (value < short.MinValue || value > short.MaxValue) - { - return false; - } - - writer.Write(DataTypes.Int16); - WriteShortValue((short)value, writer); - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WriteShortValue(short value, IMsgPackWriter writer) - { - unchecked - { - writer.Write((byte)((value >> 8) & 0xff)); - writer.Write((byte)(value & 0xff)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryWriteUInt16(ulong value, IMsgPackWriter writer) - { - if (value > ushort.MaxValue) - { - return false; - } - - writer.Write(DataTypes.UInt16); - WriteUShortValue((ushort)value, writer); - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryWriteInt32(long value, IMsgPackWriter writer) - { - if (value > int.MaxValue || value < int.MinValue) - { - return false; - } - - writer.Write(DataTypes.Int32); - WriteIntValue((int)value, writer); - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WriteIntValue(int value, IMsgPackWriter writer) - { - unchecked - { - writer.Write((byte)((value >> 24) & 0xff)); - writer.Write((byte)((value >> 16) & 0xff)); - writer.Write((byte)((value >> 8) & 0xff)); - writer.Write((byte)(value & 0xff)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryWriteUInt32(ulong value, IMsgPackWriter writer) - { - if (value > uint.MaxValue) - { - return false; - } - - writer.Write(DataTypes.UInt32); - WriteUIntValue((uint)value, writer); - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryWriteInt64(long value, IMsgPackWriter writer) - { - writer.Write(DataTypes.Int64); - WriteLongValue(value, writer); - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WriteLongValue(long value, IMsgPackWriter writer) - { - unchecked - { - writer.Write((byte)((value >> 56) & 0xff)); - writer.Write((byte)((value >> 48) & 0xff)); - writer.Write((byte)((value >> 40) & 0xff)); - writer.Write((byte)((value >> 32) & 0xff)); - writer.Write((byte)((value >> 24) & 0xff)); - writer.Write((byte)((value >> 16) & 0xff)); - writer.Write((byte)((value >> 8) & 0xff)); - writer.Write((byte)(value & 0xff)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryWriteUInt64(ulong value, IMsgPackWriter writer) - { - writer.Write(DataTypes.UInt64); - WriteULongValue(value, writer); - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WriteULongValue(ulong value, IMsgPackWriter writer) - { - unchecked - { - writer.Write((byte)((value >> 56) & 0xff)); - writer.Write((byte)((value >> 48) & 0xff)); - writer.Write((byte)((value >> 40) & 0xff)); - writer.Write((byte)((value >> 32) & 0xff)); - writer.Write((byte)((value >> 24) & 0xff)); - writer.Write((byte)((value >> 16) & 0xff)); - writer.Write((byte)((value >> 8) & 0xff)); - writer.Write((byte)(value & 0xff)); - } - } - - private static void WriteInteger(long value, IMsgPackWriter writer) - { - if (value >= 0) - { - WriteNonNegativeInteger((ulong)value, writer); - return; - } - - if (TryWriteSignedFixNum(value, writer)) - { - return; - } - - if (TryWriteInt8(value, writer)) - { - return; - } - - if (TryWriteInt16(value, writer)) - { - return; - } - - if (TryWriteInt32(value, writer)) - { - return; - } - - if (TryWriteInt64(value, writer)) - { - return; - } - - throw ExceptionUtils.IntSerializationFailure(value); - } - - private static void WriteNonNegativeInteger(ulong value, IMsgPackWriter writer) - { - if (TryWriteUnsignedFixNum(value, writer)) - { - return; - } - - if (TryWriteUInt8(value, writer)) - { - return; - } - - if (TryWriteUInt16(value, writer)) - { - return; - } - - if (TryWriteUInt32(value, writer)) - { - return; - } - - if (TryWriteUInt64(value, writer)) - { - return; - } - - throw ExceptionUtils.IntSerializationFailure(value); - } - - private static float ReadFloat(IMsgPackReader reader) - { - var bytes = ReadBytes(reader, 4); - - return new FloatBinary(bytes).value; - } - - private static ArraySegment ReadBytes(IMsgPackReader reader, uint length) - { - return reader.ReadBytes(length); - } - - [StructLayout(LayoutKind.Explicit)] - private struct FloatBinary - { - [FieldOffset(0)] - public readonly float value; - - [FieldOffset(0)] - public readonly byte byte0; - - [FieldOffset(1)] - public readonly byte byte1; - - [FieldOffset(2)] - public readonly byte byte2; - - [FieldOffset(3)] - public readonly byte byte3; - - public FloatBinary(float f) - { - this = default(FloatBinary); - value = f; - } - - public FloatBinary(ArraySegment bytes) - { - value = 0; - if (BitConverter.IsLittleEndian) - { - byte0 = bytes.Array[bytes.Offset + 3]; - byte1 = bytes.Array[bytes.Offset + 2]; - byte2 = bytes.Array[bytes.Offset + 1]; - byte3 = bytes.Array[bytes.Offset + 0]; - } - else - { - byte0 = bytes.Array[bytes.Offset + 0]; - byte1 = bytes.Array[bytes.Offset + 1]; - byte2 = bytes.Array[bytes.Offset + 2]; - byte3 = bytes.Array[bytes.Offset + 3]; - } - } - } - - [StructLayout(LayoutKind.Explicit)] - private struct DoubleBinary - { - [FieldOffset(0)] - public readonly double value; - - [FieldOffset(0)] - public readonly byte byte0; - - [FieldOffset(1)] - public readonly byte byte1; - - [FieldOffset(2)] - public readonly byte byte2; - - [FieldOffset(3)] - public readonly byte byte3; - - [FieldOffset(4)] - public readonly byte byte4; - - [FieldOffset(5)] - public readonly byte byte5; - - [FieldOffset(6)] - public readonly byte byte6; - - [FieldOffset(7)] - public readonly byte byte7; - - public DoubleBinary(double f) - { - this = default(DoubleBinary); - value = f; - } - - public DoubleBinary(ArraySegment bytes) - { - value = 0; - if (BitConverter.IsLittleEndian) - { - byte0 = bytes.Array[bytes.Offset + 7]; - byte1 = bytes.Array[bytes.Offset + 6]; - byte2 = bytes.Array[bytes.Offset + 5]; - byte3 = bytes.Array[bytes.Offset + 4]; - byte4 = bytes.Array[bytes.Offset + 3]; - byte5 = bytes.Array[bytes.Offset + 2]; - byte6 = bytes.Array[bytes.Offset + 1]; - byte7 = bytes.Array[bytes.Offset + 0]; - } - else - { - byte0 = bytes.Array[bytes.Offset + 0]; - byte1 = bytes.Array[bytes.Offset + 1]; - byte2 = bytes.Array[bytes.Offset + 2]; - byte3 = bytes.Array[bytes.Offset + 3]; - byte4 = bytes.Array[bytes.Offset + 4]; - byte5 = bytes.Array[bytes.Offset + 5]; - byte6 = bytes.Array[bytes.Offset + 6]; - byte7 = bytes.Array[bytes.Offset + 7]; - } - } - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/ReadOnlyCollection/ConstrainedFormatter.cs b/src/msgpack.light/Converters/ReadOnlyCollection/ConstrainedFormatter.cs new file mode 100644 index 0000000..6438f65 --- /dev/null +++ b/src/msgpack.light/Converters/ReadOnlyCollection/ConstrainedFormatter.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.ReadOnlyCollection +{ + public sealed class ConstrainedFormatter : IMsgPackFormatter + where TCollection : IReadOnlyCollection + { + public byte? Code { get; } + + public int? MinSize { get; } + + public int? MaxSize { get; } + + public bool Nullable { get; } + + private readonly IMsgPackFormatter _elementFormatter; + + public ConstrainedFormatter( + MsgPackContext context, + byte? code = null, + int? minSize = null, + int? maxSize = null, + bool nullable = true) + { + Code = code; + MinSize = minSize; + MaxSize = maxSize; + Nullable = nullable; + + _elementFormatter = context.GetRequiredFormatter(); + + if (minSize.HasValue && maxSize.HasValue && minSize > maxSize) + { + throw ExceptionUtils.MinimumShouldBeLessThanOrEqualToMaximum(minSize.Value, maxSize.Value); + } + + if (code == null) return; + + var codeValue = code.Value; + + if (MsgPackSpec.GetDataFamily(codeValue) != DataFamily.Array) + throw ExceptionUtils.BadCodeConstraint(codeValue, DataFamily.Array); + + (MinSize, MaxSize) = Converters.Extensions.ValidateMinMaxCode(code.Value, minSize, maxSize); + } + + int IMsgPackFormatter.GetBufferSize(TCollection value) => value.GetBufferSize(_elementFormatter); + + public bool HasConstantSize => !Nullable && _elementFormatter.HasConstantSize && MinSize.HasValue && MinSize == MaxSize; + + int IMsgPackFormatter.Format(Span destination, TCollection value) + { + if (value == null) return MsgPackSpec.WriteNil(destination); + + var span = value; + var length = span.Count; + Converters.Extensions.CheckMinMax(length, MinSize, MaxSize); + + var result = WriteHeader(destination, length); + foreach (var element in value) + { + result += _elementFormatter.Format(destination.Slice(result), element); + } + + return result; + } + + private int WriteHeader(Span buffer, int length) + { + switch (Code) + { + case null: + return MsgPackSpec.WriteArrayHeader(buffer, length); + case DataCodes.Array16: + return MsgPackSpec.WriteArray16Header(buffer, (ushort) length); + case DataCodes.Array32: + return MsgPackSpec.WriteArray32Header(buffer, (uint) length); + default: + return MsgPackSpec.WriteFixArrayHeader(buffer, (byte) length); + } + } + } +} diff --git a/src/msgpack.light/Converters/ReadOnlyCollection/Extensions.cs b/src/msgpack.light/Converters/ReadOnlyCollection/Extensions.cs new file mode 100644 index 0000000..91803f3 --- /dev/null +++ b/src/msgpack.light/Converters/ReadOnlyCollection/Extensions.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Linq; + +namespace ProGaudi.MsgPack.Converters.ReadOnlyCollection +{ + internal static class Extensions + { + public static int GetBufferSize(this TCollection value, IMsgPackFormatter elementFormatter) + where TCollection : IReadOnlyCollection + { + if (value == null) + return DataLengths.Nil; + + if (value.Count == 0) + return DataLengths.FixArrayHeader; + + if (elementFormatter.HasConstantSize) + return value.Count * elementFormatter.GetBufferSize(value.First()) + DataLengths.GetArrayHeaderLength(value.Count); + + var result = DataLengths.Array32Header; + foreach (var element in value) + { + result += elementFormatter.GetBufferSize(element); + } + + return result; + } + } +} diff --git a/src/msgpack.light/Converters/ReadOnlyCollection/UsualFormatter.cs b/src/msgpack.light/Converters/ReadOnlyCollection/UsualFormatter.cs new file mode 100644 index 0000000..2a4edd5 --- /dev/null +++ b/src/msgpack.light/Converters/ReadOnlyCollection/UsualFormatter.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.ReadOnlyCollection +{ + public sealed class UsualFormatter : IMsgPackFormatter + where TCollection : IReadOnlyCollection + { + private readonly IMsgPackFormatter _elementFormatter; + + public UsualFormatter(MsgPackContext context) + { + _elementFormatter = context.GetRequiredFormatter(); + } + + int IMsgPackFormatter.GetBufferSize(TCollection value) => value.GetBufferSize(_elementFormatter); + + public bool HasConstantSize => false; + + int IMsgPackFormatter.Format(Span destination, TCollection value) + { + if (value == null) return MsgPackSpec.WriteNil(destination); + + var result = MsgPackSpec.WriteArrayHeader(destination, value.Count); + foreach (var element in value) + { + result += _elementFormatter.Format(destination.Slice(result), element); + } + + return result; + } + } +} diff --git a/src/msgpack.light/Converters/ReadOnlyList/ConstrainedFormatter.cs b/src/msgpack.light/Converters/ReadOnlyList/ConstrainedFormatter.cs new file mode 100644 index 0000000..ccefc0e --- /dev/null +++ b/src/msgpack.light/Converters/ReadOnlyList/ConstrainedFormatter.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.ReadOnlyList +{ + public sealed class ConstrainedFormatter : IMsgPackFormatter + where TList : IReadOnlyList + { + public byte? Code { get; } + + public int? MinSize { get; } + + public int? MaxSize { get; } + + public bool Nullable { get; } + + private readonly IMsgPackFormatter _elementFormatter; + + public ConstrainedFormatter( + MsgPackContext context, + byte? code = null, + int? minSize = null, + int? maxSize = null, + bool nullable = true) + { + Code = code; + MinSize = minSize; + MaxSize = maxSize; + Nullable = nullable; + + _elementFormatter = context.GetRequiredFormatter(); + + if (minSize.HasValue && maxSize.HasValue && minSize > maxSize) + { + throw ExceptionUtils.MinimumShouldBeLessThanOrEqualToMaximum(minSize.Value, maxSize.Value); + } + + if (code == null) return; + + var codeValue = code.Value; + + if (MsgPackSpec.GetDataFamily(codeValue) != DataFamily.Array) + throw ExceptionUtils.BadCodeConstraint(codeValue, DataFamily.Array); + + (MinSize, MaxSize) = Converters.Extensions.ValidateMinMaxCode(code.Value, minSize, maxSize); + } + + int IMsgPackFormatter.GetBufferSize(TList value) => value.GetBufferSize(_elementFormatter); + + public bool HasConstantSize => !Nullable && _elementFormatter.HasConstantSize && MinSize.HasValue && MinSize == MaxSize; + + int IMsgPackFormatter.Format(Span destination, TList value) + { + if (value == null) return MsgPackSpec.WriteNil(destination); + + var span = value; + var length = span.Count; + Converters.Extensions.CheckMinMax(length, MinSize, MaxSize); + + var result = WriteHeader(destination, length); + + for (var i = 0; i < length; i++) + { + result += _elementFormatter.Format(destination.Slice(result), span[i]); + } + + return result; + } + + private int WriteHeader(Span buffer, int length) + { + switch (Code) + { + case null: + return MsgPackSpec.WriteArrayHeader(buffer, length); + case DataCodes.Array16: + return MsgPackSpec.WriteArray16Header(buffer, (ushort) length); + case DataCodes.Array32: + return MsgPackSpec.WriteArray32Header(buffer, (uint) length); + default: + return MsgPackSpec.WriteFixArrayHeader(buffer, (byte) length); + } + } + } +} diff --git a/src/msgpack.light/Converters/ReadOnlyList/Extensions.cs b/src/msgpack.light/Converters/ReadOnlyList/Extensions.cs new file mode 100644 index 0000000..7a900b8 --- /dev/null +++ b/src/msgpack.light/Converters/ReadOnlyList/Extensions.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.ReadOnlyList +{ + internal static class Extensions + { + public static int GetBufferSize(this TList value, IMsgPackFormatter elementFormatter) + where TList : IReadOnlyList + { + if (value == null) + return DataLengths.Nil; + + if (value.Count == 0) + return DataLengths.FixArrayHeader; + + if (elementFormatter.HasConstantSize) + return value.Count * elementFormatter.GetBufferSize(value[0]) + DataLengths.GetArrayHeaderLength(value.Count); + + var result = DataLengths.Array32Header; + for (var i = 0; i < value.Count; i++) + { + result += elementFormatter.GetBufferSize(value[i]); + } + + return result; + } + } +} diff --git a/src/msgpack.light/Converters/ReadOnlyList/UsualFormatter.cs b/src/msgpack.light/Converters/ReadOnlyList/UsualFormatter.cs new file mode 100644 index 0000000..2f46c2e --- /dev/null +++ b/src/msgpack.light/Converters/ReadOnlyList/UsualFormatter.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.ReadOnlyList +{ + public sealed class UsualFormatter : IMsgPackFormatter + where TList : IReadOnlyList + { + private readonly IMsgPackFormatter _elementFormatter; + + public UsualFormatter(MsgPackContext context) + { + _elementFormatter = context.GetRequiredFormatter(); + } + + int IMsgPackFormatter.GetBufferSize(TList value) => value.GetBufferSize(_elementFormatter); + + public bool HasConstantSize => false; + + int IMsgPackFormatter.Format(Span destination, TList value) + { + if (value == null) return MsgPackSpec.WriteNil(destination); + + var result = MsgPackSpec.WriteArrayHeader(destination, value.Count); + for (var i = 0; i < value.Count; i++) + { + result += _elementFormatter.Format(destination.Slice(result), value[i]); + } + + return result; + } + } +} diff --git a/src/msgpack.light/Converters/ReadOnlyListConverter.cs b/src/msgpack.light/Converters/ReadOnlyListConverter.cs deleted file mode 100644 index 546db55..0000000 --- a/src/msgpack.light/Converters/ReadOnlyListConverter.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; - -namespace ProGaudi.MsgPack.Light.Converters -{ - public class ReadOnlyListConverter : ArrayConverterBase - where TArray : IReadOnlyList - { - public override void Write(TArray value, IMsgPackWriter writer) - { - if (value == null) - { - Context.NullConverter.Write(value, writer); - return; - } - - writer.WriteArrayHeader((uint) value.Count); - - foreach (var element in value) - { - ElementConverter.Write(element, writer); - } - } - - public override TArray Read(IMsgPackReader reader) - { - throw ExceptionUtils.CantReadReadOnlyCollection(typeof(TArray)); - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/ReadOnlyMap/UsualFormatter.cs b/src/msgpack.light/Converters/ReadOnlyMap/UsualFormatter.cs new file mode 100644 index 0000000..1ddc810 --- /dev/null +++ b/src/msgpack.light/Converters/ReadOnlyMap/UsualFormatter.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; + +namespace ProGaudi.MsgPack.Converters.ReadOnlyMap +{ + public sealed class UsualFormatter : IMsgPackFormatter + where TMap : IReadOnlyDictionary + { + private readonly IMsgPackFormatter _keyFormatter; + private readonly IMsgPackFormatter _valueFormatter; + + public UsualFormatter(MsgPackContext context) + { + _keyFormatter = context.GetRequiredFormatter(); + _valueFormatter = context.GetRequiredFormatter(); + } + + public int GetBufferSize(TMap value) => value == null + ? DataLengths.Nil + : value.GetMapBufferSize(value.Count, _keyFormatter, _valueFormatter); + + public bool HasConstantSize => false; + + public int Format(Span destination, TMap value) => value == null + ? MsgPackSpec.WriteNil(destination) + : value.FormatTo(destination, value.Count, _keyFormatter, _valueFormatter); + } +} diff --git a/src/msgpack.light/Converters/ReadOnlyMapConverter.cs b/src/msgpack.light/Converters/ReadOnlyMapConverter.cs deleted file mode 100644 index 565deea..0000000 --- a/src/msgpack.light/Converters/ReadOnlyMapConverter.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; - -namespace ProGaudi.MsgPack.Light.Converters -{ - public class ReadOnlyMapConverter : MapConverterBase - where TMap : IReadOnlyDictionary - { - public override void Write(TMap value, IMsgPackWriter writer) - { - if (value == null) - { - Context.NullConverter.Write(value, writer); - return; - } - - writer.WriteMapHeader((uint) value.Count); - - foreach (var element in value) - { - KeyConverter.Write(element.Key, writer); - ValueConverter.Write(element.Value, writer); - } - } - - public override TMap Read(IMsgPackReader reader) - { - throw ExceptionUtils.CantReadReadOnlyCollection(typeof(TMap)); - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/String/ConstrainedFormatter.cs b/src/msgpack.light/Converters/String/ConstrainedFormatter.cs new file mode 100644 index 0000000..f1af937 --- /dev/null +++ b/src/msgpack.light/Converters/String/ConstrainedFormatter.cs @@ -0,0 +1,65 @@ +using System; + +namespace ProGaudi.MsgPack.Converters.String +{ + public sealed class ConstrainedFormatter : IMsgPackFormatter + { + public byte? Code { get; } + + public int? MinSize { get; } + + public int? MaxSize { get; } + + public bool Nullable { get; } + + public ConstrainedFormatter(byte? code = null, int? minSize = null, int? maxSize = null, bool nullable = true) + { + Code = code; + MinSize = minSize; + MaxSize = maxSize; + Nullable = nullable; + + if (minSize.HasValue && maxSize.HasValue && minSize > maxSize) + { + throw ExceptionUtils.MinimumShouldBeLessThanOrEqualToMaximum(minSize.Value, maxSize.Value); + } + + if (code == null) return; + + var codeValue = code.Value; + + if (MsgPackSpec.GetDataFamily(codeValue) != DataFamily.String) + throw ExceptionUtils.BadCodeConstraint(codeValue, DataFamily.String); + + (MinSize, MaxSize) = Extensions.ValidateMinMaxCode(code.Value, minSize, maxSize); + } + + public int GetBufferSize(string value) => value == null + ? DataLengths.Nil + : DataLengths.GetStringHeaderLengthByBytesCount(value.Length * 4) + value.Length * 4; + + public bool HasConstantSize => !Nullable && MinSize.HasValue && MinSize == MaxSize; + + public int Format(Span destination, string value) + { + if (value == null) return MsgPackSpec.WriteNil(destination); + + var length = value.Length; + Extensions.CheckMinMax(length, MinSize, MaxSize); + + switch (Code) + { + case null: + return MsgPackSpec.WriteString(destination, value.AsSpan()); + case DataCodes.String8: + return MsgPackSpec.WriteString8(destination, value.AsSpan()); + case DataCodes.String16: + return MsgPackSpec.WriteString16(destination, value.AsSpan()); + case DataCodes.String32: + return MsgPackSpec.WriteString32(destination, value.AsSpan()); + default: + return MsgPackSpec.WriteFixString(destination, value.AsSpan()); + } + } + } +} \ No newline at end of file diff --git a/src/msgpack.light/Converters/String/Parser.cs b/src/msgpack.light/Converters/String/Parser.cs new file mode 100644 index 0000000..3edaf3e --- /dev/null +++ b/src/msgpack.light/Converters/String/Parser.cs @@ -0,0 +1,14 @@ +using System; + +namespace ProGaudi.MsgPack.Converters.String +{ + public sealed class Parser : IMsgPackParser + { + public string Parse(ReadOnlySpan source, out int readSize) + { + if (MsgPackSpec.TryReadNil(source, out readSize)) return null; + + return MsgPackSpec.ReadString(source, out readSize); + } + } +} diff --git a/src/msgpack.light/Converters/String/SequenceParser.cs b/src/msgpack.light/Converters/String/SequenceParser.cs new file mode 100644 index 0000000..0407a13 --- /dev/null +++ b/src/msgpack.light/Converters/String/SequenceParser.cs @@ -0,0 +1,14 @@ +using System.Buffers; + +namespace ProGaudi.MsgPack.Converters.String +{ + public sealed class SequenceParser : IMsgPackSequenceParser + { + public string Parse(ReadOnlySequence source, out int readSize) + { + if (MsgPackSpec.TryReadNil(source, out readSize)) return null; + + return MsgPackSpec.ReadString(source, out readSize); + } + } +} diff --git a/src/msgpack.light/Converters/String/UsualFormatter.cs b/src/msgpack.light/Converters/String/UsualFormatter.cs new file mode 100644 index 0000000..d41f2a0 --- /dev/null +++ b/src/msgpack.light/Converters/String/UsualFormatter.cs @@ -0,0 +1,20 @@ +using System; + +namespace ProGaudi.MsgPack.Converters.String +{ + public sealed class UsualFormatter : IMsgPackFormatter + { + public int GetBufferSize(string value) => value == null + ? DataLengths.Nil + : DataLengths.GetStringHeaderLengthByBytesCount(value.Length * 4) + value.Length * 4; + + public bool HasConstantSize => false; + + public int Format(Span destination, string value) + { + if (value == null) return MsgPackSpec.WriteNil(destination); + + return MsgPackSpec.WriteString(destination, value.AsSpan()); + } + } +} diff --git a/src/msgpack.light/Converters/StringConverter.cs b/src/msgpack.light/Converters/StringConverter.cs deleted file mode 100644 index 976ddd1..0000000 --- a/src/msgpack.light/Converters/StringConverter.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System.Text; - -namespace ProGaudi.MsgPack.Light.Converters -{ - internal class StringConverter : IMsgPackConverter - { - private static readonly Encoding Utf8 = new UTF8Encoding(false); - private MsgPackContext _context; - - public void Initialize(MsgPackContext context) - { - _context = context; - } - - public void Write(string value, IMsgPackWriter writer) - { - if (value == null) - { - _context.NullConverter.Write(value, writer); - return; - } - - var data = Utf8.GetBytes(value); - - WriteStringHeaderAndLength(writer, data.Length); - - writer.Write(data); - } - - public string Read(IMsgPackReader reader) - { - var type = reader.ReadDataType(); - - switch (type) - { - case DataTypes.Null: - return null; - - case DataTypes.Str8: - return ReadString(reader, NumberConverter.ReadUInt8(reader)); - - case DataTypes.Str16: - return ReadString(reader, NumberConverter.ReadUInt16(reader)); - - case DataTypes.Str32: - return ReadString(reader, NumberConverter.ReadUInt32(reader)); - } - - uint length; - if (TryGetFixstrLength(type, out length)) - { - return ReadString(reader, length); - } - - throw ExceptionUtils.BadTypeException(type, DataTypes.FixStr, DataTypes.Str8, DataTypes.Str16, DataTypes.Str32); - } - - private string ReadString(IMsgPackReader reader, uint length) - { - var buffer = reader.ReadBytes(length); - - return Utf8.GetString(buffer.Array, buffer.Offset, buffer.Count); - } - - private bool TryGetFixstrLength(DataTypes type, out uint length) - { - length = type - DataTypes.FixStr; - return type.GetHighBits(3) == DataTypes.FixStr.GetHighBits(3); - } - - private void WriteStringHeaderAndLength(IMsgPackWriter writer, int length) - { - if (length <= 31) - { - writer.Write((byte)(((byte)DataTypes.FixStr + length) % 256)); - return; - } - - if (length <= byte.MaxValue) - { - writer.Write(DataTypes.Str8); - NumberConverter.WriteByteValue((byte) length, writer); - } - else if (length <= ushort.MaxValue) - { - writer.Write(DataTypes.Str16); - NumberConverter.WriteUShortValue((ushort)length, writer); - } - else - { - writer.Write(DataTypes.Str32); - NumberConverter.WriteUIntValue((uint)length, writer); - } - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/Converters/TimeSpanConverter.cs b/src/msgpack.light/Converters/TimeSpanConverter.cs deleted file mode 100644 index b0c99e2..0000000 --- a/src/msgpack.light/Converters/TimeSpanConverter.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; - -namespace ProGaudi.MsgPack.Light.Converters -{ - public class TimeSpanConverter : IMsgPackConverter - { - private Lazy> _longConverter = new Lazy>(); - - public void Initialize(MsgPackContext context) - { - _longConverter = new Lazy>(context.GetConverter); - } - - public void Write(TimeSpan value, IMsgPackWriter writer) - { - _longConverter.Value.Write(value.Ticks, writer); - } - - public TimeSpan Read(IMsgPackReader reader) - { - var longValue = _longConverter.Value.Read(reader); - - return TimeSpan.FromTicks(longValue); - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/DataTypes.cs b/src/msgpack.light/DataTypes.cs deleted file mode 100644 index 5306fed..0000000 --- a/src/msgpack.light/DataTypes.cs +++ /dev/null @@ -1,61 +0,0 @@ -namespace ProGaudi.MsgPack.Light -{ - public enum DataTypes : byte - { - Null = 0xc0, - - False = 0xc2, - - True = 0xc3, - - Single = 0xca, - - Double = 0xcb, - - UInt8 = 0xcc, - - UInt16 = 0xcd, - - UInt32 = 0xce, - - UInt64 = 0xcf, - - NegativeFixNum = 0xe0, //last 5 bits is value - - PositiveFixNum = 0x7f, - - Int8 = 0xd0, - - Int16 = 0xd1, - - Int32 = 0xd2, - - Int64 = 0xd3, - - FixArray = 0x90, //last 4 bits is size - - Array16 = 0xdc, - - Array32 = 0xdd, - - FixMap = 0x80, //last 4 bits is size - - Map16 = 0xde, - - Map32 = 0xdf, - - FixStr = 0xa0, //last 5 bits is size - - Str8 = 0xd9, - - Str16 = 0xda, - - Str32 = 0xdb, - - Bin8 = 0xc4, - - Bin16 = 0xc5, - - Bin32 = 0xc6 - } -} \ No newline at end of file diff --git a/src/msgpack.light/DataTypesExtension.cs b/src/msgpack.light/DataTypesExtension.cs deleted file mode 100644 index 7336dce..0000000 --- a/src/msgpack.light/DataTypesExtension.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ProGaudi.MsgPack.Light -{ - public static class DataTypesExtension - { - public static byte GetHighBits(this DataTypes type, byte bitsCount) - { - return (byte)((byte)type >> (8 - bitsCount)); - } - } -} diff --git a/src/msgpack.light/DateTimeUtils.cs b/src/msgpack.light/DateTimeUtils.cs deleted file mode 100644 index d40fce8..0000000 --- a/src/msgpack.light/DateTimeUtils.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; - -namespace ProGaudi.MsgPack.Light -{ - public static class DateTimeUtils - { - private static readonly DateTime UnixEpocUtc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - public static DateTimeOffset ToDateTimeOffset(long value) - { - return UnixEpocUtc.AddTicks(value); - } - - public static long FromDateTimeOffset(DateTimeOffset value) - { - return value.ToUniversalTime().Subtract(UnixEpocUtc).Ticks; - } - - public static DateTime ToDateTime(long value) - { - return UnixEpocUtc.AddTicks(value); - } - - public static long FromDateTime(DateTime value) - { - return value.ToUniversalTime().Subtract(UnixEpocUtc).Ticks; - } - } -} diff --git a/src/msgpack.light/ExceptionUtils.cs b/src/msgpack.light/ExceptionUtils.cs index b023a13..37885e9 100644 --- a/src/msgpack.light/ExceptionUtils.cs +++ b/src/msgpack.light/ExceptionUtils.cs @@ -1,92 +1,64 @@ using System; using System.Collections.Generic; -using System.Reflection; using System.Runtime.Serialization; -using ProGaudi.MsgPack.Light.Converters.Generation.Exceptions; - -namespace ProGaudi.MsgPack.Light +namespace ProGaudi.MsgPack { public static class ExceptionUtils { - public static Exception BadTypeException(DataTypes actual, params DataTypes[] expectedCodes) - { - return new SerializationException($"Got {actual:G} (0x{actual:X}), while expecting one of these: {String.Join(", ", expectedCodes)}"); - } - - public static Exception CantReadStringAsBinary() - { - return new SerializationException($"Reading a string as a byte array is disabled. Set 'binaryCompatibilityMode' parameter in MsgPackContext constructor to true to enable it"); - } - - public static Exception NotEnoughBytes(uint actual, uint expected) - { - return new SerializationException($"Expected {expected} bytes, got {actual} bytes."); - } - public static Exception NotEnoughBytes(int actual, int expected) { return new SerializationException($"Expected {expected} bytes, got {actual} bytes."); } - public static Exception NotEnoughBytes(long actual, uint expected) + public static Exception IntSerializationFailure(long value) { - return new SerializationException($"Expected {expected} bytes, got {actual} bytes."); + return new SerializationException($"Can't serialize {value}"); } - public static Exception NotEnoughBytes(uint actual, long expected) + public static Exception IntSerializationFailure(ulong value) { - return new SerializationException($"Expected {expected} bytes, got {actual} bytes."); + return new SerializationException($"Can't serialize {value}"); } - public static Exception CantReadReadOnlyCollection(Type type) - { - return new SerializationException($"Can't deserialize into read-only collection {type.Name}. Create a specialized converter for that."); - } + public static Exception NonNullableConstraintIsViolated() => new NonNullableConstraintViolationException(); - public static Exception NoConverterForCollectionElement(Type type, string elementName) - { - return new SerializationException($"Provide converter for {elementName}: {type.Name}"); - } + public static Exception MinimumLengthConstraintIsViolated(int minSize, int actualLength) => new MinimumConstraintViolationException(minSize, actualLength); - public static Exception IntDeserializationFailure(DataTypes type) - { - return new SerializationException($"Waited for an int, got {type:G} (0x{type:X})"); - } + public static Exception MaximumLengthConstraintIsViolated(int maxSize, int actualLength) => new MaximumConstraintViolationException(maxSize, actualLength); - public static Exception IntSerializationFailure(long value) - { - return new SerializationException($"Can't serialize {value}"); - } + public static Exception BadCodeConstraint(byte dataCode, DataFamily binary) => new CodeDoesntBelongFamilyException(dataCode, binary); - public static Exception IntSerializationFailure(ulong value) + public static Exception MinSizeIsTooBigForDataCode(DataFamily dataFamily, byte dataCode, int minSize) { - return new SerializationException($"Can't serialize {value}"); + return new BadSizeConstraintException(dataFamily, dataCode, minSize); } - public static Exception ConverterNotFound(Type type) + public static Exception MinSizeIsTooSmallForDataCode(DataFamily dataFamily, byte dataCode, int minSize) { - return new ConverterNotFoundException(type); + return new BadSizeConstraintException(dataFamily, dataCode, minSize); } - public static InvalidOperationException EnumExpected(TypeInfo type) + public static Exception MaxSizeIsTooBigForDataCode(DataFamily dataFamily, byte dataCode, int maxSize) { - return new InvalidOperationException($"Enum expected, but got {type}."); + return new BadSizeConstraintException(dataFamily, dataCode, maxSize); } - public static InvalidOperationException UnexpectedEnumUnderlyingType(Type enumUnderlyingType) + public static Exception MaxSizeIsTooSmallForDataCode(DataFamily dataFamily, byte dataCode, int maxSize) { - return new InvalidOperationException($"Unexpected underlying enum type: {enumUnderlyingType}."); + return new BadSizeConstraintException(dataFamily, dataCode, maxSize); } - public static Exception DuplicateArrayElement(Type typeToWrap, KeyValuePair pair) + public static Exception MinimumShouldBeLessThanOrEqualToMaximum(int minSize, int maxSize) { - return new DuplicateArrayElementException(typeToWrap, pair.Key, pair.Value); + return new MinimumShouldBeLessThanMaximumException(minSize, maxSize); } - public static Exception DuplicateMapElement(Type typeToWrap, KeyValuePair pair) + public static Exception BadBinaryCompatibilityCode(byte code, HashSet allowedCodes) { - return new DuplicateMapElementException(typeToWrap, pair.Key, pair.Value); + return new BadCodeConstraintException(code, allowedCodes); } + + public static Exception UnexpectedCode(byte code) => new UnexpectedCodeException(code); } } diff --git a/src/msgpack.light/Extensions.cs b/src/msgpack.light/Extensions.cs index 0fed733..5a31923 100644 --- a/src/msgpack.light/Extensions.cs +++ b/src/msgpack.light/Extensions.cs @@ -1,18 +1,48 @@ -using System; -using System.Collections.Generic; +using System.Runtime.Serialization; using JetBrains.Annotations; -namespace ProGaudi.MsgPack.Light +namespace ProGaudi.MsgPack { - internal static class Extensions + public static class Extensions { - public static TValue GetOrAdd([NotNull]this Dictionary dictionary, [NotNull]TKey key, [NotNull]Func creator) + [NotNull] + public static IMsgPackFormatter GetRequiredFormatter(this MsgPackContext context) { - TValue temp; - if (!dictionary.TryGetValue(key, out temp)) - dictionary[key] = temp = creator(key); - return temp; + var formatter = context.GetFormatter(); + + if (formatter == null) + { + throw new SerializationException($"Provide formatter for {typeof(T).Name}"); + } + + return formatter; + } + + [NotNull] + public static IMsgPackParser GetRequiredParser(this MsgPackContext context) + { + var parser = context.GetParser(); + + if (parser == null) + { + throw new SerializationException($"Provide parser for {typeof(T).Name}"); + } + + return parser; + } + + [NotNull] + public static IMsgPackSequenceParser GetRequiredSequenceParser(this MsgPackContext context) + { + var parser = context.GetSequenceParser(); + + if (parser == null) + { + throw new SerializationException($"Provide sequence parser for {typeof(T).Name}"); + } + + return parser; } } } diff --git a/src/msgpack.light/IMsgPackConverter.cs b/src/msgpack.light/IMsgPackConverter.cs deleted file mode 100644 index 1a88aa9..0000000 --- a/src/msgpack.light/IMsgPackConverter.cs +++ /dev/null @@ -1,16 +0,0 @@ -using JetBrains.Annotations; - -namespace ProGaudi.MsgPack.Light -{ - public interface IMsgPackConverter - { - void Initialize([NotNull] MsgPackContext context); - } - - public interface IMsgPackConverter : IMsgPackConverter - { - void Write([CanBeNull] T value, [NotNull] IMsgPackWriter writer); - - T Read([NotNull] IMsgPackReader reader); - } -} \ No newline at end of file diff --git a/src/msgpack.light/IMsgPackFormatter.cs b/src/msgpack.light/IMsgPackFormatter.cs new file mode 100644 index 0000000..0f9e570 --- /dev/null +++ b/src/msgpack.light/IMsgPackFormatter.cs @@ -0,0 +1,30 @@ +using System; + +namespace ProGaudi.MsgPack +{ + public interface IMsgPackFormatter + { + /// + /// Gets maximum possible size for instance. Implementation should be balanced about speed + /// and precision. Overestimating is usually better, since underestimating will result to errors in + /// method. + /// + /// Value to estimate. + /// Size of buffer to serialize value. + int GetBufferSize(T value); + + /// + /// If your type is always serializes to same amount of bytes, seal it and set this to true. + /// It will speed up serialization of your arrays. + /// + bool HasConstantSize { get; } + + /// + /// Formats into . + /// + /// Buffer, large enough to hold . + /// Value to serialize. + /// Actual count of used bytes. + int Format(Span destination, T value); + } +} \ No newline at end of file diff --git a/src/msgpack.light/IMsgPackParser.cs b/src/msgpack.light/IMsgPackParser.cs new file mode 100644 index 0000000..d784ff6 --- /dev/null +++ b/src/msgpack.light/IMsgPackParser.cs @@ -0,0 +1,15 @@ +using System; + +namespace ProGaudi.MsgPack +{ + public interface IMsgPackParser + { + /// + /// Parses source into . + /// + /// Buffer to read. + /// Count of read bytes + /// Value + T Parse(ReadOnlySpan source, out int readSize); + } +} \ No newline at end of file diff --git a/src/msgpack.light/IMsgPackReader.cs b/src/msgpack.light/IMsgPackReader.cs deleted file mode 100644 index b507470..0000000 --- a/src/msgpack.light/IMsgPackReader.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.IO; - -namespace ProGaudi.MsgPack.Light -{ - public interface IMsgPackReader - { - DataTypes ReadDataType(); - - byte ReadByte(); - - ArraySegment ReadBytes(uint length); - - void Seek(long offset, SeekOrigin origin); - - uint? ReadArrayLength(); - - uint? ReadMapLength(); - - void SkipToken(); - - byte[] ReadToken(); - } -} \ No newline at end of file diff --git a/src/msgpack.light/IMsgPackSequenceParser.cs b/src/msgpack.light/IMsgPackSequenceParser.cs new file mode 100644 index 0000000..e193911 --- /dev/null +++ b/src/msgpack.light/IMsgPackSequenceParser.cs @@ -0,0 +1,15 @@ +using System.Buffers; + +namespace ProGaudi.MsgPack +{ + public interface IMsgPackSequenceParser + { + /// + /// Parses source into . + /// + /// Buffer to read. + /// Count of read bytes + /// Value + T Parse(ReadOnlySequence source, out int readSize); + } +} \ No newline at end of file diff --git a/src/msgpack.light/IMsgPackWriter.cs b/src/msgpack.light/IMsgPackWriter.cs deleted file mode 100644 index 9940b8b..0000000 --- a/src/msgpack.light/IMsgPackWriter.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace ProGaudi.MsgPack.Light -{ - public interface IMsgPackWriter - { - void Write(DataTypes dataType); - - void Write(byte value); - - void Write(byte[] array); - - void WriteArrayHeader(uint length); - - void WriteMapHeader(uint length); - } -} diff --git a/src/msgpack.light/MaximumConstraintViolationException.cs b/src/msgpack.light/MaximumConstraintViolationException.cs new file mode 100644 index 0000000..f0f071f --- /dev/null +++ b/src/msgpack.light/MaximumConstraintViolationException.cs @@ -0,0 +1,19 @@ +using System; + +namespace ProGaudi.MsgPack +{ + [Serializable] + public sealed class MaximumConstraintViolationException : ConstraintViolationException + { + public int MaxSize { get; } + + public int ActualLength { get; } + + public MaximumConstraintViolationException(int maxSize, int actualLength, Exception innerException = null) + : base($"Data has length {actualLength}, but expected to be at most {maxSize}.", innerException) + { + MaxSize = maxSize; + ActualLength = actualLength; + } + } +} \ No newline at end of file diff --git a/src/msgpack.light/MinimumConstraintViolationException.cs b/src/msgpack.light/MinimumConstraintViolationException.cs new file mode 100644 index 0000000..94d32f6 --- /dev/null +++ b/src/msgpack.light/MinimumConstraintViolationException.cs @@ -0,0 +1,19 @@ +using System; + +namespace ProGaudi.MsgPack +{ + [Serializable] + public sealed class MinimumConstraintViolationException : ConstraintViolationException + { + public int MinSize { get; } + + public int ActualLength { get; } + + public MinimumConstraintViolationException(int minSize, int actualLength, Exception innerException = null) + : base($"Data has length {actualLength}, but expected to be at least {minSize}.", innerException) + { + MinSize = minSize; + ActualLength = actualLength; + } + } +} \ No newline at end of file diff --git a/src/msgpack.light/MinimumShouldBeLessThanMaximumException.cs b/src/msgpack.light/MinimumShouldBeLessThanMaximumException.cs new file mode 100644 index 0000000..8f45a40 --- /dev/null +++ b/src/msgpack.light/MinimumShouldBeLessThanMaximumException.cs @@ -0,0 +1,19 @@ +using System; + +namespace ProGaudi.MsgPack +{ + [Serializable] + public class MinimumShouldBeLessThanMaximumException : ConstraintViolationException + { + public int MinSize { get; } + + public int MaxSize { get; } + + public MinimumShouldBeLessThanMaximumException(int minSize, int maxSize, Exception innerException = null) + : base($"Minimum should be less, than maximum, but it isn't. {minSize} >= {maxSize}", innerException) + { + MinSize = minSize; + MaxSize = maxSize; + } + } +} \ No newline at end of file diff --git a/src/msgpack.light/Attributes/MsgPackArrayAttribute.cs b/src/msgpack.light/MsgPackArrayAttribute.cs similarity index 86% rename from src/msgpack.light/Attributes/MsgPackArrayAttribute.cs rename to src/msgpack.light/MsgPackArrayAttribute.cs index 71e743c..62f29a2 100644 --- a/src/msgpack.light/Attributes/MsgPackArrayAttribute.cs +++ b/src/msgpack.light/MsgPackArrayAttribute.cs @@ -1,6 +1,6 @@ using System; -namespace ProGaudi.MsgPack.Light +namespace ProGaudi.MsgPack { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, Inherited = false)] public class MsgPackArrayAttribute : Attribute diff --git a/src/msgpack.light/Attributes/MsgPackArrayElementAttribute.cs b/src/msgpack.light/MsgPackArrayElementAttribute.cs similarity index 88% rename from src/msgpack.light/Attributes/MsgPackArrayElementAttribute.cs rename to src/msgpack.light/MsgPackArrayElementAttribute.cs index 96228ae..9ee2323 100644 --- a/src/msgpack.light/Attributes/MsgPackArrayElementAttribute.cs +++ b/src/msgpack.light/MsgPackArrayElementAttribute.cs @@ -1,6 +1,6 @@ using System; -namespace ProGaudi.MsgPack.Light +namespace ProGaudi.MsgPack { [AttributeUsage(AttributeTargets.Property)] public class MsgPackArrayElementAttribute : Attribute diff --git a/src/msgpack.light/MsgPackByteArrayReader.cs b/src/msgpack.light/MsgPackByteArrayReader.cs deleted file mode 100644 index 060a914..0000000 --- a/src/msgpack.light/MsgPackByteArrayReader.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace ProGaudi.MsgPack.Light -{ - internal class MsgPackByteArrayReader : BaseMsgPackReader - { - private uint _firstGatheredByte; - - private readonly byte[] _data; - - private uint _offset; - - public MsgPackByteArrayReader(byte[] data) - { - _data = data; - _offset = 0; - } - - public override byte ReadByte() - { - return _data[_offset++]; - } - - public override ArraySegment ReadBytes(uint length) - { - _offset += length; - return new ArraySegment(_data, (int) (_offset - length), (int) length); - } - - public override void Seek(long offset, SeekOrigin origin) - { - switch (origin) - { - case SeekOrigin.Begin: - _offset = (uint)offset; - break; - case SeekOrigin.Current: - _offset = (uint)(_offset + offset); - break; - case SeekOrigin.End: - _offset = (uint) (_data.Length + offset); - break; - default: - throw new ArgumentOutOfRangeException(nameof(origin), origin, null); - } - } - - protected override IList StopTokenGathering() - { - return new ArraySegment(_data, (int) _firstGatheredByte,(int) (_offset - _firstGatheredByte)); - } - - protected override void StartTokenGathering() - { - _firstGatheredByte = _offset; - } - } -} diff --git a/src/msgpack.light/MsgPackContext.cs b/src/msgpack.light/MsgPackContext.cs index 6fb5970..e67deae 100644 --- a/src/msgpack.light/MsgPackContext.cs +++ b/src/msgpack.light/MsgPackContext.cs @@ -1,203 +1,192 @@ using System; +using System.Buffers; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using System.Reflection; -using ProGaudi.MsgPack.Light.Converters; -using ProGaudi.MsgPack.Light.Converters.Generation; +using JetBrains.Annotations; -namespace ProGaudi.MsgPack.Light +namespace ProGaudi.MsgPack { - public class MsgPackContext + [PublicAPI] + public sealed class MsgPackContext { - private readonly bool _convertEnumsAsStrings; + private readonly Dictionary _genericFormatters = new Dictionary(); - private static readonly IMsgPackConverter SharedNullConverter = new NullConverter(); + private readonly Dictionary _genericParsers = new Dictionary(); - private readonly ConverterGenerationContext _generatorContext = new ConverterGenerationContext(); + private readonly Dictionary _genericSequenceParsers = new Dictionary(); - private readonly Dictionary _converters; - - private readonly Dictionary _genericConverters = new Dictionary(); - - private readonly Dictionary> _objectActivators = new Dictionary>(); - - public MsgPackContext(bool strictParseOfFloat = false, bool convertEnumsAsStrings = true, bool binaryCompatibilityMode = false) + static MsgPackContext() { - _convertEnumsAsStrings = convertEnumsAsStrings; - var numberConverter = new NumberConverter(strictParseOfFloat); - _converters = new Dictionary - { - {typeof(MsgPackToken), new MsgPackTokenConverter()}, - {typeof (bool), new BoolConverter()}, - {typeof (string), new StringConverter()}, - {typeof (byte[]), new BinaryConverter(binaryCompatibilityMode)}, - {typeof (float), numberConverter}, - {typeof (double), numberConverter}, - {typeof (byte), numberConverter}, - {typeof (sbyte), numberConverter}, - {typeof (short), numberConverter}, - {typeof (ushort), numberConverter}, - {typeof (int), numberConverter}, - {typeof (uint), numberConverter}, - {typeof (long), numberConverter}, - {typeof (ulong), numberConverter}, - {typeof (DateTime), new DateTimeConverter()}, - {typeof (DateTimeOffset), new DateTimeConverter()}, - {typeof (TimeSpan), new TimeSpanConverter() }, - - {typeof (bool?), new NullableConverter()}, - {typeof (float?), new NullableConverter()}, - {typeof (double?), new NullableConverter()}, - {typeof (byte?), new NullableConverter()}, - {typeof (sbyte?), new NullableConverter()}, - {typeof (short?), new NullableConverter()}, - {typeof (ushort?), new NullableConverter()}, - {typeof (int?), new NullableConverter()}, - {typeof (uint?), new NullableConverter()}, - {typeof (long?), new NullableConverter()}, - {typeof (ulong?), new NullableConverter()}, - {typeof (DateTime?), new NullableConverter()}, - {typeof (DateTimeOffset?), new NullableConverter()} - }; - - foreach (var converter in _converters) - { - converter.Value.Initialize(this); - } + Cache>.Instance = Converters.Binary.Converter.Compatibility; + Cache>>.Instance = Converters.Binary.Converter.Compatibility; + Cache>.Instance = Converters.Binary.Converter.Compatibility; + Cache>>.Instance = Converters.Binary.Converter.Compatibility; + Cache>.Instance = Converters.Binary.Converter.Compatibility; + Cache>>.Instance = Converters.Binary.Converter.Compatibility; + + Cache>.Instance = Converters.Date.Ticks.Instance; + Cache>.Instance = Converters.Date.Ticks.Instance; + Cache>.Instance = Converters.Date.Ticks.Instance; + Cache>.Instance = Converters.Date.Ticks.Instance; + Cache>.Instance = Converters.Date.Ticks.Instance; + Cache>.Instance = Converters.Date.Ticks.Instance; + Cache>.Instance = Converters.Date.Ticks.Instance; + Cache>.Instance = Converters.Date.Ticks.Instance; + Cache>.Instance = Converters.Date.Ticks.Instance; + + Cache>.Instance = Converters.Number.UsualFormatter.Instance; + Cache>.Instance = Converters.Number.UsualFormatter.Instance; + Cache>.Instance = Converters.Number.UsualFormatter.Instance; + Cache>.Instance = Converters.Number.UsualFormatter.Instance; + Cache>.Instance = Converters.Number.UsualFormatter.Instance; + Cache>.Instance = Converters.Number.UsualFormatter.Instance; + Cache>.Instance = Converters.Number.UsualFormatter.Instance; + Cache>.Instance = Converters.Number.UsualFormatter.Instance; + Cache>.Instance = Converters.Number.UsualFormatter.Instance; + Cache>.Instance = Converters.Number.UsualFormatter.Instance; + + Cache>.Instance = Converters.Number.Parser.Instance; + Cache>.Instance = Converters.Number.Parser.Instance; + Cache>.Instance = Converters.Number.Parser.Instance; + Cache>.Instance = Converters.Number.Parser.Instance; + Cache>.Instance = Converters.Number.Parser.Instance; + Cache>.Instance = Converters.Number.Parser.Instance; + Cache>.Instance = Converters.Number.Parser.Instance; + Cache>.Instance = Converters.Number.Parser.Instance; + Cache>.Instance = Converters.Number.Parser.Instance; + Cache>.Instance = Converters.Number.Parser.Instance; + + Cache>.Instance = Converters.Number.SequenceParser.Instance; + Cache>.Instance = Converters.Number.SequenceParser.Instance; + Cache>.Instance = Converters.Number.SequenceParser.Instance; + Cache>.Instance = Converters.Number.SequenceParser.Instance; + Cache>.Instance = Converters.Number.SequenceParser.Instance; + Cache>.Instance = Converters.Number.SequenceParser.Instance; + Cache>.Instance = Converters.Number.SequenceParser.Instance; + Cache>.Instance = Converters.Number.SequenceParser.Instance; + Cache>.Instance = Converters.Number.SequenceParser.Instance; + Cache>.Instance = Converters.Number.SequenceParser.Instance; + + Cache>.Instance = new Converters.String.UsualFormatter(); + Cache>.Instance = new Converters.String.Parser(); + Cache>.Instance = new Converters.String.SequenceParser(); + + Cache>.Instance = Converters.BoolConverter.Instance; + Cache>.Instance = Converters.BoolConverter.Instance; + Cache>.Instance = Converters.BoolConverter.Instance; } - public IMsgPackConverter NullConverter => SharedNullConverter; + public void RegisterGenericFormatter(Type type) => RegisterGenericMapper(type, typeof(IMsgPackFormatter<>), _genericFormatters); -#if !NETSTANDARD1_1 - public void DiscoverConverters() - { - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - DiscoverConverters(assembly); - } - } -#endif + public void RegisterGenericParser(Type type) => RegisterGenericMapper(type, typeof(IMsgPackParser<>), _genericParsers); - public void DiscoverConverters() - { - DiscoverConverters(typeof(T).GetTypeInfo().Assembly); - } + public void RegisterGenericSequenceParser(Type type) => RegisterGenericMapper(type, typeof(IMsgPackSequenceParser<>), _genericSequenceParsers); - public void DiscoverConverters(Assembly assembly) - { - var generateMapConverter = GetType().GetTypeInfo().GetGenericMethod(nameof(GenerateAndRegisterMapConverter), 1); - var generateArrayConverter = GetType().GetTypeInfo().GetGenericMethod(nameof(GenerateAndRegisterArrayConverter), 1); - foreach (var type in assembly.ExportedTypes.Where(x => x.GetTypeInfo().GetCustomAttribute() != null)) - { - generateMapConverter.MakeGenericMethod(type).Invoke(this, null); - } + public IMsgPackFormatter RegisterFormatter(Func> func) => RegisterFormatter(func(this)); - foreach (var type in assembly.ExportedTypes.Where(x => x.GetTypeInfo().GetCustomAttribute() != null)) - { - generateArrayConverter.MakeGenericMethod(type).Invoke(this, null); - } - } + public IMsgPackFormatter RegisterFormatter(IMsgPackFormatter formatter) => Cache>.Instance = formatter; - public void GenerateAndRegisterMapConverter() + public IMsgPackFormatter GetFormatter() { - var generator = _generatorContext.GenerateMapConverter(typeof(T)); - RegisterConverter((IMsgPackConverter) generator); - } + var result = Cache>.Instance; + if (result != null) + return result; - public void GenerateAndRegisterMapConverter() - where TImplementation : TInterface - { - var generator = _generatorContext.GenerateMapConverter(typeof(TInterface), typeof(TImplementation)); - RegisterConverter((IMsgPackConverter)generator); - RegisterConverter((IMsgPackConverter)generator); + var type = typeof(T); + return Cache>.Instance = (IMsgPackFormatter)( + TryGenerateEnumMapper(type) ?? + TryGenerateArrayMapper(type, typeof(Converters.Array.UsualFormatter<>)) ?? + TryGenerateStructMapper(type, typeof(ReadOnlyMemory<>), typeof(Converters.Array.UsualFormatter<>)) ?? + TryGenerateStructMapper(type, typeof(Memory<>), typeof(Converters.Array.UsualFormatter<>)) ?? + TryGenerateStructMapper(type, typeof(Nullable<>), typeof(Converters.NullableConverter<>)) ?? + TryGenerateInterfaceMapper(type, typeof(IList<>), typeof(Converters.List.UsualFormatter<,>)) ?? + TryGenerateInterfaceMapper(type, typeof(IReadOnlyList<>), typeof(Converters.ReadOnlyList.UsualFormatter<,>)) ?? + TryGenerateInterfaceMapper(type, typeof(IDictionary<,>), typeof(Converters.Map.UsualFormatter<,,>)) ?? + TryGenerateInterfaceMapper(type, typeof(IReadOnlyDictionary<,>), typeof(Converters.ReadOnlyMap.UsualFormatter<,,>)) ?? + TryGenerateInterfaceMapper(type, typeof(ICollection<>), typeof(Converters.Collection.UsualFormatter<,>)) ?? + TryGenerateInterfaceMapper(type, typeof(IReadOnlyCollection<>), typeof(Converters.ReadOnlyCollection.UsualFormatter<,>)) ?? + TryGenerateInterfaceMapper(type, typeof(IEnumerable<>), typeof(Converters.Enumerable.UsualFormatter<,>)) ?? + TryGenerateGenericMapper(type, _genericFormatters) + ); } - public void GenerateAndRegisterArrayConverter() - { - var generator = _generatorContext.GenerateArrayConverter(typeof(T)); - RegisterConverter((IMsgPackConverter)generator); - } + public IMsgPackParser RegisterParser(Func> func) => RegisterParser(func(this)); - public void GenerateAndRegisterArrayConverter() - where TImplementation : TInterface - { - var generator = _generatorContext.GenerateArrayConverter(typeof(TInterface), typeof(TImplementation)); - RegisterConverter((IMsgPackConverter)generator); - RegisterConverter((IMsgPackConverter)generator); - } + public IMsgPackParser RegisterParser(IMsgPackParser parser) => Cache>.Instance = parser; - public void GenerateAndRegisterEnumConverter() - { - var generator = _generatorContext.GenerateEnumConverter(typeof(T), _convertEnumsAsStrings); - RegisterConverter((IMsgPackConverter)generator); - } + public IMsgPackSequenceParser RegisterParser(Func> func) => RegisterParser(func(this)); - public void RegisterConverter(IMsgPackConverter converter) - { - converter.Initialize(this); - _converters[typeof(T)] = converter; - } + public IMsgPackSequenceParser RegisterParser(IMsgPackSequenceParser parser) => Cache>.Instance = parser; - public void RegisterGenericConverter(Type type) + public IMsgPackParser GetParser() { - var converterType = GetGenericInterface(type, typeof(IMsgPackConverter<>)); - if (converterType == null) - { - throw new ArgumentException($"Error registering generic converter. Expected IMsgPackConverter<> implementation, but got {type}"); - } + var result = Cache>.Instance; + if (result != null) + return result; - var convertedType = converterType.GenericTypeArguments.Single().GetGenericTypeDefinition(); - _genericConverters.Add(convertedType, type); + var type = typeof(T); + return Cache>.Instance = (IMsgPackParser)( + TryGenerateEnumMapper(type) ?? + TryGenerateArrayMapper(type, typeof(Converters.Array.Parser<>)) ?? + TryGenerateStructMapper(type, typeof(ReadOnlyMemory<>), typeof(Converters.Array.Parser<>)) ?? + TryGenerateStructMapper(type, typeof(Memory<>), typeof(Converters.Array.Parser<>)) ?? + TryGenerateStructMapper(type, typeof(Nullable<>), typeof(Converters.NullableConverter<>)) ?? + TryGenerateInterfaceMapper(type, typeof(IList<>), typeof(Converters.List.Parser<,>)) ?? + TryGenerateInterfaceMapper(type, typeof(IDictionary<,>), typeof(Converters.Map.Parser<,,>)) ?? + TryGenerateInterfaceMapper(type, typeof(ICollection<>), typeof(Converters.Collection.Parser<,>)) ?? + TryGenerateGenericMapper(type, _genericParsers) + ); } - public IMsgPackConverter GetConverter() + public IMsgPackSequenceParser GetSequenceParser() { - var type = typeof(T); - var result = (IMsgPackConverter)GetConverterFromCache(); + var result = Cache>.Instance; if (result != null) return result; - result = (IMsgPackConverter)( - TryGenerateEnumConverter(type) ?? - TryGenerateConverterFromGenericConverter(type) ?? - TryGenerateArrayConverter(type) ?? - TryGenerateMapConverter(type) ?? - TryGenerateNullableConverter(type)); - - if (result == null) - { - throw ExceptionUtils.ConverterNotFound(type); - } - - return result; + var type = typeof(T); + return Cache>.Instance = (IMsgPackSequenceParser)( + TryGenerateEnumMapper(type) ?? + TryGenerateArrayMapper(type, typeof(Converters.Array.SequenceParser<>)) ?? + TryGenerateStructMapper(type, typeof(ReadOnlyMemory<>), typeof(Converters.Array.SequenceParser<>)) ?? + TryGenerateStructMapper(type, typeof(Memory<>), typeof(Converters.Array.SequenceParser<>)) ?? + TryGenerateStructMapper(type, typeof(Nullable<>), typeof(Converters.NullableConverter<>)) ?? + TryGenerateInterfaceMapper(type, typeof(IList<>), typeof(Converters.List.SequenceParser<,>)) ?? + TryGenerateInterfaceMapper(type, typeof(IDictionary<,>), typeof(Converters.Map.SequenceParser<,,>)) ?? + TryGenerateInterfaceMapper(type, typeof(ICollection<>), typeof(Converters.Collection.SequenceParser<,>)) ?? + TryGenerateGenericMapper(type, _genericSequenceParsers) + ); } - private IMsgPackConverter TryGenerateEnumConverter(Type type) + private void RegisterGenericMapper(Type mapper, Type baseInterface, Dictionary cache) { - var enumTypeInfo = typeof(T).GetTypeInfo(); - if (!enumTypeInfo.IsEnum) - { - return null; - } + var converterType = GetGenericInterface(mapper, baseInterface) + ?? throw new ArgumentException($"Error registering generic mapper. Expected {baseInterface.Name} implementation, but got {mapper}"); - return _converters - .GetOrAdd(type, x => CreateAndInializeConverter(()=>_generatorContext.GenerateEnumConverter(type, _convertEnumsAsStrings))); + var convertedType = converterType.GenericTypeArguments.Single().GetGenericTypeDefinition(); + cache[convertedType] = mapper; } - public Func GetObjectActivator(Type type) => _objectActivators.GetOrAdd(type, CompiledLambdaActivatorFactory.GetActivator); - - public ImmutableDictionary DumpConvertersCache() => _converters.ToImmutableDictionary(x => x.Key, x => x.Value); - - private IMsgPackConverter CreateAndInializeConverter(Func converterActivator) + private object TryGenerateInterfaceMapper(Type type, Type generic, Type mapper) { - var converter = (IMsgPackConverter)converterActivator(); - converter.Initialize(this); - return converter; + bool Predicate(Type x) => x.IsConstructedGenericType && x.GetGenericTypeDefinition() == generic; + var @interface = type.GetTypeInfo().IsInterface && Predicate(type) + ? type + : type + .GetInterfaces() + .FirstOrDefault(Predicate); + + if (@interface == null) + return null; + + return mapper + .MakeGenericType(new [] { type }.Concat(type.GetGenericArguments()).ToArray()) + .GetContextActivator()(this); } - private IMsgPackConverter TryGenerateConverterFromGenericConverter(Type type) + private object TryGenerateGenericMapper(Type type, Dictionary mappers) { if (!type.GetTypeInfo().IsGenericType) { @@ -205,66 +194,49 @@ private IMsgPackConverter TryGenerateConverterFromGenericConverter(Type type) } var genericType = type.GetGenericTypeDefinition(); - if (!_genericConverters.TryGetValue(genericType, out var genericConverterType)) + if (!mappers.TryGetValue(genericType, out var genericConverterType)) { return null; } var converterType = genericConverterType.MakeGenericType(type.GenericTypeArguments); - return _converters.GetOrAdd(type, x => CreateAndInializeConverter(GetObjectActivator(converterType))); + var contextActivator = converterType.GetContextActivator(); + return contextActivator != null ? contextActivator(this) : converterType.GetDefaultActivator()(); } - private IMsgPackConverter TryGenerateMapConverter(Type type) + private object TryGenerateStructMapper(Type type, Type generic, Type mapper) { - var mapInterface = GetGenericInterface(type, typeof(IDictionary<,>)); - if (mapInterface != null) - { - return _converters.GetOrAdd(type, x => CreateAndInializeConverter(GetObjectActivator(typeof(MapConverter<,,>).MakeGenericType( - x, - mapInterface.GenericTypeArguments[0], - mapInterface.GenericTypeArguments[1])))); - } - - mapInterface = GetGenericInterface(type, typeof(IReadOnlyDictionary<,>)); - if (mapInterface != null) - { - return _converters.GetOrAdd(type, x => CreateAndInializeConverter(GetObjectActivator(typeof(ReadOnlyMapConverter<,,>).MakeGenericType( - x, - mapInterface.GenericTypeArguments[0], - mapInterface.GenericTypeArguments[1])))); - } + if (!type.GetTypeInfo().IsValueType) + return null; - return null; - } + if (!type.IsConstructedGenericType) + return null; - private IMsgPackConverter TryGenerateNullableConverter(Type type) - { - var typeInfo = type.GetTypeInfo(); - if (!typeInfo.IsGenericType || typeInfo.GetGenericTypeDefinition() != typeof(Nullable<>)) - { + if (type.GetGenericTypeDefinition() != generic) return null; - } - return _converters.GetOrAdd(type, x => CreateAndInializeConverter(GetObjectActivator(typeof(NullableConverter<>).MakeGenericType(x.GetTypeInfo().GenericTypeArguments[0])))); + return mapper + .MakeGenericType(type.GetGenericArguments()) + .GetContextActivator()(this); } - private IMsgPackConverter TryGenerateArrayConverter(Type type) + private object TryGenerateArrayMapper(Type type, Type mapper) { - var arrayInterface = GetGenericInterface(type, typeof(IList<>)); - if (arrayInterface != null) - { - return _converters.GetOrAdd(type, x => CreateAndInializeConverter(GetObjectActivator(typeof(ArrayConverter<,>).MakeGenericType(x, arrayInterface.GenericTypeArguments[0])))); - } + if (!type.IsArray || type.GetArrayRank() != 1) + return null; - arrayInterface = GetGenericInterface(type, typeof(IReadOnlyList<>)); - return arrayInterface != null - ? _converters.GetOrAdd(type, x => CreateAndInializeConverter(GetObjectActivator(typeof(ReadOnlyListConverter<,>).MakeGenericType(x, arrayInterface.GenericTypeArguments[0])))) - : null; + var element = type.GetElementType(); + return mapper + .MakeGenericType(element) + .GetContextActivator()(this); } - private IMsgPackConverter GetConverterFromCache() + private static object TryGenerateEnumMapper(Type type) { - return _converters.TryGetValue(typeof(T), out var temp) ? temp : null; + if (!type.GetTypeInfo().IsEnum) return null; + return typeof(Converters.Enum.String<>) + .MakeGenericType(type) + .GetDefaultActivator()(); } private static TypeInfo GetGenericInterface(Type type, Type genericInterfaceType) @@ -280,5 +252,10 @@ private static TypeInfo GetGenericInterface(Type type, Type genericInterfaceType .Select(x => x.GetTypeInfo()) .FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == genericInterfaceType); } + + private static class Cache + { + public static T Instance; + } } -} \ No newline at end of file +} diff --git a/src/msgpack.light/Attributes/MsgPackMapAttribute.cs b/src/msgpack.light/MsgPackMapAttribute.cs similarity index 85% rename from src/msgpack.light/Attributes/MsgPackMapAttribute.cs rename to src/msgpack.light/MsgPackMapAttribute.cs index b2b4c0a..2fee881 100644 --- a/src/msgpack.light/Attributes/MsgPackMapAttribute.cs +++ b/src/msgpack.light/MsgPackMapAttribute.cs @@ -1,6 +1,6 @@ using System; -namespace ProGaudi.MsgPack.Light +namespace ProGaudi.MsgPack { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct, Inherited = false)] public class MsgPackMapAttribute : Attribute diff --git a/src/msgpack.light/Attributes/MsgPackMapElementAttribute.cs b/src/msgpack.light/MsgPackMapElementAttribute.cs similarity index 88% rename from src/msgpack.light/Attributes/MsgPackMapElementAttribute.cs rename to src/msgpack.light/MsgPackMapElementAttribute.cs index 373481d..900703b 100644 --- a/src/msgpack.light/Attributes/MsgPackMapElementAttribute.cs +++ b/src/msgpack.light/MsgPackMapElementAttribute.cs @@ -1,6 +1,6 @@ using System; -namespace ProGaudi.MsgPack.Light +namespace ProGaudi.MsgPack { [AttributeUsage(AttributeTargets.Property)] public class MsgPackMapElementAttribute : Attribute diff --git a/src/msgpack.light/MsgPackMemoryStreamReader.cs b/src/msgpack.light/MsgPackMemoryStreamReader.cs deleted file mode 100644 index 6838fd7..0000000 --- a/src/msgpack.light/MsgPackMemoryStreamReader.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace ProGaudi.MsgPack.Light -{ - internal class MsgPackMemoryStreamReader : BaseMsgPackReader, IDisposable - { - private readonly MemoryStream _stream; - - private readonly bool _disposeStream; - - private readonly List<(byte, byte[])> _bytesGatheringBuffer = new List<(byte, byte[])>(); - - private bool _bytesGatheringInProgress; - - public MsgPackMemoryStreamReader(MemoryStream stream, bool disposeStream = true) - { - _stream = stream; - _disposeStream = disposeStream; - } - - public override byte ReadByte() - { - var temp = _stream.ReadByte(); - if (temp == -1) - { - throw ExceptionUtils.NotEnoughBytes(0, 1); - } - - var result = (byte) temp; - if (_bytesGatheringInProgress) - { - _bytesGatheringBuffer.Add((result, (byte[]) null)); - } - - return result; - } - - public override ArraySegment ReadBytes(uint length) - { - var buffer = ReadBytesInternal(length); - if (_bytesGatheringInProgress) - { - _bytesGatheringBuffer.Add((0, buffer)); - } - - return new ArraySegment(buffer, 0, buffer.Length); - } - - public override void Seek(long offset, SeekOrigin origin) - { - if (_bytesGatheringInProgress) - { - var buffer = ReadBytesInternal((uint)offset); - _bytesGatheringBuffer.Add((0, buffer)); - } - else - { - _stream.Seek(offset, origin); - } - } - - public void Dispose() - { - if (_disposeStream) - _stream.Dispose(); - } - - protected override IList StopTokenGathering() - { - var result = new List(); - foreach (var tuple in _bytesGatheringBuffer) - { - if (tuple.Item2 != null) - { - result.AddRange(tuple.Item2); - } - else - { - result.Add(tuple.Item1); - } - } - - _bytesGatheringInProgress = false; - return result; - } - - protected override void StartTokenGathering() - { - _bytesGatheringInProgress = true; - _bytesGatheringBuffer.Clear(); - } - - private byte[] ReadBytesInternal(uint length) - { - var buffer = new byte[length]; - var read = _stream.Read(buffer, 0, buffer.Length); - if (read < buffer.Length) - throw ExceptionUtils.NotEnoughBytes(read, buffer.Length); - return buffer; - } - } -} diff --git a/src/msgpack.light/MsgPackMemoryStreamWriter.cs b/src/msgpack.light/MsgPackMemoryStreamWriter.cs deleted file mode 100644 index 0919ca0..0000000 --- a/src/msgpack.light/MsgPackMemoryStreamWriter.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.IO; - -using ProGaudi.MsgPack.Light.Converters; - -namespace ProGaudi.MsgPack.Light -{ - internal class MsgPackMemoryStreamWriter : IMsgPackWriter, IDisposable - { - private readonly MemoryStream _stream; - - private readonly bool _disposeStream; - - public MsgPackMemoryStreamWriter(MemoryStream stream, bool disposeStream = true) - { - _stream = stream; - _disposeStream = disposeStream; - } - - public void Write(DataTypes dataType) - { - _stream.WriteByte((byte) dataType); - } - - public void Write(byte value) - { - _stream.WriteByte(value); - } - - public void Write(byte[] array) - { - _stream.Write(array, 0, array.Length); - } - - public void Dispose() - { - if (_disposeStream) - _stream.Dispose(); - } - - public void WriteArrayHeader(uint length) - { - if (length <= 15) - { - NumberConverter.WriteByteValue((byte) ((byte) DataTypes.FixArray + length), this); - return; - } - - if (length <= ushort.MaxValue) - { - Write(DataTypes.Array16); - NumberConverter.WriteUShortValue((ushort) length, this); - } - else - { - Write(DataTypes.Array32); - NumberConverter.WriteUIntValue(length, this); - } - - } - - public void WriteMapHeader(uint length) - { - if (length <= 15) - { - NumberConverter.WriteByteValue((byte) ((byte) DataTypes.FixMap + length), this); - return; - } - - if (length <= ushort.MaxValue) - { - Write(DataTypes.Map16); - NumberConverter.WriteUShortValue((ushort) length, this); - } - else - { - Write(DataTypes.Map32); - NumberConverter.WriteUIntValue(length, this); - } - } - } -} diff --git a/src/msgpack.light/MsgPackSerializer.cs b/src/msgpack.light/MsgPackSerializer.cs index 9801e83..e7fd125 100644 --- a/src/msgpack.light/MsgPackSerializer.cs +++ b/src/msgpack.light/MsgPackSerializer.cs @@ -1,99 +1,70 @@ -using System.IO; -using System.Runtime.Serialization; +using System; +using System.Buffers; using JetBrains.Annotations; -namespace ProGaudi.MsgPack.Light +using ProGaudi.Buffers; + +namespace ProGaudi.MsgPack { + [PublicAPI] public static class MsgPackSerializer { - public static byte[] Serialize(T data) - { - return Serialize(data, new MsgPackContext()); - } - - public static byte[] Serialize(T data, [NotNull]MsgPackContext context) - { - var memoryStream = new MemoryStream(); - using (var writer = new MsgPackMemoryStreamWriter(memoryStream)) - { - var converter = GetConverter(context); - converter.Write(data, writer); - return memoryStream.ToArray(); - } - } - - public static void Serialize(T data, MemoryStream stream) - { - Serialize(data, stream, new MsgPackContext()); - } - - public static void Serialize(T data, MemoryStream stream, [NotNull]MsgPackContext context) + public static IMemoryOwner Serialize(T data, out int wroteSize) { - using (var writer = new MsgPackMemoryStreamWriter(stream, false)) - { - var converter = GetConverter(context); - converter.Write(data, writer); - } + return Serialize(data, new MsgPackContext(), out wroteSize); } - public static MsgPackToken SerializeToToken(T data, [NotNull] MsgPackContext context) + public static IMemoryOwner Serialize(T data, [NotNull]MsgPackContext context, out int wroteSize) { - return new MsgPackToken(context, Serialize(data, context)); + var formatter = context.GetRequiredFormatter(); + var pool = formatter.HasConstantSize ? FixedLengthMemoryPool.Shared : MemoryPool.Shared; + var memory = pool.Rent(formatter.GetBufferSize(data)); + wroteSize = formatter.Format(memory.Memory.Span, data); + return memory; } - public static MsgPackToken SerializeToToken(T data) + public static int Serialize(T data, Span destination) { - return SerializeToToken(data, new MsgPackContext()); + return Serialize(data, destination, new MsgPackContext()); } - public static T Deserialize(byte[] data) + public static int Serialize(T data, Span destination, [NotNull]MsgPackContext context) { - return Deserialize(data, new MsgPackContext()); + var converter = context.GetRequiredFormatter(); + return converter.Format(destination, data); } - public static T Deserialize(MsgPackToken token) + public static T Deserialize(ReadOnlySpan data, out int readSize) { - return Deserialize(token, new MsgPackContext()); + return Deserialize(data, new MsgPackContext(), out readSize); } - public static T Deserialize(MsgPackToken token, [NotNull]MsgPackContext context) + public static T Deserialize(ReadOnlySpan data, [NotNull] MsgPackContext context) { - return Deserialize(token.RawBytes, context); + return Deserialize(data, context, out _); } - public static T Deserialize(byte[] data, [NotNull]MsgPackContext context) + public static T Deserialize(ReadOnlySpan data, [NotNull] MsgPackContext context, out int readSize) { - var reader = new MsgPackByteArrayReader(data); - var converter = GetConverter(context); - return converter.Read(reader); + var converter = context.GetRequiredParser(); + return converter.Parse(data, out readSize); } - public static T Deserialize(MemoryStream stream) + public static T Deserialize(ReadOnlySequence data, out int readSize) { - return Deserialize(stream, new MsgPackContext()); + return Deserialize(data, new MsgPackContext(), out readSize); } - public static T Deserialize(MemoryStream stream, [NotNull]MsgPackContext context) + public static T Deserialize(ReadOnlySequence data, [NotNull] MsgPackContext context) { - using (var reader = new MsgPackMemoryStreamReader(stream, false)) - { - var converter = GetConverter(context); - return converter.Read(reader); - } + return Deserialize(data, context, out _); } - [NotNull] - private static IMsgPackConverter GetConverter(MsgPackContext context) + public static T Deserialize(ReadOnlySequence data, [NotNull] MsgPackContext context, out int readSize) { - var converter = context.GetConverter(); - - if (converter == null) - { - throw new SerializationException($"Provide converter for {typeof(T).Name}"); - } - - return converter; + var converter = context.GetRequiredSequenceParser(); + return converter.Parse(data, out readSize); } } -} \ No newline at end of file +} diff --git a/src/msgpack.light/MsgPackToken.cs b/src/msgpack.light/MsgPackToken.cs deleted file mode 100644 index 6544f58..0000000 --- a/src/msgpack.light/MsgPackToken.cs +++ /dev/null @@ -1,605 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace ProGaudi.MsgPack.Light -{ - public class MsgPackToken - { - private static readonly MsgPackContext DefaultContext = new MsgPackContext(); - - private readonly MsgPackContext _context; - - public MsgPackToken(MsgPackContext context, byte[] rawBytes) - { - RawBytes = rawBytes; - _context = context; - } - - public MsgPackToken(byte[] value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - public MsgPackToken(bool value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - public MsgPackToken(string value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - public MsgPackToken(ulong value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - public MsgPackToken(long value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - public MsgPackToken(float value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - public MsgPackToken(double value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - public MsgPackToken(DateTime value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - public MsgPackToken(DateTimeOffset value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - public MsgPackToken(TimeSpan value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - public MsgPackToken(MsgPackToken[] value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - public MsgPackToken(Dictionary value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - private MsgPackToken(bool? value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - private MsgPackToken(ulong? value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - private MsgPackToken(uint value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - private MsgPackToken(long? value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - private MsgPackToken(uint? value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - private MsgPackToken(float? value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - private MsgPackToken(double? value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - private MsgPackToken(DateTime? value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - private MsgPackToken(DateTimeOffset? value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - private MsgPackToken(TimeSpan? value, MsgPackContext context = null) - { - _context = context; - RawBytes = MsgPackSerializer.Serialize(value, _context ?? DefaultContext); - } - - internal byte[] RawBytes { get; } - - #region Bool type conversion - - public static explicit operator MsgPackToken(bool b) - { - return new MsgPackToken(b); - } - - public static explicit operator bool(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region String type conversion - - public static explicit operator MsgPackToken(string str) - { - return new MsgPackToken(str); - } - - public static explicit operator string(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region byte[] type conversion - - public static explicit operator MsgPackToken(byte[] data) - { - return new MsgPackToken(data); - } - - public static explicit operator byte[] (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region ulong type conversion - - public static explicit operator MsgPackToken(ulong value) - { - return new MsgPackToken(value); - } - - public static explicit operator ulong(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region uint type conversion - - public static explicit operator MsgPackToken(uint value) - { - return new MsgPackToken(value); - } - - public static explicit operator uint(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region ushort type conversion - - public static explicit operator MsgPackToken(ushort value) - { - return new MsgPackToken(value); - } - - public static explicit operator ushort(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region byte type conversion - - public static explicit operator MsgPackToken(byte value) - { - return new MsgPackToken(value); - } - - public static explicit operator byte(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region long type conversion - - public static explicit operator MsgPackToken(long value) - { - return new MsgPackToken(value); - } - - public static explicit operator long(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region int type conversion - - public static explicit operator MsgPackToken(int value) - { - return new MsgPackToken(value); - } - - public static explicit operator int(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region short type conversion - - public static explicit operator MsgPackToken(short value) - { - return new MsgPackToken(value); - } - - public static explicit operator short(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region sbyte type conversion - - public static explicit operator MsgPackToken(sbyte value) - { - return new MsgPackToken(value); - } - - public static explicit operator sbyte(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region float type conversion - - public static explicit operator MsgPackToken(float value) - { - return new MsgPackToken(value); - } - - public static explicit operator float(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region double type conversion - - public static explicit operator MsgPackToken(double value) - { - return new MsgPackToken(value); - } - - public static explicit operator double(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region DateTime type conversion - - public static explicit operator MsgPackToken(DateTime value) - { - return new MsgPackToken(value); - } - - public static explicit operator DateTime(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region DateTimeOffset type conversion - - public static explicit operator MsgPackToken(DateTimeOffset value) - { - return new MsgPackToken(value); - } - - public static explicit operator DateTimeOffset(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region DateTimeOffset type conversion - - public static explicit operator MsgPackToken(TimeSpan value) - { - return new MsgPackToken(value); - } - - public static explicit operator TimeSpan(MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(bool? b) - { - return new MsgPackToken(b); - } - - public static explicit operator bool? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(ulong? value) - { - return new MsgPackToken(value); - } - - public static explicit operator ulong? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(uint? value) - { - return new MsgPackToken(value); - } - - public static explicit operator uint? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(ushort? value) - { - return new MsgPackToken(value); - } - - public static explicit operator ushort? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(byte? value) - { - return new MsgPackToken(value); - } - - public static explicit operator byte? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(long? value) - { - return new MsgPackToken(value); - } - - public static explicit operator long? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(int? value) - { - return new MsgPackToken(value); - } - - public static explicit operator int? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(short? value) - { - return new MsgPackToken(value); - } - - public static explicit operator short? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(sbyte? value) - { - return new MsgPackToken(value); - } - - public static explicit operator sbyte? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(float? value) - { - return new MsgPackToken(value); - } - - public static explicit operator float? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(double? value) - { - return new MsgPackToken(value); - } - - public static explicit operator double? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(DateTime? value) - { - return new MsgPackToken(value); - } - - public static explicit operator DateTime? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(DateTimeOffset? value) - { - return new MsgPackToken(value); - } - - public static explicit operator DateTimeOffset? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Nullable type conversion - - public static explicit operator MsgPackToken(TimeSpan? value) - { - return new MsgPackToken(value); - } - - public static explicit operator TimeSpan? (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region MsgPackToken[] type conversion - - public static explicit operator MsgPackToken(MsgPackToken[] value) - { - return new MsgPackToken(value); - } - - public static explicit operator MsgPackToken[] (MsgPackToken token) - { - return token.CastTokenToValue(); - } - - #endregion - - #region Dictionary type conversion - - public static explicit operator MsgPackToken(Dictionary value) - { - return new MsgPackToken(value); - } - - public static explicit operator Dictionary(MsgPackToken token) - { - return token.CastTokenToValue>(); - } - - #endregion - - private T CastTokenToValue() - { - return MsgPackSerializer.Deserialize(RawBytes, _context ?? DefaultContext); - } - } -} \ No newline at end of file diff --git a/src/msgpack.light/NonNullableConstraintViolationException.cs b/src/msgpack.light/NonNullableConstraintViolationException.cs new file mode 100644 index 0000000..8af8a63 --- /dev/null +++ b/src/msgpack.light/NonNullableConstraintViolationException.cs @@ -0,0 +1,13 @@ +using System; + +namespace ProGaudi.MsgPack +{ + [Serializable] + public sealed class NonNullableConstraintViolationException : ConstraintViolationException + { + public NonNullableConstraintViolationException(Exception innerException = null) + : base("Data is null, but expected to be not null.", innerException) + { + } + } +} \ No newline at end of file diff --git a/src/msgpack.light/Properties/AssemblyInfo.cs b/src/msgpack.light/Properties/AssemblyInfo.cs deleted file mode 100644 index 8015327..0000000 --- a/src/msgpack.light/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// 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("04D4E761-F756-43D8-B31C-79B1B0671243")] - -[assembly: InternalsVisibleTo("MsgPack.Light.Tests")] \ No newline at end of file diff --git a/src/msgpack.light/UnexpectedCodeException.cs b/src/msgpack.light/UnexpectedCodeException.cs new file mode 100644 index 0000000..6d88673 --- /dev/null +++ b/src/msgpack.light/UnexpectedCodeException.cs @@ -0,0 +1,16 @@ +using System; + +namespace ProGaudi.MsgPack +{ + [Serializable] + public class UnexpectedCodeException : ConstraintViolationException + { + public byte DataCode { get; } + + public UnexpectedCodeException(byte dataCode, Exception innerException = null) + : base($"We don't expect code '{dataCode}' here.", innerException) + { + DataCode = dataCode; + } + } +} \ No newline at end of file diff --git a/src/msgpack.light/msgpack.light.csproj b/src/msgpack.light/msgpack.light.csproj index 5c5f421..4b9cc28 100644 --- a/src/msgpack.light/msgpack.light.csproj +++ b/src/msgpack.light/msgpack.light.csproj @@ -1,17 +1,17 @@  - net45;net46;netstandard1.1;netstandard2.0 + net45;net46;net461;net462;net47;net471;netstandard1.4;netstandard2.0;netcoreapp2.1;netcoreapp2.2 - netstandard1.1;netstandard2.0 + netstandard1.4;netstandard2.0;netcoreapp2.1;netcoreapp2.2 Lightweight msgpack serialization library true - msgpack.light - ProGaudi.MsgPack.Light + progaudi.msgpack.light + ProGaudi.MsgPack msgpack.light - Copyright © 2016, 2017 + Copyright © 2016 - 2018 msgpack;serialization https://github.com/progaudi/MsgPack.Light https://raw.githubusercontent.com/progaudi/MsgPack.Light/master/LICENSE @@ -22,12 +22,21 @@ 1.4.0 roman-kozachenko;aensidhe progaudi + latest + true - - + + all + + + all + + + - + + - \ No newline at end of file + diff --git a/tests/msgpack.light.tests/A.cs b/tests/msgpack.light.tests/A.cs new file mode 100644 index 0000000..eb789b8 --- /dev/null +++ b/tests/msgpack.light.tests/A.cs @@ -0,0 +1,47 @@ +using System; +using System.Buffers; + +namespace ProGaudi.MsgPack.Light.Tests +{ + public struct A + { + public T F { get; set; } + } + + public class GenericFormatter : IMsgPackFormatter> + { + private readonly IMsgPackFormatter _formatter; + + public GenericFormatter(MsgPackContext context) => _formatter = context.GetRequiredFormatter(); + + public int GetBufferSize(A value) => _formatter.GetBufferSize(value.F); + + public bool HasConstantSize => false; + + public int Format(Span destination, A value) => _formatter.Format(destination, value.F); + } + + public class GenericParser : IMsgPackParser> + { + private readonly IMsgPackParser _parser; + + public GenericParser(MsgPackContext context) => _parser = context.GetRequiredParser(); + + public A Parse(ReadOnlySpan source, out int readSize) + { + return new A {F = _parser.Parse(source, out readSize)}; + } + } + + public class GenericSequenceParser : IMsgPackSequenceParser> + { + private readonly IMsgPackSequenceParser _parser; + + public GenericSequenceParser(MsgPackContext context) => _parser = context.GetRequiredSequenceParser(); + + public A Parse(ReadOnlySequence source, out int readSize) + { + return new A {F = _parser.Parse(source, out readSize)}; + } + } +} diff --git a/tests/msgpack.light.tests/Enums.cs b/tests/msgpack.light.tests/Enums.cs index 9b89bb1..684c074 100644 --- a/tests/msgpack.light.tests/Enums.cs +++ b/tests/msgpack.light.tests/Enums.cs @@ -29,7 +29,7 @@ public enum SbyteEnum : sbyte Value2, Value3 = 3, Value4 = sbyte.MaxValue, - Value5 = sbyte.MinValue, + Value5 = sbyte.MinValue } public enum ByteEnum : byte @@ -38,7 +38,7 @@ public enum ByteEnum : byte Value2, Value3 = 3, Value4 = byte.MaxValue, - Value5 = byte.MinValue, + Value5 = byte.MinValue } public enum ShortEnum : short @@ -47,7 +47,7 @@ public enum ShortEnum : short Value2, Value3 = 3, Value4 = short.MaxValue, - Value5 = short.MinValue, + Value5 = short.MinValue } public enum UshortEnum : ushort @@ -56,16 +56,16 @@ public enum UshortEnum : ushort Value2, Value3 = 3, Value4 = ushort.MaxValue, - Value5 = ushort.MinValue, + Value5 = ushort.MinValue } - public enum IntEnum : int + public enum IntEnum { Value1, Value2, Value3 = 3, Value4 = int.MaxValue, - Value5 = int.MinValue, + Value5 = int.MinValue } public enum UintEnum : uint @@ -74,7 +74,7 @@ public enum UintEnum : uint Value2, Value3 = 3, Value4 = uint.MaxValue, - Value5 = uint.MinValue, + Value5 = uint.MinValue } public enum LongEnum : long @@ -83,7 +83,7 @@ public enum LongEnum : long Value2, Value3 = 3, Value4 = long.MaxValue, - Value5 = long.MinValue, + Value5 = long.MinValue } public enum UlongEnum : ulong @@ -92,6 +92,6 @@ public enum UlongEnum : ulong Value2, Value3 = 3, Value4 = ulong.MaxValue, - Value5 = ulong.MinValue, + Value5 = ulong.MinValue } } \ No newline at end of file diff --git a/tests/msgpack.light.tests/Generators/ArrayContextFixture.cs b/tests/msgpack.light.tests/Generators/ArrayContextFixture.cs deleted file mode 100644 index 96bbec8..0000000 --- a/tests/msgpack.light.tests/Generators/ArrayContextFixture.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public abstract class ArrayContextFixture : ContextFixtureBase - { - protected ArrayContextFixture() - { - OldContext = new MsgPackContext(); - OldContext.RegisterConverter(new ImageInfoArrayConverter()); - OldContext.RegisterConverter(new ImageInfoArrayConverter()); - OldContext.RegisterConverter(new ImageInfoArrayConverter()); - OldContext.RegisterConverter(new ImageInfoArrayConverter()); - - NewContext = new MsgPackContext(); - } - } -} diff --git a/tests/msgpack.light.tests/Generators/BigImageInfo.cs b/tests/msgpack.light.tests/Generators/BigImageInfo.cs deleted file mode 100644 index e4eea5a..0000000 --- a/tests/msgpack.light.tests/Generators/BigImageInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public class BigImageInfo : ImageInfo - { - [MsgPackMapElement("Size2")] - [MsgPackArrayElement(5)] - public int Size { get; set; } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/Generators/ClassInheritanceTest.cs b/tests/msgpack.light.tests/Generators/ClassInheritanceTest.cs deleted file mode 100644 index 1fae700..0000000 --- a/tests/msgpack.light.tests/Generators/ClassInheritanceTest.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; - -using Shouldly; - -using Xunit; - -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public class ClassInheritanceTest : MapGeneratorTestBase - { - [Theory] - [ClassData(typeof(FixtureProvider))] - public void WriteSmoke(ContextFixtureBase fixture) - { - var testObject = new BigImageInfo - { - Credits = Guid.NewGuid().ToString("N"), - Height = 123, - Link = Guid.NewGuid().ToString("N"), - Size = 234, - Width = 345 - }; - - MsgPackSerializer.Serialize(testObject, fixture.NewContext).ShouldBe(MsgPackSerializer.Serialize(testObject, fixture.OldContext)); - } - - - - public class MapFixture : MapContextFixture - { - public MapFixture() - { - NewContext.GenerateAndRegisterMapConverter(); - } - } - - public class ArrayFixture : ArrayContextFixture - { - public ArrayFixture() - { - NewContext.GenerateAndRegisterArrayConverter(); - } - } - } -} diff --git a/tests/msgpack.light.tests/Generators/ClassTest.cs b/tests/msgpack.light.tests/Generators/ClassTest.cs deleted file mode 100644 index 002efab..0000000 --- a/tests/msgpack.light.tests/Generators/ClassTest.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Shouldly; - -using Xunit; - -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public class ClassTest : MapGeneratorTestBase - { - [Theory] - [ClassData(typeof(FixtureProvider))] - public void WriteSmoke(ContextFixtureBase fixture) - { - var testObject = CreateTestObject(); - - MsgPackSerializer.Serialize(testObject, fixture.NewContext).ShouldBe(MsgPackSerializer.Serialize(testObject, fixture.OldContext)); - } - - [Theory] - [ClassData(typeof(FixtureProvider))] - public void ReadSmoke(ContextFixtureBase fixture) - { - var expected = CreateTestObject(); - - var actual = MsgPackSerializer.Deserialize(MsgPackSerializer.Serialize(expected, fixture.NewContext), fixture.NewContext); - AssertEqual(actual, expected); - } - - [Theory] - [ClassData(typeof(FixtureProvider))] - public void WriteNewReadOld(ContextFixtureBase fixture) - { - var expected = CreateTestObject(); - - var actual = MsgPackSerializer.Deserialize(MsgPackSerializer.Serialize(expected, fixture.NewContext), fixture.OldContext); - - AssertEqual(actual, expected); - } - - [Theory] - [ClassData(typeof(FixtureProvider))] - public void WriteOldReadNew(ContextFixtureBase fixture) - { - var expected = CreateTestObject(); - - var actual = MsgPackSerializer.Deserialize(MsgPackSerializer.Serialize(expected, fixture.OldContext), fixture.NewContext); - AssertEqual(actual, expected); - } - - public class MapFixture : MapContextFixture - { - public MapFixture() - { - NewContext.GenerateAndRegisterMapConverter(); - } - } - - public class ArrayFixture : ArrayContextFixture - { - public ArrayFixture() - { - NewContext.GenerateAndRegisterArrayConverter(); - } - } - } -} diff --git a/tests/msgpack.light.tests/Generators/ContextFixtureBase.cs b/tests/msgpack.light.tests/Generators/ContextFixtureBase.cs deleted file mode 100644 index 6098bbc..0000000 --- a/tests/msgpack.light.tests/Generators/ContextFixtureBase.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public abstract class ContextFixtureBase - { - public MsgPackContext NewContext { get; protected set; } - - public MsgPackContext OldContext { get; protected set; } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/Generators/Discovery/Properties.cs b/tests/msgpack.light.tests/Generators/Discovery/Properties.cs deleted file mode 100644 index 496f70d..0000000 --- a/tests/msgpack.light.tests/Generators/Discovery/Properties.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System.Linq; - -using ProGaudi.MsgPack.Light.Converters.Generation; - -using Shouldly; - -using Xunit; - -namespace ProGaudi.MsgPack.Light.Tests.Generators.Discovery -{ - public class Properties - { - [Fact] - public void SimpleTest() - { - var provider = new PropertyProvider(); - provider.GetProperties(typeof(IC)).Select(x => x.Name).ShouldBe(new [] { "D" }); - provider.GetProperties(typeof(IA)).Select(x => x.Name).ShouldBe(new [] { "D" }); - provider.GetProperties(typeof(IB)).Select(x => x.Name).ShouldBe(new [] { "D" }); - - provider.GetProperties(typeof(A)).Select(x => x.Name).ShouldBe(new [] { "D" }); - provider.GetProperties(typeof(B)).Select(x => x.Name).ShouldBe(new [] { "D" }); - provider.GetProperties(typeof(C)).Select(x => x.Name).ShouldBe(new [] { "D" }); - } - - [Fact] - public void NewShouldBeReturned() - { - var provider = new PropertyProvider(); - var properties = provider.GetProperties(typeof(ID)); - properties.Select(x => x.Name).ShouldBe(new[] { "D" }); - properties.Select(x => x.DeclaringType).ShouldBe(new[] {typeof(ID)}); - } - - [Fact] - public void Regression71() - { - var context = new MsgPackContext(); - Should.NotThrow(() => context.GenerateAndRegisterMapConverter()); - } - - [Fact] - public void Regression70() - { - var context = new MsgPackContext(); - Should.NotThrow(() => context.GenerateAndRegisterMapConverter()); - } - - public class C : B, IC - { - } - - public class B : A, IB - { - } - - public class A : IA - { - public string D { get; set; } - } - - public interface IC : IB - { - } - - public interface IB : IA - { - } - - public interface IA - { - [MsgPackMapElement("T")] - string D { get; } - } - - public interface ID : IA - { - new string D { get; } - } - } -} diff --git a/tests/msgpack.light.tests/Generators/FullTest.cs b/tests/msgpack.light.tests/Generators/FullTest.cs deleted file mode 100644 index e6b0311..0000000 --- a/tests/msgpack.light.tests/Generators/FullTest.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Shouldly; - -using Xunit; - -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public class FullTest : MapGeneratorTestBase - { - [Theory] - [ClassData(typeof(FixtureProvider))] - public void WriteSmoke(ContextFixtureBase fixture) - { - IImageInfo testObject = CreateTestObject(); - - MsgPackSerializer.Serialize(testObject, fixture.NewContext).ShouldBe(MsgPackSerializer.Serialize(testObject, fixture.OldContext)); - } - - [Theory] - [ClassData(typeof(FixtureProvider))] - public void ReadSmoke(ContextFixtureBase fixture) - { - IImageInfo expected = CreateTestObject(); - - var actual = MsgPackSerializer.Deserialize(MsgPackSerializer.Serialize(expected, fixture.NewContext), fixture.NewContext); - AssertEqual(actual, expected); - } - - [Theory] - [ClassData(typeof(FixtureProvider))] - public void WriteNewReadOld(ContextFixtureBase fixture) - { - IImageInfo expected = CreateTestObject(); - - var actual = MsgPackSerializer.Deserialize(MsgPackSerializer.Serialize(expected, fixture.NewContext), fixture.OldContext); - - AssertEqual(actual, expected); - } - - [Theory] - [ClassData(typeof(FixtureProvider))] - public void WriteOldReadNew(ContextFixtureBase fixture) - { - IImageInfo expected = CreateTestObject(); - - var actual = MsgPackSerializer.Deserialize(MsgPackSerializer.Serialize(expected, fixture.OldContext), fixture.NewContext); - AssertEqual(actual, expected); - } - - public class MapFixture : MapContextFixture - { - public MapFixture() - { - NewContext.GenerateAndRegisterMapConverter(); - } - } - - public class ArrayFixture : ArrayContextFixture - { - public ArrayFixture() - { - NewContext.GenerateAndRegisterArrayConverter(); - } - } - } -} diff --git a/tests/msgpack.light.tests/Generators/IImageInfo.cs b/tests/msgpack.light.tests/Generators/IImageInfo.cs deleted file mode 100644 index 9c59171..0000000 --- a/tests/msgpack.light.tests/Generators/IImageInfo.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public interface IImageInfo - { - [MsgPackMapElement("Width")] - [MsgPackArrayElement(0)] - int Width { get; } - - [MsgPackMapElement("Height")] - [MsgPackArrayElement(1)] - int Height { get; } - - [MsgPackMapElement("Link")] - [MsgPackArrayElement(2)] - string Link { get; } - - [MsgPackMapElement("Credits")] - [MsgPackArrayElement(4)] - string Credits { get; } - - string NotSerializedProperty { get; } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/Generators/IMegaImageInfo.cs b/tests/msgpack.light.tests/Generators/IMegaImageInfo.cs deleted file mode 100644 index b264eb6..0000000 --- a/tests/msgpack.light.tests/Generators/IMegaImageInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public interface IMegaImageInfo : IImageInfo - { - [MsgPackMapElement("CreationDate")] - [MsgPackArrayElement(5)] - DateTime SomeDate { get; } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/Generators/ImageInfo.cs b/tests/msgpack.light.tests/Generators/ImageInfo.cs deleted file mode 100644 index a5003c9..0000000 --- a/tests/msgpack.light.tests/Generators/ImageInfo.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public class ImageInfo : IImageInfo - { - [MsgPackMapElement("Width")] - [MsgPackArrayElement(0)] - public int Width { get; set; } - - [MsgPackMapElement("Height")] - [MsgPackArrayElement(1)] - public int Height { get; set; } - - [MsgPackMapElement("Link")] - [MsgPackArrayElement(2)] - public string Link { get; set; } - - [MsgPackMapElement("Credits")] - [MsgPackArrayElement(4)] - public string Credits { get; set; } - - public string NotSerializedProperty { get; set; } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/Generators/ImageInfoArrayConverter.cs b/tests/msgpack.light.tests/Generators/ImageInfoArrayConverter.cs deleted file mode 100644 index 373edab..0000000 --- a/tests/msgpack.light.tests/Generators/ImageInfoArrayConverter.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System; - -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - internal class ImageInfoArrayConverter : IMsgPackConverter, IMsgPackConverter, IMsgPackConverter, IMsgPackConverter - { - private Lazy> _intConverter; - private Lazy> _dateTimeConverter; - private Lazy> _stringConverter; - - public void Initialize(MsgPackContext context) - { - _intConverter = new Lazy>(context.GetConverter); - _dateTimeConverter = new Lazy>(context.GetConverter); - _stringConverter = new Lazy>(context.GetConverter); - } - - private ImageInfo ReadImplementation(IMsgPackReader reader) - { - var imageInfo = new ImageInfo(); - var nullable = reader.ReadArrayLength(); - if (!nullable.HasValue) - return null; - for (var index = 0; index < nullable.Value; ++index) - { - if (!ReadImageInfoBody(index, imageInfo, reader)) - { - reader.SkipToken(); - } - } - return imageInfo; - } - - private bool ReadImageInfoBody(int propertyIndex, ImageInfo imageInfo, IMsgPackReader reader) - { - switch (propertyIndex) - { - case 0: - imageInfo.Width = _intConverter.Value.Read(reader); - return true; - case 1: - imageInfo.Height = _intConverter.Value.Read(reader); - return true; - case 2: - imageInfo.Link = _stringConverter.Value.Read(reader); - return true; - case 4: - imageInfo.Credits = _stringConverter.Value.Read(reader); - return true; - default: - return false; - } - } - - private void WriteImplementation(IImageInfo value, IMsgPackWriter writer) - { - if (value == null) - { - writer.Write(DataTypes.Null); - } - else - { - writer.WriteArrayHeader(5U); - WriteImageInfoBody(value, writer); - } - } - - private void WriteImageInfoBody(IImageInfo value, IMsgPackWriter writer) - { - _intConverter.Value.Write(value.Width, writer); - _intConverter.Value.Write(value.Height, writer); - _stringConverter.Value.Write(value.Link, writer); - writer.Write(DataTypes.Null); - _stringConverter.Value.Write(value.Credits, writer); - } - - void IMsgPackConverter.Write(IImageInfo value, IMsgPackWriter writer) - { - WriteImplementation(value, writer); - } - - void IMsgPackConverter.Write(ImageInfo value, IMsgPackWriter writer) - { - WriteImplementation(value, writer); - } - - public void Write(BigImageInfo value, IMsgPackWriter writer) - { - if (value == null) - { - writer.Write(DataTypes.Null); - } - else - { - writer.WriteArrayHeader(6U); - - WriteImageInfoBody(value, writer); - _intConverter.Value.Write(value.Size, writer); - } - } - - public void Write(IMegaImageInfo value, IMsgPackWriter writer) - { - if (value == null) - { - writer.Write(DataTypes.Null); - } - else - { - writer.WriteArrayHeader(6U); - - WriteImageInfoBody(value, writer); - _dateTimeConverter.Value.Write(value.SomeDate, writer); - } - } - - IMegaImageInfo IMsgPackConverter.Read(IMsgPackReader reader) - { - var imageInfo = new MegaImageInfo(); - var nullable = reader.ReadArrayLength(); - if (!nullable.HasValue) - return null; - for (var index = 0; index < nullable.Value; ++index) - { - if (ReadImageInfoBody(index, imageInfo, reader)) - { - continue; - } - - if (index == 5) - { - imageInfo.SomeDate = _dateTimeConverter.Value.Read(reader); - } - else - { - reader.SkipToken(); - } - } - - return imageInfo; - } - - public BigImageInfo Read(IMsgPackReader reader) - { - var imageInfo = new BigImageInfo(); - var nullable = reader.ReadArrayLength(); - if (!nullable.HasValue) - return null; - for (var index = 0; index < nullable.Value; ++index) - { - if (ReadImageInfoBody(index, imageInfo, reader)) - { - continue; - } - - if (index == 5) - { - imageInfo.Size = _intConverter.Value.Read(reader); - } - else - { - reader.SkipToken(); - } - } - - return imageInfo; - } - - IImageInfo IMsgPackConverter.Read(IMsgPackReader reader) - { - return ReadImplementation(reader); - } - - ImageInfo IMsgPackConverter.Read(IMsgPackReader reader) - { - return ReadImplementation(reader); - } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/Generators/ImageInfoMapConverter.cs b/tests/msgpack.light.tests/Generators/ImageInfoMapConverter.cs deleted file mode 100644 index fe2819a..0000000 --- a/tests/msgpack.light.tests/Generators/ImageInfoMapConverter.cs +++ /dev/null @@ -1,189 +0,0 @@ -using System; - -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - internal class ImageInfoMapConverter : IMsgPackConverter, IMsgPackConverter, IMsgPackConverter, IMsgPackConverter - { - private Lazy> _intConverter; - private Lazy> _dateTimeConverter; - private Lazy> _stringConverter; - - public void Initialize(MsgPackContext context) - { - _intConverter = new Lazy>(context.GetConverter); - _dateTimeConverter = new Lazy>(context.GetConverter); - _stringConverter = new Lazy>(context.GetConverter); - } - - private ImageInfo ReadImplementation(IMsgPackReader reader) - { - var imageInfo = new ImageInfo(); - var nullable = reader.ReadMapLength(); - if (!nullable.HasValue) - return null; - for (var index = 0; index < nullable.Value; ++index) - { - var str = _stringConverter.Value.Read(reader); - if (!ReadImageInfoBody(str, imageInfo, reader)) - { - reader.SkipToken(); - } - } - return imageInfo; - } - - private bool ReadImageInfoBody(string propertyName, ImageInfo imageInfo, IMsgPackReader reader) - { - switch (propertyName) - { - case "Width": - imageInfo.Width = _intConverter.Value.Read(reader); - return true; - case "Height": - imageInfo.Height = _intConverter.Value.Read(reader); - return true; - case "Link": - imageInfo.Link = _stringConverter.Value.Read(reader); - return true; - case "Credits": - imageInfo.Credits = _stringConverter.Value.Read(reader); - return true; - default: - return false; - } - } - - private void WriteImplementation(IImageInfo value, IMsgPackWriter writer) - { - if (value == null) - { - writer.Write(DataTypes.Null); - } - else - { - writer.WriteMapHeader(4U); - WriteImageInfoBody(value, writer); - } - } - - private void WriteImageInfoBody(IImageInfo value, IMsgPackWriter writer) - { - _stringConverter.Value.Write("Width", writer); - _intConverter.Value.Write(value.Width, writer); - _stringConverter.Value.Write("Height", writer); - _intConverter.Value.Write(value.Height, writer); - _stringConverter.Value.Write("Link", writer); - _stringConverter.Value.Write(value.Link, writer); - _stringConverter.Value.Write("Credits", writer); - _stringConverter.Value.Write(value.Credits, writer); - } - - void IMsgPackConverter.Write(IImageInfo value, IMsgPackWriter writer) - { - WriteImplementation(value, writer); - } - - void IMsgPackConverter.Write(ImageInfo value, IMsgPackWriter writer) - { - WriteImplementation(value, writer); - } - - public void Write(BigImageInfo value, IMsgPackWriter writer) - { - if (value == null) - { - writer.Write(DataTypes.Null); - } - else - { - writer.WriteMapHeader(5U); - - _stringConverter.Value.Write("Size2", writer); - _intConverter.Value.Write(value.Size, writer); - - WriteImageInfoBody(value, writer); - } - } - - public void Write(IMegaImageInfo value, IMsgPackWriter writer) - { - if (value == null) - { - writer.Write(DataTypes.Null); - } - else - { - writer.WriteMapHeader(5U); - - _stringConverter.Value.Write("CreationDate", writer); - _dateTimeConverter.Value.Write(value.SomeDate, writer); - - WriteImageInfoBody(value, writer); - } - } - - IMegaImageInfo IMsgPackConverter.Read(IMsgPackReader reader) - { - var imageInfo = new MegaImageInfo(); - var nullable = reader.ReadMapLength(); - if (!nullable.HasValue) - return null; - for (var index = 0; index < nullable.Value; ++index) - { - var str = _stringConverter.Value.Read(reader); - if (ReadImageInfoBody(str, imageInfo, reader)) - { - continue; - } - - if (str == "CreationDate") - { - imageInfo.SomeDate = _dateTimeConverter.Value.Read(reader); - } - else - { - reader.SkipToken(); - } - } - - return imageInfo; - } - - public BigImageInfo Read(IMsgPackReader reader) - { - var imageInfo = new BigImageInfo(); - var nullable = reader.ReadMapLength(); - if (!nullable.HasValue) - return null; - for (var index = 0; index < nullable.Value; ++index) - { - var str = _stringConverter.Value.Read(reader); - if (ReadImageInfoBody(str, imageInfo, reader)) - { - continue; - } - - if (str == "Size2") - { - imageInfo.Size = _intConverter.Value.Read(reader); - } - else - { - reader.SkipToken(); - } - } - - return imageInfo; - } - - IImageInfo IMsgPackConverter.Read(IMsgPackReader reader) - { - return ReadImplementation(reader); - } - - ImageInfo IMsgPackConverter.Read(IMsgPackReader reader) - { - return ReadImplementation(reader); - } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/Generators/InterfaceInheritanceTest.cs b/tests/msgpack.light.tests/Generators/InterfaceInheritanceTest.cs deleted file mode 100644 index 40e8955..0000000 --- a/tests/msgpack.light.tests/Generators/InterfaceInheritanceTest.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; - -using Shouldly; - -using Xunit; - -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public class InterfaceInheritanceTest : MapGeneratorTestBase - { - [Theory] - [ClassData(typeof(FixtureProvider))] - public void DescendantConverterCanUseAscendant(ContextFixtureBase fixture) - { - IImageInfo expected = CreateTestObject(); - - var actual = MsgPackSerializer.Deserialize(MsgPackSerializer.Serialize(expected, fixture.OldContext), fixture.NewContext); - actual.ShouldBeAssignableTo(); - AssertEqual(actual, expected); - } - - [Theory] - [ClassData(typeof(FixtureProvider))] - public void InterfaceInheritance(ContextFixtureBase fixture) - { - IMegaImageInfo expected = new MegaImageInfo - { - Credits = Guid.NewGuid().ToString("N"), - Height = 123, - Link = Guid.NewGuid().ToString("N"), - SomeDate = DateTime.UtcNow, - Width = 345 - }; - - var actual = MsgPackSerializer.Deserialize(MsgPackSerializer.Serialize(expected, fixture.OldContext), fixture.NewContext); - actual.ShouldBeAssignableTo(); - AssertEqual(actual, expected); - } - - public class MapFixture : MapContextFixture - { - public MapFixture() - { - NewContext.GenerateAndRegisterMapConverter(); - NewContext.GenerateAndRegisterMapConverter(); - } - } - - public class ArrayFixture : ArrayContextFixture - { - public ArrayFixture() - { - NewContext.GenerateAndRegisterArrayConverter(); - NewContext.GenerateAndRegisterArrayConverter(); - } - } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/Generators/InterfaceTest.cs b/tests/msgpack.light.tests/Generators/InterfaceTest.cs deleted file mode 100644 index 5726801..0000000 --- a/tests/msgpack.light.tests/Generators/InterfaceTest.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Shouldly; - -using Xunit; - -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public class InterfaceTest : MapGeneratorTestBase - { - [Theory] - [ClassData(typeof(FixtureProvider))] - public void WriteSmoke(ContextFixtureBase fixture) - { - IImageInfo testObject = CreateTestObject(); - - MsgPackSerializer.Serialize(testObject, fixture.NewContext).ShouldBe(MsgPackSerializer.Serialize(testObject, fixture.OldContext)); - } - - [Theory] - [ClassData(typeof(FixtureProvider))] - public void ReadSmoke(ContextFixtureBase fixture) - { - IImageInfo expected = CreateTestObject(); - - var actual = MsgPackSerializer.Deserialize(MsgPackSerializer.Serialize(expected, fixture.NewContext), fixture.NewContext); - AssertEqual(actual, expected); - } - - [Theory] - [ClassData(typeof(FixtureProvider))] - public void WriteNewReadOld(ContextFixtureBase fixture) - { - IImageInfo expected = CreateTestObject(); - - var actual = MsgPackSerializer.Deserialize(MsgPackSerializer.Serialize(expected, fixture.NewContext), fixture.OldContext); - - AssertEqual(actual, expected); - } - - [Theory] - [ClassData(typeof(FixtureProvider))] - public void WriteOldReadNew(ContextFixtureBase fixture) - { - IImageInfo expected = CreateTestObject(); - - var actual = MsgPackSerializer.Deserialize(MsgPackSerializer.Serialize(expected, fixture.OldContext), fixture.NewContext); - AssertEqual(actual, expected); - } - - public class MapFixture : MapContextFixture - { - public MapFixture() - { - NewContext.GenerateAndRegisterMapConverter(); - } - } - - public class ArrayFixture : ArrayContextFixture - { - public ArrayFixture() - { - NewContext.GenerateAndRegisterArrayConverter(); - } - } - } -} diff --git a/tests/msgpack.light.tests/Generators/MapContextFixture.cs b/tests/msgpack.light.tests/Generators/MapContextFixture.cs deleted file mode 100644 index 5d55b37..0000000 --- a/tests/msgpack.light.tests/Generators/MapContextFixture.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public abstract class MapContextFixture : ContextFixtureBase - { - protected MapContextFixture() - { - OldContext = new MsgPackContext(); - OldContext.RegisterConverter(new ImageInfoMapConverter()); - OldContext.RegisterConverter(new ImageInfoMapConverter()); - OldContext.RegisterConverter(new ImageInfoMapConverter()); - OldContext.RegisterConverter(new ImageInfoMapConverter()); - - NewContext = new MsgPackContext(); - } - } -} diff --git a/tests/msgpack.light.tests/Generators/MapGeneratorTestBase.cs b/tests/msgpack.light.tests/Generators/MapGeneratorTestBase.cs deleted file mode 100644 index a1250c9..0000000 --- a/tests/msgpack.light.tests/Generators/MapGeneratorTestBase.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Shouldly; - -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public class MapGeneratorTestBase - { - protected static ImageInfo CreateTestObject() - { - return new ImageInfo - { - Credits = "123", - Height = 234, - Link = "345ыва", - Width = 456 - }; - } - - protected static void AssertEqual(IImageInfo actual, IImageInfo expected) - { - actual.Credits.ShouldBe(expected.Credits); - actual.Height.ShouldBe(expected.Height); - actual.Width.ShouldBe(expected.Width); - actual.Link.ShouldBe(expected.Link); - } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/Generators/MarkedClass.cs b/tests/msgpack.light.tests/Generators/MarkedClass.cs deleted file mode 100644 index c83a8be..0000000 --- a/tests/msgpack.light.tests/Generators/MarkedClass.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - [MsgPackMap] - public class MarkedClass - { - [MsgPackMapElement("Asdf")] - public int A { get; set; } - } -} diff --git a/tests/msgpack.light.tests/Generators/MarkedClassesTest.cs b/tests/msgpack.light.tests/Generators/MarkedClassesTest.cs deleted file mode 100644 index 6a1a3ee..0000000 --- a/tests/msgpack.light.tests/Generators/MarkedClassesTest.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; - -using Shouldly; - -using Xunit; - -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public class MarkedClassesTest - { - [Fact] - public void DiscoverTest() - { - var context = new MsgPackContext(); - context.DiscoverConverters(); - context.GetConverter().ShouldBeAssignableTo>(); - context.GetConverter().ShouldBeAssignableTo>(); - - var emptyContext = new MsgPackContext(); - - var discoveredConvertersCount = context.DumpConvertersCache().Count; - var standardConvertersCount = emptyContext.DumpConvertersCache().Count; - discoveredConvertersCount.ShouldBeGreaterThan(standardConvertersCount); - (discoveredConvertersCount - standardConvertersCount).ShouldBe(2); - } - - [Fact] - public void SmokeSerialization() - { - var oldContext = new MsgPackContext(); - oldContext.RegisterConverter(new InnerClassConverter()); - - var newContext = new MsgPackContext(); - newContext.DiscoverConverters(); - - var s = Guid.NewGuid().ToString("B"); - var expected = new InnerClass {B = s}; - MsgPackSerializer.Serialize(expected, newContext).ShouldBe(MsgPackSerializer.Serialize(expected, oldContext)); - MsgPackSerializer.Deserialize(MsgPackSerializer.Serialize(expected, oldContext), newContext).B.ShouldBe(s); - MsgPackSerializer.Deserialize(MsgPackSerializer.Serialize(expected, newContext), oldContext).B.ShouldBe(s); - } - - [MsgPackMap] - public class InnerClass - { - [MsgPackMapElement("Qwer")] - public string B { get; set; } - } - - public class InnerClassConverter : IMsgPackConverter - { - private Lazy> _stringConverter; - - public void Initialize(MsgPackContext context) - { - _stringConverter = new Lazy>(context.GetConverter); - } - - public void Write(InnerClass value, IMsgPackWriter writer) - { - if (value == null) - { - writer.Write(DataTypes.Null); - } - else - { - writer.WriteMapHeader(1U); - _stringConverter.Value.Write("Qwer", writer); - _stringConverter.Value.Write(value.B, writer); - } - } - - public InnerClass Read(IMsgPackReader reader) - { - var instance = new InnerClass(); - var nullable = reader.ReadMapLength(); - if (!nullable.HasValue) - return null; - for (var index = 0; index < nullable.Value; ++index) - { - var str = _stringConverter.Value.Read(reader); - switch (str) - { - case "Qwer": - instance.B = _stringConverter.Value.Read(reader); - break; - default: - reader.SkipToken(); - break; - } - } - return instance; - } - } - } -} diff --git a/tests/msgpack.light.tests/Generators/MegaImageInfo.cs b/tests/msgpack.light.tests/Generators/MegaImageInfo.cs deleted file mode 100644 index 543aeaf..0000000 --- a/tests/msgpack.light.tests/Generators/MegaImageInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace ProGaudi.MsgPack.Light.Tests.Generators -{ - public class MegaImageInfo : ImageInfo, IMegaImageInfo - { - public DateTime SomeDate { get; set; } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/MemoryExtensions.cs b/tests/msgpack.light.tests/MemoryExtensions.cs new file mode 100644 index 0000000..f673863 --- /dev/null +++ b/tests/msgpack.light.tests/MemoryExtensions.cs @@ -0,0 +1,11 @@ +using System; + +using Shouldly; + +namespace ProGaudi.MsgPack.Light.Tests +{ + public static class MemoryExtensions + { + public static void ShouldBe(this Memory actual, Memory expected) => actual.ToArray().ShouldBe(expected.ToArray()); + } +} diff --git a/tests/msgpack.light.tests/MsgPackContextTests.cs b/tests/msgpack.light.tests/MsgPackContextTests.cs deleted file mode 100644 index 45f0781..0000000 --- a/tests/msgpack.light.tests/MsgPackContextTests.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Shouldly; - -using Xunit; - -namespace ProGaudi.MsgPack.Light.Tests -{ - public class MsgPackContextTests - { - [Fact] - public void GetConverterShouldNotThrow() - { - var context = new MsgPackContext(); - - var ex = Should.Throw(() => context.GetConverter()); - ex.ObjectType.ShouldBe(typeof(MsgPackContextTests)); - } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/Reader/Array.cs b/tests/msgpack.light.tests/Reader/Array.cs index ab43888..7b980a7 100644 --- a/tests/msgpack.light.tests/Reader/Array.cs +++ b/tests/msgpack.light.tests/Reader/Array.cs @@ -1,6 +1,4 @@ using Shouldly; -using System.Collections.Generic; -using System.Linq; using Xunit; @@ -30,60 +28,20 @@ public void SimpleArray() 161, 101 }; - MsgPackSerializer.Deserialize(bytes).ShouldBe(tests); - - var token = Helpers.CheckTokenDeserialization(bytes); - ((MsgPackToken[])token).Select(t => (string)t).ToArray().ShouldBe(tests); - } - - [Fact] - public void TestArrayPack() - { - var expected = new object[] - { - 0, - 50505, - float.NaN, - float.MaxValue, - new[] {true, false, true}, - null, - new Dictionary {{"Ball", "Soccer"}} - }; - - var data = new byte[] - { - 151, - 0, - 205, 197, 73, - 202, 255, 192, 0, 0, - 202, 127, 127, 255, 255, - 147, - 195, - 194, - 195, - 192, - 129, - 164, 66, 97, 108, 108, 166, 83, 111, 99, 99, 101, 114 - }; - - var settings = new MsgPackContext(); - settings.RegisterConverter(new TestReflectionConverter()); - - MsgPackSerializer.Deserialize(data, settings).ShouldBe(expected); - - Helpers.CheckTokenDeserialization(data); + MsgPackSerializer.Deserialize(bytes, out var readSize).ShouldBe(tests); + readSize.ShouldBe(bytes.Length); } [Fact] public void TestNonFixedArray() { var array = new[] - { - 1, 2, 3, 4, 5, - 1, 2, 3, 4, 5, - 1, 2, 3, 4, 5, - 1, 2, 3, 4, 5, - }; + { + 1, 2, 3, 4, 5, + 1, 2, 3, 4, 5, + 1, 2, 3, 4, 5, + 1, 2, 3, 4, 5 + }; var bytes = new byte[] { @@ -94,13 +52,11 @@ public void TestNonFixedArray() 0x01, 0x02, 0x03, 0x04, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x01, 0x02, 0x03, 0x04, 0x05, + 0x01, 0x02, 0x03, 0x04, 0x05 }; - MsgPackSerializer.Deserialize(bytes).ShouldBe(array); - - var token = Helpers.CheckTokenDeserialization(bytes); - ((MsgPackToken[])token).Select(t => (int)t).ToArray().ShouldBe(array); + MsgPackSerializer.Deserialize(bytes, out int readSize).ShouldBe(array); + readSize.ShouldBe(bytes.Length); } } } diff --git a/tests/msgpack.light.tests/Reader/Binary.cs b/tests/msgpack.light.tests/Reader/Binary.cs index 8d4c3cb..f627172 100644 --- a/tests/msgpack.light.tests/Reader/Binary.cs +++ b/tests/msgpack.light.tests/Reader/Binary.cs @@ -1,4 +1,6 @@ -using System.Runtime.Serialization; +using System; + +using ProGaudi.MsgPack.Converters.Binary; using Shouldly; @@ -85,16 +87,14 @@ public class Binary })] public void Test(byte[] value, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(value); - - var token = Helpers.CheckTokenDeserialization(data); - ((byte[])token).ShouldBe(value); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(value); + readSize.ShouldBe(data.Length); } [Theory] - [InlineData(new byte[] {160})] - [InlineData(new byte[] {161, 1})] - [InlineData(new byte[] + [InlineData("Wrong data code: 0xa0. Expected: 0xc4, 0xc5 or 0xc6.", new byte[] {160})] + [InlineData("Wrong data code: 0xa1. Expected: 0xc4, 0xc5 or 0xc6.", new byte[] {161, 1})] + [InlineData("Wrong data code: 0xda. Expected: 0xc4, 0xc5 or 0xc6.", new byte[] { 218, 1, 44, @@ -131,10 +131,10 @@ public void Test(byte[] value, byte[] data) 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 })] - public void FailToReadOldBinary(byte[] data) + public void FailToReadOldBinary(string message, byte[] data) { - var e = Should.Throw(() => MsgPackSerializer.Deserialize(data)); - e.Message.ShouldBe("Reading a string as a byte array is disabled. Set 'binaryCompatibilityMode' parameter in MsgPackContext constructor to true to enable it"); + var e = Should.Throw(() => Converter.Current.Parse(data, out _)); + e.Message.ShouldBe(message); } [Theory] @@ -214,9 +214,8 @@ public void FailToReadOldBinary(byte[] data) })] public void ReadOldBinary(byte[] value, byte[] data) { - var context = new MsgPackContext(binaryCompatibilityMode: true); - var result = Should.NotThrow(() => MsgPackSerializer.Deserialize(data, context)); - result.ShouldBe(value); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(value); + readSize.ShouldBe(data.Length); } } } diff --git a/tests/msgpack.light.tests/Reader/Boolean.cs b/tests/msgpack.light.tests/Reader/Boolean.cs index 831ab82..6e07818 100644 --- a/tests/msgpack.light.tests/Reader/Boolean.cs +++ b/tests/msgpack.light.tests/Reader/Boolean.cs @@ -7,14 +7,12 @@ namespace ProGaudi.MsgPack.Light.Tests.Reader public class Boolean { [Theory] - [InlineData(true, new byte[] { (byte)DataTypes.True })] - [InlineData(false, new byte[] { (byte)DataTypes.False })] + [InlineData(true, new[] { DataCodes.True })] + [InlineData(false, new[] { DataCodes.False })] public void Test(bool value, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(value); - - var token = Helpers.CheckTokenDeserialization(data); - ((bool)token).ShouldBe(value); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(value); + readSize.ShouldBe(data.Length); } } } diff --git a/tests/msgpack.light.tests/Reader/DateTime.cs b/tests/msgpack.light.tests/Reader/DateTime.cs index cd07e24..6828261 100644 --- a/tests/msgpack.light.tests/Reader/DateTime.cs +++ b/tests/msgpack.light.tests/Reader/DateTime.cs @@ -12,52 +12,48 @@ public class DateTimeTest [Fact] public void TestDateTime() { - var tests = new List>() + var tests = new List<(byte[] data, DateTime value)> { - new KeyValuePair(new byte[] {211, 247, 96, 128, 10, 8, 74, 128, 0,}, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)), - new KeyValuePair(new byte[] {211, 35, 42, 168, 127, 252, 129, 152, 240,}, new DateTime(9999, 12, 31, 23, 59, 59, 999, DateTimeKind.Utc)), - new KeyValuePair(new byte[] {211, 0, 51, 110, 236, 17, 171, 0, 0,}, new DateTime(2015, 11, 17, 0, 0, 0, 0, DateTimeKind.Utc)), - new KeyValuePair(new byte[] {211, 247, 96, 154, 26, 189, 97, 197, 0,}, new DateTime(1, 2, 3, 4, 5, 6, DateTimeKind.Utc)), - new KeyValuePair(new byte[] {207, 247, 96, 128, 10, 8, 74, 128, 0,}, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)), - new KeyValuePair(new byte[] {207, 35, 42, 168, 127, 252, 129, 152, 240,}, new DateTime(9999, 12, 31, 23, 59, 59, 999, DateTimeKind.Utc)), - new KeyValuePair(new byte[] {207, 0, 51, 110, 236, 17, 171, 0, 0,}, new DateTime(2015, 11, 17, 0, 0, 0, 0, DateTimeKind.Utc)), - new KeyValuePair(new byte[] {207, 247, 96, 154, 26, 189, 97, 197, 0,}, new DateTime(1, 2, 3, 4, 5, 6, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {211, 247, 96, 128, 10, 8, 74, 128, 0}, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {211, 35, 42, 168, 127, 252, 129, 152, 240}, new DateTime(9999, 12, 31, 23, 59, 59, 999, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {211, 0, 51, 110, 236, 17, 171, 0, 0}, new DateTime(2015, 11, 17, 0, 0, 0, 0, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {211, 247, 96, 154, 26, 189, 97, 197, 0}, new DateTime(1, 2, 3, 4, 5, 6, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {207, 247, 96, 128, 10, 8, 74, 128, 0}, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {207, 35, 42, 168, 127, 252, 129, 152, 240}, new DateTime(9999, 12, 31, 23, 59, 59, 999, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {207, 0, 51, 110, 236, 17, 171, 0, 0}, new DateTime(2015, 11, 17, 0, 0, 0, 0, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {207, 247, 96, 154, 26, 189, 97, 197, 0}, new DateTime(1, 2, 3, 4, 5, 6, DateTimeKind.Utc)) }; foreach (var test in tests) { - MsgPackSerializer.Deserialize(test.Key).ShouldBe(test.Value); - - var token = Helpers.CheckTokenDeserialization(test.Key); - ((DateTime)token).ShouldBe(test.Value); + MsgPackSerializer.Deserialize(test.data, out var readSize).ShouldBe(test.value); + readSize.ShouldBe(test.data.Length); } } [Fact] public void TestDateTimeOffset() { - var tests = new List>() + var tests = new List<(byte[] data, DateTimeOffset value)> { - new KeyValuePair(new byte[] {211, 247, 96, 128, 10, 8, 74, 128, 0,}, DateTimeOffset.MinValue), - new KeyValuePair(new byte[] {211, 35, 42, 168, 127, 252, 129, 191, 255,}, DateTimeOffset.MaxValue), - new KeyValuePair(new byte[] {211, 0, 51, 110, 236, 17, 171, 0, 0,}, new DateTimeOffset(2015, 11, 17, 0, 0, 0, TimeSpan.Zero)), - new KeyValuePair(new byte[] {211, 247, 96, 154, 26, 189, 97, 197, 0,}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.Zero)), - new KeyValuePair(new byte[] {211, 247, 96, 153, 182, 40, 44, 229, 0,}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromHours(12))), - new KeyValuePair(new byte[] {211, 247, 96, 153, 232, 79, 4, 15, 0,}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromMinutes(361))), - new KeyValuePair(new byte[] {207, 247, 96, 128, 10, 8, 74, 128, 0,}, DateTimeOffset.MinValue), - new KeyValuePair(new byte[] {207, 35, 42, 168, 127, 252, 129, 191, 255,}, DateTimeOffset.MaxValue), - new KeyValuePair(new byte[] {207, 0, 51, 110, 236, 17, 171, 0, 0,}, new DateTimeOffset(2015, 11, 17, 0, 0, 0, TimeSpan.Zero)), - new KeyValuePair(new byte[] {207, 247, 96, 154, 26, 189, 97, 197, 0,}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.Zero)), - new KeyValuePair(new byte[] {207, 247, 96, 153, 182, 40, 44, 229, 0,}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromHours(12))), - new KeyValuePair(new byte[] {207, 247, 96, 153, 232, 79, 4, 15, 0,}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromMinutes(361))), + ValueTuple.Create(new byte[] {211, 247, 96, 128, 10, 8, 74, 128, 0}, DateTimeOffset.MinValue), + ValueTuple.Create(new byte[] {211, 35, 42, 168, 127, 252, 129, 191, 255}, DateTimeOffset.MaxValue), + ValueTuple.Create(new byte[] {211, 0, 51, 110, 236, 17, 171, 0, 0}, new DateTimeOffset(2015, 11, 17, 0, 0, 0, TimeSpan.Zero)), + ValueTuple.Create(new byte[] {211, 247, 96, 154, 26, 189, 97, 197, 0}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.Zero)), + ValueTuple.Create(new byte[] {211, 247, 96, 153, 182, 40, 44, 229, 0}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromHours(12))), + ValueTuple.Create(new byte[] {211, 247, 96, 153, 232, 79, 4, 15, 0}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromMinutes(361))), + ValueTuple.Create(new byte[] {207, 247, 96, 128, 10, 8, 74, 128, 0}, DateTimeOffset.MinValue), + ValueTuple.Create(new byte[] {207, 35, 42, 168, 127, 252, 129, 191, 255}, DateTimeOffset.MaxValue), + ValueTuple.Create(new byte[] {207, 0, 51, 110, 236, 17, 171, 0, 0}, new DateTimeOffset(2015, 11, 17, 0, 0, 0, TimeSpan.Zero)), + ValueTuple.Create(new byte[] {207, 247, 96, 154, 26, 189, 97, 197, 0}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.Zero)), + ValueTuple.Create(new byte[] {207, 247, 96, 153, 182, 40, 44, 229, 0}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromHours(12))), + ValueTuple.Create(new byte[] {207, 247, 96, 153, 232, 79, 4, 15, 0}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromMinutes(361))) }; foreach (var test in tests) { - MsgPackSerializer.Deserialize(test.Key).ShouldBe(test.Value); - - var token = Helpers.CheckTokenDeserialization(test.Key); - ((DateTimeOffset)token).ShouldBe(test.Value); + MsgPackSerializer.Deserialize(test.data, out var readSize).ShouldBe(test.value); + readSize.ShouldBe(test.data.Length); } } } diff --git a/tests/msgpack.light.tests/Reader/Double.cs b/tests/msgpack.light.tests/Reader/Double.cs index 9cdd26c..3d618a0 100644 --- a/tests/msgpack.light.tests/Reader/Double.cs +++ b/tests/msgpack.light.tests/Reader/Double.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.Serialization; using Shouldly; @@ -33,13 +32,10 @@ public class FloatingPoint [InlineData(int.MaxValue, new byte[] { 210, 127, 0xff, 0xff, 0xff })] [InlineData(long.MinValue / 128, new byte[] { 211, 0xff, 0, 0, 0, 0, 0, 0, 0 })] [InlineData(long.MaxValue / 128, new byte[] { 207, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff })] - public void TestDouble(double value, byte[] bytes) + public void TestDouble(double value, byte[] data) { - var d = MsgPackSerializer.Deserialize(bytes); - d.ShouldBe(value); - - var token = Helpers.CheckTokenDeserialization(bytes); - ((double)token).ShouldBe(value); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(value); + readSize.ShouldBe(data.Length); } [Theory] @@ -66,38 +62,8 @@ public void TestDouble(double value, byte[] bytes) [InlineData(int.MaxValue / 128, new byte[] { 206, 0, 0xff, 0xff, 0xff })] public void TestFloat(float value, byte[] bytes) { - MsgPackSerializer.Deserialize(bytes).ShouldBe(value); - - var token = Helpers.CheckTokenDeserialization(bytes); - ((float)token).ShouldBe(value); - } - - [Theory] - [InlineData(new byte[] { 208, 128 })] - [InlineData(new byte[] { 127 })] - [InlineData(new byte[] { 209, 128, 0 })] - [InlineData(new byte[] { 209, 127, 0xff })] - [InlineData(new byte[] { 210, 128, 0, 0, 0 })] - [InlineData(new byte[] { 210, 127, 0xff, 0xff, 0xff })] - [InlineData(new byte[] { 211, 0xff, 0, 0, 0, 0, 0, 0, 0 })] - [InlineData(new byte[] { 207, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff })] - public void TestDoubleStritctParsing(byte[] bytes) - { - var e = Should.Throw(() => MsgPackSerializer.Deserialize(bytes, new MsgPackContext(true))); - e.Message.ShouldBe(ExceptionUtils.BadTypeException((DataTypes)bytes[0], DataTypes.Single, DataTypes.Double).Message); - } - - [Theory] - [InlineData(new byte[] { 208, 128 })] - [InlineData(new byte[] { 127 })] - [InlineData(new byte[] { 209, 128, 0 })] - [InlineData(new byte[] { 209, 127, 0xff })] - [InlineData(new byte[] { 210, 0xff, 0, 0, 0 })] - [InlineData(new byte[] { 206, 0, 0xff, 0xff, 0xff })] - public void TestFloatStritctParsing(byte[] bytes) - { - var e = Should.Throw(() => MsgPackSerializer.Deserialize(bytes, new MsgPackContext(true))); - e.Message.ShouldBe(ExceptionUtils.BadTypeException((DataTypes)bytes[0], DataTypes.Single).Message); + MsgPackSerializer.Deserialize(bytes, out var readSize).ShouldBe(value); + readSize.ShouldBe(bytes.Length); } } } diff --git a/tests/msgpack.light.tests/Reader/Enums.cs b/tests/msgpack.light.tests/Reader/Enums.cs index 9272751..24084a1 100644 --- a/tests/msgpack.light.tests/Reader/Enums.cs +++ b/tests/msgpack.light.tests/Reader/Enums.cs @@ -6,114 +6,120 @@ namespace ProGaudi.MsgPack.Light.Tests.Reader { public class Enums { - [Theory, ClassData(typeof(EnumValuesProvider))] - public void ReadEnum(DefaultEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var bytes = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); - var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); - - enumResult.ShouldBe(enumValue); - } +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadEnum(DefaultEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// +// enumResult.ShouldBe(enumValue); +// } [Theory, ClassData(typeof(EnumValuesProvider))] public void ReadEnumAsString(DefaultEnum enumValue) { - var bytes = MsgPackSerializer.Serialize(enumValue.ToString()); - var enumResult = MsgPackSerializer.Deserialize(bytes); - - enumResult.ShouldBe(enumValue); + using (var bytes = MsgPackSerializer.Serialize(enumValue.ToString(), out var wroteSize)) + { + var readOnlySpan = bytes.Memory.Span.Slice(0, wroteSize); + var enumResult = MsgPackSerializer.Deserialize(readOnlySpan, out var readSize); + enumResult.ShouldBe(enumValue); + readSize.ShouldBe(wroteSize); + } } - [Theory, ClassData(typeof(EnumValuesProvider))] - public void ReadFlagEnum(FlagEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var bytes = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); - var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); - - enumResult.ShouldBe(enumValue); - } +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadFlagEnum(FlagEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// +// enumResult.ShouldBe(enumValue); +// } [Theory, ClassData(typeof(EnumValuesProvider))] public void ReadFlagEnumAsString(FlagEnum enumValue) { - var bytes = MsgPackSerializer.Serialize(enumValue.ToString()); - var enumResult = MsgPackSerializer.Deserialize(bytes); - - enumResult.ShouldBe(enumValue); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void ReadSbyteEnum(SbyteEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var bytes = MsgPackSerializer.Serialize((sbyte)enumValue, intEnumContext); - var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); - enumResult.ShouldBe(enumValue); + using (var bytes = MsgPackSerializer.Serialize(enumValue.ToString(), out var wroteSize)) + { + var readOnlySpan = bytes.Memory.Span.Slice(0, wroteSize); + var enumResult = MsgPackSerializer.Deserialize(readOnlySpan, out var readSize); + enumResult.ShouldBe(enumValue); + readSize.ShouldBe(wroteSize); + } } - [Theory, ClassData(typeof(EnumValuesProvider))] - public void ReadByteEnum(ByteEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var bytes = MsgPackSerializer.Serialize((byte)enumValue, intEnumContext); - var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); - enumResult.ShouldBe(enumValue); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void ReadShortEnum(ShortEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var bytes = MsgPackSerializer.Serialize((short)enumValue, intEnumContext); - var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); - enumResult.ShouldBe(enumValue); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void ReadUshortEnum(UshortEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var bytes = MsgPackSerializer.Serialize((ushort)enumValue, intEnumContext); - var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); - enumResult.ShouldBe(enumValue); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void ReadIntEnum(IntEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var bytes = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); - var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); - enumResult.ShouldBe(enumValue); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void ReadUintEnum(UintEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var bytes = MsgPackSerializer.Serialize((uint)enumValue, intEnumContext); - var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); - enumResult.ShouldBe(enumValue); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void ReadLongEnum(LongEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var bytes = MsgPackSerializer.Serialize((long)enumValue, intEnumContext); - var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); - enumResult.ShouldBe(enumValue); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void ReadUlongEnum(UlongEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var bytes = MsgPackSerializer.Serialize((ulong)enumValue, intEnumContext); - var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); - enumResult.ShouldBe(enumValue); - } +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadSbyteEnum(SbyteEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((sbyte)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadByteEnum(ByteEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((byte)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadShortEnum(ShortEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((short)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadUshortEnum(UshortEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((ushort)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadIntEnum(IntEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadUintEnum(UintEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((uint)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadLongEnum(LongEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((long)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadUlongEnum(UlongEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((ulong)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } } -} \ No newline at end of file +} diff --git a/tests/msgpack.light.tests/Reader/Generic.cs b/tests/msgpack.light.tests/Reader/Generic.cs new file mode 100644 index 0000000..fb6e5d7 --- /dev/null +++ b/tests/msgpack.light.tests/Reader/Generic.cs @@ -0,0 +1,31 @@ +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.Reader +{ + public class Generic + { + [Fact] + public void IntTest() + { + var context = new MsgPackContext(); + context.RegisterGenericParser(typeof(GenericParser<>)); + + var a = MsgPackSerializer.Deserialize>(new byte[] {10}, context, out var x); + x.ShouldBe(1); + a.F.ShouldBe(10); + } + + [Fact] + public void StringTest() + { + var context = new MsgPackContext(); + context.RegisterGenericParser(typeof(GenericParser<>)); + + var a = MsgPackSerializer.Deserialize>(new byte[] { 163, 97, 98, 99 }, context, out var x); + x.ShouldBe(4); + a.F.ShouldBe("abc"); + } + } +} diff --git a/tests/msgpack.light.tests/Reader/Helpers.cs b/tests/msgpack.light.tests/Reader/Helpers.cs deleted file mode 100644 index af2c530..0000000 --- a/tests/msgpack.light.tests/Reader/Helpers.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Text; - -using Shouldly; - -namespace ProGaudi.MsgPack.Light.Tests.Reader -{ - public class Helpers - { - public static string GenerateString(int size) - { - var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray(); - var data = GenerateBytesArray(size); - var result = new StringBuilder(size); - foreach (var b in data) - { - result.Append(chars[b % chars.Length]); - } - return result.ToString(); - } - - public static byte[] GenerateBytesArray(int size) - { - var data = new byte[size]; - var crypto = new Random(); - crypto.NextBytes(data); - return data; - } - - public static MsgPackToken CheckTokenDeserialization(byte[] data) - { - var token = MsgPackSerializer.Deserialize(data); - token.RawBytes.ShouldBe(data); - return token; - } - } -} diff --git a/tests/msgpack.light.tests/Reader/Integers.cs b/tests/msgpack.light.tests/Reader/Integers.cs index 30a24d8..c13465f 100644 --- a/tests/msgpack.light.tests/Reader/Integers.cs +++ b/tests/msgpack.light.tests/Reader/Integers.cs @@ -21,10 +21,8 @@ public class Integers [InlineData(long.MaxValue, new byte[] { 207, 127, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff })] public void TestSignedLong(long number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); - - var token = Helpers.CheckTokenDeserialization(data); - ((long)token).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } [Theory] @@ -37,14 +35,11 @@ public void TestSignedLong(long number, byte[] data) [InlineData(short.MaxValue, new byte[] {209, 127, 0xff})] [InlineData(int.MinValue, new byte[] {210, 128, 0, 0, 0})] [InlineData(int.MaxValue, new byte[] {210, 127, 0xff, 0xff, 0xff})] - [InlineData(int.MaxValue, new byte[] { 210, 127, 0xff, 0xff, 0xff })] [InlineData(50505, new byte[] {205, 197, 73})] public void TestSignedInt(int number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); - - var token = Helpers.CheckTokenDeserialization(data); - ((int)token).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } [Theory] @@ -57,10 +52,8 @@ public void TestSignedInt(int number, byte[] data) [InlineData(short.MaxValue, new byte[] {209, 127, 0xff})] public void TestSignedShort(short number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); - - var token = Helpers.CheckTokenDeserialization(data); - ((short)token).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } [Theory] @@ -71,10 +64,8 @@ public void TestSignedShort(short number, byte[] data) [InlineData(sbyte.MaxValue, new byte[] {127})] public void TestSignedByte(sbyte number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); - - var token = Helpers.CheckTokenDeserialization(data); - ((sbyte)token).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } [Theory] @@ -84,16 +75,12 @@ public void TestSignedByte(sbyte number, byte[] data) [InlineData(ushort.MaxValue, new byte[] { 0xcd, 0xff, 0xff })] [InlineData(uint.MaxValue, new byte[] { 0xce, 0xff, 0xff, 0xff, 0xff })] [InlineData(ulong.MaxValue, new byte[] { 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff })] - public void TetsUnsignedLong(ulong number, byte[] data) + public void TestUnsignedLong(ulong number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); - - var token = Helpers.CheckTokenDeserialization(data); - ((ulong)token).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } - - [Theory] [InlineData(0, new byte[] {0x00})] [InlineData(1, new byte[] {1})] @@ -101,9 +88,10 @@ public void TetsUnsignedLong(ulong number, byte[] data) [InlineData(ushort.MaxValue, new byte[] {0xcd, 0xff, 0xff})] [InlineData(uint.MaxValue, new byte[] {0xce, 0xff, 0xff, 0xff, 0xff})] [InlineData(0x10000000, new byte[] {0xce, 0x10, 0x00, 0x00, 0x00})] - public void TetsUnsignedInt(uint number, byte[] data) + public void TestUnsignedInt(uint number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } [Theory] @@ -111,18 +99,20 @@ public void TetsUnsignedInt(uint number, byte[] data) [InlineData(1, new byte[] {1})] [InlineData(byte.MaxValue, new byte[] {0xcc, 0xff})] [InlineData(ushort.MaxValue, new byte[] {0xcd, 0xff, 0xff})] - public void TetsUnsignedShort(ushort number, byte[] data) + public void TestUnsignedShort(ushort number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } [Theory] [InlineData(0, new byte[] {0x00})] [InlineData(1, new byte[] {1})] [InlineData(byte.MaxValue, new byte[] {0xcc, 0xff})] - public void TetsUnsignedByte(byte number, byte[] data) + public void TestUnsignedByte(byte number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } } } diff --git a/tests/msgpack.light.tests/Reader/Map.cs b/tests/msgpack.light.tests/Reader/Map.cs index b84ec46..e4ad790 100644 --- a/tests/msgpack.light.tests/Reader/Map.cs +++ b/tests/msgpack.light.tests/Reader/Map.cs @@ -1,6 +1,6 @@ -using Shouldly; using System.Collections.Generic; -using System.Linq; + +using Shouldly; using Xunit; @@ -8,57 +8,6 @@ namespace ProGaudi.MsgPack.Light.Tests.Reader { public class Map { - [Fact] - public void ComplexDictionary() - { - var tests = new Dictionary - { - { - "array1", - new object[] - { - "array1_value1", - "array1_value2", - "array1_value3" - } - }, - {"bool1", true}, - {"double1", 50.5}, - {"double2", 15.2}, - {"int1", 50505}, - {"int2", 50}, - {3.14f, 3.14}, - {42, 42}, - {new Dictionary {{1, 2}}, null}, - {new[] {1, 2}, null} - }; - - var data = new byte[] - { - 138, - 166, 97, 114, 114, 97, 121, 49, - 147, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 49, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 50, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 51, - 165, 98, 111, 111, 108, 49, 195, - 167, 100, 111, 117, 98, 108, 101, 49, 203, 64, 73, 64, 0, 0, 0, 0, 0, - 167, 100, 111, 117, 98, 108, 101, 50, 203, 64, 46, 102, 102, 102, 102, 102, 102, - 164, 105, 110, 116, 49, 205, 197, 73, - 164, 105, 110, 116, 50, 50, - 202, 64, 72, 245, 195, 203, 64, 9, 30, 184, 81, 235, 133, 31, - 42, 42, - 129, 1, 2, 192, - 146, 1, 2, 192 - }; - - var settings = new MsgPackContext(); - settings.RegisterConverter(new TestReflectionConverter()); - MsgPackSerializer.Serialize(tests, settings).ShouldBe(data); - - Helpers.CheckTokenDeserialization(data); - } - [Fact] public void SimpleDictionary() { @@ -81,12 +30,8 @@ public void SimpleDictionary() 5, 161, 101 }; - MsgPackSerializer.Deserialize>(bytes).ShouldBe(test); - - var token = Helpers.CheckTokenDeserialization(bytes); - ((Dictionary) token) - .ToDictionary(kvp => (int) kvp.Key, kvp => (string) kvp.Value) - .ShouldBe(test); + MsgPackSerializer.Deserialize>(bytes, out var readSize).ShouldBe(test); + readSize.ShouldBe(bytes.Length); } [Fact] @@ -120,7 +65,7 @@ public void NonFixedDictionary() 0x20, 0xa1, 0x62, 0x21, 0xa1, 0x63, 0x22, 0xa1, 0x64, - 0x23, 0xa1, 0x65, + 0x23, 0xa1, 0x65 }; var test = new Dictionary @@ -147,15 +92,11 @@ public void NonFixedDictionary() {32, "b"}, {33, "c"}, {34, "d"}, - {35, "e"}, + {35, "e"} }; - MsgPackSerializer.Deserialize>(bytes).ShouldBe(test); - - var token = Helpers.CheckTokenDeserialization(bytes); - ((Dictionary)token) - .ToDictionary(kvp => (int)kvp.Key, kvp => (string)kvp.Value) - .ShouldBe(test); + MsgPackSerializer.Deserialize>(bytes, out var readSize).ShouldBe(test); + readSize.ShouldBe(bytes.Length); } } } diff --git a/tests/msgpack.light.tests/Reader/Null.cs b/tests/msgpack.light.tests/Reader/Null.cs index 5003a98..ea3fa40 100644 --- a/tests/msgpack.light.tests/Reader/Null.cs +++ b/tests/msgpack.light.tests/Reader/Null.cs @@ -11,25 +11,29 @@ public class Null [Fact] public void ReadNullArray() { - MsgPackSerializer.Deserialize(new[] { (byte)DataTypes.Null }).ShouldBe(null); + MsgPackSerializer.Deserialize(new[] { DataCodes.Nil }, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void ReadNullByteArray() { - MsgPackSerializer.Deserialize(new[] { (byte)DataTypes.Null }).ShouldBe(null); + MsgPackSerializer.Deserialize(new[] { DataCodes.Nil }, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void ReadNullMap() { - MsgPackSerializer.Deserialize>(new[] { (byte)DataTypes.Null }).ShouldBe(null); + MsgPackSerializer.Deserialize>(new[] { DataCodes.Nil }, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void ReadNullString() { - MsgPackSerializer.Deserialize(new[] { (byte)DataTypes.Null }).ShouldBe(null); + MsgPackSerializer.Deserialize(new[] { DataCodes.Nil }, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } } } diff --git a/tests/msgpack.light.tests/Reader/Nullable.cs b/tests/msgpack.light.tests/Reader/Nullable.cs index 1fdde4a..58f4d1a 100644 --- a/tests/msgpack.light.tests/Reader/Nullable.cs +++ b/tests/msgpack.light.tests/Reader/Nullable.cs @@ -11,131 +11,106 @@ public class Nullable [Fact] public void ReadNullAsNullableBool() { - var data = new[] { (byte)DataTypes.Null }; - MsgPackSerializer.Deserialize(data).ShouldBe(null); - - var token = Helpers.CheckTokenDeserialization(data); - ((bool?)token).ShouldBe(null); + var data = new[] { DataCodes.Nil }; + var deserialize = MsgPackSerializer.Deserialize(data, out var readSize); + deserialize.ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void ReadNullAsNullableFloat() { - var data = new[] { (byte)DataTypes.Null }; - MsgPackSerializer.Deserialize(data).ShouldBe(null); - - var token = Helpers.CheckTokenDeserialization(data); - ((float?)token).ShouldBe(null); + var data = new[] { DataCodes.Nil }; + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void ReadNullAsNullableDouble() { - var data = new[] { (byte)DataTypes.Null }; - MsgPackSerializer.Deserialize(data).ShouldBe(null); - - var token = Helpers.CheckTokenDeserialization(data); - ((double?)token).ShouldBe(null); + var data = new[] { DataCodes.Nil }; + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void ReadNullAsNullableByte() { - var data = new[] { (byte)DataTypes.Null }; - MsgPackSerializer.Deserialize(data).ShouldBe(null); - - var token = Helpers.CheckTokenDeserialization(data); - ((byte?)token).ShouldBe(null); + var data = new[] { DataCodes.Nil }; + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void ReadNullAsNullableSbyte() { - var data = new[] { (byte)DataTypes.Null }; - MsgPackSerializer.Deserialize(data).ShouldBe(null); - - var token = Helpers.CheckTokenDeserialization(data); - ((sbyte?)token).ShouldBe(null); + var data = new[] { DataCodes.Nil }; + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void ReadNullAsNullableShort() { - var data = new[] { (byte)DataTypes.Null }; - MsgPackSerializer.Deserialize(data).ShouldBe(null); - - var token = Helpers.CheckTokenDeserialization(data); - ((short?)token).ShouldBe(null); + var data = new[] { DataCodes.Nil }; + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void ReadNullAsNullableUshort() { - var data = new[] { (byte)DataTypes.Null }; - MsgPackSerializer.Deserialize(data).ShouldBe(null); - - var token = Helpers.CheckTokenDeserialization(data); - ((ushort?)token).ShouldBe(null); + var data = new[] { DataCodes.Nil }; + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void ReadNullAsNullableInt() { - var data = new[] { (byte)DataTypes.Null }; - MsgPackSerializer.Deserialize(data).ShouldBe(null); - - var token = Helpers.CheckTokenDeserialization(data); - ((int?)token).ShouldBe(null); + var data = new[] { DataCodes.Nil }; + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void ReadNullAsNullableUint() { - var data = new[] { (byte)DataTypes.Null }; - MsgPackSerializer.Deserialize(data).ShouldBe(null); - - var token = Helpers.CheckTokenDeserialization(data); - ((uint?)token).ShouldBe(null); + var data = new[] { DataCodes.Nil }; + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void ReadNullAsNullableLong() { - var data = new[] { (byte)DataTypes.Null }; - MsgPackSerializer.Deserialize(data).ShouldBe(null); - - var token = Helpers.CheckTokenDeserialization(data); - ((long?)token).ShouldBe(null); + var data = new[] { DataCodes.Nil }; + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void ReadNullAsNullableUlong() { - var data = new[] { (byte)DataTypes.Null }; - MsgPackSerializer.Deserialize(data).ShouldBe(null); - - var token = Helpers.CheckTokenDeserialization(data); - ((ulong?)token).ShouldBe(null); + var data = new[] { DataCodes.Nil }; + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); } [Fact] public void False() { - var data = new[] { (byte)DataTypes.False }; - MsgPackSerializer.Deserialize(data).ShouldBe(false); - - var token = Helpers.CheckTokenDeserialization(data); - ((bool?)token).ShouldBe(false); + var data = new[] { DataCodes.False }; + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(false); + readSize.ShouldBe(1); } [Fact] public void True() { - var data = new[] { (byte)DataTypes.True }; - MsgPackSerializer.Deserialize(data).ShouldBe(true); - - var token = Helpers.CheckTokenDeserialization(data); - ((bool?)token).ShouldBe(true); + var data = new[] { DataCodes.True }; + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(true); + readSize.ShouldBe(1); } [Theory] @@ -155,10 +130,8 @@ public void True() [InlineData(double.NegativeInfinity, new byte[] { 203, 255, 240, 0, 0, 0, 0, 0, 0 })] public void TestDouble(double value, byte[] bytes) { - MsgPackSerializer.Deserialize(bytes).ShouldBe(value); - - var token = Helpers.CheckTokenDeserialization(bytes); - ((double?)token).ShouldBe(value); + MsgPackSerializer.Deserialize(bytes, out var readSize).ShouldBe(value); + readSize.ShouldBe(bytes.Length); } [Theory] @@ -178,10 +151,8 @@ public void TestDouble(double value, byte[] bytes) [InlineData(float.NegativeInfinity, new byte[] { 202, 255, 128, 0, 0 })] public void TestFloat(float value, byte[] bytes) { - MsgPackSerializer.Deserialize(bytes).ShouldBe(value); - - var token = Helpers.CheckTokenDeserialization(bytes); - ((float?)token).ShouldBe(value); + MsgPackSerializer.Deserialize(bytes, out var readSize).ShouldBe(value); + readSize.ShouldBe(bytes.Length); } [Theory] @@ -198,10 +169,8 @@ public void TestFloat(float value, byte[] bytes) [InlineData(long.MinValue, new byte[] { 211, 128, 0, 0, 0, 0, 0, 0, 0 })] public void TestSignedLong(long number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); - - var token = Helpers.CheckTokenDeserialization(data); - ((long?)token).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } [Theory] @@ -217,10 +186,8 @@ public void TestSignedLong(long number, byte[] data) [InlineData(50505, new byte[] { 205, 197, 73 })] public void TestSignedInt(int number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); - - var token = Helpers.CheckTokenDeserialization(data); - ((int?)token).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } [Theory] @@ -233,10 +200,8 @@ public void TestSignedInt(int number, byte[] data) [InlineData(short.MaxValue, new byte[] { 209, 127, 0xff })] public void TestSignedShort(short number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); - - var token = Helpers.CheckTokenDeserialization(data); - ((short?)token).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } [Theory] @@ -247,10 +212,8 @@ public void TestSignedShort(short number, byte[] data) [InlineData(sbyte.MaxValue, new byte[] { 127 })] public void TestSignedByte(sbyte number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); - - var token = Helpers.CheckTokenDeserialization(data); - ((sbyte?)token).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } [Theory] @@ -260,12 +223,10 @@ public void TestSignedByte(sbyte number, byte[] data) [InlineData(ushort.MaxValue, new byte[] { 0xcd, 0xff, 0xff })] [InlineData(uint.MaxValue, new byte[] { 0xce, 0xff, 0xff, 0xff, 0xff })] [InlineData(ulong.MaxValue, new byte[] { 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff })] - public void TetsUnsignedLong(ulong number, byte[] data) + public void TestUnsignedLong(ulong number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); - - var token = Helpers.CheckTokenDeserialization(data); - ((ulong?)token).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } [Theory] @@ -274,12 +235,10 @@ public void TetsUnsignedLong(ulong number, byte[] data) [InlineData(byte.MaxValue, new byte[] { 0xcc, 0xff })] [InlineData(ushort.MaxValue, new byte[] { 0xcd, 0xff, 0xff })] [InlineData(uint.MaxValue, new byte[] { 0xce, 0xff, 0xff, 0xff, 0xff })] - public void TetsUnsignedInt(uint number, byte[] data) + public void TestUnsignedInt(uint number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); - - var token = Helpers.CheckTokenDeserialization(data); - ((uint?)token).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } [Theory] @@ -287,24 +246,20 @@ public void TetsUnsignedInt(uint number, byte[] data) [InlineData(1, new byte[] { 1 })] [InlineData(byte.MaxValue, new byte[] { 0xcc, 0xff })] [InlineData(ushort.MaxValue, new byte[] { 0xcd, 0xff, 0xff })] - public void TetsUnsignedShort(ushort number, byte[] data) + public void TestUnsignedShort(ushort number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); - - var token = Helpers.CheckTokenDeserialization(data); - ((ushort?)token).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } [Theory] [InlineData(0, new byte[] { 0x00 })] [InlineData(1, new byte[] { 1 })] [InlineData(byte.MaxValue, new byte[] { 0xcc, 0xff })] - public void TetsUnsignedByte(byte number, byte[] data) + public void TestUnsignedByte(byte number, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(number); - - var token = Helpers.CheckTokenDeserialization(data); - ((byte?)token).ShouldBe(number); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); } } } diff --git a/tests/msgpack.light.tests/Reader/ReadToken.cs b/tests/msgpack.light.tests/Reader/ReadToken.cs deleted file mode 100644 index 924bc3d..0000000 --- a/tests/msgpack.light.tests/Reader/ReadToken.cs +++ /dev/null @@ -1,306 +0,0 @@ -using System; -using System.Collections.Generic; - -using Shouldly; - -using Xunit; - -namespace ProGaudi.MsgPack.Light.Tests.Reader -{ - public class ReadToken - { - [Theory] - [InlineData(new byte[0], - 0)] - [InlineData(new byte[] - { - 161, 97, - 161, 98, - 161, 99, - 161, 100, - 161, 101 - }, - 5)] - [InlineData(new byte[] - { - 149, - 161, 97, - 161, 98, - 161, 99, - 161, 100, - 161, 101 - }, - 1)] - [InlineData(new byte[] - { - 151, - 0, - 205, 197, 73, - 202, 255, 192, 0, 0, - 202, 127, 127, 255, 255, - 147, - 195, - 194, - 195, - 192, - 129, - 164, 66, 97, 108, 108, 166, 83, 111, 99, 99, 101, 114 - }, - 1)] - [InlineData(new byte[] - { - 0, - 205, 197, 73, - 202, 255, 192, 0, 0, - 202, 127, 127, 255, 255, - 147, - 195, - 194, - 195, - 192, - 129, - 164, 66, 97, 108, 108, 166, 83, 111, 99, 99, 101, 114 - }, - 7)] - [InlineData(new byte[] - { - 0xdc, - 0x00, - 0x14, - - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x01, 0x02, 0x03, 0x04, 0x05, - }, - 1)] - [InlineData(new byte[] - { - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x01, 0x02, 0x03, 0x04, 0x05, - }, - 20)] - [InlineData(new byte[] - { - 197, 1, 44, - - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 - }, - 1)] - [InlineData(new byte[] - { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 - }, - 300)] - [InlineData(new byte[] - { - 138, - 166, 97, 114, 114, 97, 121, 49, - 147, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 49, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 50, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 51, - 165, 98, 111, 111, 108, 49, 195, - 167, 100, 111, 117, 98, 108, 101, 49, 203, 64, 73, 64, 0, 0, 0, 0, 0, - 167, 100, 111, 117, 98, 108, 101, 50, 203, 64, 46, 102, 102, 102, 102, 102, 102, - 164, 105, 110, 116, 49, 205, 197, 73, - 164, 105, 110, 116, 50, 50, - 202, 64, 72, 245, 195, 203, 64, 9, 30, 184, 81, 235, 133, 31, - 42, 42, - 129, 1, 2, 192, - 146, 1, 2, 192 - }, - 1)] - [InlineData(new byte[] - { - 166, 97, 114, 114, 97, 121, 49, - 147, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 49, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 50, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 51, - 165, 98, 111, 111, 108, 49, 195, - 167, 100, 111, 117, 98, 108, 101, 49, 203, 64, 73, 64, 0, 0, 0, 0, 0, - 167, 100, 111, 117, 98, 108, 101, 50, 203, 64, 46, 102, 102, 102, 102, 102, 102, - 164, 105, 110, 116, 49, 205, 197, 73, - 164, 105, 110, 116, 50, 50, - 202, 64, 72, 245, 195, 203, 64, 9, 30, 184, 81, 235, 133, 31, - 42, 42, - 129, 1, 2, 192, - 146, 1, 2, 192 - }, - 20)] - [InlineData(new byte[] - { - 0xde, - 0x00, - 0x14, - - 0x01, 0xa1, 0x61, - 0x02, 0xa1, 0x62, - 0x03, 0xa1, 0x63, - 0x04, 0xa1, 0x64, - 0x05, 0xa1, 0x65, - - 0x0b, 0xa1, 0x61, - 0x0c, 0xa1, 0x62, - 0x0d, 0xa1, 0x63, - 0x0e, 0xa1, 0x64, - 0x0f, 0xa1, 0x65, - - 0x15, 0xa1, 0x61, - 0x16, 0xa1, 0x62, - 0x17, 0xa1, 0x63, - 0x18, 0xa1, 0x64, - 0x19, 0xa1, 0x65, - - 0x1f, 0xa1, 0x61, - 0x20, 0xa1, 0x62, - 0x21, 0xa1, 0x63, - 0x22, 0xa1, 0x64, - 0x23, 0xa1, 0x65, - }, - 1)] - [InlineData(new byte[] - { - 0x01, 0xa1, 0x61, - 0x02, 0xa1, 0x62, - 0x03, 0xa1, 0x63, - 0x04, 0xa1, 0x64, - 0x05, 0xa1, 0x65, - - 0x0b, 0xa1, 0x61, - 0x0c, 0xa1, 0x62, - 0x0d, 0xa1, 0x63, - 0x0e, 0xa1, 0x64, - 0x0f, 0xa1, 0x65, - - 0x15, 0xa1, 0x61, - 0x16, 0xa1, 0x62, - 0x17, 0xa1, 0x63, - 0x18, 0xa1, 0x64, - 0x19, 0xa1, 0x65, - - 0x1f, 0xa1, 0x61, - 0x20, 0xa1, 0x62, - 0x21, 0xa1, 0x63, - 0x22, 0xa1, 0x64, - 0x23, 0xa1, 0x65, - }, - 40)] - [InlineData(new byte[] { - 218, 1, 80, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, - 49, 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, - 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, - 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, - 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, - 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, - 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, - 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, - 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, - 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, - 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, - 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, - 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, - 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, - 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, - 103 - }, - 1)] - public void Test(byte[] data, int objectsCount) - { - var msgPackReaders = new IMsgPackReader[] - { - // new MsgPackMemoryStreamReader(new MemoryStream(data)), - new MsgPackByteArrayReader(data) - }; - - var readTokenBytes = new List(); - - foreach (var msgPackReader in msgPackReaders) - { - for (var i = 0; i < objectsCount; i++) - { - var tokenBytes = msgPackReader.ReadToken(); - readTokenBytes.AddRange(tokenBytes); - } - var endOfStream = false; - try - { - msgPackReader.ReadDataType(); - } - catch (Exception e) - { - endOfStream = e != null; - } - - endOfStream.ShouldBe(true); - } - - readTokenBytes.ToArray().ShouldBe(data); - } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/Reader/SkipToken.cs b/tests/msgpack.light.tests/Reader/SkipToken.cs deleted file mode 100644 index c97c3f2..0000000 --- a/tests/msgpack.light.tests/Reader/SkipToken.cs +++ /dev/null @@ -1,300 +0,0 @@ -using System; -using System.IO; - -using Xunit; -using Shouldly; - -namespace ProGaudi.MsgPack.Light.Tests.Reader -{ - public class SkipToken - { - [Theory] - [InlineData(new byte[0], - 0)] - [InlineData(new byte[] - { - 161, 97, - 161, 98, - 161, 99, - 161, 100, - 161, 101 - }, - 5)] - [InlineData(new byte[] - { - 149, - 161, 97, - 161, 98, - 161, 99, - 161, 100, - 161, 101 - }, - 1)] - [InlineData(new byte[] - { - 151, - 0, - 205, 197, 73, - 202, 255, 192, 0, 0, - 202, 127, 127, 255, 255, - 147, - 195, - 194, - 195, - 192, - 129, - 164, 66, 97, 108, 108, 166, 83, 111, 99, 99, 101, 114 - }, - 1)] - [InlineData(new byte[] - { - 0, - 205, 197, 73, - 202, 255, 192, 0, 0, - 202, 127, 127, 255, 255, - 147, - 195, - 194, - 195, - 192, - 129, - 164, 66, 97, 108, 108, 166, 83, 111, 99, 99, 101, 114 - }, - 7)] - [InlineData(new byte[] - { - 0xdc, - 0x00, - 0x14, - - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x01, 0x02, 0x03, 0x04, 0x05, - }, - 1)] - [InlineData(new byte[] - { - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x01, 0x02, 0x03, 0x04, 0x05, - 0x01, 0x02, 0x03, 0x04, 0x05, - }, - 20)] - [InlineData(new byte[] - { - 197, 1, 44, - - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 - }, - 1)] - [InlineData(new byte[] - { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, - 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 - }, - 300)] - [InlineData(new byte[] - { - 138, - 166, 97, 114, 114, 97, 121, 49, - 147, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 49, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 50, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 51, - 165, 98, 111, 111, 108, 49, 195, - 167, 100, 111, 117, 98, 108, 101, 49, 203, 64, 73, 64, 0, 0, 0, 0, 0, - 167, 100, 111, 117, 98, 108, 101, 50, 203, 64, 46, 102, 102, 102, 102, 102, 102, - 164, 105, 110, 116, 49, 205, 197, 73, - 164, 105, 110, 116, 50, 50, - 202, 64, 72, 245, 195, 203, 64, 9, 30, 184, 81, 235, 133, 31, - 42, 42, - 129, 1, 2, 192, - 146, 1, 2, 192 - }, - 1)] - [InlineData(new byte[] - { - 166, 97, 114, 114, 97, 121, 49, - 147, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 49, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 50, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 51, - 165, 98, 111, 111, 108, 49, 195, - 167, 100, 111, 117, 98, 108, 101, 49, 203, 64, 73, 64, 0, 0, 0, 0, 0, - 167, 100, 111, 117, 98, 108, 101, 50, 203, 64, 46, 102, 102, 102, 102, 102, 102, - 164, 105, 110, 116, 49, 205, 197, 73, - 164, 105, 110, 116, 50, 50, - 202, 64, 72, 245, 195, 203, 64, 9, 30, 184, 81, 235, 133, 31, - 42, 42, - 129, 1, 2, 192, - 146, 1, 2, 192 - }, - 20)] - [InlineData(new byte[] - { - 0xde, - 0x00, - 0x14, - - 0x01, 0xa1, 0x61, - 0x02, 0xa1, 0x62, - 0x03, 0xa1, 0x63, - 0x04, 0xa1, 0x64, - 0x05, 0xa1, 0x65, - - 0x0b, 0xa1, 0x61, - 0x0c, 0xa1, 0x62, - 0x0d, 0xa1, 0x63, - 0x0e, 0xa1, 0x64, - 0x0f, 0xa1, 0x65, - - 0x15, 0xa1, 0x61, - 0x16, 0xa1, 0x62, - 0x17, 0xa1, 0x63, - 0x18, 0xa1, 0x64, - 0x19, 0xa1, 0x65, - - 0x1f, 0xa1, 0x61, - 0x20, 0xa1, 0x62, - 0x21, 0xa1, 0x63, - 0x22, 0xa1, 0x64, - 0x23, 0xa1, 0x65, - }, - 1)] - [InlineData(new byte[] - { - 0x01, 0xa1, 0x61, - 0x02, 0xa1, 0x62, - 0x03, 0xa1, 0x63, - 0x04, 0xa1, 0x64, - 0x05, 0xa1, 0x65, - - 0x0b, 0xa1, 0x61, - 0x0c, 0xa1, 0x62, - 0x0d, 0xa1, 0x63, - 0x0e, 0xa1, 0x64, - 0x0f, 0xa1, 0x65, - - 0x15, 0xa1, 0x61, - 0x16, 0xa1, 0x62, - 0x17, 0xa1, 0x63, - 0x18, 0xa1, 0x64, - 0x19, 0xa1, 0x65, - - 0x1f, 0xa1, 0x61, - 0x20, 0xa1, 0x62, - 0x21, 0xa1, 0x63, - 0x22, 0xa1, 0x64, - 0x23, 0xa1, 0x65, - }, - 40)] - [InlineData(new byte[] { - 218, 1, 80, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, - 49, 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, - 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, - 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, - 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, - 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, - 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, - 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, - 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, - 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, - 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, - 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, - 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, - 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, - 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, - 103 - }, - 1)] - public void Test(byte[] data, int objectsCount) - { - var msgPackReaders = new IMsgPackReader[] - { - new MsgPackMemoryStreamReader(new MemoryStream(data)), - new MsgPackByteArrayReader(data) - }; - - foreach (var msgPackReader in msgPackReaders) - { - for (var i = 0; i < objectsCount; i++) - { - msgPackReader.SkipToken(); - } - var endOfStream = false; - try - { - msgPackReader.ReadDataType(); - } - catch (Exception e) - { - endOfStream = e != null; - } - - endOfStream.ShouldBe(true); - } - } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/Reader/String.cs b/tests/msgpack.light.tests/Reader/String.cs index ce7481d..61047ab 100644 --- a/tests/msgpack.light.tests/Reader/String.cs +++ b/tests/msgpack.light.tests/Reader/String.cs @@ -33,10 +33,8 @@ public class String [InlineData("Шла Саша по шоссе и сосала сушку", new byte[] { 217, 58, 208, 168, 208, 187, 208, 176, 32, 208, 161, 208, 176, 209, 136, 208, 176, 32, 208, 191, 208, 190, 32, 209, 136, 208, 190, 209, 129, 209, 129, 208, 181, 32, 208, 184, 32, 209, 129, 208, 190, 209, 129, 208, 176, 208, 187, 208, 176, 32, 209, 129, 209, 131, 209, 136, 208, 186, 209, 131 })] public void TestStringPack(string s, byte[] data) { - MsgPackSerializer.Deserialize(data).ShouldBe(s); - - var token = Helpers.CheckTokenDeserialization(data); - ((string)token).ShouldBe(s); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(s); + readSize.ShouldBe(data.Length); } } } diff --git a/tests/msgpack.light.tests/Reader/TimeSpan.cs b/tests/msgpack.light.tests/Reader/TimeSpan.cs index 598fd9b..8574714 100644 --- a/tests/msgpack.light.tests/Reader/TimeSpan.cs +++ b/tests/msgpack.light.tests/Reader/TimeSpan.cs @@ -12,22 +12,19 @@ public class Timespan [Fact] public void TestTimeSpan() { - var tests = new List> + var tests = new List<(TimeSpan span, byte[] blob)> { - new KeyValuePair(TimeSpan.MinValue, new byte[] {211, 128, 0, 0, 0, 0, 0, 0, 0}), - new KeyValuePair(TimeSpan.MaxValue, new byte[] {207, 127, 255, 255, 255, 255, 255, 255, 255}), - new KeyValuePair(new TimeSpan(1, 2, 3, 4, 5), new byte[] {207, 0, 0, 0, 218, 91, 159, 127, 80}), - new KeyValuePair(TimeSpan.FromTicks(-100), new byte[] {208, 156}) + ValueTuple.Create(TimeSpan.MinValue, new byte[] {211, 128, 0, 0, 0, 0, 0, 0, 0}), + ValueTuple.Create(TimeSpan.MaxValue, new byte[] {207, 127, 255, 255, 255, 255, 255, 255, 255}), + ValueTuple.Create(new TimeSpan(1, 2, 3, 4, 5), new byte[] {207, 0, 0, 0, 218, 91, 159, 127, 80}), + ValueTuple.Create(TimeSpan.FromTicks(-100), new byte[] {208, 156}) }; foreach (var test in tests) { - var value = MsgPackSerializer.Deserialize(test.Value); - value.ShouldBe(test.Key); - - var token = Helpers.CheckTokenDeserialization(test.Value); - ((TimeSpan)token).ShouldBe(test.Key); + MsgPackSerializer.Deserialize(test.blob, out var readSize).ShouldBe(test.span); + readSize.ShouldBe(test.blob.Length); } } } -} \ No newline at end of file +} diff --git a/tests/msgpack.light.tests/SequenceReader/Array.cs b/tests/msgpack.light.tests/SequenceReader/Array.cs new file mode 100644 index 0000000..cba2502 --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/Array.cs @@ -0,0 +1,62 @@ +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + public class Array + { + [Fact] + public void SimpleArray() + { + var tests = new[] + { + "a", + "b", + "c", + "d", + "e" + }; + + var bytes = new byte[] + { + 149, + 161, 97, + 161, 98, + 161, 99, + 161, 100, + 161, 101 + }; + + MsgPackSerializer.Deserialize(bytes.ToMultipleSegments(), out var readSize).ShouldBe(tests); + readSize.ShouldBe(bytes.Length); + } + + [Fact] + public void TestNonFixedArray() + { + var array = new[] + { + 1, 2, 3, 4, 5, + 1, 2, 3, 4, 5, + 1, 2, 3, 4, 5, + 1, 2, 3, 4, 5 + }; + + var bytes = new byte[] + { + 0xdc, + 0x00, + 0x14, + + 0x01, 0x02, 0x03, 0x04, 0x05, + 0x01, 0x02, 0x03, 0x04, 0x05, + 0x01, 0x02, 0x03, 0x04, 0x05, + 0x01, 0x02, 0x03, 0x04, 0x05 + }; + + MsgPackSerializer.Deserialize(bytes.ToMultipleSegments(), out var readSize).ShouldBe(array); + readSize.ShouldBe(bytes.Length); + } + } +} diff --git a/tests/msgpack.light.tests/SequenceReader/Binary.cs b/tests/msgpack.light.tests/SequenceReader/Binary.cs new file mode 100644 index 0000000..ceb22f8 --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/Binary.cs @@ -0,0 +1,221 @@ +using System; + +using ProGaudi.MsgPack.Converters.Binary; + +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + public class Binary + { + [Theory] + [InlineData(new byte[0], new byte[] {196, 0})] + [InlineData(new byte[] {1}, new byte[] {196, 1, 1})] + [InlineData(new byte[] + { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 + }, + new byte[] + { + 197, 1, 44, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 + })] + public void Test(byte[] value, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(value); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData("Wrong data code: 0xa0. Expected: 0xc4, 0xc5 or 0xc6.", new byte[] {160})] + [InlineData("Wrong data code: 0xa1. Expected: 0xc4, 0xc5 or 0xc6.", new byte[] {161, 1})] + [InlineData("Wrong data code: 0xda. Expected: 0xc4, 0xc5 or 0xc6.", new byte[] + { + 218, 1, 44, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 + })] + public void FailToReadOldBinary(string message, byte[] data) + { + var e = Should.Throw(() => Converter.Current.Parse(data.ToMultipleSegments(), out _)); + e.Message.ShouldBe(message); + } + + [Theory] + [InlineData(new byte[0], new byte[] {160})] + [InlineData(new byte[] {1}, new byte[] {161, 1})] + [InlineData(new byte[] + { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 + }, + new byte[] + { + 218, 1, 44, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 + })] + public void ReadOldBinary(byte[] value, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(value); + readSize.ShouldBe(data.Length); + } + } +} diff --git a/tests/msgpack.light.tests/SequenceReader/Boolean.cs b/tests/msgpack.light.tests/SequenceReader/Boolean.cs new file mode 100644 index 0000000..105d318 --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/Boolean.cs @@ -0,0 +1,18 @@ +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + public class Boolean + { + [Theory] + [InlineData(true, new[] { DataCodes.True })] + [InlineData(false, new[] { DataCodes.False })] + public void Test(bool value, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(value); + readSize.ShouldBe(data.Length); + } + } +} diff --git a/tests/msgpack.light.tests/SequenceReader/DateTime.cs b/tests/msgpack.light.tests/SequenceReader/DateTime.cs new file mode 100644 index 0000000..e9bd08d --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/DateTime.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; + +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + public class DateTimeTest + { + [Fact] + public void TestDateTime() + { + var tests = new List<(byte[] data, DateTime value)> + { + ValueTuple.Create(new byte[] {211, 247, 96, 128, 10, 8, 74, 128, 0}, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {211, 35, 42, 168, 127, 252, 129, 152, 240}, new DateTime(9999, 12, 31, 23, 59, 59, 999, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {211, 0, 51, 110, 236, 17, 171, 0, 0}, new DateTime(2015, 11, 17, 0, 0, 0, 0, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {211, 247, 96, 154, 26, 189, 97, 197, 0}, new DateTime(1, 2, 3, 4, 5, 6, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {207, 247, 96, 128, 10, 8, 74, 128, 0}, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {207, 35, 42, 168, 127, 252, 129, 152, 240}, new DateTime(9999, 12, 31, 23, 59, 59, 999, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {207, 0, 51, 110, 236, 17, 171, 0, 0}, new DateTime(2015, 11, 17, 0, 0, 0, 0, DateTimeKind.Utc)), + ValueTuple.Create(new byte[] {207, 247, 96, 154, 26, 189, 97, 197, 0}, new DateTime(1, 2, 3, 4, 5, 6, DateTimeKind.Utc)) + }; + + foreach (var test in tests) + { + MsgPackSerializer.Deserialize(test.data.ToMultipleSegments(), out var readSize).ShouldBe(test.value); + readSize.ShouldBe(test.data.Length); + } + } + + [Fact] + public void TestDateTimeOffset() + { + var tests = new List<(byte[] data, DateTimeOffset value)> + { + ValueTuple.Create(new byte[] {211, 247, 96, 128, 10, 8, 74, 128, 0}, DateTimeOffset.MinValue), + ValueTuple.Create(new byte[] {211, 35, 42, 168, 127, 252, 129, 191, 255}, DateTimeOffset.MaxValue), + ValueTuple.Create(new byte[] {211, 0, 51, 110, 236, 17, 171, 0, 0}, new DateTimeOffset(2015, 11, 17, 0, 0, 0, TimeSpan.Zero)), + ValueTuple.Create(new byte[] {211, 247, 96, 154, 26, 189, 97, 197, 0}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.Zero)), + ValueTuple.Create(new byte[] {211, 247, 96, 153, 182, 40, 44, 229, 0}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromHours(12))), + ValueTuple.Create(new byte[] {211, 247, 96, 153, 232, 79, 4, 15, 0}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromMinutes(361))), + ValueTuple.Create(new byte[] {207, 247, 96, 128, 10, 8, 74, 128, 0}, DateTimeOffset.MinValue), + ValueTuple.Create(new byte[] {207, 35, 42, 168, 127, 252, 129, 191, 255}, DateTimeOffset.MaxValue), + ValueTuple.Create(new byte[] {207, 0, 51, 110, 236, 17, 171, 0, 0}, new DateTimeOffset(2015, 11, 17, 0, 0, 0, TimeSpan.Zero)), + ValueTuple.Create(new byte[] {207, 247, 96, 154, 26, 189, 97, 197, 0}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.Zero)), + ValueTuple.Create(new byte[] {207, 247, 96, 153, 182, 40, 44, 229, 0}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromHours(12))), + ValueTuple.Create(new byte[] {207, 247, 96, 153, 232, 79, 4, 15, 0}, new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromMinutes(361))) + }; + + foreach (var test in tests) + { + MsgPackSerializer.Deserialize(test.data.ToMultipleSegments(), out var readSize).ShouldBe(test.value); + readSize.ShouldBe(test.data.Length); + } + } + } +} diff --git a/tests/msgpack.light.tests/SequenceReader/Double.cs b/tests/msgpack.light.tests/SequenceReader/Double.cs new file mode 100644 index 0000000..ba5a2a8 --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/Double.cs @@ -0,0 +1,69 @@ +using System; + +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + public class FloatingPoint + { + [Theory] + [InlineData(0, new byte[] {203, 0, 0, 0, 0, 0, 0, 0, 0})] + [InlineData(1, new byte[] {203, 63, 240, 0, 0, 0, 0, 0, 0})] + [InlineData(-1, new byte[] {203, 191, 240, 0, 0, 0, 0, 0, 0})] + [InlineData(Math.E, new byte[] {203, 64, 5, 191, 10, 139, 20, 87, 105})] + [InlineData(Math.PI, new byte[] {203, 64, 9, 33, 251, 84, 68, 45, 24})] + [InlineData(224, new byte[] {203, 64, 108, 0, 0, 0, 0, 0, 0})] + [InlineData(256, new byte[] {203, 64, 112, 0, 0, 0, 0, 0, 0})] + [InlineData(65530, new byte[] {203, 64, 239, 255, 64, 0, 0, 0, 0})] + [InlineData(65540, new byte[] {203, 64, 240, 0, 64, 0, 0, 0, 0})] + [InlineData(double.NaN, new byte[] {203, 255, 248, 0, 0, 0, 0, 0, 0})] + [InlineData(double.MaxValue, new byte[] {203, 127, 239, 255, 255, 255, 255, 255, 255})] + [InlineData(double.MinValue, new byte[] {203, 255, 239, 255, 255, 255, 255, 255, 255})] + [InlineData(double.PositiveInfinity, new byte[] {203, 127, 240, 0, 0, 0, 0, 0, 0})] + [InlineData(double.NegativeInfinity, new byte[] {203, 255, 240, 0, 0, 0, 0, 0, 0})] + // integers + [InlineData(sbyte.MinValue, new byte[] { 208, 128 })] + [InlineData(sbyte.MaxValue, new byte[] { 127 })] + [InlineData(short.MinValue, new byte[] { 209, 128, 0 })] + [InlineData(short.MaxValue, new byte[] { 209, 127, 0xff })] + [InlineData(int.MinValue, new byte[] { 210, 128, 0, 0, 0 })] + [InlineData(int.MaxValue, new byte[] { 210, 127, 0xff, 0xff, 0xff })] + [InlineData(long.MinValue / 128, new byte[] { 211, 0xff, 0, 0, 0, 0, 0, 0, 0 })] + [InlineData(long.MaxValue / 128, new byte[] { 207, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff })] + public void TestDouble(double value, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(value); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] {202, 0, 0, 0, 0})] + [InlineData(1, new byte[] {202, 63, 128, 0, 0})] + [InlineData(-1, new byte[] {202, 191, 128, 0, 0})] + [InlineData(2.71828, new byte[] {202, 64, 45, 248, 77})] + [InlineData(3.14159, new byte[] {202, 64, 73, 15, 208})] + [InlineData(224, new byte[] {202, 67, 96, 0, 0})] + [InlineData(256, new byte[] {202, 67, 128, 0, 0})] + [InlineData(65530, new byte[] {202, 71, 127, 250, 0})] + [InlineData(65540, new byte[] {202, 71, 128, 2, 0})] + [InlineData(float.NaN, new byte[] {202, 255, 192, 0, 0})] + [InlineData(float.MaxValue, new byte[] {202, 127, 127, 255, 255})] + [InlineData(float.MinValue, new byte[] {202, 255, 127, 255, 255})] + [InlineData(float.PositiveInfinity, new byte[] {202, 127, 128, 0, 0})] + [InlineData(float.NegativeInfinity, new byte[] {202, 255, 128, 0, 0})] + // integers + [InlineData(sbyte.MinValue, new byte[] { 208, 128 })] + [InlineData(sbyte.MaxValue, new byte[] { 127 })] + [InlineData(short.MinValue, new byte[] { 209, 128, 0 })] + [InlineData(short.MaxValue, new byte[] { 209, 127, 0xff })] + [InlineData(int.MinValue / 128, new byte[] { 210, 0xff, 0, 0, 0 })] + [InlineData(int.MaxValue / 128, new byte[] { 206, 0, 0xff, 0xff, 0xff })] + public void TestFloat(float value, byte[] bytes) + { + MsgPackSerializer.Deserialize(bytes.ToMultipleSegments(), out var readSize).ShouldBe(value); + readSize.ShouldBe(bytes.Length); + } + } +} diff --git a/tests/msgpack.light.tests/SequenceReader/Enums.cs b/tests/msgpack.light.tests/SequenceReader/Enums.cs new file mode 100644 index 0000000..e8d90b9 --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/Enums.cs @@ -0,0 +1,125 @@ +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + public class Enums + { +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadEnum(DefaultEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// +// enumResult.ShouldBe(enumValue); +// } + + [Theory, ClassData(typeof(EnumValuesProvider))] + public void ReadEnumAsString(DefaultEnum enumValue) + { + using (var bytes = MsgPackSerializer.Serialize(enumValue.ToString(), out var wroteSize)) + { + var readOnlySequence = bytes.Memory.ToMultipleSegments().Slice(0, wroteSize); + var enumResult = MsgPackSerializer.Deserialize(readOnlySequence, out var readSize); + enumResult.ShouldBe(enumValue); + readSize.ShouldBe(wroteSize); + } + } + +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadFlagEnum(FlagEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// +// enumResult.ShouldBe(enumValue); +// } + + [Theory, ClassData(typeof(EnumValuesProvider))] + public void ReadFlagEnumAsString(FlagEnum enumValue) + { + using (var bytes = MsgPackSerializer.Serialize(enumValue.ToString(), out var wroteSize)) + { + var readOnlySequence = bytes.Memory.ToMultipleSegments().Slice(0, wroteSize); + var enumResult = MsgPackSerializer.Deserialize(readOnlySequence, out var readSize); + enumResult.ShouldBe(enumValue); + readSize.ShouldBe(wroteSize); + } + } + +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadSbyteEnum(SbyteEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((sbyte)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadByteEnum(ByteEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((byte)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadShortEnum(ShortEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((short)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadUshortEnum(UshortEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((ushort)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadIntEnum(IntEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadUintEnum(UintEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((uint)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadLongEnum(LongEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((long)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void ReadUlongEnum(UlongEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var bytes = MsgPackSerializer.Serialize((ulong)enumValue, intEnumContext); +// var enumResult = MsgPackSerializer.Deserialize(bytes, intEnumContext); +// enumResult.ShouldBe(enumValue); +// } + } +} diff --git a/tests/msgpack.light.tests/SequenceReader/Extensions.cs b/tests/msgpack.light.tests/SequenceReader/Extensions.cs new file mode 100644 index 0000000..77262e3 --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/Extensions.cs @@ -0,0 +1,52 @@ +using System; +using System.Buffers; +using System.Diagnostics; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + [DebuggerStepThrough] + public static class Extensions + { + public static ReadOnlySequence ToMultipleSegments(this T[] buffer) + { + return buffer.AsMemory().ToMultipleSegments(); + } + + public static ReadOnlySequence ToMultipleSegments(this Memory memory) + { + return ((ReadOnlyMemory) memory).ToMultipleSegments(); + } + + public static ReadOnlySequence ToMultipleSegments(this ReadOnlyMemory memory) + { + var length = memory.Length; + if (length <= 1) return ZeroOrOneElementSequence(); + + var last = new Segment(memory.Slice(length - 1), null, length - 1); + var lastEmpty = new Segment(ReadOnlyMemory.Empty, last, length - 1); + var medium = new Segment(memory.Slice(1, length - 2), lastEmpty, 1); + var firstEmpty = new Segment(ReadOnlyMemory.Empty, medium, 1); + var first = new Segment(memory.Slice(0, 1), firstEmpty, 0); + return new ReadOnlySequence(first, 0, last, last.Memory.Length); + + ReadOnlySequence ZeroOrOneElementSequence() + { + var endSegment = new Segment(ReadOnlyMemory.Empty, null, length); + var element = new Segment(memory, endSegment, 0); + var startSegment = new Segment(ReadOnlyMemory.Empty, element, 0); + + return new ReadOnlySequence(startSegment, 0, endSegment, 0); + } + } + + private sealed class Segment : ReadOnlySequenceSegment + { + public Segment(ReadOnlyMemory memory, ReadOnlySequenceSegment next, long runningIndex) + { + Memory = memory; + Next = next; + RunningIndex = runningIndex; + } + } + } +} diff --git a/tests/msgpack.light.tests/SequenceReader/Generic.cs b/tests/msgpack.light.tests/SequenceReader/Generic.cs new file mode 100644 index 0000000..a9f05c9 --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/Generic.cs @@ -0,0 +1,31 @@ +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + public class Generic + { + [Fact] + public void IntTest() + { + var context = new MsgPackContext(); + context.RegisterGenericSequenceParser(typeof(GenericSequenceParser<>)); + + var a = MsgPackSerializer.Deserialize>(new byte[] {10}.ToMultipleSegments(), context, out var x); + x.ShouldBe(1); + a.F.ShouldBe(10); + } + + [Fact] + public void StringTest() + { + var context = new MsgPackContext(); + context.RegisterGenericSequenceParser(typeof(GenericSequenceParser<>)); + + var a = MsgPackSerializer.Deserialize>(new byte[] { 163, 97, 98, 99 }.ToMultipleSegments(), context, out var x); + x.ShouldBe(4); + a.F.ShouldBe("abc"); + } + } +} diff --git a/tests/msgpack.light.tests/SequenceReader/Integers.cs b/tests/msgpack.light.tests/SequenceReader/Integers.cs new file mode 100644 index 0000000..b4d162a --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/Integers.cs @@ -0,0 +1,118 @@ +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + public class Integers + { + [Theory] + [InlineData(0, new byte[] {0x00})] + [InlineData(1, new byte[] {1})] + [InlineData(-1, new byte[] {0xff})] + [InlineData(sbyte.MinValue, new byte[] {208, 128})] + [InlineData(sbyte.MaxValue, new byte[] {127})] + [InlineData(short.MinValue, new byte[] {209, 128, 0})] + [InlineData(short.MaxValue, new byte[] {209, 127, 0xff})] + [InlineData(int.MinValue, new byte[] {210, 128, 0, 0, 0})] + [InlineData(int.MaxValue, new byte[] {210, 127, 0xff, 0xff, 0xff})] + [InlineData(long.MaxValue, new byte[] {211, 127, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})] + [InlineData(long.MinValue, new byte[] {211, 128, 0, 0, 0, 0, 0, 0, 0})] + [InlineData(long.MaxValue, new byte[] { 207, 127, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff })] + public void TestSignedLong(long number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] {0x00})] + [InlineData(1, new byte[] {1})] + [InlineData(-1, new byte[] {0xff})] + [InlineData(sbyte.MinValue, new byte[] {208, 128})] + [InlineData(sbyte.MaxValue, new byte[] {127})] + [InlineData(short.MinValue, new byte[] {209, 128, 0})] + [InlineData(short.MaxValue, new byte[] {209, 127, 0xff})] + [InlineData(int.MinValue, new byte[] {210, 128, 0, 0, 0})] + [InlineData(int.MaxValue, new byte[] {210, 127, 0xff, 0xff, 0xff})] + [InlineData(50505, new byte[] {205, 197, 73})] + public void TestSignedInt(int number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] {0x00})] + [InlineData(1, new byte[] {1})] + [InlineData(-1, new byte[] {0xff})] + [InlineData(sbyte.MinValue, new byte[] {208, 128})] + [InlineData(sbyte.MaxValue, new byte[] {127})] + [InlineData(short.MinValue, new byte[] {209, 128, 0})] + [InlineData(short.MaxValue, new byte[] {209, 127, 0xff})] + public void TestSignedShort(short number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] {0x00})] + [InlineData(1, new byte[] {1})] + [InlineData(-1, new byte[] {0xff})] + [InlineData(sbyte.MinValue, new byte[] {208, 128})] + [InlineData(sbyte.MaxValue, new byte[] {127})] + public void TestSignedByte(sbyte number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] {0x00})] + [InlineData(1, new byte[] {1})] + [InlineData(byte.MaxValue, new byte[] { 0xcc, 0xff })] + [InlineData(ushort.MaxValue, new byte[] { 0xcd, 0xff, 0xff })] + [InlineData(uint.MaxValue, new byte[] { 0xce, 0xff, 0xff, 0xff, 0xff })] + [InlineData(ulong.MaxValue, new byte[] { 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff })] + public void TestUnsignedLong(ulong number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] {0x00})] + [InlineData(1, new byte[] {1})] + [InlineData(byte.MaxValue, new byte[] {0xcc, 0xff})] + [InlineData(ushort.MaxValue, new byte[] {0xcd, 0xff, 0xff})] + [InlineData(uint.MaxValue, new byte[] {0xce, 0xff, 0xff, 0xff, 0xff})] + [InlineData(0x10000000, new byte[] {0xce, 0x10, 0x00, 0x00, 0x00})] + public void TestUnsignedInt(uint number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] {0x00})] + [InlineData(1, new byte[] {1})] + [InlineData(byte.MaxValue, new byte[] {0xcc, 0xff})] + [InlineData(ushort.MaxValue, new byte[] {0xcd, 0xff, 0xff})] + public void TestUnsignedShort(ushort number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] {0x00})] + [InlineData(1, new byte[] {1})] + [InlineData(byte.MaxValue, new byte[] {0xcc, 0xff})] + public void TestUnsignedByte(byte number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + } +} diff --git a/tests/msgpack.light.tests/SequenceReader/Map.cs b/tests/msgpack.light.tests/SequenceReader/Map.cs new file mode 100644 index 0000000..7e2da7d --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/Map.cs @@ -0,0 +1,102 @@ +using System.Collections.Generic; + +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + public class Map + { + [Fact] + public void SimpleDictionary() + { + var test = new Dictionary + { + {1, "a"}, + {2, "b"}, + {3, "c"}, + {4, "d"}, + {5, "e"} + }; + + var bytes = new byte[] + { + 133, + 1, 161, 97, + 2, 161, 98, + 3, 161, 99, + 4, 161, 100, + 5, 161, 101 + }; + + MsgPackSerializer.Deserialize>(bytes.ToMultipleSegments(), out var readSize).ShouldBe(test); + readSize.ShouldBe(bytes.Length); + } + + [Fact] + public void NonFixedDictionary() + { + var bytes = new byte[] + { + 0xde, + 0x00, + 0x14, + + 0x01, 0xa1, 0x61, + 0x02, 0xa1, 0x62, + 0x03, 0xa1, 0x63, + 0x04, 0xa1, 0x64, + 0x05, 0xa1, 0x65, + + 0x0b, 0xa1, 0x61, + 0x0c, 0xa1, 0x62, + 0x0d, 0xa1, 0x63, + 0x0e, 0xa1, 0x64, + 0x0f, 0xa1, 0x65, + + 0x15, 0xa1, 0x61, + 0x16, 0xa1, 0x62, + 0x17, 0xa1, 0x63, + 0x18, 0xa1, 0x64, + 0x19, 0xa1, 0x65, + + 0x1f, 0xa1, 0x61, + 0x20, 0xa1, 0x62, + 0x21, 0xa1, 0x63, + 0x22, 0xa1, 0x64, + 0x23, 0xa1, 0x65 + }; + + var test = new Dictionary + { + {1, "a"}, + {2, "b"}, + {3, "c"}, + {4, "d"}, + {5, "e"}, + + {11, "a"}, + {12, "b"}, + {13, "c"}, + {14, "d"}, + {15, "e"}, + + {21, "a"}, + {22, "b"}, + {23, "c"}, + {24, "d"}, + {25, "e"}, + + {31, "a"}, + {32, "b"}, + {33, "c"}, + {34, "d"}, + {35, "e"} + }; + + MsgPackSerializer.Deserialize>(bytes.ToMultipleSegments(), out var readSize).ShouldBe(test); + readSize.ShouldBe(bytes.Length); + } + } +} diff --git a/tests/msgpack.light.tests/SequenceReader/Null.cs b/tests/msgpack.light.tests/SequenceReader/Null.cs new file mode 100644 index 0000000..7b6859d --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/Null.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; + +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + public class Null + { + [Fact] + public void ReadNullArray() + { + MsgPackSerializer.Deserialize(new[] { DataCodes.Nil }.ToMultipleSegments(), out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void ReadNullByteArray() + { + MsgPackSerializer.Deserialize(new[] { DataCodes.Nil }.ToMultipleSegments(), out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void ReadNullMap() + { + MsgPackSerializer.Deserialize>(new[] { DataCodes.Nil }.ToMultipleSegments(), out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void ReadNullString() + { + MsgPackSerializer.Deserialize(new[] { DataCodes.Nil }.ToMultipleSegments(), out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + } +} diff --git a/tests/msgpack.light.tests/SequenceReader/Nullable.cs b/tests/msgpack.light.tests/SequenceReader/Nullable.cs new file mode 100644 index 0000000..b45e4e2 --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/Nullable.cs @@ -0,0 +1,265 @@ +using System; + +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + public class Nullable + { + [Fact] + public void ReadNullAsNullableBool() + { + var data = new[] { DataCodes.Nil }.ToMultipleSegments(); + var deserialize = MsgPackSerializer.Deserialize(data, out var readSize); + deserialize.ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void ReadNullAsNullableFloat() + { + var data = new[] { DataCodes.Nil }.ToMultipleSegments(); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void ReadNullAsNullableDouble() + { + var data = new[] { DataCodes.Nil }.ToMultipleSegments(); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void ReadNullAsNullableByte() + { + var data = new[] { DataCodes.Nil }.ToMultipleSegments(); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void ReadNullAsNullableSbyte() + { + var data = new[] { DataCodes.Nil }.ToMultipleSegments(); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void ReadNullAsNullableShort() + { + var data = new[] { DataCodes.Nil }.ToMultipleSegments(); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void ReadNullAsNullableUshort() + { + var data = new[] { DataCodes.Nil }.ToMultipleSegments(); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void ReadNullAsNullableInt() + { + var data = new[] { DataCodes.Nil }.ToMultipleSegments(); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void ReadNullAsNullableUint() + { + var data = new[] { DataCodes.Nil }.ToMultipleSegments(); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void ReadNullAsNullableLong() + { + var data = new[] { DataCodes.Nil }.ToMultipleSegments(); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void ReadNullAsNullableUlong() + { + var data = new[] { DataCodes.Nil }.ToMultipleSegments(); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(null); + readSize.ShouldBe(1); + } + + [Fact] + public void False() + { + var data = new[] { DataCodes.False }.ToMultipleSegments(); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(false); + readSize.ShouldBe(1); + } + + [Fact] + public void True() + { + var data = new[] { DataCodes.True }.ToMultipleSegments(); + MsgPackSerializer.Deserialize(data, out var readSize).ShouldBe(true); + readSize.ShouldBe(1); + } + + [Theory] + [InlineData(0, new byte[] { 203, 0, 0, 0, 0, 0, 0, 0, 0 })] + [InlineData(1, new byte[] { 203, 63, 240, 0, 0, 0, 0, 0, 0 })] + [InlineData(-1, new byte[] { 203, 191, 240, 0, 0, 0, 0, 0, 0 })] + [InlineData(Math.E, new byte[] { 203, 64, 5, 191, 10, 139, 20, 87, 105 })] + [InlineData(Math.PI, new byte[] { 203, 64, 9, 33, 251, 84, 68, 45, 24 })] + [InlineData(224, new byte[] { 203, 64, 108, 0, 0, 0, 0, 0, 0 })] + [InlineData(256, new byte[] { 203, 64, 112, 0, 0, 0, 0, 0, 0 })] + [InlineData(65530, new byte[] { 203, 64, 239, 255, 64, 0, 0, 0, 0 })] + [InlineData(65540, new byte[] { 203, 64, 240, 0, 64, 0, 0, 0, 0 })] + [InlineData(double.NaN, new byte[] { 203, 255, 248, 0, 0, 0, 0, 0, 0 })] + [InlineData(double.MaxValue, new byte[] { 203, 127, 239, 255, 255, 255, 255, 255, 255 })] + [InlineData(double.MinValue, new byte[] { 203, 255, 239, 255, 255, 255, 255, 255, 255 })] + [InlineData(double.PositiveInfinity, new byte[] { 203, 127, 240, 0, 0, 0, 0, 0, 0 })] + [InlineData(double.NegativeInfinity, new byte[] { 203, 255, 240, 0, 0, 0, 0, 0, 0 })] + public void TestDouble(double value, byte[] bytes) + { + MsgPackSerializer.Deserialize(bytes.ToMultipleSegments(), out var readSize).ShouldBe(value); + readSize.ShouldBe(bytes.Length); + } + + [Theory] + [InlineData(0, new byte[] { 202, 0, 0, 0, 0 })] + [InlineData(1, new byte[] { 202, 63, 128, 0, 0 })] + [InlineData(-1, new byte[] { 202, 191, 128, 0, 0 })] + [InlineData(2.71828, new byte[] { 202, 64, 45, 248, 77 })] + [InlineData(3.14159, new byte[] { 202, 64, 73, 15, 208 })] + [InlineData(224, new byte[] { 202, 67, 96, 0, 0 })] + [InlineData(256, new byte[] { 202, 67, 128, 0, 0 })] + [InlineData(65530, new byte[] { 202, 71, 127, 250, 0 })] + [InlineData(65540, new byte[] { 202, 71, 128, 2, 0 })] + [InlineData(float.NaN, new byte[] { 202, 255, 192, 0, 0 })] + [InlineData(float.MaxValue, new byte[] { 202, 127, 127, 255, 255 })] + [InlineData(float.MinValue, new byte[] { 202, 255, 127, 255, 255 })] + [InlineData(float.PositiveInfinity, new byte[] { 202, 127, 128, 0, 0 })] + [InlineData(float.NegativeInfinity, new byte[] { 202, 255, 128, 0, 0 })] + public void TestFloat(float value, byte[] bytes) + { + MsgPackSerializer.Deserialize(bytes.ToMultipleSegments(), out var readSize).ShouldBe(value); + readSize.ShouldBe(bytes.Length); + } + + [Theory] + [InlineData(0, new byte[] { 0x00 })] + [InlineData(1, new byte[] { 1 })] + [InlineData(-1, new byte[] { 0xff })] + [InlineData(sbyte.MinValue, new byte[] { 208, 128 })] + [InlineData(sbyte.MaxValue, new byte[] { 127 })] + [InlineData(short.MinValue, new byte[] { 209, 128, 0 })] + [InlineData(short.MaxValue, new byte[] { 209, 127, 0xff })] + [InlineData(int.MinValue, new byte[] { 210, 128, 0, 0, 0 })] + [InlineData(int.MaxValue, new byte[] { 210, 127, 0xff, 0xff, 0xff })] + [InlineData(long.MaxValue, new byte[] { 211, 127, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff })] + [InlineData(long.MinValue, new byte[] { 211, 128, 0, 0, 0, 0, 0, 0, 0 })] + public void TestSignedLong(long number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] { 0x00 })] + [InlineData(1, new byte[] { 1 })] + [InlineData(-1, new byte[] { 0xff })] + [InlineData(sbyte.MinValue, new byte[] { 208, 128 })] + [InlineData(sbyte.MaxValue, new byte[] { 127 })] + [InlineData(short.MinValue, new byte[] { 209, 128, 0 })] + [InlineData(short.MaxValue, new byte[] { 209, 127, 0xff })] + [InlineData(int.MinValue, new byte[] { 210, 128, 0, 0, 0 })] + [InlineData(int.MaxValue, new byte[] { 210, 127, 0xff, 0xff, 0xff })] + [InlineData(50505, new byte[] { 205, 197, 73 })] + public void TestSignedInt(int number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] { 0x00 })] + [InlineData(1, new byte[] { 1 })] + [InlineData(-1, new byte[] { 0xff })] + [InlineData(sbyte.MinValue, new byte[] { 208, 128 })] + [InlineData(sbyte.MaxValue, new byte[] { 127 })] + [InlineData(short.MinValue, new byte[] { 209, 128, 0 })] + [InlineData(short.MaxValue, new byte[] { 209, 127, 0xff })] + public void TestSignedShort(short number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] { 0x00 })] + [InlineData(1, new byte[] { 1 })] + [InlineData(-1, new byte[] { 0xff })] + [InlineData(sbyte.MinValue, new byte[] { 208, 128 })] + [InlineData(sbyte.MaxValue, new byte[] { 127 })] + public void TestSignedByte(sbyte number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] { 0x00 })] + [InlineData(1, new byte[] { 1 })] + [InlineData(byte.MaxValue, new byte[] { 0xcc, 0xff })] + [InlineData(ushort.MaxValue, new byte[] { 0xcd, 0xff, 0xff })] + [InlineData(uint.MaxValue, new byte[] { 0xce, 0xff, 0xff, 0xff, 0xff })] + [InlineData(ulong.MaxValue, new byte[] { 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff })] + public void TestUnsignedLong(ulong number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] { 0x00 })] + [InlineData(1, new byte[] { 1 })] + [InlineData(byte.MaxValue, new byte[] { 0xcc, 0xff })] + [InlineData(ushort.MaxValue, new byte[] { 0xcd, 0xff, 0xff })] + [InlineData(uint.MaxValue, new byte[] { 0xce, 0xff, 0xff, 0xff, 0xff })] + public void TestUnsignedInt(uint number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] { 0x00 })] + [InlineData(1, new byte[] { 1 })] + [InlineData(byte.MaxValue, new byte[] { 0xcc, 0xff })] + [InlineData(ushort.MaxValue, new byte[] { 0xcd, 0xff, 0xff })] + public void TestUnsignedShort(ushort number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + + [Theory] + [InlineData(0, new byte[] { 0x00 })] + [InlineData(1, new byte[] { 1 })] + [InlineData(byte.MaxValue, new byte[] { 0xcc, 0xff })] + public void TestUnsignedByte(byte number, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(number); + readSize.ShouldBe(data.Length); + } + } +} diff --git a/tests/msgpack.light.tests/SequenceReader/String.cs b/tests/msgpack.light.tests/SequenceReader/String.cs new file mode 100644 index 0000000..362c1c4 --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/String.cs @@ -0,0 +1,40 @@ +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + public class String + { + [Theory] + [InlineData("asdf", new byte[] { 164, 97, 115, 100, 102 })] + [InlineData("12345678901234567890", new byte[] { 180, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48 })] + [InlineData("1234567890123456789012345678901234567890", new byte[] { 217, 40, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48 })] + [InlineData("", new byte[] { 160 })] + [InlineData("08612364123065712639gr1h2j3grtk1h23kgfrt1hj2g3fjrgf1j2hg08612364123065712639gr1h2j3grtk1h23kgfrt1hj2g3fjrgf1j2hg08612364123065712639gr1h2j3grtk1h23kgfrt1hj2g3fjrgf1j2hg08612364123065712639gr1h2j3grtk1h23kgfrt1hj2g3fjrgf1j2hg08612364123065712639gr1h2j3grtk1h23kgfrt1hj2g3fjrgf1j2hg08612364123065712639gr1h2j3grtk1h23kgfrt1hj2g3fjrgf1j2hg", new byte[] { + 218, 1, 80, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, + 49, 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, + 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, + 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, + 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, + 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, + 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, + 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, + 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, + 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, + 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, + 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, + 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, 103, 48, 56, 54, 49, 50, 51, 54, 52, 49, 50, 51, + 48, 54, 53, 55, 49, 50, 54, 51, 57, 103, 114, 49, 104, 50, 106, 51, 103, 114, 116, 107, 49, 104, 50, + 51, 107, 103, 102, 114, 116, 49, 104, 106, 50, 103, 51, 102, 106, 114, 103, 102, 49, 106, 50, 104, + 103 + })] + [InlineData("Мама мыла раму", new byte[] { 186, 208, 156, 208, 176, 208, 188, 208, 176, 32, 208, 188, 209, 139, 208, 187, 208, 176, 32, 209, 128, 208, 176, 208, 188, 209, 131 })] + [InlineData("Шла Саша по шоссе и сосала сушку", new byte[] { 217, 58, 208, 168, 208, 187, 208, 176, 32, 208, 161, 208, 176, 209, 136, 208, 176, 32, 208, 191, 208, 190, 32, 209, 136, 208, 190, 209, 129, 209, 129, 208, 181, 32, 208, 184, 32, 209, 129, 208, 190, 209, 129, 208, 176, 208, 187, 208, 176, 32, 209, 129, 209, 131, 209, 136, 208, 186, 209, 131 })] + public void TestStringPack(string s, byte[] data) + { + MsgPackSerializer.Deserialize(data.ToMultipleSegments(), out var readSize).ShouldBe(s); + readSize.ShouldBe(data.Length); + } + } +} diff --git a/tests/msgpack.light.tests/SequenceReader/TimeSpan.cs b/tests/msgpack.light.tests/SequenceReader/TimeSpan.cs new file mode 100644 index 0000000..e702bc2 --- /dev/null +++ b/tests/msgpack.light.tests/SequenceReader/TimeSpan.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; + +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.SequenceReader +{ + public class Timespan + { + [Fact] + public void TestTimeSpan() + { + var tests = new List<(TimeSpan span, byte[] blob)> + { + ValueTuple.Create(TimeSpan.MinValue, new byte[] {211, 128, 0, 0, 0, 0, 0, 0, 0}), + ValueTuple.Create(TimeSpan.MaxValue, new byte[] {207, 127, 255, 255, 255, 255, 255, 255, 255}), + ValueTuple.Create(new TimeSpan(1, 2, 3, 4, 5), new byte[] {207, 0, 0, 0, 218, 91, 159, 127, 80}), + ValueTuple.Create(TimeSpan.FromTicks(-100), new byte[] {208, 156}) + }; + + foreach (var test in tests) + { + MsgPackSerializer.Deserialize(test.blob.ToMultipleSegments(), out var readSize).ShouldBe(test.span); + readSize.ShouldBe(test.blob.Length); + } + } + } +} diff --git a/tests/msgpack.light.tests/TestReflectionConverter.cs b/tests/msgpack.light.tests/TestReflectionConverter.cs deleted file mode 100644 index f0c2baf..0000000 --- a/tests/msgpack.light.tests/TestReflectionConverter.cs +++ /dev/null @@ -1,179 +0,0 @@ -using JetBrains.Annotations; -using System; -using System.Collections.Generic; -using System.IO; - -// ReSharper disable once RedundantUsingDirective -using System.Reflection; -using System.Runtime.Serialization; - -namespace ProGaudi.MsgPack.Light.Tests -{ - public class TestReflectionConverter : IMsgPackConverter - { - private MsgPackContext _context; - - public void Initialize(MsgPackContext context) - { - _context = context; - } - - public void Write(object value, IMsgPackWriter writer) - { - if (value == null) - { - _context.NullConverter.Write(null, writer); - return; - } - - var converter = GetConverter(_context, value.GetType()); - - var methodDefinition = typeof(IMsgPackConverter<>).MakeGenericType(value.GetType()).GetMethod( - "Write", - new[] { value.GetType(), typeof(IMsgPackWriter) }); - - methodDefinition.Invoke(converter, new[] { value, writer }); - } - - public object Read(IMsgPackReader reader) - { - var msgPackType = reader.ReadDataType(); - - Type type; - switch (msgPackType) - { - case DataTypes.Null: - return null; - - case DataTypes.False: - return false; - - case DataTypes.True: - return true; - - case DataTypes.Single: - type = typeof(float); - break; - - case DataTypes.Double: - type = typeof(double); - break; - - case DataTypes.UInt8: - type = typeof(byte); - break; - - case DataTypes.UInt16: - type = typeof(ushort); - break; - - case DataTypes.UInt32: - type = typeof(uint); - break; - - case DataTypes.UInt64: - type = typeof(ulong); - break; - - case DataTypes.Int8: - type = typeof(sbyte); - break; - - case DataTypes.Int16: - type = typeof(short); - break; - - case DataTypes.Int32: - type = typeof(int); - break; - - case DataTypes.Int64: - type = typeof(long); - break; - - case DataTypes.Array16: - type = typeof(object[]); - break; - - case DataTypes.Array32: - type = typeof(object[]); - break; - - case DataTypes.Map16: - type = typeof(Dictionary); - break; - - case DataTypes.Map32: - type = typeof(Dictionary); - break; - - case DataTypes.Str8: - type = typeof(string); - break; - - case DataTypes.Str16: - type = typeof(string); - break; - - case DataTypes.Str32: - type = typeof(string); - break; - - case DataTypes.Bin8: - type = typeof(byte[]); - break; - - case DataTypes.Bin16: - type = typeof(byte[]); - break; - - case DataTypes.Bin32: - type = typeof(byte[]); - break; - - default: - type = TryInferFromFixedLength(msgPackType); - break; - } - - reader.Seek(-1, SeekOrigin.Current); - var converter = GetConverter(_context, type); - var methodDefinition = typeof(IMsgPackConverter<>).MakeGenericType(type).GetMethod( - "Read", - new[] { typeof(IMsgPackReader) }); - - return methodDefinition.Invoke(converter, new object[] { reader }); - } - - private Type TryInferFromFixedLength(DataTypes msgPackType) - { - if (msgPackType.GetHighBits(1) == DataTypes.PositiveFixNum.GetHighBits(1)) - return typeof(byte); - - if (msgPackType.GetHighBits(3) == DataTypes.NegativeFixNum.GetHighBits(3)) - return typeof(sbyte); - - if (msgPackType.GetHighBits(4) == DataTypes.FixArray.GetHighBits(4)) - return typeof(object[]); - - if (msgPackType.GetHighBits(3) == DataTypes.FixStr.GetHighBits(3)) - return typeof(string); - - if (msgPackType.GetHighBits(4) == DataTypes.FixMap.GetHighBits(4)) - return typeof(Dictionary); - - throw new SerializationException($"Can't infer type for msgpack type: {msgPackType:G} (0x{msgPackType:X})"); - } - - [NotNull] - private static object GetConverter(MsgPackContext context, Type type) - { - var methodDefinition = typeof(MsgPackContext).GetMethod(nameof(MsgPackContext.GetConverter), new Type[0]); - var concreteMethod = methodDefinition.MakeGenericMethod(type); - var converter = concreteMethod.Invoke(context, null); - if (converter == null) - throw new SerializationException($"Please, provide convertor for {type.Name}"); - return converter; - } - } -} \ No newline at end of file diff --git a/tests/msgpack.light.tests/Writer/Array.cs b/tests/msgpack.light.tests/Writer/Array.cs index ce33b9b..e3598aa 100644 --- a/tests/msgpack.light.tests/Writer/Array.cs +++ b/tests/msgpack.light.tests/Writer/Array.cs @@ -1,6 +1,3 @@ -using System.Collections.Generic; -using System.Linq; - using Shouldly; using Xunit; @@ -31,44 +28,8 @@ public void SimpleArray() 161, 101 }; - MsgPackSerializer.Serialize(tests).ShouldBe(bytes); - - new MsgPackToken(tests.Select(e => (MsgPackToken) e).ToArray()).RawBytes.ShouldBe(bytes); - } - - [Fact] - public void TestArrayPack() - { - var tests = new object[] - { - 0, - 50505, - float.NaN, - float.MaxValue, - new[] {true, false, true}, - null, - new Dictionary {{"Ball", "Soccer"}} - }; - - var data = new byte[] - { - 151, - 0, - 205, 197, 73, - 202, 255, 192, 0, 0, - 202, 127, 127, 255, 255, - 147, - 195, - 194, - 195, - 192, - 129, - 164, 66, 97, 108, 108, 166, 83, 111, 99, 99, 101, 114 - }; - - var settings = new MsgPackContext(); - settings.RegisterConverter(new TestReflectionConverter()); - MsgPackSerializer.Serialize(tests, settings).ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize(tests, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(bytes); } } } diff --git a/tests/msgpack.light.tests/Writer/Binary.cs b/tests/msgpack.light.tests/Writer/Binary.cs index c06baa0..46ecc62 100644 --- a/tests/msgpack.light.tests/Writer/Binary.cs +++ b/tests/msgpack.light.tests/Writer/Binary.cs @@ -1,3 +1,6 @@ +using ProGaudi.Buffers; +using ProGaudi.MsgPack.Converters.Binary; + using Shouldly; using Xunit; @@ -83,9 +86,11 @@ public class Binary })] public void Test(byte[] value, byte[] data) { - MsgPackSerializer.Serialize(value).ShouldBe(data); - - ((MsgPackToken)value).RawBytes.ShouldBe(data); + using (var blob = FixedLengthMemoryPool.Shared.Rent(data.Length)) + { + Converter.Current.Format(blob.Memory.Span, value); + blob.Memory.ShouldBe(data); + } } [Theory] @@ -165,9 +170,8 @@ public void Test(byte[] value, byte[] data) })] public void WriteOldBinary(byte[] value, byte[] data) { - var context = new MsgPackContext(binaryCompatibilityMode: true); - var result = Should.NotThrow(() => MsgPackSerializer.Serialize(value, context)); - result.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize(value, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } } } diff --git a/tests/msgpack.light.tests/Writer/Boolean.cs b/tests/msgpack.light.tests/Writer/Boolean.cs index 438e6bf..dd5e6d5 100644 --- a/tests/msgpack.light.tests/Writer/Boolean.cs +++ b/tests/msgpack.light.tests/Writer/Boolean.cs @@ -7,13 +7,12 @@ namespace ProGaudi.MsgPack.Light.Tests.Writer public class Boolean { [Theory] - [InlineData(true, new byte[] { (byte)DataTypes.True })] - [InlineData(false, new byte[] { (byte)DataTypes.False })] + [InlineData(true, new[] { DataCodes.True })] + [InlineData(false, new[] { DataCodes.False })] public void Test(bool value, byte[] data) { - MsgPackSerializer.Serialize(value).ShouldBe(data); - - ((MsgPackToken)value).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize(value, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } } } diff --git a/tests/msgpack.light.tests/Writer/DateTime.cs b/tests/msgpack.light.tests/Writer/DateTime.cs index 41c5545..19cb476 100644 --- a/tests/msgpack.light.tests/Writer/DateTime.cs +++ b/tests/msgpack.light.tests/Writer/DateTime.cs @@ -12,38 +12,38 @@ public class DateTimeTest [Fact] public void TestDateTime() { - var tests = new List>() + var tests = new List<(DateTime time, byte[] data)> { - new KeyValuePair(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), new byte[] {211, 247, 96, 128, 10, 8, 74, 128, 0,}), - new KeyValuePair(new DateTime(9999, 12, 31, 23, 59, 59, 999, DateTimeKind.Utc), new byte[] { 207, 35, 42, 168, 127, 252, 129, 152, 240,}), - new KeyValuePair(new DateTime(2015, 11, 17, 0, 0, 0, 0, DateTimeKind.Utc), new byte[] { 207, 0, 51, 110, 236, 17, 171, 0, 0,}), - new KeyValuePair(new DateTime(1, 2, 3, 4, 5, 6, DateTimeKind.Utc), new byte[] {211, 247, 96, 154, 26, 189, 97, 197, 0,}), + ValueTuple.Create(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), new byte[] {211, 247, 96, 128, 10, 8, 74, 128, 0}), + ValueTuple.Create(new DateTime(9999, 12, 31, 23, 59, 59, 999, DateTimeKind.Utc), new byte[] { 207, 35, 42, 168, 127, 252, 129, 152, 240}), + ValueTuple.Create(new DateTime(2015, 11, 17, 0, 0, 0, 0, DateTimeKind.Utc), new byte[] { 207, 0, 51, 110, 236, 17, 171, 0, 0}), + ValueTuple.Create(new DateTime(1, 2, 3, 4, 5, 6, DateTimeKind.Utc), new byte[] {211, 247, 96, 154, 26, 189, 97, 197, 0}) }; foreach (var test in tests) { - MsgPackSerializer.Serialize(test.Key).ShouldBe(test.Value); - ((MsgPackToken)test.Key).RawBytes.ShouldBe(test.Value); + using (var blob = MsgPackSerializer.Serialize(test.time, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(test.data); } } [Fact] public void TestDateTimeOffset() { - var tests = new List>() + var tests = new List<(DateTimeOffset time, byte[] data)> { - new KeyValuePair(DateTimeOffset.MinValue, new byte[] {211, 247, 96, 128, 10, 8, 74, 128, 0,}), - new KeyValuePair(DateTimeOffset.MaxValue, new byte[] {207, 35, 42, 168, 127, 252, 129, 191, 255,}), - new KeyValuePair(new DateTimeOffset(2015, 11, 17, 0, 0, 0, TimeSpan.Zero), new byte[] {207, 0, 51, 110, 236, 17, 171, 0, 0,}), - new KeyValuePair(new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.Zero), new byte[] {211, 247, 96, 154, 26, 189, 97, 197, 0,}), - new KeyValuePair(new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromHours(12)), new byte[] {211, 247, 96, 153, 182, 40, 44, 229, 0,}), - new KeyValuePair(new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromMinutes(361)), new byte[] {211, 247, 96, 153, 232, 79, 4, 15, 0,}), + ValueTuple.Create(DateTimeOffset.MinValue, new byte[] {211, 247, 96, 128, 10, 8, 74, 128, 0}), + ValueTuple.Create(DateTimeOffset.MaxValue, new byte[] {207, 35, 42, 168, 127, 252, 129, 191, 255}), + ValueTuple.Create(new DateTimeOffset(2015, 11, 17, 0, 0, 0, TimeSpan.Zero), new byte[] {207, 0, 51, 110, 236, 17, 171, 0, 0}), + ValueTuple.Create(new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.Zero), new byte[] {211, 247, 96, 154, 26, 189, 97, 197, 0}), + ValueTuple.Create(new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromHours(12)), new byte[] {211, 247, 96, 153, 182, 40, 44, 229, 0}), + ValueTuple.Create(new DateTimeOffset(1, 2, 3, 4, 5, 6, TimeSpan.FromMinutes(361)), new byte[] {211, 247, 96, 153, 232, 79, 4, 15, 0}) }; foreach (var test in tests) { - MsgPackSerializer.Serialize(test.Key).ShouldBe(test.Value); - ((MsgPackToken)test.Key).RawBytes.ShouldBe(test.Value); + using (var blob = MsgPackSerializer.Serialize(test.time, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(test.data); } } } diff --git a/tests/msgpack.light.tests/Writer/Double.cs b/tests/msgpack.light.tests/Writer/Double.cs index b055e56..9ebdb8c 100644 --- a/tests/msgpack.light.tests/Writer/Double.cs +++ b/tests/msgpack.light.tests/Writer/Double.cs @@ -25,8 +25,8 @@ public class FloatingPoint [InlineData(double.NegativeInfinity, new byte[] {203, 255, 240, 0, 0, 0, 0, 0, 0})] public void TestDouble(double value, byte[] bytes) { - MsgPackSerializer.Serialize(value).ShouldBe(bytes); - ((MsgPackToken)value).RawBytes.ShouldBe(bytes); + using (var blob = MsgPackSerializer.Serialize(value, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(bytes); } [Theory] @@ -46,8 +46,8 @@ public void TestDouble(double value, byte[] bytes) [InlineData(float.NegativeInfinity, new byte[] {202, 255, 128, 0, 0})] public void TestFloat(float value, byte[] bytes) { - MsgPackSerializer.Serialize(value).ShouldBe(bytes); - ((MsgPackToken)value).RawBytes.ShouldBe(bytes); + using (var blob = MsgPackSerializer.Serialize(value, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(bytes); } } } diff --git a/tests/msgpack.light.tests/Writer/Enums.cs b/tests/msgpack.light.tests/Writer/Enums.cs index fa4114c..55b7c9f 100644 --- a/tests/msgpack.light.tests/Writer/Enums.cs +++ b/tests/msgpack.light.tests/Writer/Enums.cs @@ -6,123 +6,121 @@ namespace ProGaudi.MsgPack.Light.Tests.Writer { public class Enums { - [Theory, ClassData(typeof(EnumValuesProvider))] - public void WriteEnum(DefaultEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); - var valueResult = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); - - enumResult.ShouldBe(valueResult); - } +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void WriteEnum(DefaultEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); +// var valueResult = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); +// +// enumResult.ShouldBe(valueResult); +// } [Theory, ClassData(typeof(EnumValuesProvider))] public void WriteEnumAsString(DefaultEnum enumValue) { - var enumAsStringResult = MsgPackSerializer.Serialize(enumValue); - var enumAsStringExpected = MsgPackSerializer.Serialize(enumValue.ToString()); - - enumAsStringResult.ShouldBe(enumAsStringExpected); + using (var enumBlob = MsgPackSerializer.Serialize(enumValue, out var wroteSize)) + using (var stringBlob = MsgPackSerializer.Serialize(enumValue, out var stringSize)) + enumBlob.Memory.Slice(0, wroteSize).ShouldBe(stringBlob.Memory.Slice(0, stringSize)); } - [Theory, ClassData(typeof(EnumValuesProvider))] - public void WriteFlagEnum(FlagEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); - var valueResult = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); - - enumResult.ShouldBe(valueResult); - } +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void WriteFlagEnum(FlagEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); +// var valueResult = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); +// +// enumResult.ShouldBe(valueResult); +// } [Theory, ClassData(typeof(EnumValuesProvider))] public void WriteFlagEnumAsString(FlagEnum enumValue) { - var enumAsStringResult = MsgPackSerializer.Serialize(enumValue); - var enumAsStringExpected = MsgPackSerializer.Serialize(enumValue.ToString()); - - enumAsStringResult.ShouldBe(enumAsStringExpected); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void WriteSbyteEnum(SbyteEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - - var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); - var valueResult = MsgPackSerializer.Serialize((sbyte)enumValue, intEnumContext); - - enumResult.ShouldBe(valueResult); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void WriteByteEnum(ByteEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); - var valueResult = MsgPackSerializer.Serialize((byte)enumValue, intEnumContext); - - enumResult.ShouldBe(valueResult); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void WriteShortEnum(ShortEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); - var valueResult = MsgPackSerializer.Serialize((short)enumValue, intEnumContext); - - enumResult.ShouldBe(valueResult); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void WriteUshortEnum(UshortEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); - var valueResult = MsgPackSerializer.Serialize((ushort)enumValue, intEnumContext); - - enumResult.ShouldBe(valueResult); + using (var enumBlob = MsgPackSerializer.Serialize(enumValue, out var wroteSize)) + using (var stringBlob = MsgPackSerializer.Serialize(enumValue, out var stringSize)) + enumBlob.Memory.Slice(0, wroteSize).ShouldBe(stringBlob.Memory.Slice(0, stringSize)); } - [Theory, ClassData(typeof(EnumValuesProvider))] - public void WriteIntEnum(IntEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); - var valueResult = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); - - enumResult.ShouldBe(valueResult); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void WriteUintEnum(UintEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); - var valueResult = MsgPackSerializer.Serialize((uint)enumValue, intEnumContext); - - enumResult.ShouldBe(valueResult); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void WriteLongEnum(LongEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); - var valueResult = MsgPackSerializer.Serialize((long)enumValue, intEnumContext); - - enumResult.ShouldBe(valueResult); - } - - [Theory, ClassData(typeof(EnumValuesProvider))] - public void WriteUlongEnum(UlongEnum enumValue) - { - var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); - var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); - var valueResult = MsgPackSerializer.Serialize((ulong)enumValue, intEnumContext); - - enumResult.ShouldBe(valueResult); - } +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void WriteSbyteEnum(SbyteEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// +// var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); +// var valueResult = MsgPackSerializer.Serialize((sbyte)enumValue, intEnumContext); +// +// enumResult.ShouldBe(valueResult); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void WriteByteEnum(ByteEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); +// var valueResult = MsgPackSerializer.Serialize((byte)enumValue, intEnumContext); +// +// enumResult.ShouldBe(valueResult); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void WriteShortEnum(ShortEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); +// var valueResult = MsgPackSerializer.Serialize((short)enumValue, intEnumContext); +// +// enumResult.ShouldBe(valueResult); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void WriteUshortEnum(UshortEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); +// var valueResult = MsgPackSerializer.Serialize((ushort)enumValue, intEnumContext); +// +// enumResult.ShouldBe(valueResult); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void WriteIntEnum(IntEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); +// var valueResult = MsgPackSerializer.Serialize((int)enumValue, intEnumContext); +// +// enumResult.ShouldBe(valueResult); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void WriteUintEnum(UintEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); +// var valueResult = MsgPackSerializer.Serialize((uint)enumValue, intEnumContext); +// +// enumResult.ShouldBe(valueResult); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void WriteLongEnum(LongEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); +// var valueResult = MsgPackSerializer.Serialize((long)enumValue, intEnumContext); +// +// enumResult.ShouldBe(valueResult); +// } +// +// [Theory, ClassData(typeof(EnumValuesProvider))] +// public void WriteUlongEnum(UlongEnum enumValue) +// { +// var intEnumContext = new MsgPackContext(convertEnumsAsStrings: false); +// var enumResult = MsgPackSerializer.Serialize(enumValue, intEnumContext); +// var valueResult = MsgPackSerializer.Serialize((ulong)enumValue, intEnumContext); +// +// enumResult.ShouldBe(valueResult); +// } } -} \ No newline at end of file +} diff --git a/tests/msgpack.light.tests/Writer/Generic.cs b/tests/msgpack.light.tests/Writer/Generic.cs new file mode 100644 index 0000000..00712f6 --- /dev/null +++ b/tests/msgpack.light.tests/Writer/Generic.cs @@ -0,0 +1,35 @@ +using Shouldly; + +using Xunit; + +namespace ProGaudi.MsgPack.Light.Tests.Writer +{ + public class Generic + { + [Fact] + public void IntTest() + { + var context = new MsgPackContext(); + context.RegisterGenericFormatter(typeof(GenericFormatter<>)); + + using (var bytes = MsgPackSerializer.Serialize(new A {F = 10}, context, out var x)) + { + x.ShouldBe(1); + bytes.Memory.Slice(0, x).ShouldBe(new byte[] { 10 }); + } + } + + [Fact] + public void StringTest() + { + var context = new MsgPackContext(); + context.RegisterGenericFormatter(typeof(GenericFormatter<>)); + + using (var bytes = MsgPackSerializer.Serialize(new A {F = "abc"}, context, out var x)) + { + x.ShouldBe(4); + bytes.Memory.Slice(0, x).ShouldBe(new byte[] { 163, 97, 98, 99 }); + } + } + } +} diff --git a/tests/msgpack.light.tests/Writer/Helpers.cs b/tests/msgpack.light.tests/Writer/Helpers.cs deleted file mode 100644 index eb47c8f..0000000 --- a/tests/msgpack.light.tests/Writer/Helpers.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Text; - -namespace ProGaudi.MsgPack.Light.Tests.Writer -{ - public class Helpers - { - public static string GenerateString(int size) - { - var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray(); - var data = GenerateBytesArray(size); - var result = new StringBuilder(size); - foreach (var b in data) - { - result.Append(chars[b % chars.Length]); - } - return result.ToString(); - } - - public static byte[] GenerateBytesArray(int size) - { - var data = new byte[size]; - var crypto = new Random(); - crypto.NextBytes(data); - return data; - } - } -} diff --git a/tests/msgpack.light.tests/Writer/Integers.cs b/tests/msgpack.light.tests/Writer/Integers.cs index 966b501..de22ae9 100644 --- a/tests/msgpack.light.tests/Writer/Integers.cs +++ b/tests/msgpack.light.tests/Writer/Integers.cs @@ -20,8 +20,8 @@ public class Integers [InlineData(long.MinValue, new byte[] {211, 128, 0, 0, 0, 0, 0, 0, 0})] public void TestSignedLong(long number, byte[] data) { - MsgPackSerializer.Serialize(number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize(number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] @@ -37,8 +37,8 @@ public void TestSignedLong(long number, byte[] data) [InlineData(50505, new byte[] {205, 197, 73})] public void TestSignedInt(int number, byte[] data) { - MsgPackSerializer.Serialize(number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize(number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] @@ -51,8 +51,8 @@ public void TestSignedInt(int number, byte[] data) [InlineData(short.MaxValue, new byte[] {205, 127, 0xff})] public void TestSignedShort(short number, byte[] data) { - MsgPackSerializer.Serialize(number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize(number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] @@ -63,8 +63,8 @@ public void TestSignedShort(short number, byte[] data) [InlineData(sbyte.MaxValue, new byte[] {127})] public void TestSignedByte(sbyte number, byte[] data) { - MsgPackSerializer.Serialize(number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize(number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] @@ -74,10 +74,10 @@ public void TestSignedByte(sbyte number, byte[] data) [InlineData(ushort.MaxValue, new byte[] {0xcd, 0xff, 0xff})] [InlineData(uint.MaxValue, new byte[] {0xce, 0xff, 0xff, 0xff, 0xff})] [InlineData(ulong.MaxValue, new byte[] {0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})] - public void TetsUnsignedLong(ulong number, byte[] data) + public void TestUnsignedLong(ulong number, byte[] data) { - MsgPackSerializer.Serialize(number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize(number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] @@ -87,10 +87,10 @@ public void TetsUnsignedLong(ulong number, byte[] data) [InlineData(ushort.MaxValue, new byte[] { 0xcd, 0xff, 0xff })] [InlineData(uint.MaxValue, new byte[] { 0xce, 0xff, 0xff, 0xff, 0xff })] [InlineData(0x10000000, new byte[] { 0xce, 0x10, 0x00, 0x00, 0x00 })] - public void TetsUnsignedInt(uint number, byte[] data) + public void TestUnsignedInt(uint number, byte[] data) { - MsgPackSerializer.Serialize(number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize(number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] @@ -98,20 +98,20 @@ public void TetsUnsignedInt(uint number, byte[] data) [InlineData(1, new byte[] {1})] [InlineData(byte.MaxValue, new byte[] {0xcc, 0xff})] [InlineData(ushort.MaxValue, new byte[] {0xcd, 0xff, 0xff})] - public void TetsUnsignedShort(ushort number, byte[] data) + public void TestUnsignedShort(ushort number, byte[] data) { - MsgPackSerializer.Serialize(number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize(number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] [InlineData(0, new byte[] {0x00})] [InlineData(1, new byte[] {1})] [InlineData(byte.MaxValue, new byte[] {0xcc, 0xff})] - public void TetsUnsignedByte(byte number, byte[] data) + public void TestUnsignedByte(byte number, byte[] data) { - MsgPackSerializer.Serialize(number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize(number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } } } diff --git a/tests/msgpack.light.tests/Writer/Map.cs b/tests/msgpack.light.tests/Writer/Map.cs index f89719e..9318070 100644 --- a/tests/msgpack.light.tests/Writer/Map.cs +++ b/tests/msgpack.light.tests/Writer/Map.cs @@ -1,6 +1,6 @@ -using Shouldly; using System.Collections.Generic; -using System.Linq; + +using Shouldly; using Xunit; @@ -8,55 +8,6 @@ namespace ProGaudi.MsgPack.Light.Tests.Writer { public class Map { - [Fact] - public void ComplexDictionary() - { - var tests = new Dictionary - { - { - "array1", - new object[] - { - "array1_value1", - "array1_value2", - "array1_value3" - } - }, - {"bool1", true}, - {"double1", 50.5}, - {"double2", 15.2}, - {"int1", 50505}, - {"int2", 50}, - {3.14f, 3.14}, - {42, 42}, - {new Dictionary {{1, 2}}, null}, - {new[] {1, 2}, null} - }; - - var data = new byte[] - { - 138, - 166, 97, 114, 114, 97, 121, 49, - 147, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 49, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 50, - 173, 97, 114, 114, 97, 121, 49, 95, 118, 97, 108, 117, 101, 51, - 165, 98, 111, 111, 108, 49, 195, - 167, 100, 111, 117, 98, 108, 101, 49, 203, 64, 73, 64, 0, 0, 0, 0, 0, - 167, 100, 111, 117, 98, 108, 101, 50, 203, 64, 46, 102, 102, 102, 102, 102, 102, - 164, 105, 110, 116, 49, 205, 197, 73, - 164, 105, 110, 116, 50, 50, - 202, 64, 72, 245, 195, 203, 64, 9, 30, 184, 81, 235, 133, 31, - 42, 42, - 129, 1, 2, 192, - 146, 1, 2, 192 - }; - - var settings = new MsgPackContext(); - settings.RegisterConverter(new TestReflectionConverter()); - MsgPackSerializer.Serialize(tests, settings).ShouldBe(data); - } - [Fact] public void SimpleDictionary() { @@ -79,9 +30,8 @@ public void SimpleDictionary() 5, 161, 101 }; - MsgPackSerializer.Serialize(test).ShouldBe(bytes); - - new MsgPackToken(test.ToDictionary(e => (MsgPackToken)e.Key, e => (MsgPackToken)e.Value)).RawBytes.ShouldBe(bytes); + using (var blob = MsgPackSerializer.Serialize(test, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(bytes); } } } diff --git a/tests/msgpack.light.tests/Writer/Null.cs b/tests/msgpack.light.tests/Writer/Null.cs index 898d70d..5129536 100644 --- a/tests/msgpack.light.tests/Writer/Null.cs +++ b/tests/msgpack.light.tests/Writer/Null.cs @@ -11,27 +11,29 @@ public class Null [Fact] public void WriteNullArray() { - MsgPackSerializer.Serialize((int[]) null).ShouldBe(new[] {(byte) DataTypes.Null}); + using (var blob = MsgPackSerializer.Serialize((int[]) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void WriteNullByteArray() { - MsgPackSerializer.Serialize((byte[]) null).ShouldBe(new[] {(byte) DataTypes.Null}); - ((MsgPackToken)(byte[])null).RawBytes.ShouldBe(new[] { (byte)DataTypes.Null }); + using (var blob = MsgPackSerializer.Serialize((byte[]) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void WriteNullMap() { - MsgPackSerializer.Serialize((IDictionary) null).ShouldBe(new[] {(byte) DataTypes.Null}); + using (var blob = MsgPackSerializer.Serialize((IDictionary) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void WriteNullString() { - MsgPackSerializer.Serialize((string) null).ShouldBe(new[] {(byte) DataTypes.Null}); - ((MsgPackToken)(string)null).RawBytes.ShouldBe(new[] { (byte)DataTypes.Null }); + using (var blob = MsgPackSerializer.Serialize((string) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } } } diff --git a/tests/msgpack.light.tests/Writer/Nullable.cs b/tests/msgpack.light.tests/Writer/Nullable.cs index 599c6f2..c8c8d3a 100644 --- a/tests/msgpack.light.tests/Writer/Nullable.cs +++ b/tests/msgpack.light.tests/Writer/Nullable.cs @@ -11,91 +11,91 @@ public class Nullable [Fact] public void WriteNullAsNullableBool() { - MsgPackSerializer.Serialize(default(bool?)).ShouldBe(new[] { (byte)DataTypes.Null }); - ((MsgPackToken)default(bool?)).RawBytes.ShouldBe(new[] { (byte)DataTypes.Null }); + using (var blob = MsgPackSerializer.Serialize((bool?) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void WriteNullAsNullableFloat() { - MsgPackSerializer.Serialize(default(float?)).ShouldBe(new[] { (byte)DataTypes.Null }); - ((MsgPackToken)default(float?)).RawBytes.ShouldBe(new[] { (byte)DataTypes.Null }); + using (var blob = MsgPackSerializer.Serialize((float?) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void WriteNullAsNullableDouble() { - MsgPackSerializer.Serialize(default(double?)).ShouldBe(new[] { (byte)DataTypes.Null }); - ((MsgPackToken)default(double?)).RawBytes.ShouldBe(new[] { (byte)DataTypes.Null }); + using (var blob = MsgPackSerializer.Serialize((double?) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void WriteNullAsNullableByte() { - MsgPackSerializer.Serialize(default(byte?)).ShouldBe(new[] { (byte)DataTypes.Null }); - ((MsgPackToken)default(byte?)).RawBytes.ShouldBe(new[] { (byte)DataTypes.Null }); + using (var blob = MsgPackSerializer.Serialize((byte?) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void WriteNullAsNullableSbyte() { - MsgPackSerializer.Serialize(default(sbyte?)).ShouldBe(new[] { (byte)DataTypes.Null }); - ((MsgPackToken)default(sbyte?)).RawBytes.ShouldBe(new[] { (byte)DataTypes.Null }); + using (var blob = MsgPackSerializer.Serialize((sbyte?) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void WriteNullAsNullableShort() { - MsgPackSerializer.Serialize(default(short?)).ShouldBe(new[] { (byte)DataTypes.Null }); - ((MsgPackToken)default(short?)).RawBytes.ShouldBe(new[] { (byte)DataTypes.Null }); + using (var blob = MsgPackSerializer.Serialize((short?) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void WriteNullAsNullableUshort() { - MsgPackSerializer.Serialize(default(ushort?)).ShouldBe(new[] { (byte)DataTypes.Null }); - ((MsgPackToken)default(ushort?)).RawBytes.ShouldBe(new[] { (byte)DataTypes.Null }); + using (var blob = MsgPackSerializer.Serialize((ushort?) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void WriteNullAsNullableInt() { - MsgPackSerializer.Serialize(default(int?)).ShouldBe(new[] { (byte)DataTypes.Null }); - ((MsgPackToken)default(int?)).RawBytes.ShouldBe(new[] { (byte)DataTypes.Null }); + using (var blob = MsgPackSerializer.Serialize((int?) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void WriteNullAsNullableUint() { - MsgPackSerializer.Serialize(default(uint?)).ShouldBe(new[] { (byte)DataTypes.Null }); - ((MsgPackToken)default(uint?)).RawBytes.ShouldBe(new[] { (byte)DataTypes.Null }); + using (var blob = MsgPackSerializer.Serialize((uint?) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void WriteNullAsNullableLong() { - MsgPackSerializer.Serialize(default(long?)).ShouldBe(new[] { (byte)DataTypes.Null }); - ((MsgPackToken)default(long?)).RawBytes.ShouldBe(new[] { (byte)DataTypes.Null }); + using (var blob = MsgPackSerializer.Serialize((long?) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void WriteNullAsNullableUlong() { - MsgPackSerializer.Serialize(default(ulong?)).ShouldBe(new[] { (byte)DataTypes.Null }); - ((MsgPackToken)default(ulong?)).RawBytes.ShouldBe(new[] { (byte)DataTypes.Null }); + using (var blob = MsgPackSerializer.Serialize((ulong?) null, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.Nil }); } [Fact] public void False() { - MsgPackSerializer.Serialize((bool?)false).ShouldBe(new[] { (byte)DataTypes.False }); - ((MsgPackToken)(bool?)false).RawBytes.ShouldBe(new[] { (byte)DataTypes.False }); + using (var blob = MsgPackSerializer.Serialize((bool?) false, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.False }); } [Fact] public void True() { - MsgPackSerializer.Serialize((bool?)true).ShouldBe(new[] { (byte)DataTypes.True }); - ((MsgPackToken)(bool?)true).RawBytes.ShouldBe(new[] { (byte)DataTypes.True }); + using (var blob = MsgPackSerializer.Serialize((bool?) true, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(new[] { DataCodes.True }); } [Theory] @@ -115,8 +115,8 @@ public void True() [InlineData(double.NegativeInfinity, new byte[] { 203, 255, 240, 0, 0, 0, 0, 0, 0 })] public void TestDouble(double value, byte[] bytes) { - MsgPackSerializer.Serialize((double?)value).ShouldBe(bytes); - ((MsgPackToken)value).RawBytes.ShouldBe(bytes); + using (var blob = MsgPackSerializer.Serialize((double?) value, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(bytes); } [Theory] @@ -136,8 +136,8 @@ public void TestDouble(double value, byte[] bytes) [InlineData(float.NegativeInfinity, new byte[] { 202, 255, 128, 0, 0 })] public void TestFloat(float value, byte[] bytes) { - MsgPackSerializer.Serialize((float?)value).ShouldBe(bytes); - ((MsgPackToken)value).RawBytes.ShouldBe(bytes); + using (var blob = MsgPackSerializer.Serialize((float?) value, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(bytes); } [Theory] @@ -154,8 +154,8 @@ public void TestFloat(float value, byte[] bytes) [InlineData(long.MinValue, new byte[] { 211, 128, 0, 0, 0, 0, 0, 0, 0 })] public void TestSignedLong(long number, byte[] data) { - MsgPackSerializer.Serialize((long?)number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize((long?) number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] @@ -171,8 +171,8 @@ public void TestSignedLong(long number, byte[] data) [InlineData(50505, new byte[] { 205, 197, 73 })] public void TestSignedInt(int number, byte[] data) { - MsgPackSerializer.Serialize((int?)number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize((int?) number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] @@ -185,8 +185,8 @@ public void TestSignedInt(int number, byte[] data) [InlineData(short.MaxValue, new byte[] { 205, 127, 0xff })] public void TestSignedShort(short number, byte[] data) { - MsgPackSerializer.Serialize((short?)number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize((short?) number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] @@ -197,8 +197,8 @@ public void TestSignedShort(short number, byte[] data) [InlineData(sbyte.MaxValue, new byte[] { 127 })] public void TestSignedByte(sbyte number, byte[] data) { - MsgPackSerializer.Serialize((sbyte?)number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize((sbyte?) number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] @@ -208,10 +208,10 @@ public void TestSignedByte(sbyte number, byte[] data) [InlineData(ushort.MaxValue, new byte[] { 0xcd, 0xff, 0xff })] [InlineData(uint.MaxValue, new byte[] { 0xce, 0xff, 0xff, 0xff, 0xff })] [InlineData(ulong.MaxValue, new byte[] { 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff })] - public void TetsUnsignedLong(ulong number, byte[] data) + public void TestUnsignedLong(ulong number, byte[] data) { - MsgPackSerializer.Serialize((ulong?)number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize((ulong?) number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] @@ -220,10 +220,10 @@ public void TetsUnsignedLong(ulong number, byte[] data) [InlineData(byte.MaxValue, new byte[] { 0xcc, 0xff })] [InlineData(ushort.MaxValue, new byte[] { 0xcd, 0xff, 0xff })] [InlineData(uint.MaxValue, new byte[] { 0xce, 0xff, 0xff, 0xff, 0xff })] - public void TetsUnsignedInt(uint number, byte[] data) + public void TestUnsignedInt(uint number, byte[] data) { - MsgPackSerializer.Serialize((uint?)number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize((uint?) number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] @@ -231,20 +231,20 @@ public void TetsUnsignedInt(uint number, byte[] data) [InlineData(1, new byte[] { 1 })] [InlineData(byte.MaxValue, new byte[] { 0xcc, 0xff })] [InlineData(ushort.MaxValue, new byte[] { 0xcd, 0xff, 0xff })] - public void TetsUnsignedShort(ushort number, byte[] data) + public void TestUnsignedShort(ushort number, byte[] data) { - MsgPackSerializer.Serialize((ushort?)number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize((ushort?) number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } [Theory] [InlineData(0, new byte[] { 0x00 })] [InlineData(1, new byte[] { 1 })] [InlineData(byte.MaxValue, new byte[] { 0xcc, 0xff })] - public void TetsUnsignedByte(byte number, byte[] data) + public void TestUnsignedByte(byte number, byte[] data) { - MsgPackSerializer.Serialize((byte?)number).ShouldBe(data); - ((MsgPackToken)number).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize((byte?) number, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } } diff --git a/tests/msgpack.light.tests/Writer/String.cs b/tests/msgpack.light.tests/Writer/String.cs index a766a05..3587a45 100644 --- a/tests/msgpack.light.tests/Writer/String.cs +++ b/tests/msgpack.light.tests/Writer/String.cs @@ -33,8 +33,8 @@ public class String [InlineData("Шла Саша по шоссе и сосала сушку", new byte[] { 217, 58, 208, 168, 208, 187, 208, 176, 32, 208, 161, 208, 176, 209, 136, 208, 176, 32, 208, 191, 208, 190, 32, 209, 136, 208, 190, 209, 129, 209, 129, 208, 181, 32, 208, 184, 32, 209, 129, 208, 190, 209, 129, 208, 176, 208, 187, 208, 176, 32, 209, 129, 209, 131, 209, 136, 208, 186, 209, 131 })] public void TestStringPack(string s, byte[] data) { - MsgPackSerializer.Serialize(s).ShouldBe(data); - ((MsgPackToken)s).RawBytes.ShouldBe(data); + using (var blob = MsgPackSerializer.Serialize(s, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(data); } } } diff --git a/tests/msgpack.light.tests/Writer/Timespan.cs b/tests/msgpack.light.tests/Writer/Timespan.cs index 51b4bad..0c2dd5d 100644 --- a/tests/msgpack.light.tests/Writer/Timespan.cs +++ b/tests/msgpack.light.tests/Writer/Timespan.cs @@ -12,19 +12,19 @@ public class Timespan [Fact] public void TestTimeSpan() { - var tests = new List>() + var tests = new List<(TimeSpan span, byte[] blob)> { - new KeyValuePair(TimeSpan.MinValue, new byte[] {211, 128, 0, 0, 0, 0, 0, 0, 0,}), - new KeyValuePair(TimeSpan.MaxValue, new byte[] {207, 127, 255, 255, 255, 255, 255, 255, 255}), - new KeyValuePair(new TimeSpan(1, 2, 3, 4, 5), new byte[] {207, 0, 0, 0, 218, 91, 159, 127, 80}), - new KeyValuePair(TimeSpan.FromTicks(-100), new byte[] {208, 156}), + ValueTuple.Create(TimeSpan.MinValue, new byte[] {211, 128, 0, 0, 0, 0, 0, 0, 0}), + ValueTuple.Create(TimeSpan.MaxValue, new byte[] {207, 127, 255, 255, 255, 255, 255, 255, 255}), + ValueTuple.Create(new TimeSpan(1, 2, 3, 4, 5), new byte[] {207, 0, 0, 0, 218, 91, 159, 127, 80}), + ValueTuple.Create(TimeSpan.FromTicks(-100), new byte[] {208, 156}) }; foreach (var test in tests) { - MsgPackSerializer.Serialize(test.Key).ShouldBe(test.Value); - ((MsgPackToken)test.Key).RawBytes.ShouldBe(test.Value); + using (var blob = MsgPackSerializer.Serialize(test.span, out var wroteSize)) + blob.Memory.Slice(0, wroteSize).ShouldBe(test.blob); } } } -} \ No newline at end of file +} diff --git a/tests/msgpack.light.tests/msgpack.light.tests.csproj b/tests/msgpack.light.tests/msgpack.light.tests.csproj index 813d966..2a39a80 100644 --- a/tests/msgpack.light.tests/msgpack.light.tests.csproj +++ b/tests/msgpack.light.tests/msgpack.light.tests.csproj @@ -1,8 +1,6 @@  Tests for MsgPack.Light library - Exe - netcoreapp1.0;netcoreapp1.1;netcoreapp2.0 true msgpack.light.tests ProGaudi.MsgPack.Light.Tests @@ -18,12 +16,22 @@ false + + net46;net461;net462;net47;net471;netcoreapp1.0;netcoreapp1.1;netcoreapp2.0;netcoreapp2.1;netcoreapp2.2 + + + netcoreapp1.0;netcoreapp1.1;netcoreapp2.0;netcoreapp2.1;netcoreapp2.2 + - - - - - + + + + + + all + runtime; build; native; contentfiles; analyzers + + - \ No newline at end of file +