From f628c984a824e885d8a820002036b104de52010b Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Fri, 19 Jan 2024 16:44:54 -0800 Subject: [PATCH] ClientModel: Reshuffle some whitespace and files for consistency across ClientModel (#41425) * Initial implementation of SetHeader * Add tests for SetHeader * more tests * updates * Reshuffle a bit for consistency across ClientModel files * remove SetHeader changes that will be part of a separate PR * nits * Add .editorconfig * remove most NoWarn suppressions from .csproj --- .editorconfig | 4 +- sdk/core/System.ClientModel/src/.editorconfig | 2 + .../src/ModelReaderWriter/IJsonModel.cs | 41 ++- .../ModelReaderWriter/IPersistableModel.cs | 55 ++-- .../ModelReaderWriter/JsonModelConverter.cs | 85 +++--- .../ModelReaderWriter/ModelReaderWriter.cs | 269 +++++++++-------- .../ModelReaderWriterOptions.cs | 53 ++-- .../src/ModelReaderWriter/ModelWriter.cs | 11 +- .../ModelWriterOfT.SequenceBuilder.cs | 249 ++++++++-------- .../src/ModelReaderWriter/ModelWriterOfT.cs | 273 +++++++++--------- .../PersistableModelProxyAttribute.cs | 49 ++-- .../src/System.ClientModel.csproj | 2 +- .../ModelReaderWriterExtensions.cs | 264 +++++++++++++++++ .../ClientShared/ModelReaderWriterHelper.cs | 28 ++ .../client/ClientShared/OptionalDictionary.cs | 214 ++++++++++++++ .../tests/client/ClientShared/OptionalList.cs | 191 ++++++++++++ .../client/ClientShared/OptionalProperty.cs | 107 +++++++ .../TypeFormatters.cs | 3 +- .../Internal/ModelReaderWriterExtensions.cs | 264 ----------------- .../Internal/ModelReaderWriterHelper.cs | 28 -- .../Internal/OptionalDictionary.cs | 215 -------------- .../Internal/OptionalList.cs | 192 ------------ .../Internal/OptionalProperty.cs | 110 ------- .../Models/DiscriminatorSet/BaseModel.cs | 21 +- .../Models/DiscriminatorSet/ModelX.cs | 21 +- .../Models/DiscriminatorSet/ModelY.cs | 3 +- .../DiscriminatorSet/UnknownBaseModel.cs | 3 +- .../ModelReaderWriter/Models/ModelAsStruct.cs | 18 +- .../Models/ModelWithPersistableOnly.cs | 5 +- .../ServiceModels/ApiProfile.Serialization.cs | 1 + .../AvailabilitySetData.Serialization.cs | 3 +- .../ServiceModels/AvailabilitySetData.cs | 23 +- .../ServiceModels/ComputeSku.Serialization.cs | 1 + .../InstanceViewStatus.Serialization.cs | 3 +- .../ProviderExtendedLocation.Serialization.cs | 3 +- .../ServiceModels/ProviderExtendedLocation.cs | 1 + .../ProviderResourceType.Serialization.cs | 3 +- .../ServiceModels/ProviderResourceType.cs | 1 + .../ResourceProviderData.Serialization.cs | 3 +- .../ServiceModels/ResourceProviderData.cs | 20 ++ .../ResourceTypeAlias.Serialization.cs | 3 +- .../ServiceModels/ResourceTypeAlias.cs | 1 + .../ResourceTypeAliasPath.Serialization.cs | 3 +- .../ServiceModels/ResourceTypeAliasPath.cs | 1 + ...urceTypeAliasPathMetadata.Serialization.cs | 1 + .../ResourceTypeAliasPattern.Serialization.cs | 1 + .../ServiceModels/SystemData.Serialization.cs | 3 +- .../ServiceModels/TrackedResourceData.cs | 1 + .../WritableSubResource.Serialization.cs | 1 + .../ZoneMapping.Serialization.cs | 3 +- .../ServiceModels/ZoneMapping.cs | 1 + 51 files changed, 1481 insertions(+), 1380 deletions(-) create mode 100644 sdk/core/System.ClientModel/src/.editorconfig create mode 100644 sdk/core/System.ClientModel/tests/client/ClientShared/ModelReaderWriterExtensions.cs create mode 100644 sdk/core/System.ClientModel/tests/client/ClientShared/ModelReaderWriterHelper.cs create mode 100644 sdk/core/System.ClientModel/tests/client/ClientShared/OptionalDictionary.cs create mode 100644 sdk/core/System.ClientModel/tests/client/ClientShared/OptionalList.cs create mode 100644 sdk/core/System.ClientModel/tests/client/ClientShared/OptionalProperty.cs rename sdk/core/System.ClientModel/tests/client/{ModelReaderWriter/Internal => ClientShared}/TypeFormatters.cs (98%) delete mode 100644 sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/ModelReaderWriterExtensions.cs delete mode 100644 sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/ModelReaderWriterHelper.cs delete mode 100644 sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/OptionalDictionary.cs delete mode 100644 sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/OptionalList.cs delete mode 100644 sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Internal/OptionalProperty.cs 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 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/Models/DiscriminatorSet/BaseModel.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/BaseModel.cs index 0c7f8b279f4c..fb50d2ac81b1 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/BaseModel.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/BaseModel.cs @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System.Collections.Generic; +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; +using System.Collections.Generic; using System.Text.Json; namespace System.ClientModel.Tests.Client.ModelReaderWriterTests.Models @@ -12,6 +13,24 @@ public abstract class BaseModel : IJsonModel { private Dictionary _rawData; + public static implicit operator BinaryContent(BaseModel baseModel) + { + if (baseModel == null) + { + return null; + } + + return BinaryContent.Create(baseModel, ModelReaderWriterHelper.WireOptions); + } + + public static explicit operator BaseModel(ClientResult result) + { + if (result is null) throw new ArgumentNullException(nameof(result)); + + using JsonDocument jsonDocument = JsonDocument.Parse(result.GetRawResponse().Content); + return DeserializeBaseModel(jsonDocument.RootElement, ModelReaderWriterHelper.WireOptions); + } + protected internal BaseModel(Dictionary rawData) { _rawData = rawData ?? new Dictionary(); diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/ModelX.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/ModelX.cs index b35b34098607..b381b2bbaf60 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/ModelX.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/ModelX.cs @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using ClientModel.Tests.ClientShared; +using System.ClientModel.Primitives; using System.Collections.Generic; using System.Linq; -using System.ClientModel.Primitives; using System.Text.Json; namespace System.ClientModel.Tests.Client.ModelReaderWriterTests.Models @@ -32,6 +33,24 @@ internal ModelX(string kind, string name, int xProperty, int? nullProperty, ILis public int? NullProperty = null; public IDictionary KeyValuePairs { get; } + public static implicit operator BinaryContent(ModelX modelX) + { + if (modelX == null) + { + return null; + } + + return BinaryContent.Create(modelX, ModelReaderWriterHelper.WireOptions); + } + + public static explicit operator ModelX(ClientResult result) + { + if (result is null) throw new ArgumentNullException(nameof(result)); + + using JsonDocument jsonDocument = JsonDocument.Parse(result.GetRawResponse().Content); + return DeserializeModelX(jsonDocument.RootElement, ModelReaderWriterHelper.WireOptions); + } + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) { ModelReaderWriterHelper.ValidateFormat(this, options.Format); diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/ModelY.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/ModelY.cs index af5f35bf9c3a..ac42c88881ba 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/ModelY.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/ModelY.cs @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System.Collections.Generic; +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; +using System.Collections.Generic; using System.Text.Json; namespace System.ClientModel.Tests.Client.ModelReaderWriterTests.Models diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/UnknownBaseModel.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/UnknownBaseModel.cs index dc87efca554c..492b073c665f 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/UnknownBaseModel.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/DiscriminatorSet/UnknownBaseModel.cs @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System.Collections.Generic; +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; +using System.Collections.Generic; using System.Text.Json; namespace System.ClientModel.Tests.Client.ModelReaderWriterTests.Models diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/ModelAsStruct.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/ModelAsStruct.cs index 37b365fddec1..6e557d3acf20 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/ModelAsStruct.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/ModelAsStruct.cs @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#nullable disable - -using System.Collections.Generic; +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; +using System.Collections.Generic; using System.Text.Json; namespace System.ClientModel.Tests.Client.ModelReaderWriterTests.Models @@ -59,6 +58,11 @@ BinaryData IPersistableModel.Write(ModelReaderWriterOptions optio return ModelReaderWriter.Write(this, options); } + public static implicit operator BinaryContent(ModelAsStruct model) + { + return BinaryContent.Create(model, ModelReaderWriterHelper.WireOptions); + } + ModelAsStruct IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) { ModelReaderWriterHelper.ValidateFormat(this, options.Format); @@ -97,6 +101,14 @@ ModelAsStruct IJsonModel.Create(ref Utf8JsonReader reader, ModelR return DeserializeInputAdditionalPropertiesModelStruct(doc.RootElement, options); } + public static explicit operator ModelAsStruct(ClientResult result) + { + if (result is null) throw new ArgumentNullException(nameof(result)); + + using JsonDocument doc = JsonDocument.Parse(result.GetRawResponse().Content); + return DeserializeInputAdditionalPropertiesModelStruct(doc.RootElement, ModelReaderWriterHelper.WireOptions); + } + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) => Serialize(writer, options); object IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/ModelWithPersistableOnly.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/ModelWithPersistableOnly.cs index a3613babbd5d..3c02b640d74f 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/ModelWithPersistableOnly.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/Models/ModelWithPersistableOnly.cs @@ -1,11 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using ClientModel.Tests.ClientShared; +using System.ClientModel.Primitives; using System.Collections.Generic; +using System.IO; using System.Linq; -using System.ClientModel.Primitives; using System.Text.Json; -using System.IO; namespace System.ClientModel.Tests.Client.ModelReaderWriterTests.Models { diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ApiProfile.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ApiProfile.Serialization.cs index 059a49c8332e..e4393e2a69c0 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ApiProfile.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ApiProfile.Serialization.cs @@ -5,6 +5,7 @@ #nullable disable +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; using System.Text.Json; diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/AvailabilitySetData.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/AvailabilitySetData.Serialization.cs index 677bf647bc3d..7a0a5bcd187d 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/AvailabilitySetData.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/AvailabilitySetData.Serialization.cs @@ -5,9 +5,10 @@ #nullable disable -using System.Collections.Generic; +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; using System.ClientModel.Tests.Client.Models.ResourceManager.Resources; +using System.Collections.Generic; using System.Text.Json; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Compute diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/AvailabilitySetData.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/AvailabilitySetData.cs index 4c117d0ad5ab..dd8ead307953 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/AvailabilitySetData.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/AvailabilitySetData.cs @@ -5,9 +5,10 @@ #nullable disable -using System.Collections.Generic; -using System.ClientModel.Tests.Client.Models.ResourceManager; +using ClientModel.Tests.ClientShared; using System.ClientModel.Tests.Client.Models.ResourceManager.Resources; +using System.Collections.Generic; +using System.Text.Json; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Compute { @@ -19,6 +20,24 @@ public partial class AvailabilitySetData : TrackedResourceData { internal AvailabilitySetData() { } + public static implicit operator BinaryContent(AvailabilitySetData availabilitySetData) + { + if (availabilitySetData is null) + { + return null; + } + + return BinaryContent.Create(availabilitySetData, ModelReaderWriterHelper.WireOptions); + } + + public static explicit operator AvailabilitySetData(ClientResult result) + { + if (result is null) throw new ArgumentNullException(nameof(result)); + + using JsonDocument jsonDocument = JsonDocument.Parse(result.GetRawResponse().Content); + return DeserializeAvailabilitySetData(jsonDocument.RootElement, ModelReaderWriterHelper.WireOptions); + } + /// Initializes a new instance of AvailabilitySetData. /// The location. public AvailabilitySetData(string location) : base(location) diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ComputeSku.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ComputeSku.Serialization.cs index 95720caae53d..0240a70b3d1e 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ComputeSku.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ComputeSku.Serialization.cs @@ -5,6 +5,7 @@ #nullable disable +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; using System.Text.Json; diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/InstanceViewStatus.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/InstanceViewStatus.Serialization.cs index eb04c948f4a7..01d93a0a3ff3 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/InstanceViewStatus.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/InstanceViewStatus.Serialization.cs @@ -5,8 +5,9 @@ #nullable disable -using System.Globalization; +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; +using System.Globalization; using System.Text.Json; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Compute diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderExtendedLocation.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderExtendedLocation.Serialization.cs index a06d845f9790..0e1b113b8137 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderExtendedLocation.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderExtendedLocation.Serialization.cs @@ -5,8 +5,9 @@ #nullable disable -using System.Collections.Generic; +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; +using System.Collections.Generic; using System.Text.Json; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Resources diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderExtendedLocation.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderExtendedLocation.cs index 95f68636f58d..cf36137823a0 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderExtendedLocation.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderExtendedLocation.cs @@ -5,6 +5,7 @@ #nullable disable +using ClientModel.Tests.ClientShared; using System.Collections.Generic; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Resources diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderResourceType.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderResourceType.Serialization.cs index 46966bf1d269..6789848e53d7 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderResourceType.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderResourceType.Serialization.cs @@ -5,8 +5,9 @@ #nullable disable -using System.Collections.Generic; +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; +using System.Collections.Generic; using System.Text.Json; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Resources diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderResourceType.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderResourceType.cs index 5f6af5dc013d..4c5fe551a3b1 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderResourceType.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ProviderResourceType.cs @@ -5,6 +5,7 @@ #nullable disable +using ClientModel.Tests.ClientShared; using System.Collections.Generic; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Resources diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceProviderData.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceProviderData.Serialization.cs index 6e28dd130575..50cbb69b99ee 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceProviderData.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceProviderData.Serialization.cs @@ -5,8 +5,9 @@ #nullable disable -using System.Collections.Generic; +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; +using System.Collections.Generic; using System.Text.Json; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Resources diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceProviderData.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceProviderData.cs index f50da3882e40..f4fcff41e23f 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceProviderData.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceProviderData.cs @@ -5,7 +5,9 @@ #nullable disable +using ClientModel.Tests.ClientShared; using System.Collections.Generic; +using System.Text.Json; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Resources { @@ -15,6 +17,24 @@ namespace System.ClientModel.Tests.Client.Models.ResourceManager.Resources /// public partial class ResourceProviderData { + public static implicit operator BinaryContent(ResourceProviderData resourceProviderData) + { + if (resourceProviderData == null) + { + return null; + } + + return BinaryContent.Create(resourceProviderData, ModelReaderWriterHelper.WireOptions); + } + + public static explicit operator ResourceProviderData(ClientResult result) + { + if (result is null) throw new ArgumentNullException(nameof(result)); + + using JsonDocument jsonDocument = JsonDocument.Parse(result.GetRawResponse().Content); + return DeserializeResourceProviderData(jsonDocument.RootElement, ModelReaderWriterHelper.WireOptions); + } + /// Initializes a new instance of ProviderData. public ResourceProviderData() { diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAlias.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAlias.Serialization.cs index c805a22c1886..bd5a876f5d33 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAlias.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAlias.Serialization.cs @@ -5,8 +5,9 @@ #nullable disable -using System.Collections.Generic; +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; +using System.Collections.Generic; using System.Text.Json; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Resources diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAlias.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAlias.cs index 38e562d66d48..015e1ee09f64 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAlias.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAlias.cs @@ -5,6 +5,7 @@ #nullable disable +using ClientModel.Tests.ClientShared; using System.Collections.Generic; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Resources diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPath.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPath.Serialization.cs index c9cb0eaa9940..cd11999862f6 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPath.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPath.Serialization.cs @@ -5,8 +5,9 @@ #nullable disable -using System.Collections.Generic; +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; +using System.Collections.Generic; using System.Text.Json; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Resources diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPath.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPath.cs index 0bbee9cb789c..5d42a403cb21 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPath.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPath.cs @@ -5,6 +5,7 @@ #nullable disable +using ClientModel.Tests.ClientShared; using System.Collections.Generic; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Resources diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPathMetadata.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPathMetadata.Serialization.cs index 61b717c734d1..86df483f3e68 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPathMetadata.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPathMetadata.Serialization.cs @@ -5,6 +5,7 @@ #nullable disable +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; using System.Text.Json; diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPattern.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPattern.Serialization.cs index 364acb956cce..15d867604c3a 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPattern.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ResourceTypeAliasPattern.Serialization.cs @@ -5,6 +5,7 @@ #nullable disable +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; using System.Text.Json; diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/SystemData.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/SystemData.Serialization.cs index 820ad2557461..1f698f7d257f 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/SystemData.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/SystemData.Serialization.cs @@ -5,8 +5,9 @@ #nullable disable -using System.Globalization; +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; +using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/TrackedResourceData.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/TrackedResourceData.cs index 073d5da409be..0657acf65075 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/TrackedResourceData.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/TrackedResourceData.cs @@ -3,6 +3,7 @@ #nullable disable +using ClientModel.Tests.ClientShared; using System.Collections.Generic; namespace System.ClientModel.Tests.Client.Models.ResourceManager diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/WritableSubResource.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/WritableSubResource.Serialization.cs index 4b220b3fb981..270512877fe6 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/WritableSubResource.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/WritableSubResource.Serialization.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; using System.Text.Json; using System.Text.Json.Serialization; diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ZoneMapping.Serialization.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ZoneMapping.Serialization.cs index 7899034d4619..34cb3f05eacb 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ZoneMapping.Serialization.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ZoneMapping.Serialization.cs @@ -5,8 +5,9 @@ #nullable disable -using System.Collections.Generic; +using ClientModel.Tests.ClientShared; using System.ClientModel.Primitives; +using System.Collections.Generic; using System.Text.Json; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Resources diff --git a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ZoneMapping.cs b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ZoneMapping.cs index c652c7c898a1..b04f38867584 100644 --- a/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ZoneMapping.cs +++ b/sdk/core/System.ClientModel/tests/client/ModelReaderWriter/ServiceModels/ZoneMapping.cs @@ -5,6 +5,7 @@ #nullable disable +using ClientModel.Tests.ClientShared; using System.Collections.Generic; namespace System.ClientModel.Tests.Client.Models.ResourceManager.Resources