diff --git a/.editorconfig b/.editorconfig
index 73050d175..d3df05e77 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -20,7 +20,7 @@ indent_style = tab
tab_width = 4
# 2 space indentation
-[*.{xml,csproj}]
+[*.{xml,csproj,props,targets}]
indent_style = space
indent_size = 2
@@ -42,18 +42,17 @@ csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
dotnet_sort_system_directives_first = true
csharp_space_between_method_declaration_name_and_open_parenthesis = false
-csharp_space_between_method_declaration_parameter_list_parentheses = true
+csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
-csharp_space_between_method_call_parameter_list_parentheses = true
+csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
-csharp_space_between_parentheses = expressions,type_casts,control_flow_statements
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_cast = false
csharp_space_around_declaration_statements = true
csharp_space_before_open_square_brackets = false
csharp_space_between_empty_square_brackets = false
-csharp_space_between_square_brackets = true
+csharp_space_between_square_brackets = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
@@ -62,7 +61,7 @@ csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_semicolon_in_for_statement = false
-csharp_space_around_binary_operators = true
+csharp_space_around_binary_operators = false
csharp_indent_braces = false
csharp_indent_block_contents = true
csharp_indent_switch_labels = true
@@ -75,17 +74,122 @@ csharp_preserve_single_line_statements = true
csharp_new_line_before_open_brace = all
csharp_new_line_between_query_expression_clauses = true
-# Disabled for Unity compatibility until 2017.1 RTM
[*.cs]
-dotnet_style_null_propagation = false:warning
-csharp_style_expression_bodied_methods = false:warning
-csharp_style_expression_bodied_constructors = false:warning
-csharp_style_expression_bodied_operators = false:warning
-csharp_style_expression_bodied_properties = false:warning
-csharp_style_expression_bodied_indexers = false:warning
-csharp_style_expression_bodied_accessors = false:warning
-csharp_style_pattern_matching_over_is_with_cast_check = false:warning
-csharp_style_pattern_matching_over_as_with_null_check = false:warning
-csharp_style_inlined_variable_declaration = false:warning
-csharp_style_throw_expression = false:warning
-csharp_style_conditional_delegate_call = false:warning
+dotnet_style_null_propagation = true:suggestion
+csharp_style_expression_bodied_methods = true:suggestion
+csharp_style_expression_bodied_constructors = true:suggestion
+csharp_style_expression_bodied_operators = true:suggestion
+csharp_style_expression_bodied_properties = true:suggestion
+csharp_style_expression_bodied_indexers = true:suggestion
+csharp_style_expression_bodied_accessors = true:suggestion
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+
+# From https://github.com/dotnet/roslyn/blob/master/.editorconfig
+
+# Non-private static fields are PascalCase
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style
+
+dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
+dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
+dotnet_naming_symbols.non_private_static_fields.required_modifiers = static
+
+dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
+
+# Non-private readonly fields are PascalCase
+dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields
+dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style
+
+dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field
+dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
+dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly
+
+dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case
+
+# Constants are PascalCase
+dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants
+dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style
+
+dotnet_naming_symbols.constants.applicable_kinds = field, local
+dotnet_naming_symbols.constants.required_modifiers = const
+
+dotnet_naming_style.constant_style.capitalization = pascal_case
+
+# Static fields are camelCase and start with s_
+dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields
+dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style
+
+dotnet_naming_symbols.static_fields.applicable_kinds = field
+dotnet_naming_symbols.static_fields.required_modifiers = static
+
+dotnet_naming_style.static_field_style.capitalization = camel_case
+dotnet_naming_style.static_field_style.required_prefix = s_
+
+# Instance fields are camelCase and start with _
+dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
+dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
+
+dotnet_naming_symbols.instance_fields.applicable_kinds = field
+
+dotnet_naming_style.instance_field_style.capitalization = camel_case
+dotnet_naming_style.instance_field_style.required_prefix = _
+
+# Locals and parameters are camelCase
+dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
+dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style
+
+dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local
+
+dotnet_naming_style.camel_case_style.capitalization = camel_case
+
+# Local functions are PascalCase
+dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
+dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style
+
+dotnet_naming_symbols.local_functions.applicable_kinds = local_function
+
+dotnet_naming_style.local_function_style.capitalization = pascal_case
+
+# By default, name items with PascalCase
+dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
+dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style
+
+dotnet_naming_symbols.all_members.applicable_kinds = *
+
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+
+# Blocks are allowed
+csharp_prefer_braces = true:silent
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = true
+
+# IDE0005: Remove unnecessary usings/imports
+dotnet_diagnostic.IDE0005.severity = warning
+
+# IDE0036: Order modifiers
+dotnet_diagnostic.IDE0036.severity = warning
+
+# IDE0040: Add accessibility modifiers
+dotnet_diagnostic.IDE0040.severity = warning
+
+# IDE0044: Make field readonly
+dotnet_diagnostic.IDE0044.severity = warning
+
+# CONSIDER: Are IDE0051 and IDE0052 too noisy to be warnings for IDE editing scenarios? Should they be made build-only warnings?
+# IDE0051: Remove unused private member
+dotnet_diagnostic.IDE0051.severity = warning
+
+# IDE0052: Remove unread private member
+dotnet_diagnostic.IDE0052.severity = warning
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
index 06e5a5521..f56a38d8b 100644
Binary files a/Directory.Build.props and b/Directory.Build.props differ
diff --git a/Directory.Build.targets b/Directory.Build.targets
new file mode 100644
index 000000000..4b45b5873
--- /dev/null
+++ b/Directory.Build.targets
@@ -0,0 +1,35 @@
+
+
+
+ $(DefineConstants);UNITY;AOT
+
+
+ $(DefineConstants);LIBRARY
+
+
+ $(DefineConstants);FEATURE_BINARY_SERIALIZATION
+
+
+ $(DefineConstants);FEATURE_READ_ONLY_COLLECTION;FEATURE_ISET;FEATURE_TAP;FEATURE_EXCEPTION_DISPATCH_INFO;FEATURE_TUPLE
+
+
+
+ $(DefineConstants);FEATURE_CER;FEATURE_CODE_ACCESS_SECURITY
+
+
+ $(DefineConstants);FEATURE_ASYNC_DISPOSABLE;FEATURE_ADVANCED_BIT_CONVERTER;FEATURE_DO_NOT_WRAP_EXCEPTIONS
+
+
+ $(DefineConstants);FEATURE_ASYNC_DISPOSABLE;FEATURE_ADVANCED_BIT_CONVERTER;FEATURE_DO_NOT_WRAP_EXCEPTIONS
+
+
+ $(DefineConstants);FEATURE_ASYNC_DISPOSABLE;FEATURE_ADVANCED_BIT_CONVERTER;FEATURE_DO_NOT_WRAP_EXCEPTIONS;FEATURE_ENCODING_EXTENSION;FEATURE_UTF8STRING;FEATURE_ADVANCED_OBSOLETE
+
+
+
+
+ <_Parameter1>TargetFramework
+ <_Parameter2>$(TargetFramework)
+
+
+
diff --git a/LICENSE.DotNetFoundation.txt b/LICENSE.DotNetFoundation.txt
new file mode 100644
index 000000000..a616ed188
--- /dev/null
+++ b/LICENSE.DotNetFoundation.txt
@@ -0,0 +1,23 @@
+The MIT License (MIT)
+
+Copyright (c) .NET Foundation and Contributors
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/doc/dev/JsonCollectionStatemachine.drawio.svg.drawio b/doc/dev/JsonCollectionStatemachine.drawio.svg.drawio
new file mode 100644
index 000000000..484b7d2a2
--- /dev/null
+++ b/doc/dev/JsonCollectionStatemachine.drawio.svg.drawio
@@ -0,0 +1,414 @@
+
+
+
\ No newline at end of file
diff --git a/doc/v2.md b/doc/v2.md
new file mode 100644
index 000000000..655032d4e
--- /dev/null
+++ b/doc/v2.md
@@ -0,0 +1,58 @@
+MessagePack for CLI v2
+===
+
+Goals
+---
+
+* Supports .NET Framework 3.5 and 4.8, .NET Core 2.1 and 3.1, Xamarin Android and iOS, UWP, Unity.
+ * Supproted TFM:
+ * [ ] `net35`
+ * [ ] `netstandard1.4` (for .NET 4.8)
+ * [ ] `netstandard2.0` (for .NET Core 2.1)
+ * [ ] `netstandard2.1` (for .NET Core 3.1 and after)
+ * [ ] `MonoAndroid10` (for Xamarin Android AOT)
+ * [ ] `Xamarin.iOS10` (for Xamarin iOS AOT)
+ * [ ] `uap` (for .NET Native)
+ * [ ] (N/A) (for Unity IL2CPP)
+* Supports stream based serialization/deserialization for large blobs like v1.
+* Supports various format as possible including JSON, CBOF, protbuf, etc.
+* Keep high level API compatiblity with v1.
+* Improve performance.
+
+Non-Goals
+---
+
+* 100% API compatibility with v1.
+ * Custom `Packer` and custom `Unpacker` will not be supported.
+* ABI compatibility with v1.
+* Keep performance for compatibility layer espetially custom serializer, IPackable/IUnpackable, and async operation.
+* Legacy platform support including Silverlight, .NET Standard 1.x, etc.
+* High performance in old platform such as .NET Framework and .NET Core 2.1.
+* 100% Unity stability.
+
+Status
+---
+
+* [x] Encoder/Decoder layer utlizing `ReadOnlySequence` and `IBufferWriter`
+* [x] Simple JSON serializer with some tweak points for design verification.
+* [ ] Debugging features
+* [ ] Reflection based object serializer
+* [ ] Code generator w/ CodDOM or Roslyn
+* [ ] ILGenerator based object serializer
+* [ ] `SerializationContext`
+* [ ] Known serializers
+* [ ] Timestamp
+* [ ] Multi demensional array
+* [ ] Polymorphism
+* [ ] v1 compatiblity layer
+ * [ ] `MessagePackSerializer`
+ * [ ] `MessagePackObject`
+ * [ ] `Packer` and `Unpacker`
+ * [ ] `IPackable` and `IUnpackable`
+ * other stuff...
+* [ ] msgpack for C# compatiblity such as LZ4 support
+* [ ] More formats
+ * [ ] Completes JSON serializer
+ * [ ] CBOF serializer
+ * [ ] Protobuf serializer
+ * other formats...
diff --git a/src/Common/CommonAssemblyInfo.cs b/src/Common/CommonAssemblyInfo.cs
new file mode 100644
index 000000000..b28a25074
--- /dev/null
+++ b/src/Common/CommonAssemblyInfo.cs
@@ -0,0 +1,13 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+// Universal informations for entire MsgPack for CLI.
+
+using System;
+using System.Runtime.InteropServices;
+
+[assembly: CLSCompliant(true)]
+[assembly: ComVisible(false)]
+
+
diff --git a/src/CommonAssemblyInfo.cs b/src/CommonAssemblyInfo.cs
deleted file mode 100644
index 51ac2d17d..000000000
--- a/src/CommonAssemblyInfo.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-#region -- License Terms --
-//
-// MessagePack for CLI
-//
-// Copyright (C) 2010-2016 FUJIWARA, Yusuke
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-#endregion -- License Terms --
-
-// Universal informations for entire MsgPack for CLI.
-
-using System;
-using System.Reflection;
-using System.Resources;
-using System.Runtime.InteropServices;
-
-[assembly: AssemblyCopyright( "Copyright © FUJIWARA, Yusuke 2010-2017" )]
-[assembly: AssemblyProduct( "MessagePack" )]
-[assembly: CLSCompliant( true )]
-[assembly: ComVisible( false )]
-[assembly: NeutralResourcesLanguage( "en-US" )]
-
-// This version represents API compatibility.
-// Major : Represents Major update like re-architecting, remove obsoleted APIs etc.
-// Minor : Represents Minor update like adding new feature, obsoleting APIs, fix specification issues, etc.
-// Build/Revision : Always 0 since CLI implementations does not care these number, so these changes cause some binding failures.
-[assembly: AssemblyVersion( "1.0.0.0" )]
-
-// This version represents libarary 'version' for human beings.
-// Major : Same as AssemblyVersion.
-// Minor : Same as AssemblyVersion.
-// Build : Bug fixes and improvements, which does not break API contract, but may break some code depends on internal implementation behaviors.
-// For example, some programs use reflection to retrieve private fields, analyse human readable exception messages or stack trace, or so.
-// Revision : Reserced. It might be used to indicate target platform or patch.
-[assembly: AssemblyInformationalVersion( "1.0.0-dev" )]
-
diff --git a/src/MsgPack.Abstraction/Codecs/CodecFeatures.cs b/src/MsgPack.Abstraction/Codecs/CodecFeatures.cs
new file mode 100644
index 000000000..4a0e4f234
--- /dev/null
+++ b/src/MsgPack.Abstraction/Codecs/CodecFeatures.cs
@@ -0,0 +1,148 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System.Text;
+using MsgPack.Serialization;
+
+namespace MsgPack.Codecs
+{
+ ///
+ /// Represents features of the specific codec.
+ ///
+ public sealed class CodecFeatures
+ {
+ ///
+ /// Gets a unique name of the underlying codec.
+ ///
+ ///
+ /// A unique name of the underlying codec which is non-blank string.
+ ///
+ public string Name { get; }
+
+ ///
+ /// Gets a value which indicates the underlying codec supports collection length.
+ ///
+ ///
+ /// true, if the underlyng codec supports collection length; false, otherwise.
+ ///
+ ///
+ /// When this property returns false, following methods should throw .
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool CanCountCollectionItems { get; }
+
+ ///
+ /// Gets a value which indicates the underlying codec supports custom string encoding.
+ ///
+ ///
+ /// true, if the underlyng format supports custom string encoding; false, otherwise.
+ ///
+ ///
+ /// When this property returns false, typed parameters in and methods will be ignored.
+ ///
+ public bool CanSpecifyStringEncoding { get; }
+
+ ///
+ /// Gets a value which indicates the underlying codec supports extension types.
+ ///
+ ///
+ /// true, if the underlyng codec supports extension types; false, otherwise.
+ ///
+ ///
+ /// When this property returns false, following methods should throw .
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// In additon, TExtentionType type parameter should be .
+ ///
+ public bool SupportsExtensionTypes { get; }
+
+ ///
+ /// Gets a value which indicates preferred for the underlying codec.
+ ///
+ ///
+ /// A value which indicates preferred for the underlying codec.
+ ///
+ public SerializationMethod PreferredObjectSerializationMethod { get; }
+
+ ///
+ /// Gets a value which indicates preferred for the underlying codec.
+ ///
+ ///
+ /// A value which indicates preferred for the underlying codec.
+ ///
+ public EnumSerializationMethod PreferredEnumSerializationMethod { get; }
+
+ ///
+ /// Gets a value which indicates preferred for the underlying codec.
+ ///
+ ///
+ /// A value which indicates preferred for the underlying codec.
+ ///
+ public DateTimeConversionMethod PreferredDateTimeConversionMethod { get; }
+
+ ///
+ /// Gets a value which indicates available set as .
+ ///
+ ///
+ /// A value which indicates available set as .
+ ///
+ public AvailableSerializationMethods AvailableSerializationMethods { get; }
+
+ ///
+ /// Gets the default encoding of strings.
+ ///
+ ///
+ /// The default encoding of strings.
+ ///
+ public Encoding DefaultStringEncoding { get; }
+
+ ///
+ /// Gets the precision of fraction portion on ISO 8601 date time string as specified by this codec.
+ ///
+ ///
+ /// The precision of fraction portion on ISO 8601 date time string as specified by this codec.
+ /// null means that the value will be determined by serialization option or serializer implementation.
+ ///
+ ///
+ ///
+ ///
+ public int? Iso8601FractionOfSecondsPrecision { get; }
+
+ ///
+ /// Gets a separator char for fraction portion by this codec.
+ ///
+ ///
+ /// A separator char for fraction portion.
+ /// null means that the value will be determined by serialization option or serializer implementation.
+ ///
+ public char? Iso8601DecimalSeparator { get; }
+
+ internal CodecFeatures(CodecFeaturesBuilder builder)
+ {
+ this.Name = builder.Name;
+ this.CanCountCollectionItems = builder.CanCountCollectionItems;
+ this.CanSpecifyStringEncoding = builder.CanSpecifyStringEncoding;
+ this.SupportsExtensionTypes = builder.SupportsExtensionTypes;
+ this.PreferredObjectSerializationMethod = builder.PreferredObjectSerializationMethod;
+ this.PreferredEnumSerializationMethod = builder.PreferredEnumSerializationMethod;
+ this.PreferredDateTimeConversionMethod = builder.PreferredDateTimeConversionMethod;
+ this.AvailableSerializationMethods = builder.AvailableSerializationMethods;
+ this.DefaultStringEncoding = builder.DefaultStringEncoding;
+ this.Iso8601FractionOfSecondsPrecision = builder.Iso8601FractionOfSecondsPrecision;
+ this.Iso8601DecimalSeparator = builder.Iso8601DecimalSeparator;
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Codecs/CodecFeaturesBuilder.cs b/src/MsgPack.Abstraction/Codecs/CodecFeaturesBuilder.cs
new file mode 100644
index 000000000..53f046b6a
--- /dev/null
+++ b/src/MsgPack.Abstraction/Codecs/CodecFeaturesBuilder.cs
@@ -0,0 +1,290 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System.Text;
+using MsgPack.Internal;
+using MsgPack.Serialization;
+
+namespace MsgPack.Codecs
+{
+ ///
+ /// A builder object for .
+ ///
+ public sealed class CodecFeaturesBuilder
+ {
+ ///
+ /// Gets a unique name of the underlying codec.
+ ///
+ ///
+ /// A unique name of the underlying codec which is non-blank string.
+ ///
+ public string Name { get; }
+
+ ///
+ /// Gets or sets a value which indicates the underlying codec supports collection length.
+ ///
+ ///
+ /// true, if the underlyng codec supports collection length; false, otherwise.
+ ///
+ ///
+ /// When this property returns false, following methods should throw .
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public bool CanCountCollectionItems { get; set; }
+
+ ///
+ /// Gets or sets a value which indicates the underlying codec supports custom string encoding.
+ ///
+ ///
+ /// true, if the underlyng format supports custom string encoding; false, otherwise.
+ ///
+ ///
+ /// When this property returns false, typed parameters in and methods will be ignored.
+ ///
+ public bool CanSpecifyStringEncoding { get; set; }
+
+ ///
+ /// Gets or sets a value which indicates the underlying codec supports extension types.
+ ///
+ ///
+ /// true, if the underlyng codec supports extension types; false, otherwise.
+ ///
+ ///
+ /// When this property returns false, following methods should throw .
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// In additon, TExtentionType type parameter should be .
+ ///
+ public bool SupportsExtensionTypes { get; set; }
+
+ ///
+ /// Gets a value which indicates preferred for the underlying codec.
+ ///
+ ///
+ /// A value which indicates preferred for the underlying codec.
+ ///
+ public SerializationMethod PreferredObjectSerializationMethod { get; private set; }
+
+ private EnumSerializationMethod _preferredEnumSerializationMethod;
+
+ ///
+ /// Gets or sets a value which indicates preferred for the underlying codec.
+ ///
+ ///
+ /// A value which indicates preferred for the underlying codec.
+ ///
+ ///
+ /// Setting value is not a defined value.
+ ///
+ public EnumSerializationMethod PreferredEnumSerializationMethod
+ {
+ get => this._preferredEnumSerializationMethod;
+ set => this._preferredEnumSerializationMethod = Ensure.Defined(value);
+ }
+
+ private DateTimeConversionMethod _preferredDateTimeConversionMethod;
+
+ ///
+ /// Gets or sets a value which indicates preferred for the underlying codec.
+ ///
+ ///
+ /// A value which indicates preferred for the underlying codec.
+ ///
+ ///
+ /// Setting value is not a defined value.
+ ///
+ public DateTimeConversionMethod PreferredDateTimeConversionMethod
+ {
+ get => this._preferredDateTimeConversionMethod;
+ set => this._preferredDateTimeConversionMethod = Ensure.Defined(value);
+ }
+
+ ///
+ /// Gets a value which indicates available set as .
+ ///
+ ///
+ /// A value which indicates available set as .
+ ///
+ public AvailableSerializationMethods AvailableSerializationMethods { get; private set; }
+
+ ///
+ /// Gets the default encoding of strings.
+ ///
+ ///
+ /// The default encoding of strings.
+ ///
+ public Encoding DefaultStringEncoding { get; private set; } = Utf8EncodingNonBomStrict.Instance;
+
+
+ ///
+ /// Gets the precision of fraction portion on ISO 8601 date time string as specified by this codec.
+ ///
+ ///
+ /// The precision of fraction portion on ISO 8601 date time string as specified by this codec.
+ /// null means that the value will be determined by serialization option or serializer implementation.
+ ///
+ ///
+ ///
+ ///
+ public int? Iso8601FractionOfSecondsPrecision { get; private set; }
+
+ ///
+ /// Gets a separator char for fraction portion for the underlying codec.
+ ///
+ ///
+ /// A separator char for fraction portion.
+ /// null means that the value will be determined by serialization option or serializer implementation.
+ ///
+ public char? Iso8601DecimalSeparator { get; private set; }
+
+ ///
+ /// Initializes a new instance of object.
+ ///
+ /// A unique name of the underlying codec. Note that property will be trimmed value.
+ ///
+ /// is null.
+ ///
+ ///
+ /// is empty or contains only white spaces.
+ ///
+ public CodecFeaturesBuilder(string name)
+ {
+ this.Name = Ensure.NotBlankAndTrimmed(name);
+ }
+
+ ///
+ /// Sets preferred and available serialization method for the underlying codec.
+ ///
+ ///
+ /// A value which indicates preferred for the underlying codec.
+ ///
+ ///
+ /// A value which indicates available set as .
+ ///
+ /// This instance.
+ ///
+ /// value is not a defined value.
+ /// contains any undefined flag value.
+ ///
+ public CodecFeaturesBuilder SetObjectSerializationMethod(
+ SerializationMethod preferredMethod,
+ AvailableSerializationMethods availableMethods
+ )
+ {
+ this.PreferredObjectSerializationMethod = Ensure.Defined(preferredMethod);
+ this.AvailableSerializationMethods = Ensure.Defined(availableMethods);
+ return this;
+ }
+
+ ///
+ /// Sets the default encoding of strings.
+ ///
+ /// The default encoding of strings.
+ /// This instance.
+ ///
+ /// is null.
+ ///
+ public CodecFeaturesBuilder SetDefaultStringEncoding(Encoding value)
+ {
+ this.DefaultStringEncoding = Ensure.NotNull(value);
+ return this;
+ }
+
+ ///
+ /// Resets the default encoding of strings.
+ ///
+ /// This instance.
+ public CodecFeaturesBuilder ResetDefaultStringEncoding()
+ {
+ this.DefaultStringEncoding = Utf8EncodingNonBomStrict.Instance;
+ return this;
+ }
+
+ ///
+ /// Sets the precision of ISO 8601 fraction of seconds portion for the underlying codec.
+ ///
+ /// The precision.
+ /// This instance.
+ ///
+ /// is negative value.
+ ///
+ ///
+ ///
+ ///
+ public CodecFeaturesBuilder SetIso8601FractionOfSecondsPrecision(int value)
+ {
+ this.Iso8601FractionOfSecondsPrecision = Ensure.IsNotLessThan(value, 0);
+ return this;
+ }
+
+ ///
+ /// Resets the precision of ISO 8601 fraction of seconds portion for the underlying codec.
+ ///
+ /// This instance.
+ ///
+ ///
+ ///
+ public CodecFeaturesBuilder ResetIso8601FractionOfSecondsPrecision()
+ {
+ this.Iso8601FractionOfSecondsPrecision = null;
+ return this;
+ }
+
+ ///
+ /// Sets the decimal separator of ISO 8601 for the underlying codec.
+ ///
+ /// The precision.
+ /// This instance.
+ ///
+ /// is not , nor ..
+ ///
+ public CodecFeaturesBuilder SetIso8601DecimalSeparator(char value)
+ {
+ switch(value)
+ {
+ case ',':
+ case '.':
+ {
+ this.Iso8601DecimalSeparator = value;
+ break;
+ }
+ default:
+ {
+ Throw.InvalidIso8601DecimalSeparator(value);
+ break; // Never reaches
+ }
+ }
+
+ return this;
+ }
+
+ ///
+ /// Sets the decimal separator of ISO 8601 for the underlying codec.
+ ///
+ /// This instance.
+ public CodecFeaturesBuilder ResetIso8601DecimalSeparator()
+ {
+ this.Iso8601DecimalSeparator = null;
+ return this;
+ }
+
+ ///
+ /// Builds new instance of immutable object from this builder instance.
+ ///
+ /// New instance of immutable object.
+ public CodecFeatures Build() => new CodecFeatures(this);
+ }
+}
diff --git a/src/MsgPack.Abstraction/Codecs/CodecProvider.cs b/src/MsgPack.Abstraction/Codecs/CodecProvider.cs
new file mode 100644
index 000000000..be9460ee4
--- /dev/null
+++ b/src/MsgPack.Abstraction/Codecs/CodecProvider.cs
@@ -0,0 +1,31 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using MsgPack.Internal;
+
+namespace MsgPack.Codecs
+{
+ ///
+ /// Defines basic features and interfaces of codec provider which provides encoder and decoder.
+ ///
+ public abstract class CodecProvider
+ {
+ ///
+ /// Initializes a new instance of object.
+ ///
+ protected CodecProvider() { }
+
+ ///
+ /// Gets an instance of object.
+ ///
+ /// An instance of object.
+ public abstract FormatEncoder GetEncoder();
+
+ ///
+ /// Gets an instance of object.
+ ///
+ /// An instance of object.
+ public abstract FormatDecoder GetDecoder();
+ }
+}
diff --git a/src/MsgPack.Abstraction/DecodeException.cs b/src/MsgPack.Abstraction/DecodeException.cs
new file mode 100644
index 000000000..87fc53411
--- /dev/null
+++ b/src/MsgPack.Abstraction/DecodeException.cs
@@ -0,0 +1,69 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System;
+#if FEATURE_BINARY_SERIALIZATION
+using System.Runtime.Serialization;
+#endif // FEATURE_BINARY_SERIALIZATION
+
+namespace MsgPack
+{
+#warning TODO: -> ParseException
+ ///
+ /// Defines common exception for decoding error which is caused by invalid input byte sequence.
+ ///
+#if FEATURE_BINARY_SERIALIZATION
+ [Serializable]
+#endif // FEATURE_BINARY_SERIALIZATION
+ public abstract class DecodeException : Exception
+ {
+ ///
+ /// Gets the position of the input sequence.
+ ///
+ ///
+ /// The position of the input sequence.
+ ///
+ ///
+ /// This value MAY NOT represents actual position of source byte sequence espetially in asynchronous deserialization
+ /// because the position stored in this property may reflect the offset in the buffer which is gotten from underlying byte stream rather than the stream position.
+ /// So, the serializer, which is consumer of the decoder, must provide appropriate exception message with calculated position information with this property.
+ ///
+ /// Because of above limitation, this property's value will not included in property nand result.
+ ///
+ public long Position { get; }
+
+ protected DecodeException(long position)
+ : base()
+ {
+ this.Position = position;
+ }
+
+ protected DecodeException(long position, string? message)
+ : base(message)
+ {
+ this.Position = position;
+ }
+
+ protected DecodeException(long position, string? message, Exception? innerException)
+ : base(message, innerException)
+ {
+ this.Position = position;
+ }
+
+#if FEATURE_BINARY_SERIALIZATION
+ protected DecodeException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ this.Position = info.GetInt64("Position");
+ }
+
+ public override void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ base.GetObjectData(info, context);
+ info.AddValue("Position", this.Position);
+ }
+
+#endif // FEATURE_BINARY_SERIALIZATION
+ }
+}
diff --git a/src/MsgPack.Abstraction/Ensure.Enum.cs b/src/MsgPack.Abstraction/Ensure.Enum.cs
new file mode 100644
index 000000000..a25224163
--- /dev/null
+++ b/src/MsgPack.Abstraction/Ensure.Enum.cs
@@ -0,0 +1,77 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+namespace MsgPack
+{
+ internal partial class Ensure
+ {
+ public static T Defined(T value, [CallerArgumentExpression("value")] string? paramName = null)
+ where T : Enum
+ {
+ if (EnumValidationHelper.Instance.IsDefined(value))
+ {
+ throw new ArgumentOutOfRangeException(paramName);
+ }
+
+ return value;
+ }
+
+ private sealed class EnumValidationHelper
+ where T : Enum
+ {
+ public static readonly EnumValidationHelper Instance = new EnumValidationHelper();
+
+ private readonly ulong _undefinedFlags;
+ private readonly ulong[] _constants;
+ private readonly bool _isFlags;
+
+ private EnumValidationHelper()
+ {
+ this._isFlags = typeof(T).IsDefined(typeof(FlagsAttribute));
+ var underlyingType = Enum.GetUnderlyingType(typeof(T));
+ var values =
+ (Enum.GetValues(typeof(T)) as object[])
+ .Select(v => Convert.ToUInt64(v))
+ .ToArray();
+
+ if (!this._isFlags)
+ {
+ Array.Sort(values);
+ this._constants = values;
+ this._undefinedFlags = default!;
+ }
+ else
+ {
+ this._constants = Array.Empty();
+ var flags = default(ulong);
+ foreach(var flag in values)
+ {
+ flags |= flag;
+ }
+
+ this._undefinedFlags = ~flags;
+ }
+ }
+
+ public bool IsDefined(T value)
+ {
+ var bits = Unsafe.As(ref value);
+
+ if (this._isFlags)
+ {
+ return (bits & this._undefinedFlags) == 0;
+ }
+ else
+ {
+ return Array.BinarySearch(this._constants, bits) >= 0;
+ }
+ }
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Ensure.cs b/src/MsgPack.Abstraction/Ensure.cs
new file mode 100644
index 000000000..4a9492987
--- /dev/null
+++ b/src/MsgPack.Abstraction/Ensure.cs
@@ -0,0 +1,124 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+
+namespace MsgPack
+{
+ internal static partial class Ensure
+ {
+ [return: NotNull]
+ public static T NotNull([NotNull]T value, [CallerArgumentExpression("value")]string paramName = null!)
+ {
+ if (value == null)
+ {
+ ThrowArgumentNull(paramName);
+ }
+
+ return value;
+ }
+
+ public static string NotNullNorEmpty([NotNull]string? value, [CallerArgumentExpression("value")] string paramName = null!)
+ {
+ NotNull(value);
+
+ if (value.Length ==0)
+ {
+ ThrowArgumentEmptyString(paramName);
+ }
+
+ return value;
+ }
+
+ public static string NotBlank([NotNull] string? value, [CallerArgumentExpression("value")] string paramName = null!)
+ {
+ NotNull(value);
+
+ if (String.IsNullOrWhiteSpace(value))
+ {
+ ThrowArgumentBlankString(paramName);
+ }
+
+ return value;
+ }
+
+ public static string NotBlankAndTrimmed([NotNull] string? value, [CallerArgumentExpression("value")] string paramName = null!)
+ {
+ NotNull(value);
+
+ if (String.IsNullOrWhiteSpace(value))
+ {
+ ThrowArgumentBlankString(paramName);
+ }
+
+ return value.Trim();
+ }
+
+ public static int IsNotNegative(int value, [CallerArgumentExpression("value")]string paramName = null!)
+ {
+ if (value < 0)
+ {
+ ThrowArgumentOutOfRange(paramName, "Value cannot be negative number.");
+ }
+
+ return value;
+ }
+
+ public static T IsNotLessThan(T value, T minInclusive, [CallerArgumentExpression("value")] string paramName = null!)
+ where T : struct, IComparable
+ {
+ if (value.CompareTo(minInclusive) < 0)
+ {
+ ThrowArgumentOutOfRange(paramName, $"Value cannot be less than {minInclusive}.");
+ }
+
+ return value;
+ }
+
+ public static T IsNotGreaterThan(T value, T maxInclusive, [CallerArgumentExpression("value")] string paramName = null!)
+ where T : struct, IComparable
+ {
+ if (value.CompareTo(maxInclusive) > 0)
+ {
+ ThrowArgumentOutOfRange(paramName, $"Value cannot be greater than {maxInclusive}.");
+ }
+
+ return value;
+ }
+
+ public static T IsBetween(T value, T minInclusive, T maxInclusive, [CallerArgumentExpression("value")] string paramName = null!)
+ where T : struct, IComparable
+ {
+ if (value.CompareTo(minInclusive) < 0)
+ {
+ ThrowArgumentOutOfRange(paramName, $"Value cannot be less than {minInclusive}.");
+ }
+
+ if (value.CompareTo(maxInclusive) > 0)
+ {
+ ThrowArgumentOutOfRange(paramName, $"Value cannot be greater than {maxInclusive}.");
+ }
+
+ return value;
+ }
+
+ [DoesNotReturn]
+ private static void ThrowArgumentNull(string paramName)
+ => throw new ArgumentNullException(paramName);
+
+ [DoesNotReturn]
+ private static void ThrowArgumentOutOfRange(string paramName, string message)
+ => throw new ArgumentOutOfRangeException(paramName, message);
+
+ [DoesNotReturn]
+ private static void ThrowArgumentEmptyString(string paramName)
+ => throw new ArgumentException("Value cannot be empty string.", paramName);
+
+ [DoesNotReturn]
+ private static void ThrowArgumentBlankString(string paramName)
+ => throw new ArgumentException("Value cannot be empty or blank string.", paramName);
+ }
+}
diff --git a/src/MsgPack.Abstraction/ExtensionType.cs b/src/MsgPack.Abstraction/ExtensionType.cs
new file mode 100644
index 000000000..08e7cb6e6
--- /dev/null
+++ b/src/MsgPack.Abstraction/ExtensionType.cs
@@ -0,0 +1,117 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System;
+using System.ComponentModel;
+
+namespace MsgPack
+{
+ ///
+ /// Represents a type of extension.
+ ///
+ public readonly struct ExtensionType : IComparable, IEquatable
+ {
+ ///
+ /// Gets raw tag data.
+ ///
+ /// Raw tag data. Note that the codec might not allow full length.
+ ///
+ /// Valid range and sementics depend on serialization codec.
+ ///
+ public long Tag { get; }
+
+ ///
+ /// Initializes a new instance.
+ /// This constructor should not be called from application directly.
+ ///
+ /// Raw tag data.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public ExtensionType(long tag)
+ {
+ this.Tag = tag;
+ }
+
+ ///
+ public bool Equals(ExtensionType other)
+ => this.Tag == other.Tag;
+
+ ///
+ public int CompareTo(ExtensionType other)
+ => this.Tag.CompareTo(other.Tag);
+
+ ///
+ public override bool Equals(object? obj)
+ => (obj is ExtensionType other) ? this.Equals(other) : false;
+
+ ///
+ public override int GetHashCode()
+ => this.Tag.GetHashCode();
+
+ ///
+ /// Determines whether two specified instances of are equal.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ ///
+ /// true if and represent the same type; otherwise, false.
+ ///
+ public static bool operator ==(ExtensionType left, ExtensionType right)
+ => left.Tag == right.Tag;
+
+ ///
+ /// Determines whether two specified instances of are not equal.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ ///
+ /// true if and represent the different type; otherwise, false.
+ ///
+ public static bool operator !=(ExtensionType left, ExtensionType right)
+ => left.Tag != right.Tag;
+
+ ///
+ /// Determines whether one specified object is less than a second specified object.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ ///
+ /// true if is less than in their tag; otherwise, false.
+ ///
+ public static bool operator <(ExtensionType left, ExtensionType right)
+ => left.Tag < right.Tag;
+
+ ///
+ /// Determines whether one specified object is greater than a second specified object.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ ///
+ /// true if is greater than in their tag; otherwise, false.
+ ///
+ public static bool operator >(ExtensionType left, ExtensionType right)
+ => left.Tag > right.Tag;
+
+ ///
+ /// Determines whether one specified object is less than or equal to a second specified object.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ ///
+ /// true if is less than or equal to in their tag; otherwise, false.
+ ///
+ public static bool operator <=(ExtensionType left, ExtensionType right)
+ => left.Tag <= right.Tag;
+
+ ///
+ /// Determines whether one specified object is greater than or equal to a second specified object.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ ///
+ /// true if is greater than or equal to in their tag; otherwise, false.
+ ///
+ public static bool operator >=(ExtensionType left, ExtensionType right)
+ => left.Tag >= right.Tag;
+ }
+}
diff --git a/src/MsgPack.Abstraction/ExtensionTypeObject.cs b/src/MsgPack.Abstraction/ExtensionTypeObject.cs
new file mode 100644
index 000000000..fc2b60731
--- /dev/null
+++ b/src/MsgPack.Abstraction/ExtensionTypeObject.cs
@@ -0,0 +1,175 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System;
+using System.Buffers;
+using System.Diagnostics;
+using System.Text;
+using MsgPack.Internal;
+
+namespace MsgPack
+{
+ ///
+ /// Represents extension type object data.
+ ///
+ ///
+ /// Valid range and sementics of depend on serialization codec.
+ /// In addition, some codec does not support extension type at all.
+ ///
+ public readonly struct ExtensionTypeObject : IEquatable
+ {
+ ///
+ /// Gets a type of this extension type data.
+ ///
+ /// Codec specific type of this extension type data.
+ public ExtensionType Type { get; }
+
+ ///
+ /// Gets byte sequence which is body of this extension type data.
+ ///
+ /// Byte sequence which is body of this extension type data.
+ public ReadOnlySequence Body { get; }
+
+ ///
+ /// Initializes a new instance.
+ ///
+ /// Codec specific type of this extension type data.
+ /// Byte sequence which is body of this extension type data.
+ public ExtensionTypeObject(ExtensionType type, ReadOnlySequence body)
+ {
+ this.Type = type;
+ this.Body = body;
+ }
+
+ public override string ToString()
+ {
+ const int tokensLength = 3 + 8 + 3 + 20 + 3 + 4 + 4 + 3;
+ var buffer = StringBuilderCache.Acquire((int)Math.Min(0x2000 + tokensLength, tokensLength + this.Body.Length * 2));
+ try
+ {
+ this.ToString(buffer, false);
+ return buffer.ToString();
+ }
+ finally
+ {
+ StringBuilderCache.Release(buffer);
+ }
+ }
+
+ internal void ToString(StringBuilder buffer, bool isJson)
+ {
+ if (isJson)
+ {
+ buffer.Append("{ \"TypeCode\": ").Append(this.Type.Tag).Append(", \"Body\": \"");
+
+ var body = this.Body.Slice(0, 0x2000);
+
+ const int byteSpanLength = 96;
+ const int charSpanLength = byteSpanLength / 3 * 4;
+ Span charSpan = stackalloc char[charSpanLength];
+ Span byteSpan = stackalloc byte[byteSpanLength];
+ while (!body.IsEmpty)
+ {
+ body.CopyTo(byteSpan);
+ var byteLength = (int)Math.Min(body.Length, byteSpanLength);
+ Convert.TryToBase64Chars(byteSpan.Slice(0, byteLength), charSpan, out var charsWritten, Base64FormattingOptions.None);
+ buffer.Append(charSpan.Slice(0, charsWritten));
+ body = body.Slice(byteLength);
+ }
+
+ buffer.Append("\" }");
+ }
+ else
+ {
+ buffer.Append("[").Append(this.Type.Tag).Append("]0x");
+ var body = this.Body.Slice(0, 0x5000000);
+ while (!body.IsEmpty)
+ {
+ Binary.ToHexString(body.FirstSpan, buffer);
+ body = body.Slice(body.First.Length);
+ }
+ }
+ }
+
+
+ ///
+ public override bool Equals(object? obj)
+ => obj is ExtensionTypeObject other ? this.Equals(other) : false;
+
+ ///
+ public bool Equals(ExtensionTypeObject other)
+ {
+ if (this.Type != other.Type)
+ {
+ return false;
+ }
+
+ if (this.Body.Length != other.Body.Length)
+ {
+ return false;
+ }
+
+ if (this.Body.IsSingleSegment && other.Body.IsSingleSegment)
+ {
+ return this.Body.FirstSpan.SequenceEqual(other.Body.FirstSpan);
+ }
+
+ var thisBody = this.Body;
+ var otherBody = other.Body;
+ do
+ {
+ var length = Math.Min(thisBody.FirstSpan.Length, otherBody.FirstSpan.Length);
+ var left = thisBody.FirstSpan.Slice(0, length);
+ var right = otherBody.FirstSpan.Slice(0, length);
+ if (!left.SequenceEqual(right))
+ {
+ return false;
+ }
+
+ thisBody = thisBody.Slice(length);
+ otherBody = otherBody.Slice(length);
+ } while (!thisBody.IsEmpty);
+
+ Debug.Assert(otherBody.IsEmpty);
+
+ return true;
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ var hashCode = this.Type.GetHashCode();
+ var body = this.Body;
+ while(!body.IsEmpty)
+ {
+ hashCode ^= FarmHash.Hash32WithSeed(body.FirstSpan, FarmHash.DefaultSeed);
+ body = body.Slice(body.FirstSpan.Length);
+ }
+
+ return hashCode;
+ }
+
+ ///
+ /// Determines whether two specified instances of are equal.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ ///
+ /// true if and represent the same type; otherwise, false.
+ ///
+ public static bool operator ==(ExtensionTypeObject left, ExtensionTypeObject right)
+ => left.Equals(right);
+
+ ///
+ /// Determines whether two specified instances of are not equal.
+ ///
+ /// The first object to compare.
+ /// The second object to compare.
+ ///
+ /// true if and represent the different type; otherwise, false.
+ ///
+ public static bool operator !=(ExtensionTypeObject left, ExtensionTypeObject right)
+ => !left.Equals(right);
+ }
+}
diff --git a/src/MsgPack.Abstraction/InsufficientInputException.cs b/src/MsgPack.Abstraction/InsufficientInputException.cs
new file mode 100644
index 000000000..5850afb43
--- /dev/null
+++ b/src/MsgPack.Abstraction/InsufficientInputException.cs
@@ -0,0 +1,36 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System;
+#if FEATURE_BINARY_SERIALIZATION
+using System.Runtime.Serialization;
+#endif // FEATURE_BINARY_SERIALIZATION
+
+namespace MsgPack
+{
+ ///
+ /// An exception thrown if there are no more inputs when be requested.
+ ///
+#if FEATURE_BINARY_SERIALIZATION
+ [Serializable]
+#endif // FEATURE_BINARY_SERIALIZATION
+ public sealed class InsufficientInputException : DecodeException
+ {
+ public InsufficientInputException(long position)
+ : this(position, "There are no more inputs.") { }
+
+ public InsufficientInputException(long position, string? message)
+ : base(position, message) { }
+
+ public InsufficientInputException(long position, string? message, Exception? innerException)
+ : base(position, message, innerException) { }
+
+#if FEATURE_BINARY_SERIALIZATION
+
+ private InsufficientInputException(SerializationInfo info, StreamingContext context)
+ : base(info, context) { }
+
+#endif // FEATURE_BINARY_SERIALIZATION
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/CollectionContext.cs b/src/MsgPack.Abstraction/Internal/CollectionContext.cs
new file mode 100644
index 000000000..48947396e
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/CollectionContext.cs
@@ -0,0 +1,50 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+namespace MsgPack.Internal
+{
+ public partial struct CollectionContext
+ {
+ public static CollectionContext Default =>
+ new CollectionContext(
+ OptionsDefaults.MaxArrayLength,
+ OptionsDefaults.MaxMapCount,
+ OptionsDefaults.MaxDepth,
+ currentDepth: 0
+ );
+
+ public int MaxArrayLength { get; }
+ public int MaxMapCount { get; }
+ public int MaxDepth { get; }
+ public int CurrentDepth { get; private set; }
+
+ internal CollectionContext(int maxArrayLength, int maxMapCount, int maxDepth, int currentDepth)
+ {
+ this.MaxArrayLength = maxArrayLength;
+ this.MaxMapCount = maxMapCount;
+ this.MaxDepth = Ensure.IsNotLessThan(maxDepth, 1);
+ this.CurrentDepth = currentDepth;
+ }
+
+ public int IncrementDepth(long position)
+ {
+ if (this.CurrentDepth == this.MaxDepth)
+ {
+ Throw.DepthExeeded(position, this.MaxDepth);
+ }
+
+ return this.CurrentDepth++;
+ }
+
+ public int DecrementDepth()
+ {
+ if (this.CurrentDepth == 0)
+ {
+ Throw.DepthUnderflow();
+ }
+
+ return this.CurrentDepth--;
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/CollectionItemIterator.cs b/src/MsgPack.Abstraction/Internal/CollectionItemIterator.cs
new file mode 100644
index 000000000..3e0deb847
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/CollectionItemIterator.cs
@@ -0,0 +1,84 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System.Buffers;
+using System.Runtime.CompilerServices;
+
+namespace MsgPack.Internal
+{
+ public struct CollectionItemIterator
+ {
+ public delegate bool CollectionEndDetection(ref SequenceReader source, ref long nextItemIndex, long itemsCount, out int requestHint);
+
+ private readonly long _itemsCount;
+ private long _nextItemIndex;
+ private readonly CollectionEndDetection _collectionEnds;
+
+ public CollectionItemIterator(
+ CollectionEndDetection moveNext,
+ long itemsCount
+ )
+ {
+ this._collectionEnds = Ensure.NotNull(moveNext);
+ this._itemsCount = itemsCount;
+ this._nextItemIndex = 0;
+ }
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public bool CollectionEnds(ref SequenceReader source)
+ {
+ var result = this._collectionEnds(ref source, ref this._nextItemIndex, this._itemsCount, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForDetectCollectionEnds(source.Consumed, requestHint);
+ }
+
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public bool CollectionEnds(ref SequenceReader source, out int requestHint)
+ => this._collectionEnds(ref source, ref this._nextItemIndex, this._itemsCount, out requestHint);
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public bool CollectionEnds(in ReadOnlySequence source, out int requestHint)
+ {
+ var reader = new SequenceReader(source);
+ return this.CollectionEnds(ref reader, out requestHint);
+ }
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void Drain(ref SequenceReader source)
+ {
+ if (!this.Drain(ref source, out var requestHint))
+ {
+ Throw.InsufficientInputForDrainCollectionItems(source.Consumed, requestHint);
+ }
+ }
+
+#warning TODO: CancellationToken
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public bool Drain(ref SequenceReader source, out int requestHint)
+ {
+ while (!this.CollectionEnds(ref source, out requestHint))
+ {
+ if (requestHint != 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public bool Drain(ref ReadOnlySequence source, out int requestHint)
+ {
+ var reader = new SequenceReader(source);
+ var ends = this.Drain(ref reader, out requestHint);
+ source = source.Slice((int)reader.Consumed);
+ return ends;
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/CollectionType.cs b/src/MsgPack.Abstraction/Internal/CollectionType.cs
new file mode 100644
index 000000000..ad9a9fadd
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/CollectionType.cs
@@ -0,0 +1,74 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+
+namespace MsgPack.Internal
+{
+ ///
+ /// Represents collection type.
+ ///
+ public readonly struct CollectionType : IEquatable
+ {
+ public static readonly CollectionType None = default;
+ public static readonly CollectionType Null = new CollectionType(1);
+ public static readonly CollectionType Array = new CollectionType(2);
+ public static readonly CollectionType Map = new CollectionType(3);
+
+ private readonly int _type;
+
+ public bool IsNull
+ {
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ get => this._type == 1;
+ }
+
+ public bool IsArray
+ {
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ get => this._type == 2;
+ }
+
+ public bool IsMap
+ {
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ get => this._type == 3;
+ }
+
+ public bool IsNone
+ {
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ get => this._type == 0;
+ }
+
+ private CollectionType(int type)
+ {
+ this._type = type;
+ }
+
+ public override bool Equals(object? obj)
+ => obj is CollectionType other ? this.Equals(other) : false;
+
+ public bool Equals(CollectionType other)
+ => this._type == other._type;
+
+ public override int GetHashCode()
+ => this._type;
+
+ public override string ToString()
+ => this._type switch
+ {
+ 1 => "Array",
+ 2 => "Map",
+ _ => String.Empty
+ };
+
+ public static bool operator ==(CollectionType left, CollectionType right)
+ => left.Equals(right);
+
+ public static bool operator !=(CollectionType left, CollectionType right)
+ => !left.Equals(right);
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/DecodeItemResult.cs b/src/MsgPack.Abstraction/Internal/DecodeItemResult.cs
new file mode 100644
index 000000000..67ca604f3
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/DecodeItemResult.cs
@@ -0,0 +1,78 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System;
+using System.Buffers;
+using System.Runtime.CompilerServices;
+
+namespace MsgPack.Internal
+{
+#warning TODO: Decode -> Parse, Encode -> Format
+ ///
+ /// Represents a result of .
+ ///
+ public readonly struct DecodeItemResult
+ {
+ public bool HasValue => this.ElementType != ElementType.None;
+ public ElementType ElementType { get; }
+
+ // If ElementType is string , this value is not decoded.
+ public ReadOnlySequence Value { get; }
+ public CollectionItemIterator CollectionIterator { get; }
+ public long CollectionLength { get; }
+ public ExtensionType ExtensionType { get; }
+ public ReadOnlySequence ExtensionBody => this.Value;
+
+ private DecodeItemResult(
+ ElementType elementType,
+ in ReadOnlySequence value = default,
+ in CollectionItemIterator collectionIterator = default,
+ long collectionLength = default,
+ ExtensionType extensionType = default
+ )
+ {
+ this.ElementType = elementType;
+ this.Value = value;
+ this.CollectionIterator = collectionIterator;
+ this.CollectionLength = collectionLength;
+ this.ExtensionType = extensionType;
+ }
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public static DecodeItemResult CollectionHeader(ElementType elementType, in CollectionItemIterator iterator, long length = -1)
+ => new DecodeItemResult(elementType, collectionIterator: iterator, collectionLength: length);
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public static DecodeItemResult ScalarOrSequence(ElementType elementType, ReadOnlyMemory value)
+ => ScalarOrSequence(elementType, new ReadOnlySequence(value));
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public static DecodeItemResult ScalarOrSequence(ElementType elementType, in ReadOnlySequence value)
+ => new DecodeItemResult(elementType, value: value);
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public static DecodeItemResult Null()
+ => new DecodeItemResult(ElementType.Null);
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public static DecodeItemResult True()
+ => new DecodeItemResult(ElementType.True);
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public static DecodeItemResult False()
+ => new DecodeItemResult(ElementType.False);
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public static DecodeItemResult ExtensionTypeObject(ExtensionType extensionType, in ReadOnlySequence body)
+ => new DecodeItemResult(ElementType.Extension, extensionType: extensionType, value: body);
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public static DecodeItemResult InsufficientInput()
+ => new DecodeItemResult(ElementType.None);
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public static DecodeItemResult EndOfStream()
+ => new DecodeItemResult(ElementType.None);
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/ElementType.cs b/src/MsgPack.Abstraction/Internal/ElementType.cs
new file mode 100644
index 000000000..4c69521a5
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/ElementType.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace MsgPack.Internal
+{
+ public enum ElementType
+ {
+ None = 0,
+ Int32 = 1,
+ Int64 = 2,
+ UInt64 = 3,
+ Single = 4,
+ Double = 5,
+ True = 6,
+ False = 7,
+ Null = 8,
+ Array = 0x11,
+ Map = 0x12,
+ String = 0x31,
+ Binary = 0x32,
+ Extension = 0x41,
+ Whitespace = 0x51,
+ Comment = 0x52,
+ OtherTrivia = 0x5F
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FarmHash.IntelCommon.cs b/src/MsgPack.Abstraction/Internal/FarmHash.IntelCommon.cs
new file mode 100644
index 000000000..705e763d5
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FarmHash.IntelCommon.cs
@@ -0,0 +1,78 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace MsgPack.Internal
+{
+ internal partial class FarmHash
+ {
+ // Common methods for Intel compatible CPU intrinsics and corresponds 64bit methods.
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe ulong Fetch64(byte* p)
+ => *(ulong*)p;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe Vector128 Fetch128(byte* s)
+ => Sse2.LoadVector128(s).AsUInt32(); // _mm_loadu_si128
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static ulong Rotate64(ulong val, int shift)
+ // Avoid shifting by 64: doing so yields an undefined result.
+ => shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector128 Add(Vector128 x, Vector128 y)
+ => Sse2.Add(x, y); // _mm_add_epi32
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector128 Xor(Vector128 x, Vector128 y)
+ => Sse2.Xor(x, y); // _mm_xor_si128
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector128 Or(Vector128 x, Vector128 y)
+ => Sse2.Or(x, y); // _mm_or_si128
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector128 Mul(Vector128 x, Vector128 y)
+ => Sse41.MultiplyLow(x, y); // _mm_mullo_epi32
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector128 Mul5(Vector128 x)
+ => Add(
+ x,
+ Sse2.ShiftLeftLogical(x, 2) // _mm_slli_epi32
+ );
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector128 RotateLeft(Vector128 x, byte c)
+ => Or(
+ Sse2.ShiftLeftLogical(x, c),// _mm_slli_epi32
+ Sse2.ShiftRightLogical(x, (byte)(32 - c)) // _mm_srli_epi32
+ );
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector128 Rol17(Vector128 x)
+ => RotateLeft(x, 17);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector128 Rol19(Vector128 x)
+ => RotateLeft(x, 19);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static Vector128 Shuffle0321(Vector128 x)
+ => Sse2.Shuffle(x, (0 << 6) + (3 << 4) + (2 << 2) + (1 << 0)); // _mm_shuffle_epi32
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Swap(ref ulong left, ref ulong right)
+ {
+ var temp = left;
+ left = right;
+ right = temp;
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FarmHash.MK.cs b/src/MsgPack.Abstraction/Internal/FarmHash.MK.cs
new file mode 100644
index 000000000..43f0a1e96
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FarmHash.MK.cs
@@ -0,0 +1,160 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+// This file is ported from Google's FarmHash (https://github.com/google/farmhash/)
+// Original copyright notice is following:
+
+// Copyright (c) 2014 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// FarmHash, by Geoff Pike
+
+namespace MsgPack.Internal
+{
+ internal partial class FarmHash
+ {
+ internal static class MK
+ {
+ internal static unsafe uint Hash32Len13to24(byte* s, uint len, uint seed = 0)
+ {
+ uint a = Fetch32(s - 4 + (len >> 1));
+ uint b = Fetch32(s + 4);
+ uint c = Fetch32(s + len - 8);
+ uint d = Fetch32(s + (len >> 1));
+ uint e = Fetch32(s);
+ uint f = Fetch32(s + len - 4);
+ uint h = d * c1 + len + seed;
+ a = Rotate32(a, 12) + f;
+ h = Mur(c, h) + a;
+ a = Rotate32(a, 3) + c;
+ h = Mur(e, h) + a;
+ a = Rotate32(a + f, 12) + d;
+ h = Mur(b ^ seed, h) + a;
+ return Fmix(h);
+ }
+
+ internal static unsafe uint Hash32Len0to4(byte* s, uint len, uint seed = 0)
+ {
+ uint b = seed;
+ uint c = 9;
+ for (var i = 0; i < len; i++)
+ {
+ var v = s[i];
+ b = b * c1 + v;
+ c ^= b;
+ }
+ return Fmix(Mur(b, Mur(len, c)));
+ }
+
+ internal static unsafe uint Hash32Len5to12(byte* s, uint len, uint seed = 0)
+ {
+ uint a = len, b = len * 5, c = 9, d = b + seed;
+ a += Fetch32(s);
+ b += Fetch32(s + len - 4);
+ c += Fetch32(s + ((len >> 1) & 4));
+ return Fmix(seed ^ Mur(c, Mur(b, Mur(a, d))));
+ }
+
+ public static unsafe uint Hash32(byte* s, uint len)
+ {
+ if (len <= 24)
+ {
+ return len <= 12 ?
+ (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len)) :
+ Hash32Len13to24(s, len);
+ }
+
+ // len > 24
+ uint h = len, g = c1 * len, f = g;
+ uint a0 = Rotate32(Fetch32(s + len - 4) * c1, 17) * c2;
+ uint a1 = Rotate32(Fetch32(s + len - 8) * c1, 17) * c2;
+ uint a2 = Rotate32(Fetch32(s + len - 16) * c1, 17) * c2;
+ uint a3 = Rotate32(Fetch32(s + len - 12) * c1, 17) * c2;
+ uint a4 = Rotate32(Fetch32(s + len - 20) * c1, 17) * c2;
+ h ^= a0;
+ h = Rotate32(h, 19);
+ h = h * 5 + 0xe6546b64;
+ h ^= a2;
+ h = Rotate32(h, 19);
+ h = h * 5 + 0xe6546b64;
+ g ^= a1;
+ g = Rotate32(g, 19);
+ g = g * 5 + 0xe6546b64;
+ g ^= a3;
+ g = Rotate32(g, 19);
+ g = g * 5 + 0xe6546b64;
+ f += a4;
+ f = Rotate32(f, 19) + 113;
+ uint iters = (len - 1) / 20;
+ do
+ {
+ uint a = Fetch32(s);
+ uint b = Fetch32(s + 4);
+ uint c = Fetch32(s + 8);
+ uint d = Fetch32(s + 12);
+ uint e = Fetch32(s + 16);
+ h += a;
+ g += b;
+ f += c;
+ h = Mur(d, h) + e;
+ g = Mur(c, g) + a;
+ f = Mur(b + e * c1, f) + d;
+ f += g;
+ g += f;
+ s += 20;
+ } while (--iters != 0);
+ g = Rotate32(g, 11) * c1;
+ g = Rotate32(g, 17) * c1;
+ f = Rotate32(f, 11) * c1;
+ f = Rotate32(f, 17) * c1;
+ h = Rotate32(h + g, 19);
+ h = h * 5 + 0xe6546b64;
+ h = Rotate32(h, 17) * c1;
+ h = Rotate32(h + f, 19);
+ h = h * 5 + 0xe6546b64;
+ h = Rotate32(h, 17) * c1;
+ return h;
+ }
+
+ public static unsafe uint Hash32WithSeed(byte* s, uint len, uint seed)
+ {
+ if (len <= 24)
+ {
+ if (len >= 13)
+ {
+ return Hash32Len13to24(s, len, seed * c1);
+ }
+ else if (len >= 5)
+ {
+ return Hash32Len5to12(s, len, seed);
+ }
+ else
+ {
+ return Hash32Len0to4(s, len, seed);
+ }
+ }
+
+ uint h = Hash32Len13to24(s, 24, seed ^ len);
+ return Mur(Hash32(s + 24, len - 24) + seed, h);
+ }
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FarmHash.NA.cs b/src/MsgPack.Abstraction/Internal/FarmHash.NA.cs
new file mode 100644
index 000000000..c9f76b8c5
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FarmHash.NA.cs
@@ -0,0 +1,238 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+// This file is ported from Google's FarmHash (https://github.com/google/farmhash/)
+// Original copyright notice is following:
+
+// Copyright (c) 2014 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// FarmHash, by Geoff Pike
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace MsgPack.Internal
+{
+ internal partial class FarmHash
+ {
+ private static class NA
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static ulong Hash128to64((ulong low, ulong high) x)
+ {
+ // Murmur-inspired hashing.
+ const ulong kMul = 0x9ddfea08eb382d69UL;
+ ulong a = (x.low ^ x.high) * kMul;
+ a ^= (a >> 47);
+ ulong b = (x.high ^ a) * kMul;
+ b ^= (b >> 47);
+ b *= kMul;
+ return b;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe ulong ShiftMix(ulong val)
+ {
+ return val ^ (val >> 47);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe ulong HashLen16(ulong u, ulong v)
+ {
+ return Hash128to64((u, v));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe ulong HashLen16(ulong u, ulong v, ulong mul)
+ {
+ // Murmur-inspired hashing.
+ ulong a = (u ^ v) * mul;
+ a ^= (a >> 47);
+ ulong b = (v ^ a) * mul;
+ b ^= (b >> 47);
+ b *= mul;
+ return b;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe ulong HashLen0to16(byte* s, uint len)
+ {
+ if (len >= 8)
+ {
+ ulong mul = k2 + len * 2;
+ ulong a = Fetch64(s) + k2;
+ ulong b = Fetch64(s + len - 8);
+ ulong c = Rotate64(b, 37) * mul + a;
+ ulong d = (Rotate64(a, 25) + b) * mul;
+ return HashLen16(c, d, mul);
+ }
+ if (len >= 4)
+ {
+ ulong mul = k2 + len * 2;
+ ulong a = Fetch32(s);
+ return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);
+ }
+ if (len > 0)
+ {
+ byte a = s[0];
+ byte b = s[len >> 1];
+ byte c = s[len - 1];
+ uint y = (uint)a + ((uint)b << 8);
+ uint z = len + ((uint)c << 2);
+ return ShiftMix(y * k2 ^ z * k0) * k2;
+ }
+ return k2;
+ }
+
+ // This probably works well for 16-byte strings as well, but it may be overkill
+ // in that case.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe ulong HashLen17to32(byte* s, uint len)
+ {
+ ulong mul = k2 + len * 2;
+ ulong a = Fetch64(s) * k1;
+ ulong b = Fetch64(s + 8);
+ ulong c = Fetch64(s + len - 8) * mul;
+ ulong d = Fetch64(s + len - 16) * k2;
+ return HashLen16(Rotate64(a + b, 43) + Rotate64(c, 30) + d,
+ a + Rotate64(b + k2, 18) + c, mul);
+ }
+
+ // Return a 16-byte hash for 48 bytes. Quick and dirty.
+ // Callers do best to use "random-looking" values for a and b.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe (ulong first, ulong second) WeakHashLen32WithSeeds(
+ ulong w, ulong x, ulong y, ulong z, ulong a, ulong b)
+ {
+ a += w;
+ b = Rotate64(b + a + z, 21);
+ ulong c = a;
+ a += x;
+ a += y;
+ b += Rotate64(a, 44);
+ return (a + z, b + c);
+ }
+
+ // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe (ulong first, ulong second) WeakHashLen32WithSeeds(byte* s, ulong a, ulong b)
+ {
+ return WeakHashLen32WithSeeds(Fetch64(s),
+ Fetch64(s + 8),
+ Fetch64(s + 16),
+ Fetch64(s + 24),
+ a,
+ b);
+ }
+
+ // Return an 8-byte hash for 33 to 64 bytes.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe ulong HashLen33to64(byte* s, uint len)
+ {
+ ulong mul = k2 + len * 2;
+ ulong a = Fetch64(s) * k2;
+ ulong b = Fetch64(s + 8);
+ ulong c = Fetch64(s + len - 8) * mul;
+ ulong d = Fetch64(s + len - 16) * k2;
+ ulong y = Rotate64(a + b, 43) + Rotate64(c, 30) + d;
+ ulong z = HashLen16(y, a + Rotate64(b + k2, 18) + c, mul);
+ ulong e = Fetch64(s + 16) * mul;
+ ulong f = Fetch64(s + 24);
+ ulong g = (y + Fetch64(s + len - 32)) * mul;
+ ulong h = (z + Fetch64(s + len - 24)) * mul;
+ return HashLen16(Rotate64(e + f, 43) + Rotate64(g, 30) + h,
+ e + Rotate64(f + a, 18) + g, mul);
+ }
+
+ public static unsafe ulong Hash64(byte* s, uint len)
+ {
+ const ulong seed = 81;
+ if (len <= 32)
+ {
+ if (len <= 16)
+ {
+ return HashLen0to16(s, len);
+ }
+ else
+ {
+ return HashLen17to32(s, len);
+ }
+ }
+ else if (len <= 64)
+ {
+ return HashLen33to64(s, len);
+ }
+
+ // For strings over 64 bytes we loop. Internal state consists of
+ // 56 bytes: v, w, x, y, and z.
+ ulong x = seed;
+ ulong y = unchecked(seed * k1) + 113;
+ ulong z = ShiftMix(y * k2 + 113) * k2;
+ (ulong first, ulong second) v = (0, 0);
+ (ulong first, ulong second) w = (0, 0);
+ x = x * k2 + Fetch64(s);
+
+ // Set end so that after the loop we have 1 to 64 bytes left to process.
+ byte* end = s + ((len - 1) / 64) * 64;
+ byte* last64 = end + ((len - 1) & 63) - 63;
+ Debug.Assert(s + len - 64 == last64);
+ do
+ {
+ x = Rotate64(x + y + v.first + Fetch64(s + 8), 37) * k1;
+ y = Rotate64(y + v.second + Fetch64(s + 48), 42) * k1;
+ x ^= w.second;
+ y += v.first + Fetch64(s + 40);
+ z = Rotate64(z + w.first, 33) * k1;
+ v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+ w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+ Swap(ref z, ref x);
+ s += 64;
+ } while (s != end);
+ ulong mul = k1 + ((z & 0xff) << 1);
+ // Make s point to the last 64 bytes of input.
+ s = last64;
+ w.first += ((len - 1) & 63);
+ v.first += w.first;
+ w.first += v.first;
+ x = Rotate64(x + y + v.first + Fetch64(s + 8), 37) * mul;
+ y = Rotate64(y + v.second + Fetch64(s + 48), 42) * mul;
+ x ^= w.second * 9;
+ y += v.first * 9 + Fetch64(s + 40);
+ z = Rotate64(z + w.first, 33) * mul;
+ v = WeakHashLen32WithSeeds(s, v.second * mul, x + w.first);
+ w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+ Swap(ref z, ref x);
+ return HashLen16(HashLen16(v.first, w.first, mul) + ShiftMix(y) * k0 + z,
+ HashLen16(v.second, w.second, mul) + x,
+ mul);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ulong Hash64WithSeed(byte* s, uint len, ulong seed)
+ => Hash64WithSeeds(s, len, k2, seed);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ulong Hash64WithSeeds(byte* s, uint len, ulong seed0, ulong seed1)
+ => HashLen16(Hash64(s, len) - seed0, seed1);
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FarmHash.NT.cs b/src/MsgPack.Abstraction/Internal/FarmHash.NT.cs
new file mode 100644
index 000000000..36d671bd5
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FarmHash.NT.cs
@@ -0,0 +1,43 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+// This file is ported from Google's FarmHash (https://github.com/google/farmhash/)
+// Original copyright notice is following:
+
+// Copyright (c) 2014 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// FarmHash, by Geoff Pike
+
+using System.Runtime.CompilerServices;
+
+namespace MsgPack.Internal
+{
+ internal partial class FarmHash
+ {
+ internal static class NT
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe uint Hash32WithSeed(byte* s, uint len, uint seed)
+ => (uint)(TE.Hash64WithSeed(s, len, seed) & 0xFFFFFFFF);
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FarmHash.SA.cs b/src/MsgPack.Abstraction/Internal/FarmHash.SA.cs
new file mode 100644
index 000000000..0bfb2ad24
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FarmHash.SA.cs
@@ -0,0 +1,211 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+// This file is ported from Google's FarmHash (https://github.com/google/farmhash/)
+// Original copyright notice is following:
+
+// Copyright (c) 2014 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// FarmHash, by Geoff Pike
+
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+using __m128i = System.Runtime.Intrinsics.Vector128;
+
+namespace MsgPack.Internal
+{
+ internal partial class FarmHash
+ {
+ internal static class SA
+ {
+ public static unsafe uint Hash32(byte* s, uint len)
+ {
+ const uint seed = 81;
+ if (len <= 24)
+ {
+ return len <= 12 ?
+ (len <= 4 ?
+ MK.Hash32Len0to4(s, len) :
+ MK.Hash32Len5to12(s, len)) :
+ MK.Hash32Len13to24(s, len);
+ }
+
+ if (len < 40)
+ {
+ uint a = len, b = unchecked(seed * c2), c = a + b;
+ a += Fetch32(s + len - 4);
+ b += Fetch32(s + len - 20);
+ c += Fetch32(s + len - 16);
+ uint d = a;
+ a = Rotate32(a, 21);
+ a = Mur(a, Mur(b, Mur(c, d)));
+ a += Fetch32(s + len - 12);
+ b += Fetch32(s + len - 8);
+ d += a;
+ a += d;
+ b = Mur(b, d) * c2;
+ a = Sse42.Crc32(a, b + c); // _mm_crc32_u32
+ return MK.Hash32Len13to24(s, (len + 1) / 2, a) + b;
+ }
+
+ __m128i cc1 = Vector128.Create(c1); // _mm_set1_epi32
+ __m128i cc2 = Vector128.Create(c2); // _mm_set1_epi32
+ __m128i h = Vector128.Create(seed); // _mm_set1_epi32
+ __m128i g = Vector128.Create(unchecked(c1 * seed)); // _mm_set1_epi32
+ __m128i f = g;
+ __m128i k = Vector128.Create(0xe6546b64); // _mm_set1_epi32
+ if (len < 80)
+ {
+ __m128i a = Fetch128(s);
+ __m128i b = Fetch128(s + 16);
+ __m128i c = Fetch128(s + (len - 15) / 2);
+ __m128i d = Fetch128(s + len - 32);
+ __m128i e = Fetch128(s + len - 16);
+ h = Add(h, a);
+ g = Add(g, b);
+ g = Shuffle0321(g);
+ f = Add(f, c);
+ __m128i be = Add(b, Mul(e, cc1));
+ h = Add(h, f);
+ f = Add(f, h);
+ h = Add(Add(k, Mul5(Rol19(Xor(Mul(Rol17(Mul(d, cc1)), cc2), (h))))), e);
+ k = Xor(k, Ssse3.Shuffle(g.AsByte(), f.AsByte()).AsUInt32()); // _mm_shuffle_epi8
+ g = Add(Xor(c, g), a);
+ f = Add(Xor(be, f), d);
+ k = Add(k, be);
+ k = Add(k, Ssse3.Shuffle(f.AsByte(), h.AsByte()).AsUInt32()); // _mm_shuffle_epi8
+ f = Add(f, g);
+ g = Add(g, f);
+ g = Add(
+ Vector128.Create(len), // _mm_set1_epi32
+ Mul(g, cc1)
+ );
+ }
+ else
+ {
+ // len >= 80
+ // The following is loosely modelled after farmhashmk::Hash32.
+ uint iters = (len - 1) / 80;
+ len -= iters * 80;
+
+ while (iters-- != 0)
+ {
+ //
+ __m128i a = Fetch128(s);
+ __m128i b = Fetch128(s + 16);
+ __m128i c = Fetch128(s + 32);
+ __m128i d = Fetch128(s + 48);
+ __m128i e = Fetch128(s + 64);
+ h = Add(h, a);
+ g = Add(g, b);
+ g = Shuffle0321(g);
+ f = Add(f, c);
+ __m128i be = Add(b, Mul(e, cc1));
+ h = Add(h, f);
+ f = Add(f, h);
+ h = Add(Add(k, Mul5(Rol19(Xor(Mul(Rol17(Mul(d, cc1)), cc2), (h))))), e);
+ k = Xor(k, Ssse3.Shuffle(g.AsByte(), f.AsByte()).AsUInt32()); // _mm_shuffle_epi8
+ g = Add(Xor(c, g), a);
+ f = Add(Xor(be, f), d);
+ k = Add(k, be);
+ k = Add(k, Ssse3.Shuffle(f.AsByte(), h.AsByte()).AsUInt32()); // _mm_shuffle_epi8
+ f = Add(f, g);
+ g = Add(g, f);
+ f = Mul(f, cc1);
+ //
+ s += 80;
+ }
+
+ if (len != 0)
+ {
+ h = Add(h, Vector128.Create(len)); // _mm_set1_epi32
+ s = s + len - 80;
+ //
+ __m128i a = Fetch128(s);
+ __m128i b = Fetch128(s + 16);
+ __m128i c = Fetch128(s + 32);
+ __m128i d = Fetch128(s + 48);
+ __m128i e = Fetch128(s + 64);
+ h = Add(h, a);
+ g = Add(g, b);
+ g = Shuffle0321(g);
+ f = Add(f, c);
+ __m128i be = Add(b, Mul(e, cc1));
+ h = Add(h, f);
+ f = Add(f, h);
+ h = Add(Add(k, Mul5(Rol19(Xor(Mul(Rol17(Mul(d, cc1)), cc2), (h))))), e);
+ k = Xor(k, Ssse3.Shuffle(g.AsByte(), f.AsByte()).AsUInt32()); // _mm_shuffle_epi8
+ g = Add(Xor(c, g), a);
+ f = Add(Xor(be, f), d);
+ k = Add(k, be);
+ k = Add(k, Ssse3.Shuffle(f.AsByte(), h.AsByte()).AsUInt32()); // _mm_shuffle_epi8
+ f = Add(f, g);
+ g = Add(g, f);
+ f = Mul(f, cc1);
+ //
+ }
+ }
+
+ g = Shuffle0321(g);
+ k = Xor(k, g);
+ f = Mul(f, cc1);
+ k = Mul(k, cc2);
+ g = Mul(g, cc1);
+ h = Mul(h, cc2);
+ k = Add(k, Ssse3.Shuffle(g.AsByte(), f.AsByte()).AsUInt32()); // _mm_shuffle_epi8
+ h = Add(h, f);
+ f = Add(f, h);
+ g = Add(g, k);
+ k = Add(k, g);
+ k = Xor(k, Ssse3.Shuffle(f.AsByte(), h.AsByte()).AsUInt32()); // _mm_shuffle_epi8
+ var buf = stackalloc __m128i[4];
+ buf[0] = f;
+ buf[1] = g;
+ buf[2] = k;
+ buf[3] = h;
+ s = (byte*)(buf);
+ uint x = Fetch32(s);
+ uint y = Fetch32(s + 4);
+ uint z = Fetch32(s + 8);
+ x = Sse42.Crc32(x, Fetch32(s + 12)); // _mm_crc32_u32
+ y = Sse42.Crc32(y, Fetch32(s + 16)); // _mm_crc32_u32
+ z = Sse42.Crc32(z * c1, Fetch32(s + 20)); // _mm_crc32_u32
+ x = Sse42.Crc32(x, Fetch32(s + 24)); // _mm_crc32_u32
+ y = Sse42.Crc32(y * c1, Fetch32(s + 28)); // _mm_crc32_u32
+ uint o = y;
+ z = Sse42.Crc32(z, Fetch32(s + 32)); // _mm_crc32_u32
+ x = Sse42.Crc32(x * c1, Fetch32(s + 36)); // _mm_crc32_u32
+ y = Sse42.Crc32(y, Fetch32(s + 40)); // _mm_crc32_u32
+ z = Sse42.Crc32(z * c1, Fetch32(s + 44)); // _mm_crc32_u32
+ x = Sse42.Crc32(x, Fetch32(s + 48)); // _mm_crc32_u32
+ y = Sse42.Crc32(y * c1, Fetch32(s + 52)); // _mm_crc32_u32
+ z = Sse42.Crc32(z, Fetch32(s + 56)); // _mm_crc32_u32
+ x = Sse42.Crc32(x, Fetch32(s + 60)); // _mm_crc32_u32
+ return (o - x + y - z) * c1;
+ }
+
+ public static unsafe uint Hash32WithSeed(byte* s, uint len, uint seed, uint h)
+ => Sse42.Crc32(Hash32(s + 24, len - 24) + seed, h); // _mm_crc32_u32
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FarmHash.SU.cs b/src/MsgPack.Abstraction/Internal/FarmHash.SU.cs
new file mode 100644
index 000000000..7eb408425
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FarmHash.SU.cs
@@ -0,0 +1,239 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+// This file is ported from Google's FarmHash (https://github.com/google/farmhash/)
+// Original copyright notice is following:
+
+// Copyright (c) 2014 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// FarmHash, by Geoff Pike
+
+using System.Runtime.CompilerServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+using __m128i = System.Runtime.Intrinsics.Vector128;
+
+namespace MsgPack.Internal
+{
+ internal partial class FarmHash
+ {
+ internal static class SU
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Swap(ref __m128i left, ref __m128i right)
+ {
+ var temp = left;
+ left = right;
+ right = temp;
+ }
+
+ public static unsafe uint Hash32(byte* s, uint len)
+ {
+ const uint seed = 81;
+ if (len <= 24)
+ {
+ return len <= 12 ?
+ (len <= 4 ?
+ MK.Hash32Len0to4(s, len) :
+ MK.Hash32Len5to12(s, len)) :
+ MK.Hash32Len13to24(s, len);
+ }
+
+ if (len < 40)
+ {
+ uint a = len, b = unchecked(seed * c2), c = a + b;
+ a += Fetch32(s + len - 4);
+ b += Fetch32(s + len - 20);
+ c += Fetch32(s + len - 16);
+ uint d = a;
+ a = Rotate32(a, 21);
+ a = Mur(a, Mur(b, Sse42.Crc32(c, d))); // _mm_crc32_u32
+ a += Fetch32(s + len - 12);
+ b += Fetch32(s + len - 8);
+ d += a;
+ a += d;
+ b = Mur(b, d) * c2;
+ a = Sse42.Crc32(a, b + c); // _mm_crc32_u32
+ return MK.Hash32Len13to24(s, (len + 1) / 2, a) + b;
+ }
+
+ // Murk
+ // Add(k, Mul5(Rol19(Xor(Mul(Rol17(Mul(★, cc1)), cc2),(h)))))
+ // Add(k, Mul5(Rot19(Xor(Mul(Rot17(Mul(d, cc1)), cc2), (h)))))
+
+
+ __m128i cc1 = Vector128.Create(c1); // _mm_set1_epi32
+ __m128i cc2 = Vector128.Create(c2); // _mm_set1_epi32
+ __m128i h = Vector128.Create(seed); // _mm_set1_epi32
+ __m128i g = Vector128.Create(unchecked(c1 * seed)); // _mm_set1_epi32
+ __m128i f = g;
+ __m128i k = Vector128.Create(0xe6546b64); // _mm_set1_epi32
+ __m128i q;
+ if (len < 80)
+ {
+ __m128i a = Fetch128(s);
+ __m128i b = Fetch128(s + 16);
+ __m128i c = Fetch128(s + (len - 15) / 2);
+ __m128i d = Fetch128(s + len - 32);
+ __m128i e = Fetch128(s + len - 16);
+ h = Add(h, a);
+ g = Add(g, b);
+ q = g;
+ g = Shuffle0321(g);
+ f = Add(f, c);
+ __m128i be = Add(b, Mul(e, cc1));
+ h = Add(h, f);
+ f = Add(f, h);
+ h = Add(Add(k, Mul5(Rol19(Xor(Mul(Rol17(Mul(d, cc1)), cc2), (h))))), e);
+ k = Xor(k, Ssse3.Shuffle(g.AsByte(), f.AsByte()).AsUInt32()); // _mm_shuffle_epi8
+ g = Add(Xor(c, g), a);
+ f = Add(Xor(be, f), d);
+ k = Add(k, be);
+ k = Add(k, Ssse3.Shuffle(f.AsByte(), h.AsByte()).AsUInt32()); // _mm_shuffle_epi8
+ f = Add(f, g);
+ g = Add(g, f);
+ g = Add(
+ Vector128.Create(len), // _mm_set1_epi32
+ Mul(g, cc1)
+ );
+ }
+ else
+ {
+ // len >= 80
+ // The following is loosely modelled after farmhashmk::Hash32.
+ uint iters = (len - 1) / 80;
+ len -= iters * 80;
+ q = g;
+ while (iters-- != 0)
+ {
+ //
+ __m128i a = Fetch128(s);
+ __m128i b = Fetch128(s + 16);
+ __m128i c = Fetch128(s + 32);
+ __m128i d = Fetch128(s + 48);
+ __m128i e = Fetch128(s + 64);
+ h = Add(h, a);
+ g = Add(g, b);
+ g = Shuffle0321(g);
+ f = Add(f, c);
+ __m128i be = Add(b, Mul(e, cc1));
+ h = Add(h, f);
+ f = Add(f, h);
+ h = Add(h, d);
+ q = Add(q, e);
+ h = Rol17(h);
+ h = Mul(h, cc1);
+ k = Xor(k, Ssse3.Shuffle(g.AsByte(), f.AsByte()).AsUInt32()); //_mm_shuffle_epi8
+ g = Add(Xor(c, g), a);
+ f = Add(Xor(be, f), d);
+ Swap(ref f, ref q);
+ q = Aes.InverseMixColumns(q.AsByte()).AsUInt32(); // _mm_aesimc_si128
+ k = Add(k, be);
+ k = Add(k, Ssse3.Shuffle(f.AsByte(), h.AsByte()).AsUInt32());
+ f = Add(f, g);
+ g = Add(g, f);
+ f = Mul(f, cc1);
+ //
+ s += 80;
+ }
+
+ if (len != 0)
+ {
+ h = Add(h, Vector128.Create(len)); // _mm_set1_epi32
+ s = s + len - 80;
+ //
+ __m128i a = Fetch128(s);
+ __m128i b = Fetch128(s + 16);
+ __m128i c = Fetch128(s + 32);
+ __m128i d = Fetch128(s + 48);
+ __m128i e = Fetch128(s + 64);
+ h = Add(h, a);
+ g = Add(g, b);
+ g = Shuffle0321(g);
+ f = Add(f, c);
+ __m128i be = Add(b, Mul(e, cc1));
+ h = Add(h, f);
+ f = Add(f, h);
+ h = Add(h, d);
+ q = Add(q, e);
+ h = Rol17(h);
+ h = Mul(h, cc1);
+ k = Xor(k, Ssse3.Shuffle(g.AsByte(), f.AsByte()).AsUInt32()); //_mm_shuffle_epi8
+ g = Add(Xor(c, g), a);
+ f = Add(Xor(be, f), d);
+ Swap(ref f, ref q);
+ q = Aes.InverseMixColumns(q.AsByte()).AsUInt32(); // _mm_aesimc_si128
+ k = Add(k, be);
+ k = Add(k, Ssse3.Shuffle(f.AsByte(), h.AsByte()).AsUInt32());
+ f = Add(f, g);
+ g = Add(g, f);
+ f = Mul(f, cc1);
+ //
+ }
+ }
+
+ g = Shuffle0321(g);
+ k = Xor(k, g);
+ k = Xor(k, q);
+ h = Xor(h, q);
+ f = Mul(f, cc1);
+ k = Mul(k, cc2);
+ g = Mul(g, cc1);
+ h = Mul(h, cc2);
+ k = Add(k, Ssse3.Shuffle(g.AsByte(), f.AsByte()).AsUInt32()); // _mm_shuffle_epi8
+ h = Add(h, f);
+ f = Add(f, h);
+ g = Add(g, k);
+ k = Add(k, g);
+ k = Xor(k, Ssse3.Shuffle(f.AsByte(), h.AsByte()).AsUInt32()); // _mm_shuffle_epi8
+ var buf = stackalloc __m128i[4];
+ buf[0] = f;
+ buf[1] = g;
+ buf[2] = k;
+ buf[3] = h;
+ s = (byte*)buf;
+ uint x = Fetch32(s);
+ uint y = Fetch32(s + 4);
+ uint z = Fetch32(s + 8);
+ x = Sse42.Crc32(x, Fetch32(s + 12)); // _mm_crc32_u32
+ y = Sse42.Crc32(y, Fetch32(s + 16)); // _mm_crc32_u32
+ z = Sse42.Crc32(z * c1, Fetch32(s + 20)); // _mm_crc32_u32
+ x = Sse42.Crc32(x, Fetch32(s + 24)); // _mm_crc32_u32
+ y = Sse42.Crc32(y * c1, Fetch32(s + 28)); // _mm_crc32_u32
+ uint o = y;
+ z = Sse42.Crc32(z, Fetch32(s + 32)); // _mm_crc32_u32
+ x = Sse42.Crc32(x * c1, Fetch32(s + 36)); // _mm_crc32_u32
+ y = Sse42.Crc32(y, Fetch32(s + 40)); // _mm_crc32_u32
+ z = Sse42.Crc32(z * c1, Fetch32(s + 44)); // _mm_crc32_u32
+ x = Sse42.Crc32(x, Fetch32(s + 48)); // _mm_crc32_u32
+ y = Sse42.Crc32(y * c1, Fetch32(s + 52)); // _mm_crc32_u32
+ z = Sse42.Crc32(z, Fetch32(s + 56)); // _mm_crc32_u32
+ x = Sse42.Crc32(x, Fetch32(s + 60)); // _mm_crc32_u32
+ return (o - x + y - z) * c1;
+ }
+
+ public static unsafe uint Hash32WithSeed(byte* s, uint len, uint seed, uint h)
+ => Sse42.Crc32(Hash32(s + 24, len - 24) + seed, h); // _mm_crc32_u32
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FarmHash.TE.cs b/src/MsgPack.Abstraction/Internal/FarmHash.TE.cs
new file mode 100644
index 000000000..942fbf305
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FarmHash.TE.cs
@@ -0,0 +1,258 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+// This file is ported from Google's FarmHash (https://github.com/google/farmhash/)
+// Original copyright notice is following:
+
+// Copyright (c) 2014 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// FarmHash, by Geoff Pike
+
+using System.Runtime.CompilerServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+using __m128i = System.Runtime.Intrinsics.Vector128;
+
+namespace MsgPack.Internal
+{
+ internal partial class FarmHash
+ {
+ private static class TE
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe __m128i Fetch128(byte* s)
+ => Sse2.LoadVector128(s).AsUInt64(); // _mm_loadu_si128
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static __m128i Add(__m128i x, __m128i y)
+ => Sse2.Add(x, y); // _mm_add_epi64
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static __m128i Xor(__m128i x, __m128i y)
+ => Sse2.Xor(x, y); // _mm_xor_si128
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static __m128i Mul(__m128i x, __m128i y)
+ => Sse41.MultiplyLow(x.AsUInt32(), y.AsUInt32()).AsUInt64(); // _mm_mullo_epi32
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static __m128i Shuf(__m128i x, __m128i y)
+ => Ssse3.Shuffle(x.AsByte(), y.AsByte()).AsUInt64(); // _mm_shuffle_epi8
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void swap(ref __m128i left, ref __m128i right)
+ {
+ var temp = left;
+ left = right;
+ right = temp;
+ }
+
+ // Requires n >= 256. Requires SSE4.1. Should be slightly faster if the
+ // compiler uses AVX instructions (e.g., use the -mavx flag with GCC).
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe ulong Hash64Long(byte* s, uint n, ulong seed0, ulong seed1)
+ {
+ __m128i kShuf =
+ Vector128.Create(4, 11, 10, 5, 8, 15, 6, 9, 12, 2, 14, 13, 0, 7, 3, 1).AsUInt64(); // _mm_set_epi8
+ __m128i kMult =
+ Vector128.Create(0xbd, 0xd6, 0x33, 0x39, 0x45, 0x54, 0xfa, 0x03,
+ 0x34, 0x3e, 0x33, 0xed, 0xcc, 0x9e, 0x2d, 0x51).AsUInt64(); // _mm_set_epi8
+ ulong seed2 = (seed0 + 113) * (seed1 + 9);
+ ulong seed3 = (Rotate64(seed0, 23) + 27) * (Rotate64(seed1, 30) + 111);
+ __m128i d0 = Sse2.X64.ConvertScalarToVector128UInt64(seed0); // _mm_cvtsi64_si128
+ __m128i d1 = Sse2.X64.ConvertScalarToVector128UInt64(seed1); // _mm_cvtsi64_si128
+ __m128i d2 = Shuf(kShuf, d0);
+ __m128i d3 = Shuf(kShuf, d1);
+ __m128i d4 = Xor(d0, d1);
+ __m128i d5 = Xor(d1, d2);
+ __m128i d6 = Xor(d2, d4);
+ __m128i d7 = Vector128.Create(seed2 >> 32); // _mm_set1_epi32
+ __m128i d8 = Mul(kMult, d2);
+ __m128i d9 = Vector128.Create(seed3 >> 32); // _mm_set1_epi32
+ __m128i d10 = Vector128.Create(seed3); // _mm_set1_epi32
+ __m128i d11 = Add(d2, Vector128.Create(seed2)); // _mm_set1_epi32
+ // size_t == ulong here because this code should be run under X64 process.
+ byte* end = s + (n & ~(/* size_t */ ulong)(255));
+ do
+ {
+ __m128i z;
+ z = Fetch128(s);
+ d0 = Add(d0, z);
+ d1 = Shuf(kShuf, d1);
+ d2 = Xor(d2, d0);
+ d4 = Xor(d4, z);
+ d4 = Xor(d4, d1);
+ swap(ref d0, ref d6);
+ z = Fetch128(s + 16);
+ d5 = Add(d5, z);
+ d6 = Shuf(kShuf, d6);
+ d8 = Shuf(kShuf, d8);
+ d7 = Xor(d7, d5);
+ d0 = Xor(d0, z);
+ d0 = Xor(d0, d6);
+ swap(ref d5, ref d11);
+ z = Fetch128(s + 32);
+ d1 = Add(d1, z);
+ d2 = Shuf(kShuf, d2);
+ d4 = Shuf(kShuf, d4);
+ d5 = Xor(d5, z);
+ d5 = Xor(d5, d2);
+ swap(ref d10, ref d4);
+ z = Fetch128(s + 48);
+ d6 = Add(d6, z);
+ d7 = Shuf(kShuf, d7);
+ d0 = Shuf(kShuf, d0);
+ d8 = Xor(d8, d6);
+ d1 = Xor(d1, z);
+ d1 = Add(d1, d7);
+ z = Fetch128(s + 64);
+ d2 = Add(d2, z);
+ d5 = Shuf(kShuf, d5);
+ d4 = Add(d4, d2);
+ d6 = Xor(d6, z);
+ d6 = Xor(d6, d11);
+ swap(ref d8, ref d2);
+ z = Fetch128(s + 80);
+ d7 = Xor(d7, z);
+ d8 = Shuf(kShuf, d8);
+ d1 = Shuf(kShuf, d1);
+ d0 = Add(d0, d7);
+ d2 = Add(d2, z);
+ d2 = Add(d2, d8);
+ swap(ref d1, ref d7);
+ z = Fetch128(s + 96);
+ d4 = Shuf(kShuf, d4);
+ d6 = Shuf(kShuf, d6);
+ d8 = Mul(kMult, d8);
+ d5 = Xor(d5, d11);
+ d7 = Xor(d7, z);
+ d7 = Add(d7, d4);
+ swap(ref d6, ref d0);
+ z = Fetch128(s + 112);
+ d8 = Add(d8, z);
+ d0 = Shuf(kShuf, d0);
+ d2 = Shuf(kShuf, d2);
+ d1 = Xor(d1, d8);
+ d10 = Xor(d10, z);
+ d10 = Xor(d10, d0);
+ swap(ref d11, ref d5);
+ z = Fetch128(s + 128);
+ d4 = Add(d4, z);
+ d5 = Shuf(kShuf, d5);
+ d7 = Shuf(kShuf, d7);
+ d6 = Add(d6, d4);
+ d8 = Xor(d8, z);
+ d8 = Xor(d8, d5);
+ swap(ref d4, ref d10);
+ z = Fetch128(s + 144);
+ d0 = Add(d0, z);
+ d1 = Shuf(kShuf, d1);
+ d2 = Add(d2, d0);
+ d4 = Xor(d4, z);
+ d4 = Xor(d4, d1);
+ z = Fetch128(s + 160);
+ d5 = Add(d5, z);
+ d6 = Shuf(kShuf, d6);
+ d8 = Shuf(kShuf, d8);
+ d7 = Xor(d7, d5);
+ d0 = Xor(d0, z);
+ d0 = Xor(d0, d6);
+ swap(ref d2, ref d8);
+ z = Fetch128(s + 176);
+ d1 = Add(d1, z);
+ d2 = Shuf(kShuf, d2);
+ d4 = Shuf(kShuf, d4);
+ d5 = Mul(kMult, d5);
+ d5 = Xor(d5, z);
+ d5 = Xor(d5, d2);
+ swap(ref d7, ref d1);
+ z = Fetch128(s + 192);
+ d6 = Add(d6, z);
+ d7 = Shuf(kShuf, d7);
+ d0 = Shuf(kShuf, d0);
+ d8 = Add(d8, d6);
+ d1 = Xor(d1, z);
+ d1 = Xor(d1, d7);
+ swap(ref d0, ref d6);
+ z = Fetch128(s + 208);
+ d2 = Add(d2, z);
+ d5 = Shuf(kShuf, d5);
+ d4 = Xor(d4, d2);
+ d6 = Xor(d6, z);
+ d6 = Xor(d6, d9);
+ swap(ref d5, ref d11);
+ z = Fetch128(s + 224);
+ d7 = Add(d7, z);
+ d8 = Shuf(kShuf, d8);
+ d1 = Shuf(kShuf, d1);
+ d0 = Xor(d0, d7);
+ d2 = Xor(d2, z);
+ d2 = Xor(d2, d8);
+ swap(ref d10, ref d4);
+ z = Fetch128(s + 240);
+ d3 = Add(d3, z);
+ d4 = Shuf(kShuf, d4);
+ d6 = Shuf(kShuf, d6);
+ d7 = Mul(kMult, d7);
+ d5 = Add(d5, d3);
+ d7 = Xor(d7, z);
+ d7 = Xor(d7, d4);
+ swap(ref d3, ref d9);
+ s += 256;
+ } while (s != end);
+ d6 = Add(Mul(kMult, d6), Sse2.X64.ConvertScalarToVector128UInt64(n)); // _mm_cvtsi64_si128
+ if (n % 256 != 0)
+ {
+ d7 = Add(Sse2.Shuffle(d8.AsUInt32(), (0 << 6) + (3 << 4) + (2 << 2) + (1 << 0)).AsUInt64(), d7); // _mm_shuffle_epi32
+ d8 = Add(Mul(kMult, d8), Sse2.X64.ConvertScalarToVector128UInt64(XO.Hash64(s, n % 256))); // _mm_cvtsi64_si128
+ }
+ var t = stackalloc __m128i[8];
+ d0 = Mul(kMult, Shuf(kShuf, Mul(kMult, d0)));
+ d3 = Mul(kMult, Shuf(kShuf, Mul(kMult, d3)));
+ d9 = Mul(kMult, Shuf(kShuf, Mul(kMult, d9)));
+ d1 = Mul(kMult, Shuf(kShuf, Mul(kMult, d1)));
+ d0 = Add(d11, d0);
+ d3 = Xor(d7, d3);
+ d9 = Add(d8, d9);
+ d1 = Add(d10, d1);
+ d4 = Add(d3, d4);
+ d5 = Add(d9, d5);
+ d6 = Xor(d1, d6);
+ d2 = Add(d0, d2);
+ t[0] = d0;
+ t[1] = d3;
+ t[2] = d9;
+ t[3] = d1;
+ t[4] = d4;
+ t[5] = d5;
+ t[6] = d6;
+ t[7] = d2;
+ return XO.Hash64((byte*)t, /* sizeof(t) */ 8);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ulong Hash64WithSeed(byte* s, uint len, uint seed)
+ => len >= 512 ?
+ Hash64Long(s, len, k1, seed) :
+ XO.Hash64WithSeed(s, len, seed);
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FarmHash.UO.cs b/src/MsgPack.Abstraction/Internal/FarmHash.UO.cs
new file mode 100644
index 000000000..ae087da0a
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FarmHash.UO.cs
@@ -0,0 +1,155 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+// This file is ported from Google's FarmHash (https://github.com/google/farmhash/)
+// Original copyright notice is following:
+
+// Copyright (c) 2014 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// FarmHash, by Geoff Pike
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace MsgPack.Internal
+{
+ internal partial class FarmHash
+ {
+ private static class UO
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe ulong H(ulong x, ulong y, ulong mul, int r)
+ {
+ ulong a = (x ^ y) * mul;
+ a ^= (a >> 47);
+ ulong b = (y ^ a) * mul;
+ return Rotate64(b, r) * mul;
+ }
+
+ private static unsafe ulong Hash64WithSeeds(byte* s, uint len,
+ ulong seed0, ulong seed1)
+ {
+ if (len <= 64)
+ {
+ return NA.Hash64WithSeeds(s, len, seed0, seed1);
+ }
+
+ // For strings over 64 bytes we loop. Internal state consists of
+ // 64 bytes: u, v, w, x, y, and z.
+ ulong x = seed0;
+ ulong y = seed1 * k2 + 113;
+ ulong z = NA.ShiftMix(y * k2) * k2;
+ (ulong first, ulong second) v = (seed0, seed1);
+ (ulong first, ulong second) w = (0, 0);
+ ulong u = x - z;
+ x *= k2;
+ ulong mul = k2 + (u & 0x82);
+
+ // Set end so that after the loop we have 1 to 64 bytes left to process.
+ byte* end = s + ((len - 1) / 64) * 64;
+ byte* last64 = end + ((len - 1) & 63) - 63;
+ Debug.Assert(s + len - 64 == last64);
+ do
+ {
+ ulong a0 = Fetch64(s);
+ ulong a1 = Fetch64(s + 8);
+ ulong a2 = Fetch64(s + 16);
+ ulong a3 = Fetch64(s + 24);
+ ulong a4 = Fetch64(s + 32);
+ ulong a5 = Fetch64(s + 40);
+ ulong a6 = Fetch64(s + 48);
+ ulong a7 = Fetch64(s + 56);
+ x += a0 + a1;
+ y += a2;
+ z += a3;
+ v.first += a4;
+ v.second += a5 + a1;
+ w.first += a6;
+ w.second += a7;
+
+ x = Rotate64(x, 26);
+ x *= 9;
+ y = Rotate64(y, 29);
+ z *= mul;
+ v.first = Rotate64(v.first, 33);
+ v.second = Rotate64(v.second, 30);
+ w.first ^= x;
+ w.first *= 9;
+ z = Rotate64(z, 32);
+ z += w.second;
+ w.second += z;
+ z *= 9;
+ Swap(ref u, ref y);
+
+ z += a0 + a6;
+ v.first += a2;
+ v.second += a3;
+ w.first += a4;
+ w.second += a5 + a6;
+ x += a1;
+ y += a7;
+
+ y += v.first;
+ v.first += x - y;
+ v.second += w.first;
+ w.first += v.second;
+ w.second += x - y;
+ x += w.second;
+ w.second = Rotate64(w.second, 34);
+ Swap(ref u, ref z);
+ s += 64;
+ } while (s != end);
+ // Make s point to the last 64 bytes of input.
+ s = last64;
+ u *= 9;
+ v.second = Rotate64(v.second, 28);
+ v.first = Rotate64(v.first, 20);
+ w.first += ((len - 1) & 63);
+ u += y;
+ y += u;
+ x = Rotate64(y - x + v.first + Fetch64(s + 8), 37) * mul;
+ y = Rotate64(y ^ v.second ^ Fetch64(s + 48), 42) * mul;
+ x ^= w.second * 9;
+ y += v.first + Fetch64(s + 40);
+ z = Rotate64(z + w.first, 33) * mul;
+ v = NA.WeakHashLen32WithSeeds(s, v.second * mul, x + w.first);
+ w = NA.WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+ return H(NA.HashLen16(v.first + x, w.first ^ y, mul) + z - u,
+ H(v.second + y, w.second + z, k2, 30) ^ x,
+ k2,
+ 31);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ulong Hash64WithSeed(byte* s, uint len, ulong seed)
+ => len <= 64 ?
+ NA.Hash64WithSeed(s, len, seed) :
+ Hash64WithSeeds(s, len, 0, seed);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ulong Hash64(byte* s, uint len)
+ => len <= 64 ?
+ NA.Hash64(s, len) :
+ Hash64WithSeeds(s, len, 81, 0);
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FarmHash.XO.cs b/src/MsgPack.Abstraction/Internal/FarmHash.XO.cs
new file mode 100644
index 000000000..4b29fa36b
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FarmHash.XO.cs
@@ -0,0 +1,112 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+// This file is ported from Google's FarmHash (https://github.com/google/farmhash/)
+// Original copyright notice is following:
+
+// Copyright (c) 2014 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// FarmHash, by Geoff Pike
+
+using System.Runtime.CompilerServices;
+
+namespace MsgPack.Internal
+{
+ internal partial class FarmHash
+ {
+ private static class XO
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe ulong H32(byte* s, uint len, ulong mul,
+ ulong seed0 = 0, ulong seed1 = 0)
+ {
+ ulong a = Fetch64(s) * k1;
+ ulong b = Fetch64(s + 8);
+ ulong c = Fetch64(s + len - 8) * mul;
+ ulong d = Fetch64(s + len - 16) * k2;
+ ulong u = Rotate64(a + b, 43) + Rotate64(c, 30) + d + seed0;
+ ulong v = a + Rotate64(b + k2, 18) + c + seed1;
+ a = NA.ShiftMix((u ^ v) * mul);
+ b = NA.ShiftMix((v ^ a) * mul);
+ return b;
+ }
+
+ // Return an 8-byte hash for 33 to 64 bytes.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe ulong HashLen33to64(byte* s, uint len)
+ {
+ ulong mul0 = k2 - 30;
+ ulong mul1 = k2 - 30 + 2 * len;
+ ulong h0 = H32(s, 32, mul0);
+ ulong h1 = H32(s + len - 32, 32, mul1);
+ return ((h1 * mul1) + h0) * mul1;
+ }
+
+ // Return an 8-byte hash for 65 to 96 bytes.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static unsafe ulong HashLen65to96(byte* s, uint len)
+ {
+ ulong mul0 = k2 - 114;
+ ulong mul1 = k2 - 114 + 2 * len;
+ ulong h0 = H32(s, 32, mul0);
+ ulong h1 = H32(s + 32, 32, mul1);
+ ulong h2 = H32(s + len - 32, 32, mul1, h0, h1);
+ return (h2 * 9 + (h0 >> 17) + (h1 >> 21)) * mul1;
+ }
+
+ internal static unsafe ulong Hash64(byte* s, uint len)
+ {
+ if (len <= 32)
+ {
+ if (len <= 16)
+ {
+ return NA.HashLen0to16(s, len);
+ }
+ else
+ {
+ return NA.HashLen17to32(s, len);
+ }
+ }
+ else if (len <= 64)
+ {
+ return HashLen33to64(s, len);
+ }
+ else if (len <= 96)
+ {
+ return HashLen65to96(s, len);
+ }
+ else if (len <= 256)
+ {
+ return NA.Hash64(s, len);
+ }
+ else
+ {
+ return UO.Hash64(s, len);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ulong Hash64WithSeed(byte* s, uint len, ulong seed)
+ => UO.Hash64WithSeed(s, len, seed);
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FarmHash.cs b/src/MsgPack.Abstraction/Internal/FarmHash.cs
new file mode 100644
index 000000000..63865d04b
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FarmHash.cs
@@ -0,0 +1,147 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+// This file is ported from Google's FarmHash (https://github.com/google/farmhash/)
+// Original copyright notice is following:
+
+// Copyright (c) 2014 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// FarmHash, by Geoff Pike
+
+using System;
+using System.Buffers.Binary;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics.X86;
+
+using RandomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator;
+
+namespace MsgPack.Internal
+{
+ internal static partial class FarmHash
+ {
+ private const uint c1 = 0xcc9e2d51;
+ private const uint c2 = 0x1b873593;
+ private const ulong k0 = 0xc3a5c85c97cb3127UL;
+ private const ulong k1 = 0xb492b66fbe98f273UL;
+ private const ulong k2 = 0x9ae16a3b2f90404fUL;
+
+ ///
+ /// Hash function for a byte array.
+ /// May change from time to time, may differ on different platforms.
+ ///
+ /// Target byte span.
+ /// Non-cryptgraphic, temporal hash value suitable as hash code.
+ public static unsafe int Hash32WithSeed(ReadOnlySpan bytes, uint seed)
+ {
+ var len = (uint)bytes.Length;
+ unchecked
+ {
+ fixed (byte* s = bytes)
+ {
+ if (Sse41.IsSupported && RuntimeInformation.ProcessArchitecture == Architecture.X64)
+ {
+ return (int)NT.Hash32WithSeed(s, len, seed);
+ }
+
+ if (Sse42.IsSupported)
+ {
+ // farmhashsa::Hash32WithSeed and farmshahsu::Hash32WithSeed is same for less than or equal to 24bytes,
+ // so inline here to reduce code size.
+ if (len <= 24)
+ {
+ if (len >= 13)
+ {
+ return (int)MK.Hash32Len13to24(s, len, seed * c1);
+ }
+ else if (len >= 5)
+ {
+ return (int)MK.Hash32Len5to12(s, len, seed);
+ }
+ else
+ {
+ return (int)MK.Hash32Len0to4(s, len, seed);
+ }
+ }
+
+ // Calculation of h is also common.
+ uint h = MK.Hash32Len13to24(s, 24, seed ^ len);
+
+ if (Aes.IsSupported)
+ {
+ return (int)SU.Hash32WithSeed(s, (uint)bytes.Length, seed, h);
+ }
+ else
+ {
+ return (int)SA.Hash32WithSeed(s, (uint)bytes.Length, seed, h);
+ }
+ }
+
+ return (int)MK.Hash32WithSeed(s, (uint)bytes.Length, seed);
+ }
+ }
+ }
+
+ public static readonly uint DefaultSeed = InitializeRandomSeed();
+
+ private static uint InitializeRandomSeed()
+ {
+ using var rng = RandomNumberGenerator.Create();
+ Span bytes = stackalloc byte[sizeof(uint)];
+ rng.GetBytes(bytes);
+ return BinaryPrimitives.ReadUInt32LittleEndian(bytes);
+ }
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ private static unsafe uint Fetch32(byte* p)
+ => *(uint*)p;
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ private static uint Rotate32(uint val, int shift)
+ // Avoid shifting by 32: doing so yields an undefined result.
+ => shift == 0 ? val : ((val >> shift) | (val << (32 - shift)));
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ private static uint Fmix(uint h)
+ {
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+ return h;
+ }
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ private static uint Mur(uint a, uint h)
+ {
+ // Helper from Murmur3 for combining two 32-bit values.
+ a *= c1;
+ a = Rotate32(a, 17);
+ a *= c2;
+ h ^= a;
+ h = Rotate32(h, 19);
+ return h * 5 + 0xe6546b64;
+ }
+ }
+}
+
diff --git a/src/MsgPack.Abstraction/Internal/FormatDecoder.Primitives.cs b/src/MsgPack.Abstraction/Internal/FormatDecoder.Primitives.cs
new file mode 100644
index 000000000..9e7144635
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FormatDecoder.Primitives.cs
@@ -0,0 +1,876 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+//
+// This file is generated from acompanying .tt file.
+// DO NOT edit this file directly, edit .tt file instead.
+
+using System;
+using System.Buffers;
+using System.Runtime.CompilerServices;
+
+namespace MsgPack.Internal
+{
+ partial class FormatDecoder
+ {
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Byte DecodeByte(ref SequenceReader source)
+ {
+ var result = this.DecodeByte(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Byte), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract Byte DecodeByte(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Byte? DecodeNullableByte(ref SequenceReader source)
+ {
+ var result = this.DecodeNullableByte(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Byte), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract Byte? DecodeNullableByte(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Int16 DecodeInt16(ref SequenceReader source)
+ {
+ var result = this.DecodeInt16(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Int16), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract Int16 DecodeInt16(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Int16? DecodeNullableInt16(ref SequenceReader source)
+ {
+ var result = this.DecodeNullableInt16(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Int16), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract Int16? DecodeNullableInt16(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Int32 DecodeInt32(ref SequenceReader source)
+ {
+ var result = this.DecodeInt32(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Int32), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract Int32 DecodeInt32(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Int32? DecodeNullableInt32(ref SequenceReader source)
+ {
+ var result = this.DecodeNullableInt32(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Int32), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract Int32? DecodeNullableInt32(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Int64 DecodeInt64(ref SequenceReader source)
+ {
+ var result = this.DecodeInt64(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Int64), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract Int64 DecodeInt64(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Int64? DecodeNullableInt64(ref SequenceReader source)
+ {
+ var result = this.DecodeNullableInt64(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Int64), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract Int64? DecodeNullableInt64(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public SByte DecodeSByte(ref SequenceReader source)
+ {
+ var result = this.DecodeSByte(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(SByte), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract SByte DecodeSByte(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public SByte? DecodeNullableSByte(ref SequenceReader source)
+ {
+ var result = this.DecodeNullableSByte(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(SByte), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract SByte? DecodeNullableSByte(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public UInt16 DecodeUInt16(ref SequenceReader source)
+ {
+ var result = this.DecodeUInt16(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(UInt16), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract UInt16 DecodeUInt16(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public UInt16? DecodeNullableUInt16(ref SequenceReader source)
+ {
+ var result = this.DecodeNullableUInt16(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(UInt16), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract UInt16? DecodeNullableUInt16(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public UInt32 DecodeUInt32(ref SequenceReader source)
+ {
+ var result = this.DecodeUInt32(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(UInt32), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract UInt32 DecodeUInt32(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public UInt32? DecodeNullableUInt32(ref SequenceReader source)
+ {
+ var result = this.DecodeNullableUInt32(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(UInt32), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract UInt32? DecodeNullableUInt32(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public UInt64 DecodeUInt64(ref SequenceReader source)
+ {
+ var result = this.DecodeUInt64(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(UInt64), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract UInt64 DecodeUInt64(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public UInt64? DecodeNullableUInt64(ref SequenceReader source)
+ {
+ var result = this.DecodeNullableUInt64(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(UInt64), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract UInt64? DecodeNullableUInt64(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Single DecodeSingle(ref SequenceReader source)
+ {
+ var result = this.DecodeSingle(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Single), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract Single DecodeSingle(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Single? DecodeNullableSingle(ref SequenceReader source)
+ {
+ var result = this.DecodeNullableSingle(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Single), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract Single? DecodeNullableSingle(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Double DecodeDouble(ref SequenceReader source)
+ {
+ var result = this.DecodeDouble(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Double), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract Double DecodeDouble(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Double? DecodeNullableDouble(ref SequenceReader source)
+ {
+ var result = this.DecodeNullableDouble(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Double), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract Double? DecodeNullableDouble(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Boolean DecodeBoolean(ref SequenceReader source)
+ {
+ var result = this.DecodeBoolean(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Boolean), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract Boolean DecodeBoolean(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Boolean? DecodeNullableBoolean(ref SequenceReader source)
+ {
+ var result = this.DecodeNullableBoolean(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(Boolean), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract Boolean? DecodeNullableBoolean(ref SequenceReader source, out int requestHint);
+
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FormatDecoder.Primitives.tt b/src/MsgPack.Abstraction/Internal/FormatDecoder.Primitives.tt
new file mode 100644
index 000000000..f31bf57a4
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FormatDecoder.Primitives.tt
@@ -0,0 +1,117 @@
+<#@ template debug="false" hostspecific="false" language="C#" #>
+<#@ output extension=".cs" #>
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+//
+// This file is generated from acompanying .tt file.
+// DO NOT edit this file directly, edit .tt file instead.
+
+using System;
+using System.Buffers;
+using System.Runtime.CompilerServices;
+
+namespace MsgPack.Internal
+{
+ partial class FormatDecoder
+ {
+<#
+foreach (var outputType in new [] {
+ "Byte",
+ "Int16",
+ "Int32",
+ "Int64",
+ "SByte",
+ "UInt16",
+ "UInt32",
+ "UInt64",
+ "Single",
+ "Double",
+ "Boolean"
+})
+{
+#>
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public <#= outputType #> Decode<#= outputType #>(ref SequenceReader source)
+ {
+ var result = this.Decode<#= outputType #>(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(<#= outputType #>), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract <#= outputType #> Decode<#= outputType #>(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public <#= outputType #>? DecodeNullable<#= outputType #>(ref SequenceReader source)
+ {
+ var result = this.DecodeNullable<#= outputType #>(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(<#= outputType #>), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Encodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract <#= outputType #>? DecodeNullable<#= outputType #>(ref SequenceReader source, out int requestHint);
+
+<#
+}
+#>
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FormatDecoder.Strings.cs b/src/MsgPack.Abstraction/Internal/FormatDecoder.Strings.cs
new file mode 100644
index 000000000..87f7ad1e5
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FormatDecoder.Strings.cs
@@ -0,0 +1,548 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+//
+// This file is generated from acompanying .tt file.
+// DO NOT edit this file directly, edit .tt file instead.
+
+#nullable enable
+
+using System;
+using System.Buffers;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading;
+
+namespace MsgPack.Internal
+{
+ partial class FormatDecoder
+ {
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public String DecodeString(ref SequenceReader source, Encoding? encoding = null, CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeString(ref source, out var requestHint, encoding, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForString(source.Consumed, typeof(String), encoding, requestHint);
+ }
+
+ return result!;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract String? DecodeString(ref SequenceReader source, out int requestHint, Encoding? encoding = null, CancellationToken cancellationToken = default);
+
+ ///
+ /// Decodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public String? DecodeNullableString(ref SequenceReader source, Encoding? encoding = null, CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeNullableString(ref source, out var requestHint, encoding, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForString(source.Consumed, typeof(String), encoding, requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract String? DecodeNullableString(ref SequenceReader source, out int requestHint, Encoding? encoding = null, CancellationToken cancellationToken = default);
+
+ ///
+ /// Decodes the value from specified sequence to of .
+ ///
+ /// SequenceReader<byte>.
+ /// of which will store the decoded binary.
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// The length of the decoded value.
+ /// This value can be 0 for empty string.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public int DecodeString(ref SequenceReader source, Span buffer, Encoding? encoding = null, CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeString(ref source, buffer, out var requestHint, encoding, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForString(source.Consumed, typeof(String), encoding, requestHint);
+ }
+
+ return result!;
+ }
+
+ ///
+ /// Decodes the value from specified sequence to of .
+ ///
+ /// SequenceReader<byte>.
+ /// of which will store the decoded binary.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// The length of the decoded value.
+ /// This value can be 0 for empty string.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract int DecodeString(ref SequenceReader source, Span buffer, out int requestHint, Encoding? encoding = null, CancellationToken cancellationToken = default);
+
+ ///
+ /// Decodes the value or null from specified sequence to of .
+ ///
+ /// SequenceReader<byte>.
+ /// of which will store the decoded binary.
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ ///
+ /// The length of the decoded value;
+ /// null when the underlying value is null.
+ /// This value can be 0 for empty string.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public int? DecodeNullableString(ref SequenceReader source, Span buffer, Encoding? encoding = null, CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeNullableString(ref source, buffer, out var requestHint, encoding, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForString(source.Consumed, typeof(String), encoding, requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes the value or null from specified sequence to of .
+ ///
+ /// SequenceReader<byte>.
+ /// of which will store the decoded binary.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ ///
+ /// The length of the decoded value;
+ /// null when the underlying value is null.
+ /// This value can be 0 for empty string.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract int? DecodeNullableString(ref SequenceReader source, Span buffer, out int requestHint, Encoding? encoding = null, CancellationToken cancellationToken = default);
+
+
+#if FEATURE_UTF8STRING
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Utf8String DecodeUtf8String(ref SequenceReader source, Encoding? encoding = null, CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeUtf8String(ref source, out var requestHint, encoding, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForUtf8String(source.Consumed, typeof(Utf8String), encoding, requestHint);
+ }
+
+ return result!;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract Utf8String? DecodeUtf8String(ref SequenceReader source, out int requestHint, Encoding? encoding = null, CancellationToken cancellationToken = default);
+
+ ///
+ /// Decodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public Utf8String? DecodeNullableUtf8String(ref SequenceReader source, Encoding? encoding = null, CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeNullableUtf8String(ref source, out var requestHint, encoding, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForUtf8String(source.Consumed, typeof(Utf8String), encoding, requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract Utf8String? DecodeNullableUtf8String(ref SequenceReader source, out int requestHint, Encoding? encoding = null, CancellationToken cancellationToken = default);
+
+ ///
+ /// Decodes the value from specified sequence to .
+ ///
+ /// SequenceReader<byte>.
+ /// which will store the decoded binary.
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// The length of the decoded value.
+ /// This value can be 0 for empty string.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public int DecodeUtf8String(ref SequenceReader source, Utf8Span buffer, Encoding? encoding = null, CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeUtf8String(ref source, buffer, out var requestHint, encoding, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForUtf8String(source.Consumed, typeof(Utf8String), encoding, requestHint);
+ }
+
+ return result!;
+ }
+
+ ///
+ /// Decodes the value from specified sequence to .
+ ///
+ /// SequenceReader<byte>.
+ /// which will store the decoded binary.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// The length of the decoded value.
+ /// This value can be 0 for empty string.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract int DecodeUtf8String(ref SequenceReader source, Utf8Span buffer, out int requestHint, Encoding? encoding = null, CancellationToken cancellationToken = default);
+
+ ///
+ /// Decodes the value or null from specified sequence to .
+ ///
+ /// SequenceReader<byte>.
+ /// which will store the decoded binary.
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ ///
+ /// The length of the decoded value;
+ /// null when the underlying value is null.
+ /// This value can be 0 for empty string.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public int? DecodeNullableUtf8String(ref SequenceReader source, Utf8Span buffer, Encoding? encoding = null, CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeNullableUtf8String(ref source, buffer, out var requestHint, encoding, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForUtf8String(source.Consumed, typeof(Utf8String), encoding, requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes the value or null from specified sequence to .
+ ///
+ /// SequenceReader<byte>.
+ /// which will store the decoded binary.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ /// Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM.
+ ///
+ /// The length of the decoded value;
+ /// null when the underlying value is null.
+ /// This value can be 0 for empty string.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract int? DecodeNullableUtf8String(ref SequenceReader source, Utf8Span buffer, out int requestHint, Encoding? encoding = null, CancellationToken cancellationToken = default);
+
+
+#endif // FEATURE_UTF8STRING
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public byte[] DecodeBinary(ref SequenceReader source, CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeBinary(ref source, out var requestHint, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(byte[]), requestHint);
+ }
+
+ return result!;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract byte[]? DecodeBinary(ref SequenceReader source, out int requestHint, CancellationToken cancellationToken = default);
+
+ ///
+ /// Decodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public byte[]? DecodeNullableBinary(ref SequenceReader source, CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeNullableBinary(ref source, out var requestHint, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(byte[]), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract byte[]? DecodeNullableBinary(ref SequenceReader source, out int requestHint, CancellationToken cancellationToken = default);
+
+ ///
+ /// Decodes the value from specified sequence to of .
+ ///
+ /// SequenceReader<byte>.
+ /// of which will store the decoded binary.
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// The length of the decoded value.
+ /// This value can be 0 for empty string.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public int DecodeBinary(ref SequenceReader source, Span buffer, CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeBinary(ref source, buffer, out var requestHint, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(byte[]), requestHint);
+ }
+
+ return result!;
+ }
+
+ ///
+ /// Decodes the value from specified sequence to of .
+ ///
+ /// SequenceReader<byte>.
+ /// of which will store the decoded binary.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// The length of the decoded value.
+ /// This value can be 0 for empty string.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract int DecodeBinary(ref SequenceReader source, Span buffer, out int requestHint, CancellationToken cancellationToken = default);
+
+ ///
+ /// Decodes the value or null from specified sequence to of .
+ ///
+ /// SequenceReader<byte>.
+ /// of which will store the decoded binary.
+ ///
+ /// The length of the decoded value;
+ /// null when the underlying value is null.
+ /// This value can be 0 for empty string.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public int? DecodeNullableBinary(ref SequenceReader source, Span buffer, CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeNullableBinary(ref source, buffer, out var requestHint, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput(source.Consumed, typeof(byte[]), requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes the value or null from specified sequence to of .
+ ///
+ /// SequenceReader<byte>.
+ /// of which will store the decoded binary.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// The length of the decoded value;
+ /// null when the underlying value is null.
+ /// This value can be 0 for empty string.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract int? DecodeNullableBinary(ref SequenceReader source, Span buffer, out int requestHint, CancellationToken cancellationToken = default);
+
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FormatDecoder.Strings.tt b/src/MsgPack.Abstraction/Internal/FormatDecoder.Strings.tt
new file mode 100644
index 000000000..b949abac6
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FormatDecoder.Strings.tt
@@ -0,0 +1,301 @@
+<#@ template debug="false" hostspecific="false" language="C#" #>
+<#@ output extension=".cs" #>
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+//
+// This file is generated from acompanying .tt file.
+// DO NOT edit this file directly, edit .tt file instead.
+
+#nullable enable
+
+using System;
+using System.Buffers;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading;
+
+namespace MsgPack.Internal
+{
+ partial class FormatDecoder
+ {
+<#
+foreach (var spec in new [] {
+ new
+ {
+ Name = "String", Type = "String", SpanType = "Span", ThrowSuffix = "ForString", SpanTypeDoc = " of ",
+ ExtraParameters = "Encoding? encoding = null, ",
+ ExtraParameterDocs = new [] { "Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM." },
+ ExtraArguments = "encoding, ", IfDef = String.Empty
+ },
+ new
+ {
+ Name = "Utf8String", Type = "Utf8String", SpanType = "Utf8Span", ThrowSuffix = "ForUtf8String", SpanTypeDoc = "",
+ ExtraParameters = "Encoding? encoding = null, ",
+ ExtraParameterDocs = new [] { "Specify charactor encoding. This value can be omitted, and default is UTF-8 without BOM." },
+ ExtraArguments = "encoding, ", IfDef = "FEATURE_UTF8STRING"
+ },
+ new
+ {
+ Name = "Binary", Type = "byte[]", SpanType = "Span", ThrowSuffix = String.Empty, SpanTypeDoc = " of ",
+ ExtraParameters = String.Empty,
+ ExtraParameterDocs = Array.Empty(),
+ ExtraArguments = String.Empty, IfDef = String.Empty
+ },
+})
+{
+ if (!String.IsNullOrEmpty(spec.IfDef))
+ {
+#>
+
+#if <#= spec.IfDef #>
+
+<#
+ }
+#>
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+<#
+ foreach (var doc in spec.ExtraParameterDocs)
+ {
+#>
+ /// <#= doc #>
+<#
+ }
+#>
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public <#= spec.Type #> Decode<#= spec.Name #>(ref SequenceReader source, <#= spec.ExtraParameters #>CancellationToken cancellationToken = default)
+ {
+ var result = this.Decode<#= spec.Name #>(ref source, out var requestHint, <#= spec.ExtraArguments #>cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput<#= spec.ThrowSuffix #>(source.Consumed, typeof(<#= spec.Type #>), <#= spec.ExtraArguments #>requestHint);
+ }
+
+ return result!;
+ }
+
+ ///
+ /// Decodes value from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+<#
+ foreach (var doc in spec.ExtraParameterDocs)
+ {
+#>
+ /// <#= doc #>
+<#
+ }
+#>
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract <#= spec.Type #>? Decode<#= spec.Name #>(ref SequenceReader source, out int requestHint, <#= spec.ExtraParameters #>CancellationToken cancellationToken = default);
+
+ ///
+ /// Decodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+<#
+ foreach (var doc in spec.ExtraParameterDocs)
+ {
+#>
+ /// <#= doc #>
+<#
+ }
+#>
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public <#= spec.Type #>? DecodeNullable<#= spec.Name #>(ref SequenceReader source, <#= spec.ExtraParameters #>CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeNullable<#= spec.Name #>(ref source, out var requestHint, <#= spec.ExtraArguments #>cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput<#= spec.ThrowSuffix #>(source.Consumed, typeof(<#= spec.Type #>), <#= spec.ExtraArguments #>requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes value or null from specified sequence.
+ ///
+ /// SequenceReader<byte>.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+<#
+ foreach (var doc in spec.ExtraParameterDocs)
+ {
+#>
+ /// <#= doc #>
+<#
+ }
+#>
+ ///
+ /// Decoded value if this method succeeds to decode value.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract <#= spec.Type #>? DecodeNullable<#= spec.Name #>(ref SequenceReader source, out int requestHint, <#= spec.ExtraParameters #>CancellationToken cancellationToken = default);
+
+ ///
+ /// Decodes the value from specified sequence to <#= spec.SpanTypeDoc #>.
+ ///
+ /// SequenceReader<byte>.
+ /// <#= spec.SpanTypeDoc #> which will store the decoded binary.
+<#
+ foreach (var doc in spec.ExtraParameterDocs)
+ {
+#>
+ /// <#= doc #>
+<#
+ }
+#>
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// The length of the decoded value.
+ /// This value can be 0 for empty string.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public int Decode<#= spec.Name #>(ref SequenceReader source, <#= spec.SpanType #> buffer, <#= spec.ExtraParameters #>CancellationToken cancellationToken = default)
+ {
+ var result = this.Decode<#= spec.Name #>(ref source, buffer, out var requestHint, <#= spec.ExtraArguments #>cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput<#= spec.ThrowSuffix #>(source.Consumed, typeof(<#= spec.Type #>), <#= spec.ExtraArguments #>requestHint);
+ }
+
+ return result!;
+ }
+
+ ///
+ /// Decodes the value from specified sequence to <#= spec.SpanTypeDoc #>.
+ ///
+ /// SequenceReader<byte>.
+ /// <#= spec.SpanTypeDoc #> which will store the decoded binary.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+<#
+ foreach (var doc in spec.ExtraParameterDocs)
+ {
+#>
+ /// <#= doc #>
+<#
+ }
+#>
+ /// to cancel long running operation. This value can be omitted.
+ ///
+ /// The length of the decoded value.
+ /// This value can be 0 for empty string.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ public abstract int Decode<#= spec.Name #>(ref SequenceReader source, <#= spec.SpanType #> buffer, out int requestHint, <#= spec.ExtraParameters #>CancellationToken cancellationToken = default);
+
+ ///
+ /// Decodes the value or null from specified sequence to <#= spec.SpanTypeDoc #>.
+ ///
+ /// SequenceReader<byte>.
+ /// <#= spec.SpanTypeDoc #> which will store the decoded binary.
+<#
+ foreach (var doc in spec.ExtraParameterDocs)
+ {
+#>
+ /// <#= doc #>
+<#
+ }
+#>
+ ///
+ /// The length of the decoded value;
+ /// null when the underlying value is null.
+ /// This value can be 0 for empty string.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public int? DecodeNullable<#= spec.Name #>(ref SequenceReader source, <#= spec.SpanType #> buffer, <#= spec.ExtraParameters #>CancellationToken cancellationToken = default)
+ {
+ var result = this.DecodeNullable<#= spec.Name #>(ref source, buffer, out var requestHint, <#= spec.ExtraArguments #>cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInput<#= spec.ThrowSuffix #>(source.Consumed, typeof(<#= spec.Type #>), <#= spec.ExtraArguments #>requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes the value or null from specified sequence to <#= spec.SpanTypeDoc #>.
+ ///
+ /// SequenceReader<byte>.
+ /// <#= spec.SpanTypeDoc #> which will store the decoded binary.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+<#
+ foreach (var doc in spec.ExtraParameterDocs)
+ {
+#>
+ /// <#= doc #>
+<#
+ }
+#>
+ ///
+ /// The length of the decoded value;
+ /// null when the underlying value is null.
+ /// This value can be 0 for empty string.
+ /// Note that the value of this return is not defined when is 0.
+ ///
+ /// contains valid byte sequence for the underlying format.
+ /// The underlying format value is not compatible to type.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract int? DecodeNullable<#= spec.Name #>(ref SequenceReader source, <#= spec.SpanType #> buffer, out int requestHint, <#= spec.ExtraParameters #>CancellationToken cancellationToken = default);
+
+<#
+ if (!String.IsNullOrEmpty(spec.IfDef))
+ {
+#>
+
+#endif // <#= spec.IfDef #>
+
+<#
+ }
+}
+#>
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FormatDecoder.cs b/src/MsgPack.Abstraction/Internal/FormatDecoder.cs
new file mode 100644
index 000000000..684ea87ef
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FormatDecoder.cs
@@ -0,0 +1,258 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System;
+using System.Buffers;
+using System.Runtime.CompilerServices;
+using System.Threading;
+
+namespace MsgPack.Internal
+{
+ ///
+ /// Defines an interface and basic functionarity of stateless .
+ ///
+ ///
+ /// The is stateless, so caller (serializer, writer, etc.) can cache the instance for performance.
+ ///
+ public abstract partial class FormatDecoder
+ {
+ public FormatDecoderOptions Options { get; }
+
+ protected FormatDecoder(FormatDecoderOptions options)
+ {
+ this.Options = Ensure.NotNull(options);
+ }
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void Skip(ref SequenceReader source, in CollectionContext collectionContext, CancellationToken cancellationToken = default)
+ {
+ this.Skip(ref source, collectionContext, out var requestHint, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForSkip(source.Consumed, requestHint);
+ }
+ }
+
+ public abstract void Skip(ref SequenceReader source, in CollectionContext collectionContext, out int requestHint, CancellationToken cancellationToken = default);
+
+ public void DecodeItem(ref SequenceReader source, out DecodeItemResult result, CancellationToken cancellationToken = default)
+ {
+ this.DecodeItem(ref source, out result, out var requestHint, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForAnyItem(source.Consumed, requestHint);
+ }
+ }
+
+ public abstract void DecodeItem(ref SequenceReader source, out DecodeItemResult result, out int requestHint, CancellationToken cancellationToken = default);
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void GetRawString(ref SequenceReader source, out ReadOnlySpan rawString, CancellationToken cancellationToken = default)
+ {
+ if (!this.GetRawString(ref source, out rawString, out var requestHint, cancellationToken))
+ {
+ Throw.InsufficientInputForRawString(source.Consumed, requestHint);
+ }
+ }
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public bool TryDecodeNull(ref SequenceReader source)
+ {
+ if (this.TryDecodeNull(ref source, out var requestHint))
+ {
+ return true;
+ }
+
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForNull(source.Consumed, requestHint);
+ }
+
+ return false;
+ }
+
+ public abstract bool TryDecodeNull(ref SequenceReader source, out int requestHint);
+
+
+ public abstract bool GetRawString(ref SequenceReader source, out ReadOnlySpan rawString, out int requestHint, CancellationToken cancellationToken = default);
+
+ ///
+ /// Decodes current data as array or map header, and returns the items count if known.
+ ///
+ /// Reader of source byte sequence. If and only if this method succeeds, the reader will be advanced.
+ /// Items count if known; -1 if underlying format does not contain any count information; 0 if underlying format is not an array nor a map.
+ ///
+ /// for array, for map (dictionary).
+ /// This method does not return anything else, but may throw an exception.
+ ///
+ /// The decoded value is not an array nor a map.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public CollectionType DecodeArrayOrMapHeader(ref SequenceReader source, out int itemsCount)
+ {
+ var result = this.DecodeArrayOrMapHeader(ref source, out itemsCount, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForDecodeArrayOrMapHeader(source.Consumed, requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes current data as array or map header, and returns the items count if known.
+ ///
+ /// Reader of source byte sequence. If and only if this method succeeds, the reader will be advanced.
+ /// Items count if known; -1 if underlying format does not contain any count information; 0 if underlying format is not an array nor a map.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// for array, for map (dictionary), or if there were not enough bytes to decode.
+ /// This method does not return anything else, but may throw an exception.
+ ///
+ /// The decoded value is not an array nor a map.
+ public abstract CollectionType DecodeArrayOrMapHeader(ref SequenceReader source, out int itemsCount, out int requestHint);
+
+ ///
+ /// Decodes current data as array header, and returns the items count if known.
+ ///
+ /// Reader of source byte sequence. If and only if this method succeeds, the reader will be advanced.
+ ///
+ /// Items count if known; -1 if underlying format does not contain any count information.
+ /// Note that 0 is valid value when the array is empty.
+ ///
+ /// The decoded value is not an array.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public int DecodeArrayHeader(ref SequenceReader source)
+ {
+ var result = this.DecodeArrayHeader(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForDecodeArrayHeader(source.Consumed, requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes current data as array header, and returns the items count if known.
+ ///
+ /// Reader of source byte sequence. If and only if this method succeeds, the reader will be advanced.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Items count if known; -1 if underlying format does not contain any count information.
+ /// Note that 0 is valid value when the array is empty.
+ ///
+ /// The decoded value is not an array.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public abstract int DecodeArrayHeader(ref SequenceReader source, out int requestHint);
+
+ ///
+ /// Decodes current data as map header, and returns the items count if known.
+ ///
+ /// Reader of source byte sequence. If and only if this method succeeds, the reader will be advanced.
+ ///
+ /// Items count if known; -1 if underlying format does not contain any count information.
+ /// Note that 0 is valid value when the map is empty.
+ ///
+ /// The decoded value is not a map.
+ /// does not contain enough bytes to decode.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public int DecodeMapHeader(ref SequenceReader source)
+ {
+ var result = this.DecodeMapHeader(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForDecodeMapHeader(source.Consumed, requestHint);
+ }
+
+ return result;
+ }
+
+ ///
+ /// Decodes current data as map header, and returns the items count if known.
+ ///
+ /// Reader of source byte sequence. If and only if this method succeeds, the reader will be advanced.
+ ///
+ /// 0 if this method succeeds to decode value; Positive integer when does not contain enough bytes to decode, and required memory bytes hint is stored.
+ /// Note that -1 represents unknown size. If so, caller must supply new buffer with most efficient size.
+ ///
+ ///
+ /// Items count if known; -1 if underlying format does not contain any count information.
+ /// Note that 0 is valid value when the map is empty.
+ ///
+ /// The decoded value is not a map.
+ public abstract int DecodeMapHeader(ref SequenceReader source, out int requestHint);
+
+ public virtual void DecodeExtension(ref SequenceReader source, out ExtensionTypeObject result, out int requestHint, CancellationToken cancellationToken = default)
+ {
+ Throw.ExtensionsIsNotSupported();
+ // never
+ result = default;
+ requestHint = -1;
+ }
+
+ public CollectionType DecodeArrayOrMap(ref SequenceReader source, out CollectionItemIterator iterator)
+ {
+ var result = this.DecodeArrayOrMap(ref source, out iterator, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForDecodeArrayOrMapHeader(source.Consumed, requestHint);
+ }
+
+ return result;
+ }
+
+ public abstract CollectionType DecodeArrayOrMap(ref SequenceReader source, out CollectionItemIterator iterator, out int requestHint);
+
+ public CollectionItemIterator DecodeArray(ref SequenceReader source)
+ {
+ var result = this.DecodeArray(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForDecodeArrayHeader(source.Consumed, requestHint);
+ }
+
+ return result;
+ }
+
+ public abstract CollectionItemIterator DecodeArray(ref SequenceReader source, out int requestHint);
+
+ public CollectionItemIterator DecodeMap(ref SequenceReader source)
+ {
+ var result = this.DecodeMap(ref source, out var requestHint);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForDecodeMapHeader(source.Consumed, requestHint);
+ }
+
+ return result;
+ }
+
+ public abstract CollectionItemIterator DecodeMap(ref SequenceReader source, out int requestHint);
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void Drain(ref SequenceReader source, in CollectionContext collectionContext, long itemsCount, CancellationToken cancellationToken = default)
+ {
+ if (itemsCount <= 0)
+ {
+ return;
+ }
+
+ this.Drain(ref source, collectionContext, itemsCount, out var requestHint, cancellationToken);
+ if (requestHint != 0)
+ {
+ Throw.InsufficientInputForDecodeMapHeader(source.Consumed, requestHint);
+ }
+ }
+
+ public abstract void Drain(ref SequenceReader source, in CollectionContext collectionContext, long itemsCount, out int requestHint, CancellationToken cancellationToken = default);
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FormatDecoderOptions.cs b/src/MsgPack.Abstraction/Internal/FormatDecoderOptions.cs
new file mode 100644
index 000000000..6fa191e60
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FormatDecoderOptions.cs
@@ -0,0 +1,51 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System.Buffers;
+using MsgPack.Codecs;
+
+namespace MsgPack.Internal
+{
+ public abstract class FormatDecoderOptions
+ {
+ public bool CanTreatRealAsInteger { get; }
+
+ public int CancellationSupportThreshold { get; }
+
+ public ArrayPool ByteBufferPool { get; }
+
+ public ArrayPool CharBufferPool { get; }
+
+ public int MaxByteBufferLength { get; }
+
+ public int MaxCharBufferLength { get; }
+
+ public int MaxNumberLengthInBytes { get; }
+
+ public int MaxStringLengthInBytes { get; }
+
+ public int MaxBinaryLengthInBytes { get; }
+
+ public bool ClearsBuffer { get; }
+
+ public CodecFeatures Features { get; }
+
+ protected FormatDecoderOptions(FormatDecoderOptionsBuilder builder, CodecFeatures features)
+ {
+ builder = Ensure.NotNull(builder);
+
+ this.CanTreatRealAsInteger = builder.CanTreatRealAsInteger;
+ this.CancellationSupportThreshold = builder.CancellationSupportThreshold;
+ this.ClearsBuffer = builder.ClearsBuffer;
+ this.ByteBufferPool = builder.ByteBufferPool;
+ this.CharBufferPool = builder.CharBufferPool;
+ this.MaxByteBufferLength = builder.MaxByteBufferLength;
+ this.MaxCharBufferLength = builder.MaxCharBufferLength;
+ this.MaxNumberLengthInBytes = builder.MaxNumberLengthInBytes;
+ this.MaxStringLengthInBytes = builder.MaxStringLengthInBytes;
+ this.MaxBinaryLengthInBytes = builder.MaxBinaryLengthInBytes;
+ this.Features = Ensure.NotNull(features);
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FormatDecoderOptionsBuilder.cs b/src/MsgPack.Abstraction/Internal/FormatDecoderOptionsBuilder.cs
new file mode 100644
index 000000000..44b584d1a
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FormatDecoderOptionsBuilder.cs
@@ -0,0 +1,94 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System.Buffers;
+
+namespace MsgPack.Internal
+{
+#warning Remove unused buffer max pr rename to initial buffer length if appropriate.
+ public abstract class FormatDecoderOptionsBuilder
+ {
+ public bool CanTreatRealAsInteger { get; set; } = OptionsDefaults.CanTreatRealAsInteger;
+
+ private int _cancellationSupportThreshold = OptionsDefaults.CancellationSupportThreshold;
+
+ public int CancellationSupportThreshold
+ {
+ get => this._cancellationSupportThreshold;
+ set => this._cancellationSupportThreshold = Ensure.IsNotLessThan(value, 1);
+ }
+
+ private int _maxNumberLengthInBytes = OptionsDefaults.MaxNumberLengthInBytes;
+
+ public int MaxNumberLengthInBytes
+ {
+ get => this._maxNumberLengthInBytes;
+ set => this._maxNumberLengthInBytes = Ensure.IsBetween(value, 1, OptionsDefaults.MaxSingleByteCollectionLength);
+ }
+
+ private int _maxStringLengthInBytes = OptionsDefaults.MaxStringLengthInBytes;
+
+ public int MaxStringLengthInBytes
+ {
+ get => this._maxStringLengthInBytes;
+ set => this._maxStringLengthInBytes = Ensure.IsBetween(value, 1, OptionsDefaults.MaxMultiByteCollectionLength);
+ }
+
+ private int _naxBinaryLengthInBytes = OptionsDefaults.MaxBinaryLengthInBytes;
+
+ public int MaxBinaryLengthInBytes
+ {
+ get => this._naxBinaryLengthInBytes;
+ set => this._naxBinaryLengthInBytes = Ensure.IsBetween(value, 1, OptionsDefaults.MaxSingleByteCollectionLength);
+ }
+
+ private int _maxByteBufferLength = OptionsDefaults.MaxByteBufferLength;
+
+ public int MaxByteBufferLength
+ {
+ get => this._maxByteBufferLength;
+ set => this._maxByteBufferLength = Ensure.IsNotLessThan(value, 4);
+ }
+
+ private int _maxCharBufferLength = OptionsDefaults.MaxCharBufferLength;
+
+ public int MaxCharBufferLength
+ {
+ get => this._maxCharBufferLength;
+ set => this._maxCharBufferLength = Ensure.IsNotLessThan(value, 2);
+ }
+
+ private ArrayPool _byteBufferPool = OptionsDefaults.ByteBufferPool;
+
+ public ArrayPool ByteBufferPool
+ {
+ get => this._byteBufferPool;
+ set => this._byteBufferPool = Ensure.NotNull(value);
+ }
+
+ private ArrayPool _charBufferPool = OptionsDefaults.CharBufferPool;
+
+ public ArrayPool CharBufferPool
+ {
+ get => this._charBufferPool;
+ set => this._charBufferPool = Ensure.NotNull(value);
+ }
+
+ public bool ClearsBuffer { get; set; } = OptionsDefaults.ClearsBufferOnReturn;
+
+ protected FormatDecoderOptionsBuilder() { }
+
+ public FormatDecoderOptionsBuilder WithoutBufferClear()
+ {
+ this.ClearsBuffer = false;
+ return this;
+ }
+
+ public FormatDecoderOptionsBuilder ProhibitTreatRealAsInteger()
+ {
+ this.CanTreatRealAsInteger = false;
+ return this;
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FormatEncoder.Primitives.cs b/src/MsgPack.Abstraction/Internal/FormatEncoder.Primitives.cs
new file mode 100644
index 000000000..0c4701a06
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FormatEncoder.Primitives.cs
@@ -0,0 +1,228 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+//
+// This file is generated from acompanying .tt file.
+// DO NOT edit this file directly, edit .tt file instead.
+
+using System;
+using System.Buffers;
+using System.Runtime.CompilerServices;
+
+namespace MsgPack.Internal
+{
+ partial class FormatEncoder
+ {
+ ///
+ /// Encodes value to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ /// is null.
+ /// The underlying format does not suppor this type.
+ public abstract void EncodeInt32(Int32 value, IBufferWriter buffer);
+
+ ///
+ /// Encodes value or null to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void EncodeInt32(Int32? value, IBufferWriter buffer)
+ {
+ buffer = Ensure.NotNull(buffer);
+
+ if (value == null)
+ {
+ this.EncodeNull(buffer);
+ }
+ else
+ {
+ this.EncodeInt32(value.GetValueOrDefault(), buffer);
+ }
+ }
+ ///
+ /// Encodes value to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ /// is null.
+ /// The underlying format does not suppor this type.
+ public abstract void EncodeInt64(Int64 value, IBufferWriter buffer);
+
+ ///
+ /// Encodes value or null to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void EncodeInt64(Int64? value, IBufferWriter buffer)
+ {
+ buffer = Ensure.NotNull(buffer);
+
+ if (value == null)
+ {
+ this.EncodeNull(buffer);
+ }
+ else
+ {
+ this.EncodeInt64(value.GetValueOrDefault(), buffer);
+ }
+ }
+ ///
+ /// Encodes value to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ /// is null.
+ /// The underlying format does not suppor this type.
+ public abstract void EncodeUInt32(UInt32 value, IBufferWriter buffer);
+
+ ///
+ /// Encodes value or null to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void EncodeUInt32(UInt32? value, IBufferWriter buffer)
+ {
+ buffer = Ensure.NotNull(buffer);
+
+ if (value == null)
+ {
+ this.EncodeNull(buffer);
+ }
+ else
+ {
+ this.EncodeUInt32(value.GetValueOrDefault(), buffer);
+ }
+ }
+ ///
+ /// Encodes value to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ /// is null.
+ /// The underlying format does not suppor this type.
+ public abstract void EncodeUInt64(UInt64 value, IBufferWriter buffer);
+
+ ///
+ /// Encodes value or null to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void EncodeUInt64(UInt64? value, IBufferWriter buffer)
+ {
+ buffer = Ensure.NotNull(buffer);
+
+ if (value == null)
+ {
+ this.EncodeNull(buffer);
+ }
+ else
+ {
+ this.EncodeUInt64(value.GetValueOrDefault(), buffer);
+ }
+ }
+ ///
+ /// Encodes value to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ /// is null.
+ /// The underlying format does not suppor this type.
+ public abstract void EncodeSingle(Single value, IBufferWriter buffer);
+
+ ///
+ /// Encodes value or null to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void EncodeSingle(Single? value, IBufferWriter buffer)
+ {
+ buffer = Ensure.NotNull(buffer);
+
+ if (value == null)
+ {
+ this.EncodeNull(buffer);
+ }
+ else
+ {
+ this.EncodeSingle(value.GetValueOrDefault(), buffer);
+ }
+ }
+ ///
+ /// Encodes value to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ /// is null.
+ /// The underlying format does not suppor this type.
+ public abstract void EncodeDouble(Double value, IBufferWriter buffer);
+
+ ///
+ /// Encodes value or null to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void EncodeDouble(Double? value, IBufferWriter buffer)
+ {
+ buffer = Ensure.NotNull(buffer);
+
+ if (value == null)
+ {
+ this.EncodeNull(buffer);
+ }
+ else
+ {
+ this.EncodeDouble(value.GetValueOrDefault(), buffer);
+ }
+ }
+ ///
+ /// Encodes value to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ /// is null.
+ /// The underlying format does not suppor this type.
+ public abstract void EncodeBoolean(Boolean value, IBufferWriter buffer);
+
+ ///
+ /// Encodes value or null to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void EncodeBoolean(Boolean? value, IBufferWriter buffer)
+ {
+ buffer = Ensure.NotNull(buffer);
+
+ if (value == null)
+ {
+ this.EncodeNull(buffer);
+ }
+ else
+ {
+ this.EncodeBoolean(value.GetValueOrDefault(), buffer);
+ }
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FormatEncoder.Primitives.tt b/src/MsgPack.Abstraction/Internal/FormatEncoder.Primitives.tt
new file mode 100644
index 000000000..939f76871
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FormatEncoder.Primitives.tt
@@ -0,0 +1,65 @@
+<#@ template debug="false" hostspecific="false" language="C#" #>
+<#@ output extension=".cs" #>
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+//
+// This file is generated from acompanying .tt file.
+// DO NOT edit this file directly, edit .tt file instead.
+
+using System;
+using System.Buffers;
+using System.Runtime.CompilerServices;
+
+namespace MsgPack.Internal
+{
+ partial class FormatEncoder
+ {
+<#
+foreach (var inputType in new [] {
+ "Int32",
+ "Int64",
+ "UInt32",
+ "UInt64",
+ "Single",
+ "Double",
+ "Boolean"
+})
+{
+#>
+ ///
+ /// Encodes value to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ /// is null.
+ /// The underlying format does not suppor this type.
+ public abstract void Encode<#= inputType #>(<#= inputType #> value, IBufferWriter buffer);
+
+ ///
+ /// Encodes value or null to specified buffer.
+ /// The implementation will choose most compact format.
+ ///
+ /// Value to be encoded.
+ /// IBufferWriter<byte>.
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void Encode<#= inputType #>(<#= inputType #>? value, IBufferWriter buffer)
+ {
+ buffer = Ensure.NotNull(buffer);
+
+ if (value == null)
+ {
+ this.EncodeNull(buffer);
+ }
+ else
+ {
+ this.Encode<#= inputType #>(value.GetValueOrDefault(), buffer);
+ }
+ }
+<#
+}
+#>
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FormatEncoder.cs b/src/MsgPack.Abstraction/Internal/FormatEncoder.cs
new file mode 100644
index 000000000..928c1e26c
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FormatEncoder.cs
@@ -0,0 +1,186 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System;
+using System.Buffers;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading;
+
+namespace MsgPack.Internal
+{
+ ///
+ /// Defines an interface and basic functionarity of stateless .
+ ///
+ ///
+ /// The is stateless, so caller (serializer, reader, etc.) can cache the instance for performance.
+ ///
+ public abstract partial class FormatEncoder
+ {
+ public FormatEncoderOptions Options { get; }
+
+ protected FormatEncoder(FormatEncoderOptions options)
+ {
+ this.Options = Ensure.NotNull(options);
+ }
+
+ public abstract void EncodeNull(IBufferWriter buffer);
+
+#if FEATURE_UTF8STRING
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void EncodeString(Utf8String? value, IBufferWriter buffer)
+ => this.EncodeString(value.AsBytes(), buffer);
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void EncodeString(Utf8Span value, IBufferWriter buffer)
+ => this.EncodeString(value.AsBytes(), buffer);
+#endif // FEATURE_UTF8STRING
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void EncodeString(string? value, IBufferWriter buffer, Encoding? encoding = null, CancellationToken cancellationToken = default)
+ {
+ if (value == null)
+ {
+ this.EncodeNull(buffer);
+ return;
+ }
+
+ this.EncodeString(value.AsSpan(), buffer, encoding, cancellationToken);
+ }
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void EncodeString(StringBuilder? value, IBufferWriter buffer, Encoding? encoding = null, CancellationToken cancellationToken = default)
+ {
+ if (value == null)
+ {
+ this.EncodeNull(buffer);
+ return;
+ }
+
+ this.EncodeString(value.ToSequence(), buffer, encoding, cancellationToken);
+ }
+
+ public abstract void EncodeString(ReadOnlySpan value, IBufferWriter buffer, Encoding? encoding = null, CancellationToken cancellationToken = default);
+
+ public abstract void EncodeString(in ReadOnlySequence value, IBufferWriter buffer, Encoding? encoding = null, CancellationToken cancellationToken = default);
+
+ public abstract void EncodeString(ReadOnlySpan encodedValue, int charLength, IBufferWriter buffer, CancellationToken cancellationToken = default);
+
+ public abstract void EncodeString(in ReadOnlySequence encodedValue, int charLength, IBufferWriter buffer, CancellationToken cancellationToken = default);
+
+ public abstract void EncodeRawString(ReadOnlySpan rawString, int charLength, IBufferWriter buffer, CancellationToken cancellationToken = default);
+
+ public abstract void EncodeBinary(ReadOnlySpan value, IBufferWriter buffer, CancellationToken cancellationToken = default);
+
+ public abstract void EncodeBinary(in ReadOnlySequence value, IBufferWriter buffer, CancellationToken cancellationToken = default);
+
+ public abstract void EncodeArrayStart(int length, IBufferWriter buffer, in CollectionContext collectionContext);
+
+ public abstract void EncodeArrayEnd(int length, IBufferWriter buffer, in CollectionContext collectionContext);
+
+ public abstract void EncodeArrayItemStart(int index, IBufferWriter buffer, in CollectionContext collectionContext);
+
+ public abstract void EncodeArrayItemEnd(int index, IBufferWriter buffer, in CollectionContext collectionContext);
+
+ public abstract void EncodeMapStart(int length, IBufferWriter buffer, in CollectionContext collectionContext);
+
+ public abstract void EncodeMapEnd(int length, IBufferWriter buffer, in CollectionContext collectionContext);
+
+ public abstract void EncodeMapKeyStart(int index, IBufferWriter buffer, in CollectionContext collectionContext);
+
+ public abstract void EncodeMapKeyEnd(int index, IBufferWriter buffer, in CollectionContext collectionContext);
+
+ public abstract void EncodeMapValueStart(int index, IBufferWriter buffer, in CollectionContext collectionContext);
+
+ public abstract void EncodeMapValueEnd(int index, IBufferWriter buffer, in CollectionContext collectionContext);
+
+ public virtual void EncodeExtension(ExtensionType typeCode, ReadOnlySpan serializedValue, IBufferWriter buffer)
+ => Throw.ExtensionsIsNotSupported();
+
+ public virtual void EncodeExtension(ExtensionType typeCode, in ReadOnlySequence serializedValue, IBufferWriter buffer)
+ => Throw.ExtensionsIsNotSupported();
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void WriteRaw(ReadOnlySpan value, IBufferWriter buffer, CancellationToken cancellationToken = default)
+ {
+ if (value.Length <= this.Options.CancellationSupportThreshold)
+ {
+ buffer.Write(value);
+ }
+ else
+ {
+ WriteRawSlow(buffer, value, buffer.GetSpan(), cancellationToken);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void WriteRawSlow(IBufferWriter buffer, in ReadOnlySpan source, Span destination, CancellationToken cancellationToken)
+ {
+ // https://github.com/dotnet/runtime/blob/af1db3eccbc238745e1d163458c92c1bfa650fbd/src/libraries/System.Memory/src/System/Buffers/BuffersExtensions.cs#L133
+ ReadOnlySpan input = source;
+ while (true)
+ {
+ if (destination.IsEmpty)
+ {
+ ThrowBufferWriterReturnsEmptyBuffer(nameof(buffer));
+ }
+
+ var writeSize = Math.Min(destination.Length, input.Length);
+ input.Slice(0, writeSize).CopyTo(destination);
+ buffer.Advance(writeSize);
+ input = input.Slice(writeSize);
+ if (input.Length > 0)
+ {
+ destination = buffer.GetSpan();
+
+ cancellationToken.ThrowIfCancellationRequested();
+ continue;
+ }
+
+ return;
+ }
+ }
+
+ private static void ThrowBufferWriterReturnsEmptyBuffer(string paramName)
+ => throw new ArgumentOutOfRangeException(paramName);
+
+ [MethodImpl(MethodImplOptionsShim.AggressiveInlining)]
+ public void WriteRaw(in ReadOnlySequence value, IBufferWriter buffer, CancellationToken cancellationToken = default)
+ {
+ buffer = Ensure.NotNull(buffer);
+
+ if (value.Length <= this.Options.MaxByteBufferLength)
+ {
+ var length32 = unchecked((int)value.Length);
+ var span = buffer.GetSpan(length32);
+ value.CopyTo(span);
+ buffer.Advance(length32);
+ return;
+ }
+
+ WriteRawSlow(value, buffer, cancellationToken);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void WriteRawSlow(in ReadOnlySequence value, IBufferWriter buffer, CancellationToken cancellationToken = default)
+ {
+ var reader = new SequenceReader(value);
+ while (!reader.End)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var sink = buffer.GetSpan();
+ if (sink.IsEmpty)
+ {
+ ThrowBufferWriterReturnsEmptyBuffer(nameof(buffer));
+ }
+
+ var source = reader.UnreadSpan.Slice(0, Math.Min(sink.Length, reader.UnreadSpan.Length));
+ source.CopyTo(sink);
+ buffer.Advance(source.Length);
+ reader.Advance(source.Length);
+ }
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FormatEncoderOptions.cs b/src/MsgPack.Abstraction/Internal/FormatEncoderOptions.cs
new file mode 100644
index 000000000..53da6645f
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FormatEncoderOptions.cs
@@ -0,0 +1,39 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System.Buffers;
+using MsgPack.Codecs;
+
+namespace MsgPack.Internal
+{
+ public abstract class FormatEncoderOptions
+ {
+ public int CancellationSupportThreshold { get; }
+
+ public int MaxByteBufferLength { get; }
+
+ public int MaxCharBufferLength { get; }
+
+ public ArrayPool ByteBufferPool { get; }
+
+ public ArrayPool CharBufferPool { get; }
+
+ public bool ClearsBuffer { get; }
+
+ public CodecFeatures Features { get; }
+
+ protected FormatEncoderOptions(FormatEncoderOptionsBuilder builder, CodecFeatures features)
+ {
+ builder = Ensure.NotNull(builder);
+
+ this.CancellationSupportThreshold = builder.CancellationSupportThreshold;
+ this.MaxByteBufferLength = builder.MaxByteBufferLength;
+ this.MaxCharBufferLength = builder.MaxCharBufferLength;
+ this.ByteBufferPool = builder.ByteBufferPool;
+ this.CharBufferPool = builder.CharBufferPool;
+ this.ClearsBuffer = builder.ClearsBuffer;
+ this.Features = Ensure.NotNull(features);
+ }
+ }
+}
diff --git a/src/MsgPack.Abstraction/Internal/FormatEncoderOptionsBuilder.cs b/src/MsgPack.Abstraction/Internal/FormatEncoderOptionsBuilder.cs
new file mode 100644
index 000000000..d31f70499
--- /dev/null
+++ b/src/MsgPack.Abstraction/Internal/FormatEncoderOptionsBuilder.cs
@@ -0,0 +1,61 @@
+// Copyright (c) FUJIWARA, Yusuke and all contributors.
+// This file is licensed under Apache2 license.
+// See the LICENSE in the project root for more information.
+
+using System.Buffers;
+
+namespace MsgPack.Internal
+{
+ public abstract class FormatEncoderOptionsBuilder
+ {
+ private int _cancellationSupportThreshold = OptionsDefaults.CancellationSupportThreshold;
+
+ public int CancellationSupportThreshold
+ {
+ get => this._cancellationSupportThreshold;
+ set => this._cancellationSupportThreshold = Ensure.IsNotLessThan(value, 1);
+ }
+
+ private int _maxByteBufferLength = OptionsDefaults.MaxByteBufferLength;
+
+ public int MaxByteBufferLength
+ {
+ get => this._maxByteBufferLength;
+ set => this._maxByteBufferLength = Ensure.IsNotLessThan(value, 4);
+ }
+
+ private int _maxCharBufferLength = OptionsDefaults.MaxCharBufferLength;
+
+ public int MaxCharBufferLength
+ {
+ get => this._maxCharBufferLength;
+ set => this._maxCharBufferLength = Ensure.IsNotLessThan(value, 2);
+ }
+
+ private ArrayPool _byteBufferPool = OptionsDefaults.ByteBufferPool;
+
+ public ArrayPool