diff --git a/.editorconfig b/.editorconfig
index ea126e005b6d..2cfcd6caa9fc 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -9,13 +9,13 @@ trim_trailing_whitespace = true
# Default settings:
# A newline ending every file
# Use 4 spaces as indentation
-[sdk/*/Azure.*/**]
+[sdk/*/{Azure.*,System.*}/**]
insert_final_newline = true
indent_style = space
indent_size = 4
# C# files
-[sdk/*/Azure.*/**.cs]
+[sdk/*/{Azure.*,System.*}/**.cs]
# New line preferences
csharp_new_line_before_open_brace = all # vs-default: any
csharp_new_line_before_else = true # vs-default: true
diff --git a/sdk/core/System.ClientModel/src/.editorconfig b/sdk/core/System.ClientModel/src/.editorconfig
new file mode 100644
index 000000000000..20210a1ece2f
--- /dev/null
+++ b/sdk/core/System.ClientModel/src/.editorconfig
@@ -0,0 +1,2 @@
+[/**.cs]
+csharp_style_namespace_declarations = file_scoped:error
diff --git a/sdk/core/System.ClientModel/src/ModelReaderWriter/IJsonModel.cs b/sdk/core/System.ClientModel/src/ModelReaderWriter/IJsonModel.cs
index 3e4201fd1eeb..0fc498a4da62 100644
--- a/sdk/core/System.ClientModel/src/ModelReaderWriter/IJsonModel.cs
+++ b/sdk/core/System.ClientModel/src/ModelReaderWriter/IJsonModel.cs
@@ -3,33 +3,32 @@
using System.Text.Json;
-namespace System.ClientModel.Primitives
+namespace System.ClientModel.Primitives;
+
+///
+/// Allows an object to control its own JSON writing and reading.
+///
+/// The type the model can be converted into.
+public interface IJsonModel : IPersistableModel
{
///
- /// Allows an object to control its own JSON writing and reading.
+ /// Writes the model to the provided .
///
- /// The type the model can be converted into.
- public interface IJsonModel : IPersistableModel
- {
- ///
- /// Writes the model to the provided .
- ///
- /// The to write into.
- /// The to use.
- /// If the model does not support the requested .
+ /// The to write into.
+ /// The to use.
+ /// If the model does not support the requested .
#pragma warning disable AZC0014 // Avoid using banned types in public API
- void Write(Utf8JsonWriter writer, ModelReaderWriterOptions options);
+ void Write(Utf8JsonWriter writer, ModelReaderWriterOptions options);
#pragma warning restore AZC0014 // Avoid using banned types in public API
- ///
- /// Reads one JSON value (including objects or arrays) from the provided reader and converts it to a model.
- ///
- /// The to read.
- /// The to use.
- /// A representation of the JSON value.
- /// If the model does not support the requested .
+ ///
+ /// Reads one JSON value (including objects or arrays) from the provided reader and converts it to a model.
+ ///
+ /// The to read.
+ /// The to use.
+ /// A representation of the JSON value.
+ /// If the model does not support the requested .
#pragma warning disable AZC0014 // Avoid using banned types in public API
- T Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options);
+ T Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options);
#pragma warning restore AZC0014 // Avoid using banned types in public API
- }
}
diff --git a/sdk/core/System.ClientModel/src/ModelReaderWriter/IPersistableModel.cs b/sdk/core/System.ClientModel/src/ModelReaderWriter/IPersistableModel.cs
index e9085f8a8519..619db66beb63 100644
--- a/sdk/core/System.ClientModel/src/ModelReaderWriter/IPersistableModel.cs
+++ b/sdk/core/System.ClientModel/src/ModelReaderWriter/IPersistableModel.cs
@@ -1,37 +1,36 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-namespace System.ClientModel.Primitives
+namespace System.ClientModel.Primitives;
+
+///
+/// Allows an object to control its own writing and reading.
+/// The format is determined by the implementer.
+///
+/// The type the model can be converted into.
+public interface IPersistableModel
{
///
- /// Allows an object to control its own writing and reading.
- /// The format is determined by the implementer.
+ /// Writes the model into a .
///
- /// The type the model can be converted into.
- public interface IPersistableModel
- {
- ///
- /// Writes the model into a .
- ///
- /// The to use.
- /// A binary representation of the written model.
- /// If the model does not support the requested .
- BinaryData Write(ModelReaderWriterOptions options);
+ /// The to use.
+ /// A binary representation of the written model.
+ /// If the model does not support the requested .
+ BinaryData Write(ModelReaderWriterOptions options);
- ///
- /// Converts the provided into a model.
- ///
- /// The to parse.
- /// The to use.
- /// A representation of the data.
- /// If the model does not support the requested .
- T Create(BinaryData data, ModelReaderWriterOptions options);
+ ///
+ /// Converts the provided into a model.
+ ///
+ /// The to parse.
+ /// The to use.
+ /// A representation of the data.
+ /// If the model does not support the requested .
+ T Create(BinaryData data, ModelReaderWriterOptions options);
- ///
- /// Gets the data interchange format (JSON, Xml, etc) that the model uses when communicating with the service.
- /// The to use.
- ///
- /// The format that the model uses when communicating with the serivce.
- string GetFormatFromOptions(ModelReaderWriterOptions options);
- }
+ ///
+ /// Gets the data interchange format (JSON, Xml, etc) that the model uses when communicating with the service.
+ /// The to use.
+ ///
+ /// The format that the model uses when communicating with the serivce.
+ string GetFormatFromOptions(ModelReaderWriterOptions options);
}
diff --git a/sdk/core/System.ClientModel/src/ModelReaderWriter/JsonModelConverter.cs b/sdk/core/System.ClientModel/src/ModelReaderWriter/JsonModelConverter.cs
index 2c7427abe88a..e6af2dc32edc 100644
--- a/sdk/core/System.ClientModel/src/ModelReaderWriter/JsonModelConverter.cs
+++ b/sdk/core/System.ClientModel/src/ModelReaderWriter/JsonModelConverter.cs
@@ -5,57 +5,56 @@
using System.Text.Json;
using System.Text.Json.Serialization;
-namespace System.ClientModel.Primitives
+namespace System.ClientModel.Primitives;
+
+///
+/// A generic converter which allows to be able to write and read any models that implement .
+///
+[RequiresUnreferencedCode("The constructors of the type being deserialized are dynamically accessed and may be trimmed.")]
+#pragma warning disable AZC0014 // Avoid using banned types in public API
+internal class JsonModelConverter : JsonConverter>
+#pragma warning restore AZC0014 // Avoid using banned types in public API
{
///
- /// A generic converter which allows to be able to write and read any models that implement .
+ /// Gets the used to read and write models.
///
- [RequiresUnreferencedCode("The constructors of the type being deserialized are dynamically accessed and may be trimmed.")]
-#pragma warning disable AZC0014 // Avoid using banned types in public API
- internal class JsonModelConverter : JsonConverter>
-#pragma warning restore AZC0014 // Avoid using banned types in public API
+ public ModelReaderWriterOptions Options { get; }
+
+ ///
+ /// Initializes a new instance of with a default options of .
+ ///
+ public JsonModelConverter()
+ : this(ModelReaderWriterOptions.Json) { }
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The to use.
+ public JsonModelConverter(ModelReaderWriterOptions options)
{
- ///
- /// Gets the used to read and write models.
- ///
- public ModelReaderWriterOptions Options { get; }
-
- ///
- /// Initializes a new instance of with a default options of .
- ///
- public JsonModelConverter()
- : this(ModelReaderWriterOptions.Json) { }
-
- ///
- /// Initializes a new instance of .
- ///
- /// The to use.
- public JsonModelConverter(ModelReaderWriterOptions options)
- {
- Options = options;
- }
-
- ///
- public override bool CanConvert(Type typeToConvert)
- {
- return !Attribute.IsDefined(typeToConvert, typeof(JsonConverterAttribute));
- }
-
- ///
+ Options = options;
+ }
+
+ ///
+ public override bool CanConvert(Type typeToConvert)
+ {
+ return !Attribute.IsDefined(typeToConvert, typeof(JsonConverterAttribute));
+ }
+
+ ///
#pragma warning disable AZC0014 // Avoid using banned types in public API
- public override IJsonModel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override IJsonModel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
#pragma warning restore AZC0014 // Avoid using banned types in public API
- {
- using JsonDocument document = JsonDocument.ParseValue(ref reader);
- return (IJsonModel)ModelReaderWriter.Read(BinaryData.FromString(document.RootElement.GetRawText()), typeToConvert, Options)!;
- }
+ {
+ using JsonDocument document = JsonDocument.ParseValue(ref reader);
+ return (IJsonModel)ModelReaderWriter.Read(BinaryData.FromString(document.RootElement.GetRawText()), typeToConvert, Options)!;
+ }
- ///
+ ///
#pragma warning disable AZC0014 // Avoid using banned types in public API
- public override void Write(Utf8JsonWriter writer, IJsonModel value, JsonSerializerOptions options)
+ public override void Write(Utf8JsonWriter writer, IJsonModel value, JsonSerializerOptions options)
#pragma warning restore AZC0014 // Avoid using banned types in public API
- {
- value.Write(writer, Options);
- }
+ {
+ value.Write(writer, Options);
}
}
diff --git a/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelReaderWriter.cs b/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelReaderWriter.cs
index a5cc631ed687..b22b8b8ae988 100644
--- a/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelReaderWriter.cs
+++ b/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelReaderWriter.cs
@@ -5,179 +5,178 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
-namespace System.ClientModel.Primitives
+namespace System.ClientModel.Primitives;
+
+///
+/// Provides functionality to read and write and .
+///
+public static class ModelReaderWriter
{
///
- /// Provides functionality to read and write and .
+ /// Converts the value of a model into a .
///
- public static class ModelReaderWriter
+ /// The type of the value to write.
+ /// The model to convert.
+ /// The to use.
+ /// A representation of the model in the specified by the .
+ /// If the model does not support the requested .
+ /// If is null.
+ public static BinaryData Write(T model, ModelReaderWriterOptions? options = default)
+ where T : IPersistableModel
{
- ///
- /// Converts the value of a model into a .
- ///
- /// The type of the value to write.
- /// The model to convert.
- /// The to use.
- /// A representation of the model in the specified by the .
- /// If the model does not support the requested .
- /// If is null.
- public static BinaryData Write(T model, ModelReaderWriterOptions? options = default)
- where T : IPersistableModel
+ if (model is null)
{
- if (model is null)
- {
- throw new ArgumentNullException(nameof(model));
- }
+ throw new ArgumentNullException(nameof(model));
+ }
- options ??= ModelReaderWriterOptions.Json;
+ options ??= ModelReaderWriterOptions.Json;
- if (IsJsonFormatRequested(model, options) && model is IJsonModel jsonModel)
- {
- using (ModelWriter writer = new ModelWriter(jsonModel, options))
- {
- return writer.ToBinaryData();
- }
- }
- else
+ if (IsJsonFormatRequested(model, options) && model is IJsonModel jsonModel)
+ {
+ using (ModelWriter writer = new ModelWriter(jsonModel, options))
{
- return model.Write(options);
+ return writer.ToBinaryData();
}
}
+ else
+ {
+ return model.Write(options);
+ }
+ }
- ///
- /// Converts the value of a model into a .
- ///
- /// The model to convert.
- /// The to use.
- /// A representation of the model in the specified by the .
- /// Throws if does not implement .
- /// If the model does not support the requested .
- /// If is null.
- public static BinaryData Write(object model, ModelReaderWriterOptions? options = default)
+ ///
+ /// Converts the value of a model into a .
+ ///
+ /// The model to convert.
+ /// The to use.
+ /// A representation of the model in the specified by the .
+ /// Throws if does not implement .
+ /// If the model does not support the requested .
+ /// If is null.
+ public static BinaryData Write(object model, ModelReaderWriterOptions? options = default)
+ {
+ if (model is null)
{
- if (model is null)
- {
- throw new ArgumentNullException(nameof(model));
- }
+ throw new ArgumentNullException(nameof(model));
+ }
- options ??= ModelReaderWriterOptions.Json;
+ options ??= ModelReaderWriterOptions.Json;
- var iModel = model as IPersistableModel;
- if (iModel is null)
- {
- throw new InvalidOperationException($"{model.GetType().Name} does not implement {nameof(IPersistableModel)}");
- }
+ var iModel = model as IPersistableModel;
+ if (iModel is null)
+ {
+ throw new InvalidOperationException($"{model.GetType().Name} does not implement {nameof(IPersistableModel)}");
+ }
- if (IsJsonFormatRequested(iModel, options) && model is IJsonModel jsonModel)
- {
- using (ModelWriter writer = new ModelWriter(jsonModel, options))
- {
- return writer.ToBinaryData();
- }
- }
- else
+ if (IsJsonFormatRequested(iModel, options) && model is IJsonModel jsonModel)
+ {
+ using (ModelWriter writer = new ModelWriter(jsonModel, options))
{
- return iModel.Write(options);
+ return writer.ToBinaryData();
}
}
+ else
+ {
+ return iModel.Write(options);
+ }
+ }
- ///
- /// Converts the into a .
- ///
- /// The to convert.
- /// The to use.
- /// A representation of the .
- /// Throws if does not have a public or internal parameterless constructor.
- /// If the model does not support the requested .
- /// If is null.
- /// If does not have a public or non public empty constructor.
- public static T? Read<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(BinaryData data, ModelReaderWriterOptions? options = default)
- where T : IPersistableModel
+ ///
+ /// Converts the into a .
+ ///
+ /// The to convert.
+ /// The to use.
+ /// A representation of the .
+ /// Throws if does not have a public or internal parameterless constructor.
+ /// If the model does not support the requested .
+ /// If is null.
+ /// If does not have a public or non public empty constructor.
+ public static T? Read<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(BinaryData data, ModelReaderWriterOptions? options = default)
+ where T : IPersistableModel
+ {
+ if (data is null)
{
- if (data is null)
- {
- throw new ArgumentNullException(nameof(data));
- }
+ throw new ArgumentNullException(nameof(data));
+ }
- options ??= ModelReaderWriterOptions.Json;
+ options ??= ModelReaderWriterOptions.Json;
- return GetInstance().Create(data, options);
+ return GetInstance().Create(data, options);
+ }
+
+ ///
+ /// Converts the into a .
+ ///
+ /// The to convert.
+ /// The type of the objec to convert and return.
+ /// The to use.
+ /// A representation of the .
+ /// Throws if does not implement .
+ /// Throws if does not have a public or internal parameterless constructor.
+ /// If the model does not support the requested .
+ /// If or are null.
+ /// If does not have a public or non public empty constructor.
+ public static object? Read(BinaryData data, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type returnType, ModelReaderWriterOptions? options = default)
+ {
+ if (data is null)
+ {
+ throw new ArgumentNullException(nameof(data));
}
- ///
- /// Converts the into a .
- ///
- /// The to convert.
- /// The type of the objec to convert and return.
- /// The to use.
- /// A representation of the .
- /// Throws if does not implement .
- /// Throws if does not have a public or internal parameterless constructor.
- /// If the model does not support the requested .
- /// If or are null.
- /// If does not have a public or non public empty constructor.
- public static object? Read(BinaryData data, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type returnType, ModelReaderWriterOptions? options = default)
+ if (returnType is null)
{
- if (data is null)
- {
- throw new ArgumentNullException(nameof(data));
- }
+ throw new ArgumentNullException(nameof(returnType));
+ }
- if (returnType is null)
- {
- throw new ArgumentNullException(nameof(returnType));
- }
+ options ??= ModelReaderWriterOptions.Json;
- options ??= ModelReaderWriterOptions.Json;
+ return GetInstance(returnType).Create(data, options);
+ }
- return GetInstance(returnType).Create(data, options);
+ private static IPersistableModel GetInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type returnType)
+ {
+ var model = GetObjectInstance(returnType) as IPersistableModel;
+ if (model is null)
+ {
+ throw new InvalidOperationException($"{returnType.Name} does not implement {nameof(IPersistableModel)}");
}
+ return model;
+ }
- private static IPersistableModel GetInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type returnType)
+ private static IPersistableModel GetInstance<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>()
+ where T : IPersistableModel
+ {
+ var model = GetObjectInstance(typeof(T)) as IPersistableModel;
+ if (model is null)
{
- var model = GetObjectInstance(returnType) as IPersistableModel;
- if (model is null)
- {
- throw new InvalidOperationException($"{returnType.Name} does not implement {nameof(IPersistableModel)}");
- }
- return model;
+ throw new InvalidOperationException($"{typeof(T).Name} does not implement {nameof(IPersistableModel)}");
}
+ return model;
+ }
+
+ private static object GetObjectInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type returnType)
+ {
+ PersistableModelProxyAttribute? attribute = Attribute.GetCustomAttribute(returnType, typeof(PersistableModelProxyAttribute), false) as PersistableModelProxyAttribute;
+ Type typeToActivate = attribute is null ? returnType : attribute.ProxyType;
- private static IPersistableModel GetInstance<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>()
- where T : IPersistableModel
+ if (returnType.IsAbstract && attribute is null)
{
- var model = GetObjectInstance(typeof(T)) as IPersistableModel;
- if (model is null)
- {
- throw new InvalidOperationException($"{typeof(T).Name} does not implement {nameof(IPersistableModel)}");
- }
- return model;
+ throw new InvalidOperationException($"{returnType.Name} must be decorated with {nameof(PersistableModelProxyAttribute)} to be used with {nameof(ModelReaderWriter)}");
}
- private static object GetObjectInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type returnType)
+ var obj = Activator.CreateInstance(typeToActivate, true);
+ if (obj is null)
{
- PersistableModelProxyAttribute? attribute = Attribute.GetCustomAttribute(returnType, typeof(PersistableModelProxyAttribute), false) as PersistableModelProxyAttribute;
- Type typeToActivate = attribute is null ? returnType : attribute.ProxyType;
-
- if (returnType.IsAbstract && attribute is null)
- {
- throw new InvalidOperationException($"{returnType.Name} must be decorated with {nameof(PersistableModelProxyAttribute)} to be used with {nameof(ModelReaderWriter)}");
- }
-
- var obj = Activator.CreateInstance(typeToActivate, true);
- if (obj is null)
- {
- throw new InvalidOperationException($"Unable to create instance of {typeToActivate.Name}.");
- }
- return obj;
+ throw new InvalidOperationException($"Unable to create instance of {typeToActivate.Name}.");
}
+ return obj;
+ }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool IsJsonFormatRequested(IPersistableModel model, ModelReaderWriterOptions options)
- => options.Format == "J" || (options.Format == "W" && model.GetFormatFromOptions(options) == "J");
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static bool IsJsonFormatRequested(IPersistableModel model, ModelReaderWriterOptions options)
+ => options.Format == "J" || (options.Format == "W" && model.GetFormatFromOptions(options) == "J");
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static bool IsJsonFormatRequested(IPersistableModel model, ModelReaderWriterOptions options)
- => IsJsonFormatRequested(model, options);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static bool IsJsonFormatRequested(IPersistableModel model, ModelReaderWriterOptions options)
+ => IsJsonFormatRequested(model, options);
}
diff --git a/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelReaderWriterOptions.cs b/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelReaderWriterOptions.cs
index ffa6d755237f..090b5b0431a0 100644
--- a/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelReaderWriterOptions.cs
+++ b/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelReaderWriterOptions.cs
@@ -1,37 +1,36 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
-namespace System.ClientModel.Primitives
+namespace System.ClientModel.Primitives;
+
+///
+/// Provides the client options for reading and writing models.
+///
+public class ModelReaderWriterOptions
{
+ private static ModelReaderWriterOptions? s_jsonOptions;
///
- /// Provides the client options for reading and writing models.
+ /// Default options for writing models into JSON format.
///
- public class ModelReaderWriterOptions
- {
- private static ModelReaderWriterOptions? s_jsonOptions;
- ///
- /// Default options for writing models into JSON format.
- ///
- public static ModelReaderWriterOptions Json => s_jsonOptions ??= new ModelReaderWriterOptions("J");
-
- private static ModelReaderWriterOptions? s_xmlOptions;
- ///
- /// Default options for writing models into XML format.
- ///
- public static ModelReaderWriterOptions Xml => s_xmlOptions ??= new ModelReaderWriterOptions("X");
+ public static ModelReaderWriterOptions Json => s_jsonOptions ??= new ModelReaderWriterOptions("J");
- ///
- /// Initializes a new instance of .
- ///
- /// The format to read and write models.
- public ModelReaderWriterOptions (string format)
- {
- Format = format;
- }
+ private static ModelReaderWriterOptions? s_xmlOptions;
+ ///
+ /// Default options for writing models into XML format.
+ ///
+ public static ModelReaderWriterOptions Xml => s_xmlOptions ??= new ModelReaderWriterOptions("X");
- ///
- /// Gets the format to read and write the model.
- ///
- public string Format { get; }
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The format to read and write models.
+ public ModelReaderWriterOptions (string format)
+ {
+ Format = format;
}
+
+ ///
+ /// Gets the format to read and write the model.
+ ///
+ public string Format { get; }
}
diff --git a/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelWriter.cs b/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelWriter.cs
index dd25ed4bca9b..b72726636222 100644
--- a/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelWriter.cs
+++ b/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelWriter.cs
@@ -3,13 +3,12 @@
using System.ClientModel.Primitives;
-namespace System.ClientModel.Internal
+namespace System.ClientModel.Internal;
+
+internal class ModelWriter : ModelWriter
{
- internal class ModelWriter : ModelWriter
+ public ModelWriter(IJsonModel model, ModelReaderWriterOptions options)
+ : base(model, options)
{
- public ModelWriter(IJsonModel model, ModelReaderWriterOptions options)
- : base(model, options)
- {
- }
}
}
diff --git a/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelWriterOfT.SequenceBuilder.cs b/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelWriterOfT.SequenceBuilder.cs
index f1d5b0a7c387..2b7322f64aba 100644
--- a/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelWriterOfT.SequenceBuilder.cs
+++ b/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelWriterOfT.SequenceBuilder.cs
@@ -6,169 +6,168 @@
using System.Threading;
using System.Threading.Tasks;
-namespace System.ClientModel.Internal
+namespace System.ClientModel.Internal;
+
+internal partial class ModelWriter : IDisposable
{
- internal partial class ModelWriter : IDisposable
+ ///
+ /// This class is a helper to write to a in a thread safe manner.
+ /// It uses the shared pool to allocate buffers and returns them to the pool when disposed.
+ /// Since there is no way to ensure someone didn't keep a reference to one of the buffers
+ /// it must be disposed of in the same context it was created and its referenced should not be stored or shared.
+ ///
+ private sealed class SequenceBuilder : IBufferWriter, IDisposable
{
+ private struct Buffer
+ {
+ public byte[] Array;
+ public int Written;
+ }
+
+ private volatile Buffer[] _buffers; // this is an array so items can be accessed by ref
+ private volatile int _count;
+ private readonly int _segmentSize;
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The size of each buffer segment.
+ public SequenceBuilder(int segmentSize = 16384)
+ {
+ // we perf tested a very large and a small model and found that the performance
+ // for 4k, 8k, 16k, 32k, was neglible for the small model but had a 30% alloc improvment
+ // from 4k to 16k on the very large model.
+ _segmentSize = segmentSize;
+ _buffers = Array.Empty();
+ }
+
///
- /// This class is a helper to write to a in a thread safe manner.
- /// It uses the shared pool to allocate buffers and returns them to the pool when disposed.
- /// Since there is no way to ensure someone didn't keep a reference to one of the buffers
- /// it must be disposed of in the same context it was created and its referenced should not be stored or shared.
+ /// Notifies the that bytes bytes were written to the output or .
+ /// You must request a new buffer after calling to continue writing more data; you cannot write to a previously acquired buffer.
///
- private sealed class SequenceBuilder : IBufferWriter, IDisposable
+ /// The number of bytes written to the or .
+ ///
+ public void Advance(int bytesWritten)
{
- private struct Buffer
+ ref Buffer last = ref _buffers[_count - 1];
+ last.Written += bytesWritten;
+ if (last.Written > last.Array.Length)
{
- public byte[] Array;
- public int Written;
+ throw new ArgumentOutOfRangeException(nameof(bytesWritten));
}
+ }
- private volatile Buffer[] _buffers; // this is an array so items can be accessed by ref
- private volatile int _count;
- private readonly int _segmentSize;
-
- ///
- /// Initializes a new instance of .
- ///
- /// The size of each buffer segment.
- public SequenceBuilder(int segmentSize = 16384)
+ ///
+ /// Returns a to write to that is at least the requested size, as specified by the parameter.
+ ///
+ /// The minimum length of the returned . If less than 256, a buffer of size 256 will be returned.
+ /// A memory buffer of at least bytes. If is less than 256, a buffer of size 256 will be returned.
+ public Memory GetMemory(int sizeHint = 0)
+ {
+ if (sizeHint < 256)
{
- // we perf tested a very large and a small model and found that the performance
- // for 4k, 8k, 16k, 32k, was neglible for the small model but had a 30% alloc improvment
- // from 4k to 16k on the very large model.
- _segmentSize = segmentSize;
- _buffers = Array.Empty();
+ sizeHint = 256;
}
- ///
- /// Notifies the that bytes bytes were written to the output or .
- /// You must request a new buffer after calling to continue writing more data; you cannot write to a previously acquired buffer.
- ///
- /// The number of bytes written to the or .
- ///
- public void Advance(int bytesWritten)
+ int sizeToRent = sizeHint > _segmentSize ? sizeHint : _segmentSize;
+
+ if (_buffers.Length == 0)
{
- ref Buffer last = ref _buffers[_count - 1];
- last.Written += bytesWritten;
- if (last.Written > last.Array.Length)
- {
- throw new ArgumentOutOfRangeException(nameof(bytesWritten));
- }
+ ExpandBuffers(sizeToRent);
}
- ///
- /// Returns a to write to that is at least the requested size, as specified by the parameter.
- ///
- /// The minimum length of the returned . If less than 256, a buffer of size 256 will be returned.
- /// A memory buffer of at least bytes. If is less than 256, a buffer of size 256 will be returned.
- public Memory GetMemory(int sizeHint = 0)
+ ref Buffer last = ref _buffers[_count - 1];
+ Memory free = last.Array.AsMemory(last.Written);
+ if (free.Length >= sizeHint)
{
- if (sizeHint < 256)
- {
- sizeHint = 256;
- }
-
- int sizeToRent = sizeHint > _segmentSize ? sizeHint : _segmentSize;
-
- if (_buffers.Length == 0)
- {
- ExpandBuffers(sizeToRent);
- }
-
- ref Buffer last = ref _buffers[_count - 1];
- Memory free = last.Array.AsMemory(last.Written);
- if (free.Length >= sizeHint)
- {
- return free;
- }
+ return free;
+ }
- // else allocate a new buffer:
- ExpandBuffers(sizeToRent);
+ // else allocate a new buffer:
+ ExpandBuffers(sizeToRent);
- return _buffers[_count - 1].Array;
- }
+ return _buffers[_count - 1].Array;
+ }
- private readonly object _lock = new object();
- private void ExpandBuffers(int sizeToRent)
+ private readonly object _lock = new object();
+ private void ExpandBuffers(int sizeToRent)
+ {
+ lock (_lock)
{
- lock (_lock)
+ int bufferCount = _count == 0 ? 1 : _count * 2;
+
+ Buffer[] resized = new Buffer[bufferCount];
+ if (_count > 0)
{
- int bufferCount = _count == 0 ? 1 : _count * 2;
-
- Buffer[] resized = new Buffer[bufferCount];
- if (_count > 0)
- {
- _buffers.CopyTo(resized, 0);
- }
- _buffers = resized;
- _buffers[_count].Array = ArrayPool.Shared.Rent(sizeToRent);
- _count = bufferCount == 1 ? bufferCount : _count + 1;
+ _buffers.CopyTo(resized, 0);
}
+ _buffers = resized;
+ _buffers[_count].Array = ArrayPool.Shared.Rent(sizeToRent);
+ _count = bufferCount == 1 ? bufferCount : _count + 1;
}
+ }
+
+ ///
+ /// Returns a to write to that is at least the requested size, as specified by the parameter.
+ ///
+ /// The minimum length of the returned . If less than 256, a buffer of size 256 will be returned.
+ /// A buffer of at least bytes. If is less than 256, a buffer of size 256 will be returned.
+ public Span GetSpan(int sizeHint = 0)
+ {
+ Memory memory = GetMemory(sizeHint);
+ return memory.Span;
+ }
- ///
- /// Returns a to write to that is at least the requested size, as specified by the parameter.
- ///
- /// The minimum length of the returned . If less than 256, a buffer of size 256 will be returned.
- /// A buffer of at least bytes. If is less than 256, a buffer of size 256 will be returned.
- public Span GetSpan(int sizeHint = 0)
+ ///
+ /// Disposes the SequenceWriter and returns the underlying buffers to the pool.
+ ///
+ public void Dispose()
+ {
+ int bufferCountToFree;
+ Buffer[] buffersToFree;
+ lock (_lock)
{
- Memory memory = GetMemory(sizeHint);
- return memory.Span;
+ bufferCountToFree = _count;
+ buffersToFree = _buffers;
+ _count = 0;
+ _buffers = Array.Empty();
}
- ///
- /// Disposes the SequenceWriter and returns the underlying buffers to the pool.
- ///
- public void Dispose()
+ for (int i = 0; i < bufferCountToFree; i++)
{
- int bufferCountToFree;
- Buffer[] buffersToFree;
- lock (_lock)
- {
- bufferCountToFree = _count;
- buffersToFree = _buffers;
- _count = 0;
- _buffers = Array.Empty();
- }
-
- for (int i = 0; i < bufferCountToFree; i++)
- {
- ArrayPool.Shared.Return(buffersToFree[i].Array);
- }
+ ArrayPool.Shared.Return(buffersToFree[i].Array);
}
+ }
- public bool TryComputeLength(out long length)
+ public bool TryComputeLength(out long length)
+ {
+ length = 0;
+ for (int i = 0; i < _count; i++)
{
- length = 0;
- for (int i = 0; i < _count; i++)
- {
- length += _buffers[i].Written;
- }
- return true;
+ length += _buffers[i].Written;
}
+ return true;
+ }
- public void CopyTo(Stream stream, CancellationToken cancellation)
+ public void CopyTo(Stream stream, CancellationToken cancellation)
+ {
+ for (int i = 0; i < _count; i++)
{
- for (int i = 0; i < _count; i++)
- {
- cancellation.ThrowIfCancellationRequested();
+ cancellation.ThrowIfCancellationRequested();
- Buffer buffer = _buffers[i];
- stream.Write(buffer.Array, 0, buffer.Written);
- }
+ Buffer buffer = _buffers[i];
+ stream.Write(buffer.Array, 0, buffer.Written);
}
+ }
- public async Task CopyToAsync(Stream stream, CancellationToken cancellation)
+ public async Task CopyToAsync(Stream stream, CancellationToken cancellation)
+ {
+ for (int i = 0; i < _count; i++)
{
- for (int i = 0; i < _count; i++)
- {
- cancellation.ThrowIfCancellationRequested();
+ cancellation.ThrowIfCancellationRequested();
- Buffer buffer = _buffers[i];
- await stream.WriteAsync(buffer.Array, 0, buffer.Written, cancellation).ConfigureAwait(false);
- }
+ Buffer buffer = _buffers[i];
+ await stream.WriteAsync(buffer.Array, 0, buffer.Written, cancellation).ConfigureAwait(false);
}
}
}
diff --git a/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelWriterOfT.cs b/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelWriterOfT.cs
index aeaf66d28838..c99950a4faae 100644
--- a/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelWriterOfT.cs
+++ b/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelWriterOfT.cs
@@ -9,188 +9,187 @@
using System.Threading;
using System.Threading.Tasks;
-namespace System.ClientModel.Internal
+namespace System.ClientModel.Internal;
+
+///
+/// Provides an efficient way to write into a using multiple pooled buffers.
+///
+internal partial class ModelWriter : IDisposable
{
- ///
- /// Provides an efficient way to write into a using multiple pooled buffers.
- ///
- internal partial class ModelWriter : IDisposable
- {
- private readonly IJsonModel _model;
- private readonly ModelReaderWriterOptions _options;
+ private readonly IJsonModel _model;
+ private readonly ModelReaderWriterOptions _options;
- private readonly object _writeLock = new object();
- private readonly object _readLock = new object();
+ private readonly object _writeLock = new object();
+ private readonly object _readLock = new object();
- private volatile SequenceBuilder? _sequenceBuilder;
- private volatile bool _isDisposed;
+ private volatile SequenceBuilder? _sequenceBuilder;
+ private volatile bool _isDisposed;
- private volatile int _readCount;
+ private volatile int _readCount;
- private ManualResetEvent? _readersFinished;
- private ManualResetEvent ReadersFinished => _readersFinished ??= new ManualResetEvent(true);
+ private ManualResetEvent? _readersFinished;
+ private ManualResetEvent ReadersFinished => _readersFinished ??= new ManualResetEvent(true);
- ///
- /// Initializes a new instance of .
- ///
- /// The model to write.
- /// The to use.
- /// If the model does not support the requested .
- public ModelWriter(IJsonModel model, ModelReaderWriterOptions options)
- {
- _model = model;
- _options = options;
- }
+ ///
+ /// Initializes a new instance of .
+ ///
+ /// The model to write.
+ /// The to use.
+ /// If the model does not support the requested .
+ public ModelWriter(IJsonModel model, ModelReaderWriterOptions options)
+ {
+ _model = model;
+ _options = options;
+ }
- private SequenceBuilder GetSequenceBuilder()
+ private SequenceBuilder GetSequenceBuilder()
+ {
+ if (_sequenceBuilder is null)
{
- if (_sequenceBuilder is null)
+ lock (_writeLock)
{
- lock (_writeLock)
+ if (_isDisposed)
{
- if (_isDisposed)
- {
- throw new ObjectDisposedException(nameof(ModelWriter));
- }
+ throw new ObjectDisposedException(nameof(ModelWriter));
+ }
- if (_sequenceBuilder is null)
- {
- SequenceBuilder sequenceBuilder = new SequenceBuilder();
- using var jsonWriter = new Utf8JsonWriter(sequenceBuilder);
- _model.Write(jsonWriter, _options);
- jsonWriter.Flush();
- _sequenceBuilder = sequenceBuilder;
- }
+ if (_sequenceBuilder is null)
+ {
+ SequenceBuilder sequenceBuilder = new SequenceBuilder();
+ using var jsonWriter = new Utf8JsonWriter(sequenceBuilder);
+ _model.Write(jsonWriter, _options);
+ jsonWriter.Flush();
+ _sequenceBuilder = sequenceBuilder;
}
}
- return _sequenceBuilder;
}
+ return _sequenceBuilder;
+ }
- internal void CopyTo(Stream stream, CancellationToken cancellation)
+ internal void CopyTo(Stream stream, CancellationToken cancellation)
+ {
+ SequenceBuilder builder = GetSequenceBuilder();
+ IncrementRead();
+ try
{
- SequenceBuilder builder = GetSequenceBuilder();
- IncrementRead();
- try
- {
- builder.CopyTo(stream, cancellation);
- }
- finally
- {
- DecrementRead();
- }
+ builder.CopyTo(stream, cancellation);
}
+ finally
+ {
+ DecrementRead();
+ }
+ }
- internal bool TryComputeLength(out long length)
+ internal bool TryComputeLength(out long length)
+ {
+ SequenceBuilder builder = GetSequenceBuilder();
+ IncrementRead();
+ try
{
- SequenceBuilder builder = GetSequenceBuilder();
- IncrementRead();
- try
- {
- return builder.TryComputeLength(out length);
- }
- finally
- {
- DecrementRead();
- }
+ return builder.TryComputeLength(out length);
+ }
+ finally
+ {
+ DecrementRead();
}
+ }
- internal async Task CopyToAsync(Stream stream, CancellationToken cancellation)
+ internal async Task CopyToAsync(Stream stream, CancellationToken cancellation)
+ {
+ SequenceBuilder builder = GetSequenceBuilder();
+ IncrementRead();
+ try
{
- SequenceBuilder builder = GetSequenceBuilder();
- IncrementRead();
- try
- {
- await builder.CopyToAsync(stream, cancellation).ConfigureAwait(false);
- }
- finally
- {
- DecrementRead();
- }
+ await builder.CopyToAsync(stream, cancellation).ConfigureAwait(false);
}
+ finally
+ {
+ DecrementRead();
+ }
+ }
- ///
- /// Converts the to a .
- ///
- /// A representation of the written in JSON format.
- public BinaryData ToBinaryData()
+ ///
+ /// Converts the to a .
+ ///
+ /// A representation of the written in JSON format.
+ public BinaryData ToBinaryData()
+ {
+ SequenceBuilder builder = GetSequenceBuilder();
+ IncrementRead();
+ try
{
- SequenceBuilder builder = GetSequenceBuilder();
- IncrementRead();
- try
- {
- bool gotLength = builder.TryComputeLength(out long length);
- if (length > int.MaxValue)
- {
- throw new InvalidOperationException($"Length of serialized model is too long. Value was {length} max is {int.MaxValue}");
- }
- Debug.Assert(gotLength);
- using var stream = new MemoryStream((int)length);
- builder.CopyTo(stream, default);
- return new BinaryData(stream.GetBuffer().AsMemory(0, (int)stream.Position));
- }
- finally
+ bool gotLength = builder.TryComputeLength(out long length);
+ if (length > int.MaxValue)
{
- DecrementRead();
+ throw new InvalidOperationException($"Length of serialized model is too long. Value was {length} max is {int.MaxValue}");
}
+ Debug.Assert(gotLength);
+ using var stream = new MemoryStream((int)length);
+ builder.CopyTo(stream, default);
+ return new BinaryData(stream.GetBuffer().AsMemory(0, (int)stream.Position));
+ }
+ finally
+ {
+ DecrementRead();
}
+ }
- ///
- public void Dispose()
+ ///
+ public void Dispose()
+ {
+ if (!_isDisposed)
{
- if (!_isDisposed)
+ lock (_writeLock)
{
- lock (_writeLock)
+ if (!_isDisposed)
{
- if (!_isDisposed)
- {
- _isDisposed = true;
-
- if (_readersFinished is null || _readersFinished.WaitOne())
- {
- //only dispose if no readers ever happened or if all readers are done
- _sequenceBuilder?.Dispose();
- }
+ _isDisposed = true;
- _sequenceBuilder = null;
- _readersFinished?.Dispose();
- _readersFinished = null;
+ if (_readersFinished is null || _readersFinished.WaitOne())
+ {
+ //only dispose if no readers ever happened or if all readers are done
+ _sequenceBuilder?.Dispose();
}
+
+ _sequenceBuilder = null;
+ _readersFinished?.Dispose();
+ _readersFinished = null;
}
}
}
+ }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void IncrementRead()
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void IncrementRead()
+ {
+ if (_isDisposed)
{
- if (_isDisposed)
- {
- throw new ObjectDisposedException(nameof(ModelWriter));
- }
+ throw new ObjectDisposedException(nameof(ModelWriter));
+ }
- lock (_readLock)
- {
- _readCount++;
- ReadersFinished.Reset();
- }
+ lock (_readLock)
+ {
+ _readCount++;
+ ReadersFinished.Reset();
+ }
- if (_isDisposed)
- {
- DecrementRead();
- throw new ObjectDisposedException(nameof(ModelWriter));
- }
+ if (_isDisposed)
+ {
+ DecrementRead();
+ throw new ObjectDisposedException(nameof(ModelWriter));
}
+ }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void DecrementRead()
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void DecrementRead()
+ {
+ lock (_readLock)
{
- lock (_readLock)
+ _readCount--;
+ if (_readCount == 0)
{
- _readCount--;
- if (_readCount == 0)
- {
- // notify we reached zero readers in case dispose is waiting
- ReadersFinished.Set();
- }
+ // notify we reached zero readers in case dispose is waiting
+ ReadersFinished.Set();
}
}
}
diff --git a/sdk/core/System.ClientModel/src/ModelReaderWriter/PersistableModelProxyAttribute.cs b/sdk/core/System.ClientModel/src/ModelReaderWriter/PersistableModelProxyAttribute.cs
index 1fbb55220431..bb24356db1a2 100644
--- a/sdk/core/System.ClientModel/src/ModelReaderWriter/PersistableModelProxyAttribute.cs
+++ b/sdk/core/System.ClientModel/src/ModelReaderWriter/PersistableModelProxyAttribute.cs
@@ -3,34 +3,33 @@
using System.Diagnostics.CodeAnalysis;
-namespace System.ClientModel.Primitives
+namespace System.ClientModel.Primitives;
+
+///
+/// Attribute that indicates a proxy to use for reading a model.
+/// The proxy must implement and have a public or non-public parameterless constructor.
+///
+[AttributeUsage(AttributeTargets.Class)]
+public sealed class PersistableModelProxyAttribute : Attribute
{
///
- /// Attribute that indicates a proxy to use for reading a model.
- /// The proxy must implement and have a public or non-public parameterless constructor.
+ /// Instantiates a new instance of the class.
///
- [AttributeUsage(AttributeTargets.Class)]
- public sealed class PersistableModelProxyAttribute : Attribute
+ ///
+ /// The to create and call read on.
+ /// The must have a public or non-public parameterless constructor.
+ /// The must implement where T is the type of the abstract class.
+ ///
+ public PersistableModelProxyAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type proxyType)
{
- ///
- /// Instantiates a new instance of the class.
- ///
- ///
- /// The to create and call read on.
- /// The must have a public or non-public parameterless constructor.
- /// The must implement where T is the type of the abstract class.
- ///
- public PersistableModelProxyAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type proxyType)
- {
- ProxyType = proxyType;
- }
-
- ///
- /// Gets the to create and call read on.
- /// The must have a public or non-public parameterless constructor.
- /// The must implement where T is the type of the abstract class.
- ///
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
- public Type ProxyType { get; }
+ ProxyType = proxyType;
}
+
+ ///
+ /// Gets the to create and call read on.
+ /// The must have a public or non-public parameterless constructor.
+ /// The must implement where T is the type of the abstract class.
+ ///
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
+ public Type ProxyType { get; }
}
diff --git a/sdk/core/System.ClientModel/src/System.ClientModel.csproj b/sdk/core/System.ClientModel/src/System.ClientModel.csproj
index ca58dd585085..8b7950170a58 100644
--- a/sdk/core/System.ClientModel/src/System.ClientModel.csproj
+++ b/sdk/core/System.ClientModel/src/System.ClientModel.csproj
@@ -8,7 +8,7 @@
enable
netstandard2.0;net6.0
- $(NoWarn);AZC0001;AZC0012;AZC0014;CS1591;NETSDK1138
+ $(NoWarn);AZC0001;CS1591
DotNetPackageIcon.png
$(RepoEngPath)/images/$(PackageIcon)
diff --git a/sdk/core/System.ClientModel/tests/client/ClientShared/ModelReaderWriterExtensions.cs b/sdk/core/System.ClientModel/tests/client/ClientShared/ModelReaderWriterExtensions.cs
new file mode 100644
index 000000000000..b4ad891ec481
--- /dev/null
+++ b/sdk/core/System.ClientModel/tests/client/ClientShared/ModelReaderWriterExtensions.cs
@@ -0,0 +1,264 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#nullable enable
+
+using System;
+using System.ClientModel.Primitives;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using System.Text.Json;
+
+namespace ClientModel.Tests.ClientShared;
+
+internal static class ModelReaderWriterExtensions
+{
+ // TODO: These are copied from shared source files. If they become
+ // public we need to refactor and consolidate to a single place.
+
+ #region JsonElement
+
+ public static object? GetObject(in this JsonElement element)
+ {
+ switch (element.ValueKind)
+ {
+ case JsonValueKind.String:
+ return element.GetString();
+ case JsonValueKind.Number:
+ if (element.TryGetInt32(out int intValue))
+ {
+ return intValue;
+ }
+ if (element.TryGetInt64(out long longValue))
+ {
+ return longValue;
+ }
+ return element.GetDouble();
+ case JsonValueKind.True:
+ return true;
+ case JsonValueKind.False:
+ return false;
+ case JsonValueKind.Undefined:
+ case JsonValueKind.Null:
+ return null;
+ case JsonValueKind.Object:
+ var dictionary = new Dictionary();
+ foreach (JsonProperty jsonProperty in element.EnumerateObject())
+ {
+ dictionary.Add(jsonProperty.Name, jsonProperty.Value.GetObject());
+ }
+ return dictionary;
+ case JsonValueKind.Array:
+ var list = new List();
+ foreach (JsonElement item in element.EnumerateArray())
+ {
+ list.Add(item.GetObject());
+ }
+ return list.ToArray();
+ default:
+ throw new NotSupportedException("Not supported value kind " + element.ValueKind);
+ }
+ }
+
+ public static byte[]? GetBytesFromBase64(in this JsonElement element, string format)
+ {
+ if (element.ValueKind == JsonValueKind.Null)
+ {
+ return null;
+ }
+
+ return format switch
+ {
+ "U" => TypeFormatters.FromBase64UrlString(element.GetRequiredString()),
+ "D" => element.GetBytesFromBase64(),
+ _ => throw new ArgumentException($"Format is not supported: '{format}'", nameof(format))
+ };
+ }
+
+ public static DateTimeOffset GetDateTimeOffset(in this JsonElement element, string format) => format switch
+ {
+ "U" when element.ValueKind == JsonValueKind.Number => DateTimeOffset.FromUnixTimeSeconds(element.GetInt64()),
+ // relying on the param check of the inner call to throw ArgumentNullException if GetString() returns null
+ _ => TypeFormatters.ParseDateTimeOffset(element.GetString()!, format)
+ };
+
+ public static TimeSpan GetTimeSpan(in this JsonElement element, string format) =>
+ // relying on the param check of the inner call to throw ArgumentNullException if GetString() returns null
+ TypeFormatters.ParseTimeSpan(element.GetString()!, format);
+
+ public static char GetChar(this in JsonElement element)
+ {
+ if (element.ValueKind == JsonValueKind.String)
+ {
+ var text = element.GetString();
+ if (text == null || text.Length != 1)
+ {
+ throw new NotSupportedException($"Cannot convert \"{text}\" to a Char");
+ }
+ return text[0];
+ }
+ else
+ {
+ throw new NotSupportedException($"Cannot convert {element.ValueKind} to a Char");
+ }
+ }
+
+ [Conditional("DEBUG")]
+ public static void ThrowNonNullablePropertyIsNull(this JsonProperty property)
+ {
+ throw new JsonException($"A property '{property.Name}' defined as non-nullable but received as null from the service. " +
+ $"This exception only happens in DEBUG builds of the library and would be ignored in the release build");
+ }
+
+ public static string GetRequiredString(in this JsonElement element)
+ {
+ var value = element.GetString();
+ if (value == null)
+ throw new InvalidOperationException($"The requested operation requires an element of type 'String', but the target element has type '{element.ValueKind}'.");
+
+ return value;
+ }
+
+ #endregion
+
+ #region Utf8JsonWriter
+ public static void WriteStringValue(this Utf8JsonWriter writer, DateTimeOffset value, string format) =>
+ writer.WriteStringValue(TypeFormatters.ToString(value, format));
+
+ public static void WriteStringValue(this Utf8JsonWriter writer, DateTime value, string format) =>
+ writer.WriteStringValue(TypeFormatters.ToString(value, format));
+
+ public static void WriteStringValue(this Utf8JsonWriter writer, TimeSpan value, string format) =>
+ writer.WriteStringValue(TypeFormatters.ToString(value, format));
+
+ public static void WriteStringValue(this Utf8JsonWriter writer, char value) =>
+ writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
+
+ public static void WriteNonEmptyArray(this Utf8JsonWriter writer, string name, IReadOnlyList values)
+ {
+ if (values.Any())
+ {
+ writer.WriteStartArray(name);
+ foreach (var s in values)
+ {
+ writer.WriteStringValue(s);
+ }
+
+ writer.WriteEndArray();
+ }
+ }
+
+ public static void WriteBase64StringValue(this Utf8JsonWriter writer, byte[] value, string format)
+ {
+ if (value == null)
+ {
+ writer.WriteNullValue();
+ return;
+ }
+
+ switch (format)
+ {
+ case "U":
+ writer.WriteStringValue(TypeFormatters.ToBase64UrlString(value));
+ break;
+ case "D":
+ writer.WriteBase64StringValue(value);
+ break;
+ default:
+ throw new ArgumentException($"Format is not supported: '{format}'", nameof(format));
+ }
+ }
+
+ public static void WriteNumberValue(this Utf8JsonWriter writer, DateTimeOffset value, string format)
+ {
+ if (format != "U") throw new ArgumentOutOfRangeException(format, "Only 'U' format is supported when writing a DateTimeOffset as a Number.");
+
+ writer.WriteNumberValue(value.ToUnixTimeSeconds());
+ }
+
+ public static void WriteObjectValue(this Utf8JsonWriter writer, object value)
+ {
+ switch (value)
+ {
+ case null:
+ writer.WriteNullValue();
+ break;
+ case IJsonModel writeable:
+ writeable.Write(writer, ModelReaderWriterHelper.WireOptions);
+ break;
+ case byte[] bytes:
+ writer.WriteBase64StringValue(bytes);
+ break;
+ case BinaryData bytes:
+ writer.WriteBase64StringValue(bytes);
+ break;
+ case JsonElement json:
+ json.WriteTo(writer);
+ break;
+ case int i:
+ writer.WriteNumberValue(i);
+ break;
+ case decimal d:
+ writer.WriteNumberValue(d);
+ break;
+ case double d:
+ if (double.IsNaN(d))
+ {
+ writer.WriteStringValue("NaN");
+ }
+ else
+ {
+ writer.WriteNumberValue(d);
+ }
+ break;
+ case float f:
+ writer.WriteNumberValue(f);
+ break;
+ case long l:
+ writer.WriteNumberValue(l);
+ break;
+ case string s:
+ writer.WriteStringValue(s);
+ break;
+ case bool b:
+ writer.WriteBooleanValue(b);
+ break;
+ case Guid g:
+ writer.WriteStringValue(g);
+ break;
+ case DateTimeOffset dateTimeOffset:
+ writer.WriteStringValue(dateTimeOffset, "O");
+ break;
+ case DateTime dateTime:
+ writer.WriteStringValue(dateTime, "O");
+ break;
+ case IEnumerable> enumerable:
+ writer.WriteStartObject();
+ foreach (KeyValuePair pair in enumerable)
+ {
+ writer.WritePropertyName(pair.Key);
+ writer.WriteObjectValue(pair.Value);
+ }
+ writer.WriteEndObject();
+ break;
+ case IEnumerable objectEnumerable:
+ writer.WriteStartArray();
+ foreach (object item in objectEnumerable)
+ {
+ writer.WriteObjectValue(item);
+ }
+ writer.WriteEndArray();
+ break;
+ case TimeSpan timeSpan:
+ writer.WriteStringValue(timeSpan, "P");
+ break;
+
+ default:
+ throw new NotSupportedException("Not supported type " + value.GetType());
+ }
+ }
+
+#endregion
+}
diff --git a/sdk/core/System.ClientModel/tests/client/ClientShared/ModelReaderWriterHelper.cs b/sdk/core/System.ClientModel/tests/client/ClientShared/ModelReaderWriterHelper.cs
new file mode 100644
index 000000000000..01aec41339bd
--- /dev/null
+++ b/sdk/core/System.ClientModel/tests/client/ClientShared/ModelReaderWriterHelper.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.ClientModel.Primitives;
+using System.Runtime.CompilerServices;
+
+namespace ClientModel.Tests.ClientShared;
+
+internal static class ModelReaderWriterHelper
+{
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ValidateFormat(IPersistableModel model, string format)
+ {
+ bool implementsJson = model is IJsonModel;
+ bool isValid = (format == "J" && implementsJson) || format == "W";
+ if (!isValid)
+ {
+ throw new FormatException($"The model {model.GetType().Name} does not support '{format}' format.");
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ValidateFormat(IPersistableModel model, string format) => ValidateFormat(model, format);
+
+ private static ModelReaderWriterOptions _wireOptions;
+ public static ModelReaderWriterOptions WireOptions => _wireOptions ??= new ModelReaderWriterOptions("W");
+}
diff --git a/sdk/core/System.ClientModel/tests/client/ClientShared/OptionalDictionary.cs b/sdk/core/System.ClientModel/tests/client/ClientShared/OptionalDictionary.cs
new file mode 100644
index 000000000000..c79c187c4210
--- /dev/null
+++ b/sdk/core/System.ClientModel/tests/client/ClientShared/OptionalDictionary.cs
@@ -0,0 +1,214 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+#nullable enable
+
+namespace ClientModel.Tests.ClientShared;
+
+internal class OptionalDictionary : IDictionary, IReadOnlyDictionary where TKey : notnull
+{
+ private IDictionary? _innerDictionary;
+
+ public OptionalDictionary()
+ {
+ }
+
+ public OptionalDictionary(OptionalProperty> optionalDictionary) : this(optionalDictionary.Value)
+ {
+ }
+
+ public OptionalDictionary(OptionalProperty> optionalDictionary) : this(optionalDictionary.Value)
+ {
+ }
+
+ private OptionalDictionary(IDictionary dictionary)
+ {
+ if (dictionary == null) return;
+
+ _innerDictionary = new Dictionary(dictionary);
+ }
+
+ private OptionalDictionary(IReadOnlyDictionary dictionary)
+ {
+ if (dictionary == null) return;
+
+ _innerDictionary = new Dictionary();
+ foreach (KeyValuePair pair in dictionary)
+ {
+ _innerDictionary.Add(pair);
+ }
+ }
+
+ public bool IsUndefined => _innerDictionary == null;
+
+ public IEnumerator> GetEnumerator()
+ {
+ if (IsUndefined)
+ {
+ IEnumerator> GetEmptyEnumerator()
+ {
+ yield break;
+ }
+ return GetEmptyEnumerator();
+ }
+ return EnsureDictionary().GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public void Add(KeyValuePair item)
+ {
+ EnsureDictionary().Add(item);
+ }
+
+ public void Clear()
+ {
+ EnsureDictionary().Clear();
+ }
+
+ public bool Contains(KeyValuePair item)
+ {
+ if (IsUndefined)
+ {
+ return false;
+ }
+
+ return EnsureDictionary().Contains(item);
+ }
+
+ public void CopyTo(KeyValuePair[] array, int arrayIndex)
+ {
+ if (IsUndefined)
+ {
+ return;
+ }
+
+ EnsureDictionary().CopyTo(array, arrayIndex);
+ }
+
+ public bool Remove(KeyValuePair item)
+ {
+ if (IsUndefined)
+ {
+ return false;
+ }
+
+ return EnsureDictionary().Remove(item);
+ }
+
+ public int Count
+ {
+ get
+ {
+ if (IsUndefined)
+ {
+ return 0;
+ }
+
+ return EnsureDictionary().Count;
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ if (IsUndefined)
+ {
+ return false;
+ }
+ return EnsureDictionary().IsReadOnly;
+ }
+ }
+
+ public void Add(TKey key, TValue value)
+ {
+ EnsureDictionary().Add(key, value);
+ }
+
+ public bool ContainsKey(TKey key)
+ {
+ if (IsUndefined)
+ {
+ return false;
+ }
+
+ return EnsureDictionary().ContainsKey(key);
+ }
+
+ public bool Remove(TKey key)
+ {
+ if (IsUndefined)
+ {
+ return false;
+ }
+
+ return EnsureDictionary().Remove(key);
+ }
+
+ public bool TryGetValue(TKey key, out TValue value)
+ {
+ if (IsUndefined)
+ {
+ value = default!;
+ return false;
+ }
+ return EnsureDictionary().TryGetValue(key, out value!);
+ }
+
+ public TValue this[TKey key]
+ {
+ get
+ {
+ if (IsUndefined)
+ {
+ throw new KeyNotFoundException(nameof(key));
+ }
+
+ return EnsureDictionary()[key];
+ }
+ set => EnsureDictionary()[key] = value;
+ }
+
+ IEnumerable IReadOnlyDictionary.Keys => Keys;
+
+ IEnumerable IReadOnlyDictionary.Values => Values;
+
+ public ICollection Keys
+ {
+ get
+ {
+ if (IsUndefined)
+ {
+ return Array.Empty();
+ }
+
+ return EnsureDictionary().Keys;
+ }
+ }
+
+ public ICollection Values
+ {
+ get
+ {
+ if (IsUndefined)
+ {
+ return Array.Empty();
+ }
+
+ return EnsureDictionary().Values;
+ }
+ }
+
+ private IDictionary EnsureDictionary()
+ {
+ return _innerDictionary ??= new Dictionary();
+ }
+}
diff --git a/sdk/core/System.ClientModel/tests/client/ClientShared/OptionalList.cs b/sdk/core/System.ClientModel/tests/client/ClientShared/OptionalList.cs
new file mode 100644
index 000000000000..0460b0cebc49
--- /dev/null
+++ b/sdk/core/System.ClientModel/tests/client/ClientShared/OptionalList.cs
@@ -0,0 +1,191 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+#nullable enable
+
+namespace ClientModel.Tests.ClientShared;
+
+internal class OptionalList : IList, IReadOnlyList
+{
+ private IList? _innerList;
+
+ public OptionalList()
+ {
+ }
+
+ public OptionalList(OptionalProperty> optionalList) : this(optionalList.Value)
+ {
+ }
+
+ public OptionalList(OptionalProperty> optionalList) : this(optionalList.Value)
+ {
+ }
+
+ private OptionalList(IEnumerable innerList)
+ {
+ if (innerList == null)
+ {
+ return;
+ }
+
+ _innerList = innerList.ToList();
+ }
+
+ private OptionalList(IList innerList)
+ {
+ if (innerList == null)
+ {
+ return;
+ }
+
+ _innerList = innerList;
+ }
+
+ public bool IsUndefined => _innerList == null;
+
+ public void Reset()
+ {
+ _innerList = null;
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ if (IsUndefined)
+ {
+ IEnumerator EnumerateEmpty()
+ {
+ yield break;
+ }
+
+ return EnumerateEmpty();
+ }
+ return EnsureList().GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public void Add(T item)
+ {
+ EnsureList().Add(item);
+ }
+
+ public void Clear()
+ {
+ EnsureList().Clear();
+ }
+
+ public bool Contains(T item)
+ {
+ if (IsUndefined)
+ {
+ return false;
+ }
+
+ return EnsureList().Contains(item);
+ }
+
+ public void CopyTo(T[] array, int arrayIndex)
+ {
+ if (IsUndefined)
+ {
+ return;
+ }
+
+ EnsureList().CopyTo(array, arrayIndex);
+ }
+
+ public bool Remove(T item)
+ {
+ if (IsUndefined)
+ {
+ return false;
+ }
+
+ return EnsureList().Remove(item);
+ }
+
+ public int Count
+ {
+ get
+ {
+ if (IsUndefined)
+ {
+ return 0;
+ }
+ return EnsureList().Count;
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ if (IsUndefined)
+ {
+ return false;
+ }
+
+ return EnsureList().IsReadOnly;
+ }
+ }
+
+ public int IndexOf(T item)
+ {
+ if (IsUndefined)
+ {
+ return -1;
+ }
+
+ return EnsureList().IndexOf(item);
+ }
+
+ public void Insert(int index, T item)
+ {
+ EnsureList().Insert(index, item);
+ }
+
+ public void RemoveAt(int index)
+ {
+ if (IsUndefined)
+ {
+ throw new ArgumentOutOfRangeException(nameof(index));
+ }
+
+ EnsureList().RemoveAt(index);
+ }
+
+ public T this[int index]
+ {
+ get
+ {
+ if (IsUndefined)
+ {
+ throw new ArgumentOutOfRangeException(nameof(index));
+ }
+
+ return EnsureList()[index];
+ }
+ set
+ {
+ if (IsUndefined)
+ {
+ throw new ArgumentOutOfRangeException(nameof(index));
+ }
+
+ EnsureList()[index] = value;
+ }
+ }
+
+ private IList EnsureList()
+ {
+ return _innerList ??= new List();
+ }
+}
diff --git a/sdk/core/System.ClientModel/tests/client/ClientShared/OptionalProperty.cs b/sdk/core/System.ClientModel/tests/client/ClientShared/OptionalProperty.cs
new file mode 100644
index 000000000000..d86de7e9627e
--- /dev/null
+++ b/sdk/core/System.ClientModel/tests/client/ClientShared/OptionalProperty.cs
@@ -0,0 +1,107 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Collections.Generic;
+using System.Text.Json;
+
+namespace ClientModel.Tests.ClientShared;
+
+internal static class OptionalProperty
+{
+ public static bool IsCollectionDefined(IEnumerable collection)
+ {
+ return !(collection is OptionalList changeTrackingList && changeTrackingList.IsUndefined);
+ }
+
+ public static bool IsCollectionDefined(IReadOnlyDictionary collection)
+ {
+ return !(collection is OptionalDictionary changeTrackingList && changeTrackingList.IsUndefined);
+ }
+
+ public static bool IsCollectionDefined(IDictionary collection)
+ {
+ return !(collection is OptionalDictionary changeTrackingList && changeTrackingList.IsUndefined);
+ }
+
+ public static bool IsDefined(T? value) where T : struct
+ {
+ return value.HasValue;
+ }
+ public static bool IsDefined(object value)
+ {
+ return value != null;
+ }
+ public static bool IsDefined(string value)
+ {
+ return value != null;
+ }
+
+ public static bool IsDefined(JsonElement value)
+ {
+ return value.ValueKind != JsonValueKind.Undefined;
+ }
+
+ public static IReadOnlyDictionary ToDictionary(OptionalProperty> optional)
+ {
+ if (optional.HasValue)
+ {
+ return optional.Value;
+ }
+ return new OptionalDictionary(optional);
+ }
+
+ public static IDictionary ToDictionary(OptionalProperty> optional)
+ {
+ if (optional.HasValue)
+ {
+ return optional.Value;
+ }
+ return new OptionalDictionary(optional);
+ }
+ public static IReadOnlyList ToList(OptionalProperty> optional)
+ {
+ if (optional.HasValue)
+ {
+ return optional.Value;
+ }
+ return new OptionalList(optional);
+ }
+
+ public static IList ToList(OptionalProperty> optional)
+ {
+ if (optional.HasValue)
+ {
+ return optional.Value;
+ }
+ return new OptionalList(optional);
+ }
+
+ public static T? ToNullable(OptionalProperty optional) where T : struct
+ {
+ if (optional.HasValue)
+ {
+ return optional.Value;
+ }
+ return default;
+ }
+
+ public static T? ToNullable(OptionalProperty optional) where T : struct
+ {
+ return optional.Value;
+ }
+}
+
+public readonly struct OptionalProperty
+{
+ public OptionalProperty(T value) : this()
+ {
+ Value = value;
+ HasValue = true;
+ }
+
+ public T Value { get; }
+ public bool HasValue { get; }
+
+ public static implicit operator OptionalProperty(T value) => new OptionalProperty(value);
+ public static implicit operator T(OptionalProperty optional) => optional.Value;
+}
diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/TypeFormatters.cs b/sdk/core/System.ClientModel/tests/client/ClientShared/TypeFormatters.cs
similarity index 98%
rename from sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/TypeFormatters.cs
rename to sdk/core/System.ClientModel/tests/client/ClientShared/TypeFormatters.cs
index 34a83103e6fc..863ec55193d3 100644
--- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/TypeFormatters.cs
+++ b/sdk/core/System.ClientModel/tests/client/ClientShared/TypeFormatters.cs
@@ -3,11 +3,12 @@
#nullable enable
+using System;
using System.Collections.Generic;
using System.Globalization;
using System.Xml;
-namespace System.ClientModel.Tests.Client;
+namespace ClientModel.Tests.ClientShared;
internal class TypeFormatters
{
diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/ModelReaderWriterExtensions.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/ModelReaderWriterExtensions.cs
deleted file mode 100644
index ace7b8403733..000000000000
--- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/ModelReaderWriterExtensions.cs
+++ /dev/null
@@ -1,264 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-#nullable enable
-
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Globalization;
-using System.Linq;
-using System.ClientModel.Primitives;
-using System.Text.Json;
-
-namespace System.ClientModel.Tests.Client
-{
- internal static class ModelReaderWriterExtensions
- {
- // TODO: These are copied from shared source files. If they become
- // public we need to refactor and consolidate to a single place.
-
- #region JsonElement
-
- public static object? GetObject(in this JsonElement element)
- {
- switch (element.ValueKind)
- {
- case JsonValueKind.String:
- return element.GetString();
- case JsonValueKind.Number:
- if (element.TryGetInt32(out int intValue))
- {
- return intValue;
- }
- if (element.TryGetInt64(out long longValue))
- {
- return longValue;
- }
- return element.GetDouble();
- case JsonValueKind.True:
- return true;
- case JsonValueKind.False:
- return false;
- case JsonValueKind.Undefined:
- case JsonValueKind.Null:
- return null;
- case JsonValueKind.Object:
- var dictionary = new Dictionary();
- foreach (JsonProperty jsonProperty in element.EnumerateObject())
- {
- dictionary.Add(jsonProperty.Name, jsonProperty.Value.GetObject());
- }
- return dictionary;
- case JsonValueKind.Array:
- var list = new List();
- foreach (JsonElement item in element.EnumerateArray())
- {
- list.Add(item.GetObject());
- }
- return list.ToArray();
- default:
- throw new NotSupportedException("Not supported value kind " + element.ValueKind);
- }
- }
-
- public static byte[]? GetBytesFromBase64(in this JsonElement element, string format)
- {
- if (element.ValueKind == JsonValueKind.Null)
- {
- return null;
- }
-
- return format switch
- {
- "U" => TypeFormatters.FromBase64UrlString(element.GetRequiredString()),
- "D" => element.GetBytesFromBase64(),
- _ => throw new ArgumentException($"Format is not supported: '{format}'", nameof(format))
- };
- }
-
- public static DateTimeOffset GetDateTimeOffset(in this JsonElement element, string format) => format switch
- {
- "U" when element.ValueKind == JsonValueKind.Number => DateTimeOffset.FromUnixTimeSeconds(element.GetInt64()),
- // relying on the param check of the inner call to throw ArgumentNullException if GetString() returns null
- _ => TypeFormatters.ParseDateTimeOffset(element.GetString()!, format)
- };
-
- public static TimeSpan GetTimeSpan(in this JsonElement element, string format) =>
- // relying on the param check of the inner call to throw ArgumentNullException if GetString() returns null
- TypeFormatters.ParseTimeSpan(element.GetString()!, format);
-
- public static char GetChar(this in JsonElement element)
- {
- if (element.ValueKind == JsonValueKind.String)
- {
- var text = element.GetString();
- if (text == null || text.Length != 1)
- {
- throw new NotSupportedException($"Cannot convert \"{text}\" to a Char");
- }
- return text[0];
- }
- else
- {
- throw new NotSupportedException($"Cannot convert {element.ValueKind} to a Char");
- }
- }
-
- [Conditional("DEBUG")]
- public static void ThrowNonNullablePropertyIsNull(this JsonProperty property)
- {
- throw new JsonException($"A property '{property.Name}' defined as non-nullable but received as null from the service. " +
- $"This exception only happens in DEBUG builds of the library and would be ignored in the release build");
- }
-
- public static string GetRequiredString(in this JsonElement element)
- {
- var value = element.GetString();
- if (value == null)
- throw new InvalidOperationException($"The requested operation requires an element of type 'String', but the target element has type '{element.ValueKind}'.");
-
- return value;
- }
-
- #endregion
-
- #region Utf8JsonWriter
- public static void WriteStringValue(this Utf8JsonWriter writer, DateTimeOffset value, string format) =>
- writer.WriteStringValue(TypeFormatters.ToString(value, format));
-
- public static void WriteStringValue(this Utf8JsonWriter writer, DateTime value, string format) =>
- writer.WriteStringValue(TypeFormatters.ToString(value, format));
-
- public static void WriteStringValue(this Utf8JsonWriter writer, TimeSpan value, string format) =>
- writer.WriteStringValue(TypeFormatters.ToString(value, format));
-
- public static void WriteStringValue(this Utf8JsonWriter writer, char value) =>
- writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture));
-
- public static void WriteNonEmptyArray(this Utf8JsonWriter writer, string name, IReadOnlyList values)
- {
- if (values.Any())
- {
- writer.WriteStartArray(name);
- foreach (var s in values)
- {
- writer.WriteStringValue(s);
- }
-
- writer.WriteEndArray();
- }
- }
-
- public static void WriteBase64StringValue(this Utf8JsonWriter writer, byte[] value, string format)
- {
- if (value == null)
- {
- writer.WriteNullValue();
- return;
- }
-
- switch (format)
- {
- case "U":
- writer.WriteStringValue(TypeFormatters.ToBase64UrlString(value));
- break;
- case "D":
- writer.WriteBase64StringValue(value);
- break;
- default:
- throw new ArgumentException($"Format is not supported: '{format}'", nameof(format));
- }
- }
-
- public static void WriteNumberValue(this Utf8JsonWriter writer, DateTimeOffset value, string format)
- {
- if (format != "U") throw new ArgumentOutOfRangeException(format, "Only 'U' format is supported when writing a DateTimeOffset as a Number.");
-
- writer.WriteNumberValue(value.ToUnixTimeSeconds());
- }
-
- public static void WriteObjectValue(this Utf8JsonWriter writer, object value)
- {
- switch (value)
- {
- case null:
- writer.WriteNullValue();
- break;
- case IJsonModel writeable:
- writeable.Write(writer, ModelReaderWriterHelper.WireOptions);
- break;
- case byte[] bytes:
- writer.WriteBase64StringValue(bytes);
- break;
- case BinaryData bytes:
- writer.WriteBase64StringValue(bytes);
- break;
- case JsonElement json:
- json.WriteTo(writer);
- break;
- case int i:
- writer.WriteNumberValue(i);
- break;
- case decimal d:
- writer.WriteNumberValue(d);
- break;
- case double d:
- if (double.IsNaN(d))
- {
- writer.WriteStringValue("NaN");
- }
- else
- {
- writer.WriteNumberValue(d);
- }
- break;
- case float f:
- writer.WriteNumberValue(f);
- break;
- case long l:
- writer.WriteNumberValue(l);
- break;
- case string s:
- writer.WriteStringValue(s);
- break;
- case bool b:
- writer.WriteBooleanValue(b);
- break;
- case Guid g:
- writer.WriteStringValue(g);
- break;
- case DateTimeOffset dateTimeOffset:
- writer.WriteStringValue(dateTimeOffset, "O");
- break;
- case DateTime dateTime:
- writer.WriteStringValue(dateTime, "O");
- break;
- case IEnumerable> enumerable:
- writer.WriteStartObject();
- foreach (KeyValuePair pair in enumerable)
- {
- writer.WritePropertyName(pair.Key);
- writer.WriteObjectValue(pair.Value);
- }
- writer.WriteEndObject();
- break;
- case IEnumerable objectEnumerable:
- writer.WriteStartArray();
- foreach (object item in objectEnumerable)
- {
- writer.WriteObjectValue(item);
- }
- writer.WriteEndArray();
- break;
- case TimeSpan timeSpan:
- writer.WriteStringValue(timeSpan, "P");
- break;
-
- default:
- throw new NotSupportedException("Not supported type " + value.GetType());
- }
- }
-
-#endregion
- }
-}
\ No newline at end of file
diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/ModelReaderWriterHelper.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/ModelReaderWriterHelper.cs
deleted file mode 100644
index e783ae53acd6..000000000000
--- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/ModelReaderWriterHelper.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-using System.ClientModel.Primitives;
-using System.Runtime.CompilerServices;
-
-namespace System.ClientModel.Tests.Client
-{
- internal static class ModelReaderWriterHelper
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void ValidateFormat(IPersistableModel model, string format)
- {
- bool implementsJson = model is IJsonModel;
- bool isValid = (format == "J" && implementsJson) || format == "W";
- if (!isValid)
- {
- throw new FormatException($"The model {model.GetType().Name} does not support '{format}' format.");
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void ValidateFormat(IPersistableModel model, string format) => ValidateFormat(model, format);
-
- private static ModelReaderWriterOptions _wireOptions;
- public static ModelReaderWriterOptions WireOptions => _wireOptions ??= new ModelReaderWriterOptions("W");
- }
-}
diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/OptionalDictionary.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/OptionalDictionary.cs
deleted file mode 100644
index 0545517016c0..000000000000
--- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/OptionalDictionary.cs
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-
-#nullable enable
-
-namespace System.ClientModel.Tests.Client
-{
- internal class OptionalDictionary : IDictionary, IReadOnlyDictionary where TKey: notnull
- {
- private IDictionary? _innerDictionary;
-
- public OptionalDictionary()
- {
- }
-
- public OptionalDictionary(OptionalProperty> optionalDictionary) : this(optionalDictionary.Value)
- {
- }
-
- public OptionalDictionary(OptionalProperty> optionalDictionary) : this(optionalDictionary.Value)
- {
- }
-
- private OptionalDictionary(IDictionary dictionary)
- {
- if (dictionary == null) return;
-
- _innerDictionary = new Dictionary(dictionary);
- }
-
- private OptionalDictionary(IReadOnlyDictionary dictionary)
- {
- if (dictionary == null) return;
-
- _innerDictionary = new Dictionary();
- foreach (KeyValuePair pair in dictionary)
- {
- _innerDictionary.Add(pair);
- }
- }
-
- public bool IsUndefined => _innerDictionary == null;
-
- public IEnumerator> GetEnumerator()
- {
- if (IsUndefined)
- {
- IEnumerator> GetEmptyEnumerator()
- {
- yield break;
- }
- return GetEmptyEnumerator();
- }
- return EnsureDictionary().GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
- public void Add(KeyValuePair item)
- {
- EnsureDictionary().Add(item);
- }
-
- public void Clear()
- {
- EnsureDictionary().Clear();
- }
-
- public bool Contains(KeyValuePair item)
- {
- if (IsUndefined)
- {
- return false;
- }
-
- return EnsureDictionary().Contains(item);
- }
-
- public void CopyTo(KeyValuePair[] array, int arrayIndex)
- {
- if (IsUndefined)
- {
- return;
- }
-
- EnsureDictionary().CopyTo(array, arrayIndex);
- }
-
- public bool Remove(KeyValuePair item)
- {
- if (IsUndefined)
- {
- return false;
- }
-
- return EnsureDictionary().Remove(item);
- }
-
- public int Count
- {
- get
- {
- if (IsUndefined)
- {
- return 0;
- }
-
- return EnsureDictionary().Count;
- }
- }
-
- public bool IsReadOnly
- {
- get
- {
- if (IsUndefined)
- {
- return false;
- }
- return EnsureDictionary().IsReadOnly;
- }
- }
-
- public void Add(TKey key, TValue value)
- {
- EnsureDictionary().Add(key, value);
- }
-
- public bool ContainsKey(TKey key)
- {
- if (IsUndefined)
- {
- return false;
- }
-
- return EnsureDictionary().ContainsKey(key);
- }
-
- public bool Remove(TKey key)
- {
- if (IsUndefined)
- {
- return false;
- }
-
- return EnsureDictionary().Remove(key);
- }
-
- public bool TryGetValue(TKey key, out TValue value)
- {
- if (IsUndefined)
- {
- value = default!;
- return false;
- }
- return EnsureDictionary().TryGetValue(key, out value!);
- }
-
- public TValue this[TKey key]
- {
- get
- {
- if (IsUndefined)
- {
- throw new KeyNotFoundException(nameof(key));
- }
-
- return EnsureDictionary()[key];
- }
- set => EnsureDictionary()[key] = value;
- }
-
- IEnumerable IReadOnlyDictionary.Keys => Keys;
-
- IEnumerable IReadOnlyDictionary.Values => Values;
-
- public ICollection Keys
- {
- get
- {
- if (IsUndefined)
- {
- return Array.Empty();
- }
-
- return EnsureDictionary().Keys;
- }
- }
-
- public ICollection Values
- {
- get
- {
- if (IsUndefined)
- {
- return Array.Empty();
- }
-
- return EnsureDictionary().Values;
- }
- }
-
- private IDictionary EnsureDictionary()
- {
- return _innerDictionary ??= new Dictionary();
- }
- }
-}
diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/OptionalList.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/OptionalList.cs
deleted file mode 100644
index 778573e86d39..000000000000
--- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/OptionalList.cs
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-
-#nullable enable
-
-namespace System.ClientModel.Tests.Client
-{
- internal class OptionalList: IList, IReadOnlyList
- {
- private IList? _innerList;
-
- public OptionalList()
- {
- }
-
- public OptionalList(OptionalProperty> optionalList) : this(optionalList.Value)
- {
- }
-
- public OptionalList(OptionalProperty> optionalList) : this(optionalList.Value)
- {
- }
-
- private OptionalList(IEnumerable innerList)
- {
- if (innerList == null)
- {
- return;
- }
-
- _innerList = innerList.ToList();
- }
-
- private OptionalList(IList innerList)
- {
- if (innerList == null)
- {
- return;
- }
-
- _innerList = innerList;
- }
-
- public bool IsUndefined => _innerList == null;
-
- public void Reset()
- {
- _innerList = null;
- }
-
- public IEnumerator GetEnumerator()
- {
- if (IsUndefined)
- {
- IEnumerator EnumerateEmpty()
- {
- yield break;
- }
-
- return EnumerateEmpty();
- }
- return EnsureList().GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
- public void Add(T item)
- {
- EnsureList().Add(item);
- }
-
- public void Clear()
- {
- EnsureList().Clear();
- }
-
- public bool Contains(T item)
- {
- if (IsUndefined)
- {
- return false;
- }
-
- return EnsureList().Contains(item);
- }
-
- public void CopyTo(T[] array, int arrayIndex)
- {
- if (IsUndefined)
- {
- return;
- }
-
- EnsureList().CopyTo(array, arrayIndex);
- }
-
- public bool Remove(T item)
- {
- if (IsUndefined)
- {
- return false;
- }
-
- return EnsureList().Remove(item);
- }
-
- public int Count
- {
- get
- {
- if (IsUndefined)
- {
- return 0;
- }
- return EnsureList().Count;
- }
- }
-
- public bool IsReadOnly
- {
- get
- {
- if (IsUndefined)
- {
- return false;
- }
-
- return EnsureList().IsReadOnly;
- }
- }
-
- public int IndexOf(T item)
- {
- if (IsUndefined)
- {
- return -1;
- }
-
- return EnsureList().IndexOf(item);
- }
-
- public void Insert(int index, T item)
- {
- EnsureList().Insert(index, item);
- }
-
- public void RemoveAt(int index)
- {
- if (IsUndefined)
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
-
- EnsureList().RemoveAt(index);
- }
-
- public T this[int index]
- {
- get
- {
- if (IsUndefined)
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
-
- return EnsureList()[index];
- }
- set
- {
- if (IsUndefined)
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
-
- EnsureList()[index] = value;
- }
- }
-
- private IList EnsureList()
- {
- return _innerList ??= new List();
- }
- }
-}
diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/OptionalProperty.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/OptionalProperty.cs
deleted file mode 100644
index 0e746c348dd4..000000000000
--- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/OptionalProperty.cs
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-#nullable disable
-
-using System.Collections.Generic;
-using System.Text.Json;
-
-namespace System.ClientModel.Tests.Client
-{
- internal static class OptionalProperty
- {
- public static bool IsCollectionDefined(IEnumerable collection)
- {
- return !(collection is OptionalList changeTrackingList && changeTrackingList.IsUndefined);
- }
-
- public static bool IsCollectionDefined(IReadOnlyDictionary collection)
- {
- return !(collection is OptionalDictionary changeTrackingList && changeTrackingList.IsUndefined);
- }
-
- public static bool IsCollectionDefined(IDictionary collection)
- {
- return !(collection is OptionalDictionary changeTrackingList && changeTrackingList.IsUndefined);
- }
-
- public static bool IsDefined(T? value) where T: struct
- {
- return value.HasValue;
- }
- public static bool IsDefined(object value)
- {
- return value != null;
- }
- public static bool IsDefined(string value)
- {
- return value != null;
- }
-
- public static bool IsDefined(JsonElement value)
- {
- return value.ValueKind != JsonValueKind.Undefined;
- }
-
- public static IReadOnlyDictionary ToDictionary(OptionalProperty> optional)
- {
- if (optional.HasValue)
- {
- return optional.Value;
- }
- return new OptionalDictionary(optional);
- }
-
- public static IDictionary ToDictionary(OptionalProperty> optional)
- {
- if (optional.HasValue)
- {
- return optional.Value;
- }
- return new OptionalDictionary(optional);
- }
- public static IReadOnlyList ToList(OptionalProperty> optional)
- {
- if (optional.HasValue)
- {
- return optional.Value;
- }
- return new OptionalList(optional);
- }
-
- public static IList