{"id":13629204,"url":"https://github.com/altasoft/DomainPrimitives","last_synced_at":"2025-04-17T04:33:14.871Z","repository":{"id":216293705,"uuid":"740940103","full_name":"altasoft/DomainPrimitives","owner":"altasoft","description":"C# Domain Primitives generator","archived":false,"fork":false,"pushed_at":"2025-04-10T07:56:28.000Z","size":3090,"stargazers_count":58,"open_issues_count":1,"forks_count":0,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-04-10T08:07:51.015Z","etag":null,"topics":["ddd","domain","dotnet","dotnet-core","entity","primitive-types","source-generators","strongly-typed","value-object"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/altasoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-09T11:36:15.000Z","updated_at":"2025-04-10T07:55:23.000Z","dependencies_parsed_at":"2024-05-01T14:53:48.149Z","dependency_job_id":"4bba33fa-b585-46e0-b1d2-8e6039523e5b","html_url":"https://github.com/altasoft/DomainPrimitives","commit_stats":null,"previous_names":["altasoft/domainprimitives"],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/altasoft%2FDomainPrimitives","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/altasoft%2FDomainPrimitives/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/altasoft%2FDomainPrimitives/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/altasoft%2FDomainPrimitives/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/altasoft","download_url":"https://codeload.github.com/altasoft/DomainPrimitives/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249316056,"owners_count":21249885,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ddd","domain","dotnet","dotnet-core","entity","primitive-types","source-generators","strongly-typed","value-object"],"created_at":"2024-08-01T22:01:04.495Z","updated_at":"2025-04-17T04:33:14.861Z","avatar_url":"https://github.com/altasoft.png","language":"C#","readme":"# DomainPrimitives for C#  \n\n[![Version](https://img.shields.io/nuget/v/AltaSoft.DomainPrimitives?label=Version\u0026color=0c3c60\u0026style=for-the-badge\u0026logo=nuget)](https://www.nuget.org/profiles/AltaSoft)\n[![Dot NET 7+](https://img.shields.io/static/v1?label=DOTNET\u0026message=7%2B\u0026color=0c3c60\u0026style=for-the-badge)](https://dotnet.microsoft.com)\n\n# Table of Contents\n\n- [Introduction](#introduction)\n- [Key Features](#key-features)\n- [Generator Features](#generator-features)\n- [Supported Underlying types](#supported-underlying-types)\n- [Getting Started](#getting-started)\n- [Prerequisites](#prerequisites)\n- [Installation](#installation)\n- [Creating your Domain type](#creating-your-domain-type)\n- [Json Conversion](#json-conversion)\n- [Contributions](#contributions)\n- [Contact](#contact)\n- [License](#license)\n\n## Introduction\n\nWelcome to **AltaSoft.DomainPrimitives** - a C# toolkit purposefully designed to accelerate the development of domain-specific primitives within your applications. This streamlined solution empowers developers to efficiently encapsulate fundamental domain logic. Through this toolkit, you'll significantly reduce code complexity while improving the maintainability of your project.\n## Key Features\n* **Simplified Primitive Creation** - Utilize source generators to swiftly create domain-specific primitives with ease and precision.\n* **Versatile Underlying Type Support** - Embrace a wide array of underlying types, catering to diverse application requirements.\n* **Enhanced Code Quality** - Create clean, maintainable, and thoroughly testable code through encapsulation and robust design principles.\n\n\nWith `AltaSoft.DomainPrimitives`, experience an accelerated development process while upholding code quality standards. This toolkit empowers developers to focus on the core business logic without compromising on precision or efficiency.\n \n## Generator Features \n\nThe **AltaSoft.DomainPrimitives.Generator** offers a diverse set of features:\n\n* **Implicit Operators:** Streamlines type conversion to/from the underlying primitive type. [Example](#implicit-usage-of-domaintype)\n* **Specialized Constructor Generation:**  Automatically validates and constructs instances of this domain type. This constructor, tailored for the domain primitive, utilizes the underlying type as a parameter, ensuring the value's correctness within the domain.\n* **TryCreate method:** Introduces a TryCreate method that attempts to create an instance of the domain type and returns a bool indicating the success or failure of the creation process, along with any validation errors.\n* **JsonConverters:** Handles JSON serialization and deserialization for the underlying type. [Example](#json-conversion)\n* **TypeConverters:** Assists in type conversion to/from it's underlying type. [Please refer to generated type converter below](#type-converter)\n* **Swagger Custom Type Mappings:** Facilitates easy integration with Swagger by treating the primitive type as it's underlying type. [Please refer to generated swagger helper below](#swagger-mappers)\n* **Interface Implementations:** All DomainPritmitives Implement `IConvertible`, `IComparable`, `IComparable\u003cT\u003e`, `IEquatable\u003cT\u003e`, `IEqualityComparer\u003cT\u003e`, `IParsable` interfaces.\n* **NumberType Operations:** Automatically generates basic arithmetic and comparison operators, by implementing Static abstract interfaces. [More details regarding numeric types](#number-types-attribute)\n* **IParsable Implementation:** Automatically generates parsing for non-string types.\n* **XML Serialiaziton** Generates IXmlSerializable interface implementation, to serialize and deserialize from/to xml.\n* **EntityFrameworkCore ValueConverters** Facilitates seamless integration with EntityFrameworkCore by using ValueConverters to treat the primitive type as its underlying type. For more details, refer to [EntityFrameworkCore ValueConverters](EntityFrameworkCoreExample.md)\n\n## Supported Underlying types \n1. `string`\n2. `Guid`\n3. `byte`\n4. `sbyte`\n5. `short`\n6. `ushort`\n7. `int`\n8. `uint`\n9. `long`\n10. `ulong`\n11. `decimal`\n12. `double`\n13. `float`\n14. `bool`\n15. `char`\n16. `TimeSpan`\n17. `DateTime`\n18. `DateTimeOffset`\n19. `DateOnly`\n20. `TimeOnly`\n\n\n## Getting Started\n\n### Prerequisites\n*\t.NET 7 or higher\n*\tNuGet Package Manager\n\n### Installation\n\nTo use **AltaSoft.DomainPrimitives**, install two NuGet packages:\n\n1. `AltaSoft.DomainPrimitives`\n2. `AltaSoft.DomainPrimitives.Generator`\n\nIn your project file add references as follows:\n\n```xml\n\u003cItemGroup\u003e\n  \u003cPackageReference Include=\"AltaSoft.DomainPrimitives\" Version=\"x.x.x\" /\u003e\n  \u003cPackageReference Include=\"AltaSoft.DomainPrimitives.Generator\" Version=\"x.x.x\" PrivateAssets=\"all\" /\u003e\n\u003c/ItemGroup\u003e\n```\n\n\n## **Creating your Domain type**\nFor optimal performance, it is recommended to use `readonly struct`, especially when wrapping value types. If the type is a `reference` type, consider using `class` over `struct`.\n\n```csharp\npublic readonly partial struct PositiveInteger : IDomainValue\u003cint\u003e\n{\n    /// \u003cinheritdoc/\u003e\n    public static PrimitiveValidationResult Validate(int value)\n    {\n        if (value \u003c= 0)\n            return PrimitiveValidationResult.Error(\"value is non-positive\");\n\n        return PrimitiveValidationResult.Ok;\n    }\n}\n```\n\nThis will automatically generate by default 4 classes\n## **PositiveInteger.Generated**\n```csharp\n//------------------------------------------------------------------------------\n// \u003cauto-generated\u003e\n//     This code was generated by 'AltaSoft DomainPrimitives Generator'.\n//     Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.\n// \u003c/auto-generated\u003e\n//------------------------------------------------------------------------------\n\n#nullable enable\n\nusing System;\nusing System.Numerics;\nusing System.Diagnostics;\nusing System.Runtime.CompilerServices;\nusing AltaSoft.DomainPrimitives;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Text.Json.Serialization;\nusing AltaSoft.DomainPrimitives.XmlDataTypes.Converters;\nusing System.ComponentModel;\nusing System.Xml;\nusing System.Xml.Schema;\nusing System.Xml.Serialization;\n\nnamespace AltaSoft.DomainPrimitives.XmlDataTypes;\n\n[JsonConverter(typeof(PositiveIntegerJsonConverter))]\n[TypeConverter(typeof(PositiveIntegerTypeConverter))]\n[UnderlyingPrimitiveType(typeof(int))]\n[DebuggerDisplay(\"{_value}\")]\npublic readonly partial struct PositiveInteger : IEquatable\u003cPositiveInteger\u003e\n        , IComparable\n        , IComparable\u003cPositiveInteger\u003e\n        , IAdditionOperators\u003cPositiveInteger, PositiveInteger, PositiveInteger\u003e\n        , ISubtractionOperators\u003cPositiveInteger, PositiveInteger, PositiveInteger\u003e\n        , IMultiplyOperators\u003cPositiveInteger, PositiveInteger, PositiveInteger\u003e\n        , IDivisionOperators\u003cPositiveInteger, PositiveInteger, PositiveInteger\u003e\n        , IModulusOperators\u003cPositiveInteger, PositiveInteger, PositiveInteger\u003e\n        , IComparisonOperators\u003cPositiveInteger, PositiveInteger, bool\u003e\n        , IParsable\u003cPositiveInteger\u003e\n        , IConvertible\n        , IXmlSerializable\n#if NET8_0_OR_GREATER\n        , IUtf8SpanFormattable\n#endif\n{\n    /// \u003cinheritdoc/\u003e\n     public Type GetUnderlyingPrimitiveType() =\u003e typeof(int);\n    /// \u003cinheritdoc/\u003e\n     public object GetUnderlyingPrimitiveValue() =\u003e (int)this;\n\n    private int _valueOrThrow =\u003e _isInitialized ? _value : throw new InvalidDomainValueException(\"The domain value has not been initialized\", this);\n    [DebuggerBrowsable(DebuggerBrowsableState.Never)]\n    private readonly int _value;\n    [DebuggerBrowsable(DebuggerBrowsableState.Never)]\n    private readonly bool _isInitialized;\n\n    /// \u003csummary\u003e\n    /// Initializes a new instance of the \u003csee cref=\"PositiveInteger\"/\u003e class by validating the specified \u003csee cref=\"int\"/\u003e value using \u003csee cref=\"Validate\"/\u003e static method.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"value\"\u003eThe value to be validated.\u003c/param\u003e\n    public PositiveInteger(int value) : this(value, true)\n    {\n    }\n\n    private PositiveInteger(int value, bool validate) \n    {\n        if (validate)\n        {\n            ValidateOrThrow(value);\n        }\n        _value = value;\n        _isInitialized = true;\n    }\n\n    /// \u003cinheritdoc/\u003e\n    [Obsolete(\"Domain primitive cannot be created using empty Constructor\", true)]\n    public PositiveInteger()\n    {\n    }\n\n    /// \u003csummary\u003e\n    /// Tries to create an instance of AsciiString from the specified value.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"value\"\u003eThe value to create PositiveInteger from\u003c/param\u003e\n    /// \u003cparam name=\"result\"\u003eWhen this method returns, contains the created PositiveInteger if the conversion succeeded, or null if the conversion failed.\u003c/param\u003e\n    /// \u003creturns\u003etrue if the conversion succeeded; otherwise, false.\u003c/returns\u003e\n    public static bool TryCreate(int value, [NotNullWhen(true)] out PositiveInteger? result)\n    {\n        return TryCreate(value, out result, out _);\n    }\n\n    /// \u003csummary\u003e\n    /// Tries to create an instance of AsciiString from the specified value.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"value\"\u003eThe value to create PositiveInteger from\u003c/param\u003e\n    /// \u003cparam name=\"result\"\u003eWhen this method returns, contains the created PositiveInteger if the conversion succeeded, or null if the conversion failed.\u003c/param\u003e\n    /// \u003cparam name=\"errorMessage\"\u003eWhen this method returns, contains the error message if the conversion failed; otherwise, null.\u003c/param\u003e\n    /// \u003creturns\u003etrue if the conversion succeeded; otherwise, false.\u003c/returns\u003e\n    public static bool TryCreate(int value,[NotNullWhen(true)]  out PositiveInteger? result, [NotNullWhen(false)]  out string? errorMessage)\n    {\n        var validationResult = Validate(value);\n        if (!validationResult.IsValid)\n        {\n            result = null;\n            errorMessage = validationResult.ErrorMessage;\n            return false;\n        }\n\n        result = new (value, false);\n        errorMessage = null;\n        return true;\n    }\n\n    /// \u003csummary\u003e\n    ///  Validates the specified value and throws an exception if it is not valid.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"value\"\u003eThe value to validate\u003c/param\u003e\n    /// \u003cexception cref=\"InvalidDomainValueException\"\u003eThrown when the value is not valid.\u003c/exception\u003e\n    public void ValidateOrThrow(int value)\n    {\n        var result = Validate(value);\n        if (!result.IsValid)\n        \tthrow new InvalidDomainValueException(result.ErrorMessage, this);\n    }\n\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public override bool Equals(object? obj) =\u003e obj is PositiveInteger other \u0026\u0026 Equals(other);\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public bool Equals(PositiveInteger other)\n    {\n        if (!_isInitialized || !other._isInitialized)\n            return false;\n        return _value.Equals(other._value);\n    }\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static bool operator ==(PositiveInteger left, PositiveInteger right) =\u003e left.Equals(right);\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static bool operator !=(PositiveInteger left, PositiveInteger right) =\u003e !(left == right);\n\n    /// \u003cinheritdoc/\u003e\n    public int CompareTo(object? obj)\n    {\n        if (obj is null)\n            return 1;\n\n        if (obj is PositiveInteger c)\n            return CompareTo(c);\n\n        throw new ArgumentException(\"Object is not a PositiveInteger\", nameof(obj));\n    }\n\n    /// \u003cinheritdoc/\u003e\n    public int CompareTo(PositiveInteger other)\n    {\n        if (!other._isInitialized)\n            return 1;\n        if (!_isInitialized)\n            return -1;\n        return _value.CompareTo(other._value);\n    }\n\n    /// \u003csummary\u003e\n    /// Implicit conversion from \u003csee cref = \"int\"/\u003e to \u003csee cref = \"PositiveInteger\"/\u003e\n    /// \u003c/summary\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static implicit operator PositiveInteger(int value) =\u003e new(value);\n\n    /// \u003csummary\u003e\n    /// Implicit conversion from \u003csee cref = \"int\"/\u003e (nullable) to \u003csee cref = \"PositiveInteger\"/\u003e (nullable)\n    /// \u003c/summary\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    [return: NotNullIfNotNull(nameof(value))]\n    public static implicit operator PositiveInteger?(int? value) =\u003e value is null ? null : new(value.Value);\n\n    /// \u003csummary\u003e\n    /// Implicit conversion from \u003csee cref = \"PositiveInteger\"/\u003e to \u003csee cref = \"int\"/\u003e\n    /// \u003c/summary\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static implicit operator int(PositiveInteger value) =\u003e (int)value._valueOrThrow;\n\n    /// \u003csummary\u003e\n    /// Implicit conversion from \u003csee cref = \"PositiveInteger\"/\u003e (nullable) to \u003csee cref = \"int\"/\u003e (nullable)\n    /// \u003c/summary\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    [return: NotNullIfNotNull(nameof(value))]\n    public static implicit operator int?(PositiveInteger? value) =\u003e value is null ? null : (int?)value.Value._valueOrThrow;\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static PositiveInteger operator +(PositiveInteger left, PositiveInteger right) =\u003e new(left._valueOrThrow + right._valueOrThrow);\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static PositiveInteger operator -(PositiveInteger left, PositiveInteger right) =\u003e new(left._valueOrThrow - right._valueOrThrow);\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static PositiveInteger operator *(PositiveInteger left, PositiveInteger right) =\u003e new(left._valueOrThrow * right._valueOrThrow);\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static PositiveInteger operator /(PositiveInteger left, PositiveInteger right) =\u003e new(left._valueOrThrow / right._valueOrThrow);\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static PositiveInteger operator %(PositiveInteger left, PositiveInteger right) =\u003e new(left._valueOrThrow % right._valueOrThrow);\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static bool operator \u003c(PositiveInteger left, PositiveInteger right) =\u003e left._valueOrThrow \u003c right._valueOrThrow;\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static bool operator \u003c=(PositiveInteger left, PositiveInteger right) =\u003e left._valueOrThrow \u003c= right._valueOrThrow;\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static bool operator \u003e(PositiveInteger left, PositiveInteger right) =\u003e left._valueOrThrow \u003e right._valueOrThrow;\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static bool operator \u003e=(PositiveInteger left, PositiveInteger right) =\u003e left._valueOrThrow \u003e= right._valueOrThrow;\n\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public static PositiveInteger Parse(string s, IFormatProvider? provider) =\u003e int.Parse(s, provider);\n\n    /// \u003cinheritdoc/\u003e\n    public static bool TryParse([NotNullWhen(true)] string? s, IFormatProvider? provider, [MaybeNullWhen(false)] out PositiveInteger result)\n    {\n        if (!int.TryParse(s, provider, out var value))\n        {\n            result = default;\n            return false;\n        }\n\n        if (TryCreate(value, out var created))\n        {\n            result = created.Value;\n            return true;\n        }\n\n        result = default;\n        return false;\n    }\n\n#if NET8_0_OR_GREATER\n    /// \u003cinheritdoc cref=\"IUtf8SpanFormattable.TryFormat\"/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public bool TryFormat(Span\u003cbyte\u003e utf8Destination, out int bytesWritten, ReadOnlySpan\u003cchar\u003e format, IFormatProvider? provider)\n    {\n        return ((IUtf8SpanFormattable)_valueOrThrow).TryFormat(utf8Destination, out bytesWritten, format, provider);\n    }\n#endif\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public override int GetHashCode() =\u003e _valueOrThrow.GetHashCode();\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    TypeCode IConvertible.GetTypeCode() =\u003e ((IConvertible)(Int32)_valueOrThrow).GetTypeCode();\n\n    /// \u003cinheritdoc/\u003e\n    bool IConvertible.ToBoolean(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToBoolean(provider);\n\n    /// \u003cinheritdoc/\u003e\n    byte IConvertible.ToByte(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToByte(provider);\n\n    /// \u003cinheritdoc/\u003e\n    char IConvertible.ToChar(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToChar(provider);\n\n    /// \u003cinheritdoc/\u003e\n    DateTime IConvertible.ToDateTime(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToDateTime(provider);\n\n    /// \u003cinheritdoc/\u003e\n    decimal IConvertible.ToDecimal(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToDecimal(provider);\n\n    /// \u003cinheritdoc/\u003e\n    double IConvertible.ToDouble(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToDouble(provider);\n\n    /// \u003cinheritdoc/\u003e\n    short IConvertible.ToInt16(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToInt16(provider);\n\n    /// \u003cinheritdoc/\u003e\n    int IConvertible.ToInt32(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToInt32(provider);\n\n    /// \u003cinheritdoc/\u003e\n    long IConvertible.ToInt64(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToInt64(provider);\n\n    /// \u003cinheritdoc/\u003e\n    sbyte IConvertible.ToSByte(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToSByte(provider);\n\n    /// \u003cinheritdoc/\u003e\n    float IConvertible.ToSingle(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToSingle(provider);\n\n    /// \u003cinheritdoc/\u003e\n    string IConvertible.ToString(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToString(provider);\n\n    /// \u003cinheritdoc/\u003e\n    object IConvertible.ToType(Type conversionType, IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToType(conversionType, provider);\n\n    /// \u003cinheritdoc/\u003e\n    ushort IConvertible.ToUInt16(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToUInt16(provider);\n\n    /// \u003cinheritdoc/\u003e\n    uint IConvertible.ToUInt32(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToUInt32(provider);\n\n    /// \u003cinheritdoc/\u003e\n    ulong IConvertible.ToUInt64(IFormatProvider? provider) =\u003e ((IConvertible)(Int32)_valueOrThrow).ToUInt64(provider);\n\n    /// \u003cinheritdoc/\u003e\n    public XmlSchema? GetSchema() =\u003e null;\n\n    /// \u003cinheritdoc/\u003e\n    public void ReadXml(XmlReader reader)\n    {\n        var value = reader.ReadElementContentAs\u003cint\u003e();\n        ValidateOrThrow(value);\n        System.Runtime.CompilerServices.Unsafe.AsRef(in _value) = value;\n        System.Runtime.CompilerServices.Unsafe.AsRef(in _isInitialized) = true;\n    }\n\n    /// \u003cinheritdoc/\u003e\n    public void WriteXml(XmlWriter writer) =\u003e writer.WriteValue(((int)_valueOrThrow).ToXmlString());\n\n    /// \u003cinheritdoc/\u003e\n    [MethodImpl(MethodImplOptions.AggressiveInlining)]\n    public override string ToString() =\u003e _valueOrThrow.ToString();\n}\n\n```\n##  **JsonConverter**\n```csharp\n//------------------------------------------------------------------------------\n// \u003cauto-generated\u003e\n//     This code was generated by 'AltaSoft DomainPrimitives Generator'.\n//     Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.\n// \u003c/auto-generated\u003e\n//------------------------------------------------------------------------------\n\n#nullable enable\n\nusing AltaSoft.DomainPrimitives;\nusing System;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing System.Globalization;\nusing System.Text.Json.Serialization.Metadata;\n\n\nnamespace AltaSoft.DomainPrimitives.Converters;\n\n/// \u003csummary\u003e\n/// JsonConverter for \u003csee cref = \"PositiveInteger\"/\u003e\n/// \u003c/summary\u003e\npublic sealed class PositiveIntegerJsonConverter : JsonConverter\u003cPositiveInteger\u003e\n{\n\t/// \u003cinheritdoc/\u003e\n\tpublic override PositiveInteger Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n\t{\n\t\ttry\n\t\t{\n\t\t\treturn JsonInternalConverters.Int32Converter.Read(ref reader, typeToConvert, options);\n\t\t}\n\t\tcatch (InvalidDomainValueException ex)\n\t\t{\n\t\t\tthrow new JsonException(ex.Message);\n\t\t}\n\t}\n\n\t/// \u003cinheritdoc/\u003e\n\tpublic override void Write(Utf8JsonWriter writer, PositiveInteger value, JsonSerializerOptions options)\n\t{\n\t\tJsonInternalConverters.Int32Converter.Write(writer, (int)value, options);\n\t}\n\n\t/// \u003cinheritdoc/\u003e\n\tpublic override PositiveInteger ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n\t{\n\t\ttry\n\t\t{\n\t\t\treturn JsonInternalConverters.Int32Converter.ReadAsPropertyName(ref reader, typeToConvert, options);\n\t\t}\n\t\tcatch (InvalidDomainValueException ex)\n\t\t{\n\t\t\tthrow new JsonException(ex.Message);\n\t\t}\n\t}\n\n\t/// \u003cinheritdoc/\u003e\n\tpublic override void WriteAsPropertyName(Utf8JsonWriter writer, PositiveInteger value, JsonSerializerOptions options)\n\t{\n\t\tJsonInternalConverters.Int32Converter.WriteAsPropertyName(writer, (int)value, options);\n\t}\n}\n\n```\n## **Type Converter**\n```csharp\n//------------------------------------------------------------------------------\n// \u003cauto-generated\u003e\n//     This code was generated by 'AltaSoft DomainPrimitives Generator'.\n//     Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.\n// \u003c/auto-generated\u003e\n//------------------------------------------------------------------------------\n\n#nullable enable\n\nusing AltaSoft.DomainPrimitives;\nusing System;\nusing System.ComponentModel;\nusing System.Globalization;\n\n\nnamespace AltaSoft.DomainPrimitives.Converters;\n\n/// \u003csummary\u003e\n/// TypeConverter for \u003csee cref = \"PositiveInteger\"/\u003e\n/// \u003c/summary\u003e\npublic sealed class PositiveIntegerTypeConverter : Int32Converter\n{\n\t/// \u003cinheritdoc/\u003e\n\tpublic override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)\n\t{\n\t\tvar result = base.ConvertFrom(context, culture, value);\n\t\tif (result is null)\n\t\t\treturn null;\n\t\ttry\n\t\t{\n\t\t\treturn new PositiveInteger((int)result);\n\t\t}\n\t\tcatch (InvalidDomainValueException ex)\n\t\t{\n\t\t\tthrow new FormatException(\"Cannot parse PositiveInteger\", ex);\n\t\t}\n\t}\n}\n```\n## **Swagger Mappers**\n\nA single file for all domainPrimitives containing all type mappings is generated.\n**Please note that you need to manually add Swashbuckle.AspNetCore.SwaggerGen nuget package to the project**\n\n```csharp\n//------------------------------------------------------------------------------\n// \u003cauto-generated\u003e\n//     This code was generated by 'AltaSoft DomainPrimitives Generator'.\n//     Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.\n// \u003c/auto-generated\u003e\n//------------------------------------------------------------------------------\n\n#nullable enable\n\nusing AltaSoft.DomainPrimitives;\nusing Microsoft.Extensions.DependencyInjection;\nusing Swashbuckle.AspNetCore.SwaggerGen;\nusing Microsoft.OpenApi.Models;\n\nnamespace AltaSoft.DomainPrimitives.Converters.Extensions;\n\n/// \u003csummary\u003e\n/// Helper class providing methods to configure Swagger mappings for DomainPrimitive types of AltaSoft.DomainPrimitives\n/// \u003c/summary\u003e\npublic static class SwaggerTypeHelper\n{\n\t/// \u003csummary\u003e\n\t/// Adds Swagger mappings for specific custom types to ensure proper OpenAPI documentation generation.\n\t/// \u003c/summary\u003e\n\t/// \u003cparam name=\"options\"\u003eThe SwaggerGenOptions instance to which mappings are added.\u003c/param\u003e\n\t/// \u003cremarks\u003e\n\t/// The method adds Swagger mappings for the following types:\n\t/// \u003csee cref=\"PositiveInteger\"/\u003e\n\t/// \u003c/remarks\u003e\n\tpublic static void AddSwaggerMappings(this SwaggerGenOptions options)\n\t{\n\t\toptions.MapType\u003cPositiveInteger\u003e(() =\u003e new OpenApiSchema\n\t\t{\n\t\t\tType = \"integer\",\n\t\t\tFormat = \"int32\",\n\t\t\tTitle = \"PositiveInteger\",\n\t\t\tDescription = @\"A domain primitive type representing a positive integer.\"\n\t\t});\n\t\toptions.MapType\u003cPositiveInteger?\u003e(() =\u003e new OpenApiSchema\n\t\t{\n\t\t\tType = \"integer\",\n\t\t\tFormat = \"int32\",\n\t\t\tNullable = true,\n\t\t\tTitle = \"Nullable\u003cPositiveInteger\u003e\",\n\t\t\tDescription = @\"A domain primitive type representing a positive integer.\"\n\t\t});\n\t}\n```\n## Specialized ToString method \nBy Default IDomainValue uses its underlying type's ToString method however this can be overriden by implementing a method specified below\n\n```csharp \nstatic virtual string ToString(T value) =\u003e value.ToString() ?? string.Empty;\n```\n\n## Managing Generated Operators for numeric types\n\nMathematical operators for particular numeric types can be customized using the `SupportedOperationsAttribute`. If left unspecified, all operators are generated by default (as shown below). Once this attribute is applied, manual specification of the operators becomes mandatory. Note that for `byte`, `sbyte`, `short`, and `ushort` types, mathematical operators will not be generated by default.\n\n### Default numeric types Generated Operators \n1. `byte, sbyte` =\u003e `None`\n2. `short, ushort` =\u003e `None`\n3. `int, uint` =\u003e `+ - / * %`\n3. `long, ulong` =\u003e `+ - / * %`\n3. `double` =\u003e `+ - / * %`\n3. `decimal` =\u003e `+ - / * %`\n\n### using `SupportedOperationsAttribute`\n\n```csharp\n[SupportedOperations(Addition = false, Division = false, Modulus = false, Multiplication = true, Subtraction = true)]\npublic readonly partial struct PositiveInteger : IDomainValue\u003cint\u003e\n{\n\t /// \u003cinheritdoc/\u003e\n    public static PrimitiveValidationResult Validate(int value)\n    {\n        if (value \u003c= 0)\n            return PrimitiveValidationResult.Error(\"value is non-positive\");\n\n        return PrimitiveValidationResult.Ok;\n    }\n}\n```\n### For further customization of the operators, consider implementing specific interfaces. This action will override the generated operators for the respective domain type:\n\n```csharp\npublic readonly partial struct PositiveInteger :\n\tIDomainValue\u003cint\u003e,\n\tIAdditionOperators\u003cPositiveInteger, PositiveInteger, PositiveInteger\u003e\n{\n\t /// \u003cinheritdoc/\u003e\n    public static PrimitiveValidationResult Validate(int value)\n    {\n        if (value \u003c= 0)\n            return PrimitiveValidationResult.Error(\"value is non-positive\");\n\n        return PrimitiveValidationResult.Ok;\n    }\n\t\n\t// custom + operator\n\tpublic static PositiveInteger operator +(PositiveInteger left, PositiveInteger right)\n\t{\n\t\treturn (left._value + right._value + 1);\n\t}\n}\n```\n\n## Managing Serialization Format for date-related types\n\nCertain date-related types like `DateTime`, `DateOnly`, `TimeOnly`, `DateTimeOffset`, and `TimeSpan` can modify their serialization/deserialization format using the `SerializationFormatAttribute`. \nFor instance, consider the `GDay` type, which represents an XML gDay value. It implements the `IDomainValue\u003cDateOnly\u003e` interface and utilizes the `SerializationFormatAttribute` to specify a serialization format.\n```csharp\n\n/// \u003csummary\u003e\n/// Represents an XML GDay value object, providing operations for parsing and handling gDay values.\n/// \u003c/summary\u003e\n[SerializationFormat(\"dd\")]\npublic readonly partial struct GDay : IDomainValue\u003cDateOnly\u003e\n{\n\t /// \u003cinheritdoc/\u003e\n    public static PrimitiveValidationResult Validate(int value)\n    {\n        return PrimitiveValidationResult.Ok;\n    }\n\n\t/// \u003cinheritdoc/\u003e\n\tpublic static DateOnly Default =\u003e default;\n\n\t// Customized string representation of DateOnly\n\t/// \u003cinheritdoc/\u003e\n\tpublic static string ToString(DateOnly value) =\u003e value.ToString(\"dd\");\n}\n```\n\n# Disable Generation of Converters \n\nTo disable the generation of Converters, Swagger Mappers or XML serialization, in .csproj file follow the below described steps.\n\n```xml\n  \u003cPropertyGroup\u003e\n    \u003cDomainPrimitiveGenerator_GenerateJsonConverters\u003efalse\u003c/DomainPrimitiveGenerator_GenerateJsonConverters\u003e\n    \u003cDomainPrimitiveGenerator_GenerateTypeConverters\u003efalse\u003c/DomainPrimitiveGenerator_GenerateTypeConverters\u003e\n    \u003cDomainPrimitiveGenerator_GenerateSwaggerConverters\u003efalse\u003c/DomainPrimitiveGenerator_GenerateSwaggerConverters\u003e\n    \u003cDomainPrimitiveGenerator_GenerateXmlSerialization\u003efalse\u003c/DomainPrimitiveGenerator_GenerateXmlSerialization\u003e \n  \u003c/PropertyGroup\u003e\n```\n\n:warning: Please note that `DomainPrimitiveGenerator_GenerateXmlSerialization` value by default is `false`.\n\n# Additional Features \n1.  **PrimitiveValidationResult:** Offers an Ok result and a string containing the error message. It also includes an implicit operator to automatically convert a string to an error value.\n [PrimitiveValidationResult](src/AltaSoft.DomainPrimitives/PrimitiveValidationResult.cs) \n\n\n2. **AltaSoft.DomainPrimitives.StringLengthAttribute** can be used to specify minimum and maximum length restrictions on DomainPrimitives \n\t```csharp\n\t[StringLength(minimumLength:1, maximumLength:100, validate:false)]\n\tpublic partial class AsciiString : IDomainValue\u003cstring\u003e\n\t{\n\t\t/// \u003cinheritdoc/\u003e\n\t\tpublic static PrimitiveValidationResult Validate(string value)\n\t\t{\n\t\t\tvar input = value.AsSpan();\n\n\t\t\t// ReSharper disable once ForCanBeConvertedToForeach\n\t\t\tfor (var i = 0; i \u003c input.Length; i++)\n\t\t\t{\n\t\t\t\tif (!char.IsAscii(input[i]))\n\t\t\t\t\treturn \"value contains non-ascii characters\";\n\t\t\t}\n\n\t\t\treturn PrimitiveValidationResult.Ok;\n\t\t}\n\t}\n\t```\n\tThe Validate property can be used to automatically enforce boolean and string length validations within domain primitives.\u003cbr/\u003e\n\tAdditionally, this attribute can be utilized by **ORMs** to impose string length restrictions in the database.\n\n\n3. **Chaining Primitive Types**\n\n\t* Chaining of primitive types is possible. For instance, considering the `PositiveInteger` and `BetweenOneAnd100` DomainPrimitives:\n\n    ```csharp\n    public readonly partial struct PositiveInteger : IDomainValue\u003cint\u003e\n\t{\n\t/// \u003cinheritdoc/\u003e\n    public static PrimitiveValidationResult Validate(int value)\n    {\n        if (value \u003c= 0)\n            return PrimitiveValidationResult.Error(\"value is non-positive\");\n\n        return PrimitiveValidationResult.Ok;\n    }\n\t}\n\n    public readonly partial struct BetweenOneAnd100 : IDomainValue\u003cPositiveInteger\u003e\n    {\n\t\tpublic static PrimitiveValidationResult Validate(PositiveInteger value)\n\t\t{\n\t\t\tif (value \u003c 100)\n\t\t\t\treturn \"Value must be less than 100\"; //implicit operator to convert string to PrimitiveValidationResult\n\n\t\t\treturn PrimitiveValidationResult.Ok;\t\t\n\t\t}\n    }\n    ```\n4. \n\tDefined type `BetweenOneAnd100` automatically inherits restrictions from PositiveInteger. Operators restricted in PositiveInteger are also inherited. Further restrictions on operators can be added using the `SupportedOperationsAttribute`:\t\n\t\n    ```csharp\n\t[SupportedOperations(Addition=false)]\n\tpublic readonly partial struct BetweenOneAnd100 : IDomainValue\u003cPositiveInteger\u003e\n\t{\n\t\tpublic static PrimitiveValidationResult Validate(PositiveInteger value)\n\t\t{\n\t\t\tif (value \u003c 100)\n\t\t\t\treturn \"Value must be less than 100\";\n\n\t\t\treturn PrimitiveValidationResult.Ok;\t\t\n\t\t}\n\t}\n\t```\n\n\n# Restrictions \n\n1. **Implementation of IDomainValue Interface**\n\t* DomainPrimitives are mandated to implement the `IDomainValue\u003cT\u003e` interface to ensure adherence to domain-specific constraints and behaviors.\n\n2. **Constructor Limitation**\n\t * No constructors should be explicitly defined within DomainPrimitives. Doing so will result in a compiler error.\n\n3. **Prohibition of Public Properties or Fields**\n\t* DomainPrimitive types should not contain any explicitly defined public properties or fields. The backing field will be automatically generated.\n\t\t* If any property or field is explicitly named `_value`, `_valueOrDefault`, or `_isInitialized`, a compiler error will be triggered.\n\n# Examples \n\n## Implicit Usage of DomainType\n\n```csharp\npublic readonly partial struct PositiveAmount : IDomainValue\u003cdecimal\u003e\n{\n\tpublic static PrimitiveValidationResult Validate(decimal value)\n\t{\n\t\tif (value \u003c= 0m)\n\t\t\treturn \"Must be a a positive number\";\n\n\t\treturn PrimitiveValidationResult.Ok;\t\t\t\n\t}\n\n}\n\npublic static class Example\n{\n\tpublic static void ImplicitConversion()\n\t{\n\t\tvar amount = new PositiveAmount(100m);\n\t\tPositiveAmount amount2 = 100m; // implicitly converted to PositiveAmount\n\n\t\t//implicilty casted to decimal\n\t\tdecimal amountInDecimal = amount + amount2;        \n\t}\n}\n\n```\n# Json Conversion \n\n```csharp \n[SupportedOperations] // no mathematical operators should be generated\npublic readonly partial struct CustomerId : IDomainValue\u003cint\u003e\n{\n\tpublic static PrimitiveValidationResult Validate(decimal value)\n\t{\n\t\tif (value \u003c= 0m)\n\t\t\treturn \"Must be a a positive number\";\n\n\t\treturn PrimitiveValidationResult.Ok;\t\t\n\t}\n}\n\npublic sealed class Transaction\n{\n\tpublic CustomerId FromId { get; set; }\n\tpublic CustomerId? ToId { get; set; }\n\tpublic PositiveAmount Amount { get; set; }\n\tpublic PositiveAmount? Fees { get; set; }\n}\n\npublic static void JsonSerializationAndDeserialization()\n{\n\tvar amount = new Transaction()\n        {\n            Amount = 100.523m,\n            Fees = null,\n            FromId = 1,\n            ToId = null\n        };\n\n    var jsonValue = JsonSerializer.Serialize(amount); //this will produce the same result as changing customerId to int and PositiveAmount to decimal\n    var newValue = JsonSerializer.Deserialize\u003cTransaction\u003e(jsonValue)\n}\n```\n`Serialized Json`\n```json\n{\n    \"FromId\": 1,\n    \"ToId\": null,\n    \"Amount\": 100.523,\n    \"Fees\": null\n}\n```\n\n# Contributions \nContributions to AltaSoft.DomainPrimitives are welcome! Whether you have suggestions or wish to contribute code, feel free to submit a pull request or open an issue.\n\n# Contact\nFor support, questions, or additional information, please visit GitHub Issues.\n\n# License\nThis project is licensed under [MIT](LICENSE.TXT). See the LICENSE file for details.\n\n\n","funding_links":[],"categories":["Content","Source Generators"],"sub_categories":["97. [DomainPrimitives](https://ignatandrei.github.io/RSCG_Examples/v2/docs/DomainPrimitives) , in the [PrimitiveObsession](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#primitiveobsession) category","Domain Driven Design (DDD)"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faltasoft%2FDomainPrimitives","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faltasoft%2FDomainPrimitives","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faltasoft%2FDomainPrimitives/lists"}