Phone

Library for phone numbers.
git clone https://git.philomathiclife.com/repos/Phone
Log | Files | Refs | README

Phone.cs (12044B)


      1 using Std;
      2 using Std.Clone;
      3 using Std.Cmp;
      4 using Std.Convert;
      5 using Std.Error;
      6 using Std.Hashing;
      7 using Std.Maybe;
      8 using Std.Ops;
      9 using Std.Result;
     10 using System;
     11 using System.Diagnostics;
     12 using System.Globalization;
     13 using System.Runtime.InteropServices;
     14 using System.Text;
     15 #region Namespaces
     16 namespace Phones {
     17     #region Types
     18     [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode, Pack = 1, Size = 1)]
     19     public readonly struct PhoneErr: ISum<PhoneErr.Tag, PhoneErr.Tag, PhoneErr.Tag, PhoneErr.Tag, PhoneErr.Tag, PhoneErr.Tag>, IClone<PhoneErr>, IEquality<PhoneErr>, IError, IHashable, IInto<PhoneErr> {
     20 
     21         #region Type-level Constructors
     22         #endregion
     23 
     24         #region Instance Constructors
     25         public PhoneErr() => throw new InvalidOperationException("Parameterless constructor is not allowed to be called!");
     26         PhoneErr(Tag val) => Var = val;
     27         #endregion
     28 
     29         #region Type-level Fields
     30         public static readonly PhoneErr InvalidMask = new(Tag.InvalidMask);
     31         public static readonly PhoneErr InvalidAreaCode = new(Tag.InvalidAreaCode);
     32         public static readonly PhoneErr InvalidCentralOfficeCode = new(Tag.InvalidCentralOfficeCode);
     33         public static readonly PhoneErr InvalidLineNumber = new(Tag.InvalidLineNumber);
     34         public static readonly PhoneErr InvalidLength = new(Tag.InvalidLength);
     35         public static readonly PhoneErr InvalidChar = new(Tag.InvalidChar);
     36         #endregion
     37 
     38         #region Instance Fields
     39         [FieldOffset(0)] public readonly Tag Var;
     40         #endregion
     41 
     42         #region Type-level Properties
     43         #endregion
     44 
     45         #region Instance Properties
     46         public readonly Var6 Variant => (Var6)Var;
     47         public readonly Tag Variant0 => Var == Tag.InvalidMask ? Var : throw new InvalidOperationException($"The PhoneErr variant, {Var.ToString()} is not InvalidMask!");
     48         public readonly Tag Variant1 => Var == Tag.InvalidAreaCode ? Var : throw new InvalidOperationException($"The PhoneErr variant, {Var.ToString()} is not InvalidAreaCode!");
     49         public readonly Tag Variant2 => Var == Tag.InvalidCentralOfficeCode ? Var : throw new InvalidOperationException($"The PhoneErr variant, {Var.ToString()} is not InvalidCentralOfficeCode!");
     50         public readonly Tag Variant3 => Var == Tag.InvalidLineNumber ? Var : throw new InvalidOperationException($"The PhoneErr variant, {Var.ToString()} is not InvalidLineNumber!");
     51         public readonly Tag Variant4 => Var == Tag.InvalidLength ? Var : throw new InvalidOperationException($"The PhoneErr variant, {Var.ToString()} is not InvalidLength!");
     52         public readonly Tag Variant5 => Var == Tag.InvalidChar ? Var : throw new InvalidOperationException($"The PhoneErr variant, {Var.ToString()} is not InvalidChar!");
     53         #endregion
     54 
     55         #region Type-level Functions
     56         #endregion
     57 
     58         #region Instance Functions
     59         public readonly PhoneErr Clone() => this;
     60         public readonly bool Equals(in PhoneErr other) => this == other;
     61         public override readonly bool Equals(object? _) => false;
     62         public override readonly int GetHashCode() => 0;
     63         public readonly Unit Hash<THasher>(ref THasher hasher) where THasher: notnull, IHasher => hasher.WriteUnsafe(this);
     64         public readonly PhoneErr Into() => this;
     65         public readonly string IntoString() => ToString();
     66         readonly string IInto<string>.Into() => IntoString();
     67         public readonly Maybe<IError> Source() => Maybe<IError>.None();
     68         public readonly Maybe<StackTrace> StackTrace() => Maybe<StackTrace>.None();
     69         public override readonly string ToString() => $"PhoneErr({Var.ToString()})";
     70         readonly Result<PhoneErr, Bottom> ITryInto<PhoneErr, Bottom>.TryInto() => new(this);
     71         readonly Result<string, Bottom> ITryInto<string, Bottom>.TryInto() => new(ToString());
     72         #endregion
     73 
     74         #region Operators
     75         public static bool operator !=(PhoneErr val0, PhoneErr val1) => !(val0 == val1);
     76         public static bool operator ==(PhoneErr val0, PhoneErr val1) => val0.Var == val1.Var;
     77         #endregion
     78 
     79         #region Types
     80         public enum Tag: byte {
     81             InvalidMask = byte.MinValue,
     82             InvalidAreaCode = 1,
     83             InvalidCentralOfficeCode = 2,
     84             InvalidLineNumber = 3,
     85             InvalidLength = 4,
     86             InvalidChar = 5,
     87         }
     88         #endregion
     89     }
     90     [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode, Pack = 2, Size = 6)]
     91     public readonly struct Phone: IClone<Phone>, IEquality<Phone>, IOrd<Phone>, IHashable, IInto<Phone>, IInto<string>, IInto<ulong>, ITryFrom<Phone, string, PhoneErr>, ITryFrom<Phone, ulong, PhoneErr> {
     92 
     93         #region Type-level Constructors
     94         #endregion
     95 
     96         #region Instance Constructors
     97         public Phone() => throw new InvalidOperationException("Parameterless constructor is not allowed to be called.");
     98         Phone(ushort area, ushort office, ushort line) => (AreaCode, CentralOfficeCode, LineNumber) = (area, office, line);
     99         #endregion
    100 
    101         #region Type-level Fields
    102         public const byte CountryCode = 1;
    103         public const byte InternationalCallPrefix = 11;
    104         static readonly Fn<PhoneErr, PhoneErr> fMaskErr = (_) => PhoneErr.InvalidMask;
    105         #endregion
    106 
    107         #region Instance Fields
    108         [FieldOffset(0)] public readonly ushort AreaCode;
    109         [FieldOffset(2)] public readonly ushort CentralOfficeCode;
    110         [FieldOffset(4)] public readonly ushort LineNumber;
    111         #endregion
    112 
    113         #region Type-level Properties
    114         #endregion
    115 
    116         #region Instance Properties
    117         #endregion
    118 
    119         #region Type-level Functions
    120         public static Result<Phone, PhoneErr> TryFrom(ulong mask) => (mask >> 48) == ulong.MinValue ? TryFromParts((ushort)(mask & 0xFFFFul), (ushort)((mask << 32) >> 48), (ushort)(mask >> 32)).MapErr(fMaskErr) : new(PhoneErr.InvalidMask);
    121         public static Result<Phone, PhoneErr> TryFromParts(ushort areaCode, ushort centralOfficeCode, ushort lineNumber) => areaCode is > 199 and < 1000 && areaCode % 100 < 90 ? centralOfficeCode is > 199 and < 1000 && centralOfficeCode % 100 != 11 ? lineNumber < 10000 ? new(new Phone(areaCode, centralOfficeCode, lineNumber)) : new(PhoneErr.InvalidLineNumber) : new(PhoneErr.InvalidCentralOfficeCode) : new(PhoneErr.InvalidAreaCode);
    122         public static Result<Phone, PhoneErr> TryFromConcatenatedString(ReadOnlySpan<char> phone) => phone.Length == 10 ? ushort.TryParse(phone[..3], NumberStyles.None, CultureInfo.InvariantCulture, out var area) && ushort.TryParse(phone[3..6], NumberStyles.None, CultureInfo.InvariantCulture, out var office) && ushort.TryParse(phone[6..], NumberStyles.None, CultureInfo.InvariantCulture, out var line) ? TryFromParts(area, office, line) : new(PhoneErr.InvalidChar) : new(PhoneErr.InvalidLength);
    123         public static Result<Phone, PhoneErr> TryFromHyphenatedString(ReadOnlySpan<char> phone) => phone.Length == 12 ? phone[3] == '-' && phone[7] == '-' && ushort.TryParse(phone[..3], NumberStyles.None, CultureInfo.InvariantCulture, out var area) && ushort.TryParse(phone[4..7], NumberStyles.None, CultureInfo.InvariantCulture, out var office) && ushort.TryParse(phone[8..], NumberStyles.None, CultureInfo.InvariantCulture, out var line) ? TryFromParts(area, office, line) : new(PhoneErr.InvalidChar) : new(PhoneErr.InvalidLength);
    124         public static Result<Phone, PhoneErr> TryFromStandardString(ReadOnlySpan<char> phone) => phone.Length == 14 ? phone[0] == '(' && phone[4] == ')' && phone[5] == ' ' && phone[9] == '-' && ushort.TryParse(phone[1..4], NumberStyles.None, CultureInfo.InvariantCulture, out var area) && ushort.TryParse(phone[6..9], NumberStyles.None, CultureInfo.InvariantCulture, out var office) && ushort.TryParse(phone[10..], NumberStyles.None, CultureInfo.InvariantCulture, out var line) ? TryFromParts(area, office, line) : new(PhoneErr.InvalidChar) : new(PhoneErr.InvalidLength);
    125         public static Result<Phone, PhoneErr> TryFromTypicalFormatStringWithCallingCode(ReadOnlySpan<char> phone) => phone.Length == 15 ? phone[0] == '+' && phone[1] == '1' && phone[2] == ' ' && phone[6] == ' ' && phone[10] == '-' && ushort.TryParse(phone[3..6], NumberStyles.None, CultureInfo.InvariantCulture, out var area) && ushort.TryParse(phone[7..10], NumberStyles.None, CultureInfo.InvariantCulture, out var office) && ushort.TryParse(phone[11..], NumberStyles.None, CultureInfo.InvariantCulture, out var line) ? TryFromParts(area, office, line) : new(PhoneErr.InvalidChar) : new(PhoneErr.InvalidLength);
    126         public static Result<Phone, PhoneErr> TryFromChars(ReadOnlySpan<char> phone) => phone.Length == 10 ? TryFromConcatenatedString(phone) : phone.Length == 12 ? TryFromHyphenatedString(phone) : phone.Length == 14 ? TryFromStandardString(phone) : phone.Length == 15 ? TryFromTypicalFormatStringWithCallingCode(phone) : new(PhoneErr.InvalidLength);
    127         public static Result<Phone, PhoneErr> TryFrom(string phone) => TryFromChars(phone.AsSpan());
    128         #endregion
    129 
    130         #region Instance Functions
    131         public readonly Phone Clone() => this;
    132         public readonly Ordering Cmp(in Phone other) => IntoMask().CompareTo(other.IntoMask()) switch {
    133             > 0 => Ordering.Greater,
    134             0 => Ordering.Equivalent,
    135             _ => Ordering.Less,
    136         };
    137         public readonly bool Equals(in Phone other) => this == other;
    138         public override readonly bool Equals(object? _) => false;
    139         public override readonly int GetHashCode() => 0;
    140         public readonly Unit Hash<THasher>(ref THasher hasher) where THasher: notnull, IHasher => hasher.WriteUnsafe(this);
    141         public readonly ulong IntoMask() => (((ulong)LineNumber) << 32) | (((ulong)CentralOfficeCode) << 16) | AreaCode;
    142         public readonly Phone Into() => this;
    143         public readonly string IntoTypicalFormatStringWithCallingCode() => new StringBuilder("+1 ", 15).Append(AreaCode.ToString("D3")).Append(' ').Append(CentralOfficeCode.ToString("D3")).Append('-').Append(LineNumber.ToString("D4")).ToString();
    144         public readonly string IntoStandardString() => new StringBuilder("(", 14).Append(AreaCode.ToString("D3")).Append(") ").Append(CentralOfficeCode.ToString("D3")).Append('-').Append(LineNumber.ToString("D4")).ToString();
    145         public readonly string IntoHyphenatedString() => new StringBuilder(AreaCode.ToString("D3"), 12).Append('-').Append(CentralOfficeCode.ToString("D3")).Append('-').Append(LineNumber.ToString("D4")).ToString();
    146         public readonly string IntoConcatenatedString() => ToString();
    147         readonly string IInto<string>.Into() => IntoConcatenatedString();
    148         readonly ulong IInto<ulong>.Into() => IntoMask();
    149         public readonly Maybe<Ordering> PartialCmp(in Phone other) => new(Cmp(in other));
    150         public override readonly string ToString() => new StringBuilder(AreaCode.ToString("D3"), 10).Append(CentralOfficeCode.ToString("D3")).Append(LineNumber.ToString("D4")).ToString();
    151         readonly Result<Phone, Bottom> ITryInto<Phone, Bottom>.TryInto() => new(this);
    152         readonly Result<string, Bottom> ITryInto<string, Bottom>.TryInto() => new(ToString());
    153         readonly Result<ulong, Bottom> ITryInto<ulong, Bottom>.TryInto() => new(IntoMask());
    154         #endregion
    155 
    156         #region Operators
    157         public static bool operator <(Phone val0, Phone val1) => val0.Cmp(in val1).Var == Ordering.Ord.Less;
    158         public static bool operator <=(Phone val0, Phone val1) => !(val0 > val1);
    159         public static bool operator !=(Phone val0, Phone val1) => !(val0 == val1);
    160         public static bool operator ==(Phone val0, Phone val1) => val0.IntoMask() == val1.IntoMask();
    161         public static bool operator >(Phone val0, Phone val1) => val0.Cmp(in val1).Var == Ordering.Ord.Greater;
    162         public static bool operator >=(Phone val0, Phone val1) => !(val0 < val1);
    163         #endregion
    164 
    165         #region Types
    166         #endregion
    167     }
    168     #endregion
    169 
    170     #region Namespaces
    171     #endregion
    172 }
    173 #endregion