Std

Mainly a port of Rust's std.
git clone https://git.philomathiclife.com/repos/Std
Log | Files | Refs | README

IP.cs (35955B)


      1 using Std.Clone;
      2 using Std.Cmp;
      3 using static Std.Cmp.Ordering;
      4 using Std.Convert;
      5 using Std.Hashing;
      6 using Std.Maybe;
      7 using static Std.Maybe.Maybe<Std.Cmp.Ordering>;
      8 using static Std.Maybe.Maybe<uint>;
      9 using static Std.Net.Functions;
     10 using Std.Num;
     11 using Std.Result;
     12 using System;
     13 using System.Runtime.InteropServices;
     14 using System.Text;
     15 #region Namespaces
     16 namespace Std.Net {
     17     #region Types
     18     public interface IIP {
     19 
     20         #region Type-level Constructors
     21         #endregion
     22 
     23         #region Instance Constructors
     24         #endregion
     25 
     26         #region Type-level Fields
     27         #endregion
     28 
     29         #region Instance Fields
     30         #endregion
     31 
     32         #region Type-level Properties
     33         #endregion
     34 
     35         #region Instance Properties
     36         #endregion
     37 
     38         #region Type-level Functions
     39         #endregion
     40 
     41         #region Instance Functions
     42         public abstract IPAddr IntoIPAddr();
     43         public abstract string IntoString();
     44         public abstract bool IsBenchmarking();
     45         public abstract bool IsDocumentation();
     46         public abstract bool IsGlobal();
     47         public abstract bool IsIETFProtocol();
     48         public abstract bool IsLinkLocal();
     49         public abstract bool IsLoopback();
     50         public abstract bool IsMulticast();
     51         public abstract bool IsUnspecified();
     52         internal abstract void Sealed();
     53         #endregion
     54 
     55         #region Operators
     56         #endregion
     57 
     58         #region Types
     59         #endregion
     60     }
     61     [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode, Pack = 8, Size = 24)]
     62     public readonly struct IPAddr: IIP, ISum<IPv4Addr, IPv6Addr>, IClone<IPAddr>, IEquality<IPAddr>, IHashable, IInto<IPAddr>, IInto<byte[]>, IInto<string>, IPartialOrd<IPAddr, IPv4Addr>, IPartialOrd<IPAddr, IPv6Addr>, IPartialOrd<IPAddr, IPAddr>, ITryInto<IPv4Addr, IPVersionMismatchError>, ITryInto<IPv6Addr, IPVersionMismatchError>, ITryFrom<IPAddr, string, AddrParseError> {
     63 
     64         #region Type-level Constructors
     65         #endregion
     66 
     67         #region Instance Constructors
     68         public IPAddr() => throw new InvalidOperationException("Parameterless constructor is not allowed to be called!");
     69         IPAddr(IPv4Addr val) {
     70 
     71             _v6 = default;
     72             (Version, _v4) = (Tag.V4, val);
     73         }
     74         IPAddr(IPv6Addr val) {
     75 
     76             _v4 = default;
     77             (Version, _v6) = (Tag.V6, val);
     78         }
     79         #endregion
     80 
     81         #region Type-level Fields
     82         #endregion
     83 
     84         #region Instance Fields
     85         [FieldOffset(0)] public readonly Tag Version;
     86         [FieldOffset(8)] internal readonly IPv6Addr _v6;
     87         [FieldOffset(8)] internal readonly IPv4Addr _v4;
     88         #endregion
     89 
     90         #region Type-level Properties
     91         #endregion
     92 
     93         #region Instance Properties
     94         public readonly Var2 Variant => Version == Tag.V4 ? Var2.V0 : Var2.V1;
     95         public readonly IPv4Addr Variant0 => Version == Tag.V4 ? _v4 : throw new InvalidOperationException($"The IPAddr variant, {Version.ToString()} is not V4!");
     96         public readonly IPv6Addr Variant1 => Version == Tag.V6 ? _v6 : throw new InvalidOperationException($"The IPAddr variant, {Version.ToString()} is not V6!");
     97         #endregion
     98 
     99         #region Type-level Functions
    100         public static IPAddr FromBEBytesIPv4(ReadOnlySpan<byte> val) => new(IPv4Addr.FromBEBytes(val));
    101         public static IPAddr FromBEBytesIPv6(ReadOnlySpan<byte> val) => new(IPv6Addr.FromBEBytes(val));
    102         public static IPAddr V4(IPv4Addr val) => new(val);
    103         public static IPAddr V6(IPv6Addr val) => new(val);
    104         public static Result<IPAddr, AddrParseError> TryFromSlice(ReadOnlySpan<char> val) {
    105 
    106             var res = IPv4Addr.TryFrom(val);
    107             if (res.IsOK) { return new(new IPAddr(res.Unwrap())); }
    108             var res2 = IPv6Addr.TryFrom(val);
    109             return res2.IsOK ? new(new IPAddr(res2.Unwrap())) : new(res2.UnwrapErr());
    110         }
    111         public static Result<IPAddr, AddrParseError> TryFrom(string val) => TryFromSlice(val.AsSpan());
    112         #endregion
    113 
    114         #region Instance Functions
    115         public readonly IPAddr Clone() => this;
    116         public readonly bool Equals(in IPAddr other) => this == other;
    117         public override readonly bool Equals(object? _) => false;
    118         public override readonly int GetHashCode() => 0;
    119         public readonly Unit Hash<THasher>(ref THasher hasher) where THasher: notnull, IHasher => hasher.WriteUnsafe(this);
    120         public readonly IPAddr Into() => this;
    121         public readonly string IntoString() => ToString();
    122         public readonly Unit IntoBEBytes(Span<byte> val) => Version == Tag.V4 ? _v4.IntoBEBytes(val) : _v6.IntoBEBytes(val);
    123         public readonly byte[] IntoBEBytes() => Version == Tag.V4 ? _v4.IntoBEBytes() : _v6.IntoBEBytes();
    124         public readonly Result<IPv4Addr, IPVersionMismatchError> TryIntoIPv4() => Version == Tag.V4 ? new(_v4) : new(IPVersionMismatchError.IPVersionMismatch);
    125         public readonly Result<IPv6Addr, IPVersionMismatchError> TryIntoIPv6() => Version != Tag.V4 ? new(_v6) : new(IPVersionMismatchError.IPVersionMismatch);
    126         readonly string IInto<string>.Into() => IntoString();
    127         readonly byte[] IInto<byte[]>.Into() => IntoBEBytes();
    128         public readonly IPv4Addr IntoV4() => Version == Tag.V4 ? _v4 : throw new InvalidOperationException($"V6({_v6.IntoString()})");
    129         public readonly IPv6Addr IntoV46() => Version == Tag.V6 ? _v6 : throw new InvalidOperationException($"V4({_v4.IntoString()})");
    130         public readonly bool IsBenchmarking() => Version == Tag.V4 ? _v4.IsBenchmarking() : _v6.IsBenchmarking();
    131         public readonly bool IsDocumentation() => Version == Tag.V4 ? _v4.IsDocumentation() : _v6.IsDocumentation();
    132         public readonly bool IsGlobal() => Version == Tag.V4 ? _v4.IsGlobal() : _v6.IsGlobal();
    133         public readonly bool IsIETFProtocol() => Version == Tag.V4 ? _v4.IsIETFProtocol() : _v6.IsIETFProtocol();
    134         public readonly bool IsLinkLocal() => Version == Tag.V4 ? _v4.IsLinkLocal() : _v6.IsLinkLocal();
    135         public readonly bool IsLoopback() => Version == Tag.V4 ? _v4.IsLoopback() : _v6.IsLoopback();
    136         public readonly bool IsMulticast() => Version == Tag.V4 ? _v4.IsMulticast() : _v6.IsMulticast();
    137         readonly IPAddr IIP.IntoIPAddr() => this;
    138         public readonly bool IsUnspecified() => Version == Tag.V4 ? _v4.IsUnspecified() : _v6.IsUnspecified();
    139         public readonly Maybe<Ordering> PartialCmp(in IPAddr other) => Version == Tag.V4 ? other.Version == Tag.V4 ? new(_v4.Cmp(other._v4)) : Maybe<Ordering>.None() : other.Version == Tag.V4 ? Maybe<Ordering>.None() : new(_v6.Cmp(in other._v6));
    140         public readonly Maybe<Ordering> PartialCmp(in IPv4Addr other) => Version == Tag.V4 ? new(_v4.Cmp(other)) : Maybe<Ordering>.None();
    141         public readonly Maybe<Ordering> PartialCmp(in IPv6Addr other) => Version == Tag.V6 ? new(_v6.Cmp(other)) : Maybe<Ordering>.None();
    142         readonly void IIP.Sealed(){}
    143         public override readonly string ToString() => Version == Tag.V4 ? _v4.ToString() : _v6.ToString();
    144         readonly Result<IPAddr, Bottom> ITryInto<IPAddr, Bottom>.TryInto() => new(this);
    145         readonly Result<string, Bottom> ITryInto<string, Bottom>.TryInto() => new(ToString());
    146         readonly Result<byte[], Bottom> ITryInto<byte[], Bottom>.TryInto() => new(IntoBEBytes());
    147         readonly Result<IPv4Addr, IPVersionMismatchError> ITryInto<IPv4Addr, IPVersionMismatchError>.TryInto() => TryIntoIPv4();
    148         readonly Result<IPv6Addr, IPVersionMismatchError> ITryInto<IPv6Addr, IPVersionMismatchError>.TryInto() => TryIntoIPv6();
    149         #endregion
    150 
    151         #region Operators
    152         public static bool operator !=(IPAddr val0, IPAddr val1) => !(val0 == val1);
    153         public static bool operator !=(IPAddr val0, IPv4Addr val1) => val0.Version != Tag.V4 || val0._v4 != val1;
    154         public static bool operator !=(IPAddr val0, IPv6Addr val1) => val0.Version != Tag.V6 || val0._v6 != val1;
    155         public static bool operator <(IPAddr val0, IPAddr val1) => val0.Version == Tag.V4 ? val1.Version == Tag.V4 && val0._v4 < val1._v4 : val1.Version == Tag.V6 && val0._v6 < val1._v6;
    156         public static bool operator <(IPAddr val0, IPv4Addr val1) => val0.Version == Tag.V4 && val0._v4 < val1;
    157         public static bool operator <(IPAddr val0, IPv6Addr val1) => val0.Version == Tag.V6 && val0._v6 < val1;
    158         public static bool operator <=(IPAddr val0, IPAddr val1) => val0.Version == Tag.V4 ? val1.Version == Tag.V4 && val0._v4 <= val1._v4 : val1.Version == Tag.V6 && val0._v6 <= val1._v6;
    159         public static bool operator <=(IPAddr val0, IPv4Addr val1) => val0.Version == Tag.V4 && val0._v4 <= val1;
    160         public static bool operator <=(IPAddr val0, IPv6Addr val1) => val0.Version == Tag.V6 && val0._v6 <= val1;
    161         public static bool operator ==(IPAddr val0, IPAddr val1) => val0.Version == Tag.V4 ? val1.Version == Tag.V4 && val0._v4 == val1._v4 : val1.Version == Tag.V6 && val0._v6 == val1._v6;
    162         public static bool operator ==(IPAddr val0, IPv4Addr val1) => val0.Version == Tag.V4 && val0._v4 == val1;
    163         public static bool operator ==(IPAddr val0, IPv6Addr val1) => val0.Version == Tag.V6 && val0._v6 == val1;
    164         public static bool operator >(IPAddr val0, IPAddr val1) => val0.Version == Tag.V4 ? val1.Version == Tag.V4 && val0._v4 > val1._v4 : val1.Version == Tag.V6 && val0._v6 > val1._v6;
    165         public static bool operator >(IPAddr val0, IPv4Addr val1) => val0.Version == Tag.V4 && val0._v4 > val1;
    166         public static bool operator >(IPAddr val0, IPv6Addr val1) => val0.Version == Tag.V6 && val0._v6 > val1;
    167         public static bool operator >=(IPAddr val0, IPAddr val1) => val0.Version == Tag.V4 ? val1.Version == Tag.V4 && val0._v4 >= val1._v4 : val1.Version == Tag.V6 && val0._v6 >= val1._v6;
    168         public static bool operator >=(IPAddr val0, IPv4Addr val1) => val0.Version == Tag.V4 && val0._v4 >= val1;
    169         public static bool operator >=(IPAddr val0, IPv6Addr val1) => val0.Version == Tag.V6 && val0._v6 >= val1;
    170         #endregion
    171 
    172         #region Types
    173         public enum Tag: ulong {
    174             V4 = ulong.MinValue,
    175             V6 = ulong.MaxValue,
    176         }
    177         #endregion
    178     }
    179     [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode, Pack = 4, Size = 4)]
    180     public readonly struct IPv4Addr: IClone<IPv4Addr>, IEquality<IPv4Addr>, IInto<IPAddr>, IInto<string>, IInto<IPv4Addr>, IInto<uint>, IOrd<IPv4Addr>, IIP, IInto<byte[]>, IHashable, IPartialOrd<IPv4Addr, IPAddr>, IFrom<IPv4Addr, uint>, ITryFrom<IPv4Addr, string, AddrParseError> {
    181 
    182         #region Type-level Constructors
    183         #endregion
    184 
    185         #region Instance Constructors
    186         public IPv4Addr() => throw new InvalidOperationException("Parameterless constructor is not allowed to be called!");
    187         public IPv4Addr(uint val) => Value = val;
    188         #endregion
    189 
    190         #region Type-level Fields
    191         #endregion
    192 
    193         #region Instance Fields
    194         [FieldOffset(0)] public readonly uint Value;
    195         #endregion
    196 
    197         #region Type-level Properties
    198         #endregion
    199 
    200         #region Instance Properties
    201         #endregion
    202 
    203         #region Type-level Functions
    204         public static IPv4Addr FromBEBytes(ReadOnlySpan<byte> val) => new(((uint)val[0] << 24) | ((uint)val[1] << 16) | ((uint)val[2] << 8) | val[3]);
    205         public static IPv4Addr New(uint val) => new(val);
    206         // Follows IETF RFC 6943 Section 3.1.1. "strict" form.
    207         // Only a single pass through of val is done (i.e., each char is visited exactly once).
    208         // No allocations for strings, arrays, etc. are used; instead we efficiently perform addition, multiplication, and bit shifts.
    209         public static Result<IPv4Addr, AddrParseError> TryFrom(ReadOnlySpan<char> val) {
    210 
    211             if (val.Length is < 7 or > 15) { return new(AddrParseError.InvalidLength); }
    212             var (octet, octetCharCount, base256, ip) = (ulong.MinValue, uint.MinValue, 32, ulong.MinValue);
    213             ulong c;
    214 
    215             for (var i = 0; i < val.Length; i++) {
    216                 c = val[i];
    217 
    218                 if (c is >= 48ul and <= 57ul) {
    219                     octet = (octet * 10ul) + (c - 48ul);
    220                     octetCharCount++;
    221                 } else if (c == 46ul) {
    222 
    223                     if (octetCharCount is uint.MinValue or > 3u || octet > byte.MaxValue) {
    224                         return new(AddrParseError.InvalidFormat);
    225                     } else {
    226                         ip |= octet << (base256 -= 8);
    227                         (octet, octetCharCount) = (ulong.MinValue, uint.MinValue);
    228                     }
    229                 } else {
    230                     return new(AddrParseError.InvalidCharacter);
    231                 }
    232             }
    233             return base256 != 8 || octetCharCount is uint.MinValue or > 3u || octet > byte.MaxValue ? new(AddrParseError.InvalidFormat) : new(new IPv4Addr((uint)(octet | ip)));
    234         }
    235         public static IPv4Addr From(uint val) => new(val);
    236         static Result<IPv4Addr, Bottom> ITryFrom<IPv4Addr, uint, Bottom>.TryFrom(uint val) => new(From(val));
    237         public static Result<IPv4Addr, AddrParseError> TryFrom(string val) => TryFrom(val.AsSpan());
    238         #endregion
    239 
    240         #region Instance Functions
    241         public readonly IPv4Addr Clone() => this;
    242         public readonly Ordering Cmp(in IPv4Addr other) => Value.CompareTo(other.Value) switch {
    243             < 0 => Less,
    244             > 0 => Greater,
    245             0 => Equivalent,
    246         };
    247         public readonly bool Equals(in IPv4Addr other) => this == other;
    248         public override readonly bool Equals(object? _) => false;
    249         public override readonly int GetHashCode() => 0;
    250         public readonly Unit Hash<THasher>(ref THasher hasher) where THasher: notnull, IHasher => hasher.WriteUnsafe(this);
    251         public readonly IPv4Addr Into() => this;
    252         public readonly IPAddr IntoIPAddr() => IPAddr.V4(this);
    253         public readonly string IntoString() => ToString();
    254         public readonly uint IntoUint() => Value;
    255         public readonly byte[] IntoBEBytes() {
    256 
    257             var copy = Value;
    258             ReadOnlySpan<byte> val;
    259             unsafe { val = new(&copy, 4); }
    260             return new byte[] { val[3], val[2], val[1], val[0] };
    261         }
    262         public readonly Unit IntoBEBytes(Span<byte> bytes) {
    263 
    264             var copy = Value;
    265             ReadOnlySpan<byte> val;
    266             unsafe { val = new(&copy, 4); }
    267             (bytes[0], bytes[1], bytes[2], bytes[3]) = (val[3], val[2], val[1], val[0]);
    268             return new Unit();
    269         }
    270         readonly string IInto<string>.Into() => IntoString();
    271         readonly uint IInto<uint>.Into() => IntoUint();
    272         readonly IPAddr IInto<IPAddr>.Into() => IntoIPAddr();
    273         readonly byte[] IInto<byte[]>.Into() => IntoBEBytes();
    274         public readonly bool IsAMT() => Value is >= 3224682752u and < 3224683008u;
    275         public readonly bool IsAS112() => Value is >= 3223307264u and < 3223307520u;
    276         public readonly bool IsBenchmarking() => Value is >= 3323068416u and < 3323199488u;
    277         public readonly bool IsBroadcast() => Value == uint.MaxValue;
    278         public readonly bool IsIETFProtocol() => Value is >= 3221225472u and < 3221225728u;
    279         public readonly bool IsDocumentation() => Value is (>= 3221225984u and < 3221226240u) or (>= 3325256704u and < 3325256960u) or (>= 3405803776u and < 3405804032u);
    280         public readonly bool IsGlobal() => IsTraversalNATAnycast() || IsPortControlAnycast() || !(IsBenchmarking() || IsBroadcast() || IsDocumentation() || IsIETFProtocol() || IsLinkLocal() || IsLoopback() || IsThisNetwork() || IsPrivate() || IsReserved() || IsSharedAddress());
    281         public readonly bool IsDirectDelegationAS112() => Value is >= 3232706560u and < 3232706816u;
    282         public readonly bool IsLinkLocal() => Value is >= 2851995648u and < 2852061184u;
    283         public readonly bool IsLoopback() => Value is >= 2130706432u and < 2147483648u;
    284         public readonly bool IsThisNetwork() => Value is >= uint.MinValue and < 16777216u;
    285         public readonly bool IsMulticast() => Value is >= 3758096384u and < 4026531840u;
    286         public readonly bool IsPortControlAnycast() => Value == 3221225481u;
    287         public readonly bool IsPrivate() => Value is (>= 167772160u and < 184549376u) or (>= 2886729728u and < 2887778304u) or (>= 3232235520u and < 3232301056u);
    288         public readonly bool IsReserved() => Value is >= 4026531840u and < uint.MaxValue;
    289         public readonly bool IsSharedAddress() => Value is >= 1681915904u and < 1686110208u;
    290         public readonly bool IsTraversalNATAnycast() => Value == 3221225482u;
    291         public readonly bool IsUnspecified() => Value == uint.MinValue;
    292         public readonly Maybe<Ordering> PartialCmp(in IPv4Addr other) => Some(Cmp(in other));
    293         public readonly Maybe<Ordering> PartialCmp(in IPAddr other) => other.Version == IPAddr.Tag.V4 ? Some(Cmp(in other._v4)) : Maybe<Ordering>.None();
    294         readonly void IIP.Sealed(){}
    295         public readonly IPv6Addr ToIPv6Compatible() => new(new U128(Value, ulong.MinValue));
    296         public readonly IPv6Addr ToIPv6Mapped() => new(new U128(281470681743360ul + Value, ulong.MinValue));
    297         // Returns a string per IETF RFC 6943 Section 3.1.1. "strict" form with the added
    298         // restriction that leading 0s are not used.
    299         public override readonly string ToString() => $"{(Value >> 24).ToString()}.{(Value & 0xff0000u).ToString()}.{(Value & 0xff00u).ToString()}.{(Value << 24).ToString()}";
    300         readonly Result<IPv4Addr, Bottom> ITryInto<IPv4Addr, Bottom>.TryInto() => new(this);
    301         readonly Result<string, Bottom> ITryInto<string, Bottom>.TryInto() => new(ToString());
    302         readonly Result<uint, Bottom> ITryInto<uint, Bottom>.TryInto() => new(IntoUint());
    303         readonly Result<byte[], Bottom> ITryInto<byte[], Bottom>.TryInto() => new(IntoBEBytes());
    304         readonly Result<IPAddr, Bottom> ITryInto<IPAddr, Bottom>.TryInto() => new(IntoIPAddr());
    305         #endregion
    306 
    307         #region Operators
    308         public static bool operator !=(IPv4Addr val0, IPv4Addr val1) => val0.Value != val1.Value;
    309         public static bool operator !=(IPv4Addr val0, IPAddr val1) => val1 != val0;
    310         public static bool operator <(IPv4Addr val0, IPv4Addr val1) => val0.Value < val1.Value;
    311         public static bool operator <(IPv4Addr val0, IPAddr val1) => val1 > val0;
    312         public static bool operator <=(IPv4Addr val0, IPv4Addr val1) => val0.Value <= val1.Value;
    313         public static bool operator <=(IPv4Addr val0, IPAddr val1) => val1 >= val0;
    314         public static bool operator ==(IPv4Addr val0, IPv4Addr val1) => val0.Value == val1.Value;
    315         public static bool operator ==(IPv4Addr val0, IPAddr val1) => val1 == val0;
    316         public static bool operator >(IPv4Addr val0, IPv4Addr val1) => val0.Value > val1.Value;
    317         public static bool operator >(IPv4Addr val0, IPAddr val1) => val1 < val0;
    318         public static bool operator >=(IPv4Addr val0, IPv4Addr val1) => val0.Value >= val1.Value;
    319         public static bool operator >=(IPv4Addr val0, IPAddr val1) => val1 <= val0;
    320         #endregion
    321 
    322         #region Types
    323         #endregion
    324     }
    325     [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode, Pack = 8, Size = 16)]
    326     public readonly struct IPv6Addr: IClone<IPv6Addr>, IEquality<IPv6Addr>, IInto<IPAddr>, IInto<string>, IInto<IPv6Addr>, IInto<U128>, IIP, IOrd<IPv6Addr>, IInto<byte[]>, IHashable, IPartialOrd<IPv6Addr, IPAddr>, ITryFrom<IPv6Addr, string, AddrParseError> {
    327 
    328         #region Type-level Constructors
    329         #endregion
    330 
    331         #region Instance Constructors
    332         public IPv6Addr() => throw new InvalidOperationException("Parameterless constructor is not allowed to be called!");
    333         public IPv6Addr(U128 val) => Value = val;
    334         #endregion
    335 
    336         #region Type-level Fields
    337         #endregion
    338 
    339         #region Instance Fields
    340         [FieldOffset(0)] public readonly U128 Value;
    341         #endregion
    342 
    343         #region Type-level Properties
    344         #endregion
    345 
    346         #region Instance Properties
    347         #endregion
    348 
    349         #region Type-level Functions
    350         public static IPv6Addr FromBEBytes(ReadOnlySpan<byte> val) => new(U128.FromBEBytes(val));
    351         public static IPv6Addr New(U128 val) => new(val);
    352         // Follows IETF RFC 4291 Section 2.2.
    353         public static Result<IPv6Addr, AddrParseError> TryFrom(ReadOnlySpan<char> val) {
    354 
    355             if (val.Length is < 2 or > 45 || (val[0] == ':' && val[1] != ':')) { return new(AddrParseError.InvalidLength); }
    356             Span<ulong> octetPairs = stackalloc ulong[8];
    357             var (octetPair, colonConsec, charCount, compressedIndex, colonIndex) = (ulong.MinValue, uint.MinValue, uint.MinValue, 0, 0);
    358             ulong c;
    359             var index = 0;
    360             var maxIndex = 7;
    361 
    362             for (var i = 0; i < val.Length; i++) {
    363                 c = val[i];
    364 
    365                 if (c is >= 48ul and <= 57ul) {
    366                     octetPair = (octetPair << 4) | (c - 48ul);
    367                     colonConsec = uint.MinValue;
    368                     charCount++;
    369                 } else if (c is >= 97ul and <= 102ul) {
    370                     octetPair = (octetPair << 4) | (c - 87ul);
    371                     colonConsec = uint.MinValue;
    372                     charCount++;
    373                 } else if (c is >= 65ul and <= 70ul) {
    374                     octetPair = (octetPair << 4) | (c - 55ul);
    375                     colonConsec = uint.MinValue;
    376                     charCount++;
    377                 } else if (c == 58ul) {
    378 
    379                     if (charCount > 4 || index > maxIndex || colonConsec > 1u || (compressedIndex > 0 && colonConsec == 1u)) {
    380                         return new(AddrParseError.InvalidFormat);
    381                     } else if (colonConsec++ == uint.MinValue) {
    382                         octetPairs[index++] = octetPair;
    383                     } else {
    384                         compressedIndex = index;
    385                     }
    386                     (octetPair, charCount, colonIndex) = (ulong.MinValue, uint.MinValue, i);
    387                 } else if (c == 46ul) {
    388                     // IPv6 addresses are allowed to be terminated by an IPv4 address.
    389                     if (index is 0 or > 6) { return new(AddrParseError.InvalidFormat); }
    390                     var ipv4 = IPv4Addr.TryFrom(val[(colonIndex + 1)..]);
    391 
    392                     if (ipv4.IsErr) {
    393                         return new(ipv4.UnwrapErr());
    394                     } else {
    395                         // Transform the IPv4 address into the last 2 octet-pairs.
    396                         var x = ipv4.Unwrap().IntoUint();
    397                         (charCount, colonConsec, octetPairs[index++], octetPair) = (3, uint.MinValue, x >> 16, x & 0xffffu);
    398                         break;
    399                     }
    400                 } else {
    401                     return new(AddrParseError.InvalidCharacter);
    402                 }
    403             }
    404             if (charCount > 4 || index == 0 || index > maxIndex || colonConsec == 1u) { return new(AddrParseError.InvalidFormat); }
    405             octetPairs[index++] = octetPair;
    406             // We shift the octet-pairs after the double colon.
    407             if (index <= maxIndex) { while (index > compressedIndex) { (octetPairs[--index], octetPairs[maxIndex--]) = (ulong.MinValue, octetPairs[index]); } }
    408             return new(new IPv6Addr(new U128(octetPairs[7] | (octetPairs[6] << 16) | (octetPairs[5] << 32) | (octetPairs[4] << 48), octetPairs[3] | (octetPairs[2] << 16) | (octetPairs[1] << 32) | (octetPairs[0] << 48))));
    409         }
    410         public static Result<IPv6Addr, AddrParseError> TryFrom(string val) => TryFrom(val.AsSpan());
    411         #endregion
    412 
    413         #region Instance Functions
    414         public readonly IPv6Addr Clone() => this;
    415         public readonly Ordering Cmp(in IPv6Addr other) => Value.Cmp(in other.Value);
    416         public readonly bool Equals(in IPv6Addr other) => this == other;
    417         public override readonly bool Equals(object? _) => false;
    418         public override readonly int GetHashCode() => 0;
    419         public readonly Unit Hash<THasher>(ref THasher hasher) where THasher: notnull, IHasher => hasher.WriteUnsafe(this);
    420         public readonly IPv6Addr Into() => this;
    421         public readonly string IntoString() => ToString();
    422         public readonly IPAddr IntoIPAddr() => IPAddr.V6(this);
    423         readonly IPAddr IInto<IPAddr>.Into() => IntoIPAddr();
    424         public readonly U128 IntoU128() => Value;
    425         public readonly Unit IntoBEBytes(Span<byte> val) => Value.IntoBEBytes(val);
    426         public readonly byte[] IntoBEBytes() => Value.IntoBEBytes();
    427         readonly string IInto<string>.Into() => IntoString();
    428         readonly U128 IInto<U128>.Into() => IntoU128();
    429         readonly byte[] IInto<byte[]>.Into() => IntoBEBytes();
    430         public readonly bool Is6To4() => this >= _6To4.Item0 && this < _6To4.Item1;
    431         public readonly bool IsAMT() => this >= _AMT.Item0 && this < _AMT.Item1;
    432         public readonly bool IsAS1122() => this >= _AS1122.Item0 && this < _AS1122.Item1;
    433         public readonly bool IsBenchmarking() => this >= _benchmarking.Item0 && this < _benchmarking.Item1;
    434         public readonly bool IsDirectDelegationAS112() => this >= _directDelegationAS112.Item0 && this < _directDelegationAS112.Item1;
    435         public readonly bool IsDiscard() => this >= _discard.Item0 && this < _discard.Item1;
    436         public readonly bool IsDocumentation() => this >= _documentation.Item0 && this < _documentation.Item1;
    437         public readonly bool IsGlobal() => (this >= _IPv4IPv6TranslatedGlobal.Item0 && this < _IPv4IPv6TranslatedGlobal.Item1) || !(IsLoopback() || IsUnspecified() || IsIPv4Mapped() || IsIPv4IPv6Translated() || IsDiscard() || IsBenchmarking() || IsDocumentation() || IsLinkLocal() || IsIETFProtocol() || IsUniqueLocal() || IsTEREDO() || Is6To4());
    438         public readonly bool IsIETFProtocol() => this >= _IETFProtocol.Item0 && this < _IETFProtocol.Item1;
    439         public readonly bool IsIPv4Mapped() => this >= _IPv4MappedRange.Item0 && this < _IPv4MappedRange.Item1;
    440         public readonly bool IsIPv4IPv6Translated() => (this >= _IPv4IPv6Translated.Item0 && this < _IPv4IPv6Translated.Item1) || (this >= _IPv4IPv6TranslatedGlobal.Item0 && this < _IPv4IPv6TranslatedGlobal.Item1);
    441         public readonly bool IsLinkLocal() => this >= _linkLocal.Item0 && this < _linkLocal.Item1;
    442         public readonly bool IsLinkLocalStrict() => this >= _linkLocalStrict.Item0 && this < _linkLocalStrict.Item1;
    443         public readonly bool IsLoopback() => this == _loopback;
    444         public readonly bool IsMulticast() => this >= _multicast.Item0 && this <= _multicast.Item1;
    445         public readonly bool IsORCHID() => this >= _ORCHID.Item0 && this < _ORCHID.Item1;
    446         public readonly bool IsPortControlAnycast() => this == _portControlAnycast;
    447         public readonly bool IsTEREDO() => this >= _TEREDO.Item0 && this < _TEREDO.Item1;
    448         public readonly bool IsTraversalRelaysNATAnycast() => this == _traversalRelaysNATAnycast;
    449         public readonly bool IsUniqueLocal() => this >= _uniqueLocal.Item0 && this < _uniqueLocal.Item1;
    450         public readonly bool IsUnspecified() => this == _unspecified;
    451         public readonly Maybe<Ordering> PartialCmp(in IPv6Addr other) => Some(Cmp(in other));
    452         public readonly Maybe<Ordering> PartialCmp(in IPAddr other) => other.Version == IPAddr.Tag.V6 ? Some(Cmp(in other._v6)) : Maybe<Ordering>.None();
    453         readonly void IIP.Sealed(){}
    454         public readonly Maybe<IPv4Addr> ToIPv4() => Value <= new U128(uint.MaxValue, ulong.MinValue) ? new(new IPv4Addr((uint)Value)) : ToIPv4Mapped();
    455         public readonly Maybe<IPv4Addr> ToIPv4Mapped() => IsIPv4Mapped() ? new(new IPv4Addr((uint)((ulong)Value - 281470681743360ul))) : Maybe<IPv4Addr>.None();
    456         // Returns a string conforming to IETF RFC 5952 Section 4.
    457         public override readonly string ToString() {
    458 
    459             if (Value == U128.MinValue) { return "::"; }
    460             Span<byte> val = stackalloc byte[16];
    461             _ = IntoBEBytes(val);
    462             var fstSkippedOctetPair = -1;
    463             var fstMaxSkippedOctetPair = -1;
    464             var skipCounter = 0;
    465             var maxSkip = 0;
    466 
    467             for (var i = 0; i < val.Length; i += 2) {
    468 
    469                 if (val[i] + val[i + 1] == byte.MinValue) {
    470                     if (skipCounter == 0) { fstSkippedOctetPair = i; }
    471                     skipCounter++;
    472                 } else {
    473 
    474                     if (skipCounter > maxSkip && skipCounter > 1) {
    475                         fstMaxSkippedOctetPair = fstSkippedOctetPair;
    476                         maxSkip = skipCounter;
    477                     }
    478                     skipCounter = 0;
    479                 }
    480             }
    481 
    482             if (skipCounter > maxSkip && skipCounter > 1) {
    483                 fstMaxSkippedOctetPair = fstSkippedOctetPair;
    484                 maxSkip = skipCounter;
    485             }
    486 
    487             if (maxSkip > 1) {
    488                 StringBuilder ip = new(31);
    489                 for (var i = 0; i < fstMaxSkippedOctetPair; i += 2) { ip = ip.Append($"{((val[i] << 8) | val[i + 1]).ToString("x")}:"); }
    490                 ip = fstMaxSkippedOctetPair == 0 ? ip.Append("::") : ip.Append(':');
    491                 for (var i = fstMaxSkippedOctetPair + (2 * maxSkip); i < val.Length; i += 2) { ip = ip.Append($"{((val[i] << 8) | val[i + 1]).ToString("x")}:"); }
    492                 return fstMaxSkippedOctetPair + (2 * maxSkip) != 16 ? ip.Remove(ip.Length - 1, 1).ToString() : ip.ToString();
    493             } else {
    494                 return $"{((val[0] << 8) | val[1]).ToString("x")}:{((val[2] << 8) | val[3]).ToString("x")}:{((val[4] << 8) | val[5]).ToString("x")}:{((val[6] << 8) | val[7]).ToString("x")}:{((val[8] << 8) | val[9]).ToString("x")}:{((val[10] << 8) | val[11]).ToString("x")}:{((val[12] << 8) | val[13]).ToString("x")}:{((val[14] << 8) | val[15]).ToString("x")}";
    495             }
    496         }
    497         readonly Result<IPv6Addr, Bottom> ITryInto<IPv6Addr, Bottom>.TryInto() => new(this);
    498         readonly Result<string, Bottom> ITryInto<string, Bottom>.TryInto() => new(ToString());
    499         readonly Result<IPAddr, Bottom> ITryInto<IPAddr, Bottom>.TryInto() => new(IntoIPAddr());
    500         readonly Result<U128, Bottom> ITryInto<U128, Bottom>.TryInto() => new(IntoU128());
    501         readonly Result<byte[], Bottom> ITryInto<byte[], Bottom>.TryInto() => new(IntoBEBytes());
    502         #endregion
    503 
    504         #region Operators
    505         public static bool operator !=(IPv6Addr val0, IPv6Addr val1) => val0.Value != val1.Value;
    506         public static bool operator !=(IPv6Addr val0, IPAddr val1) => val1 != val0;
    507         public static bool operator <(IPv6Addr val0, IPv6Addr val1) => val0.Value < val1.Value;
    508         public static bool operator <(IPv6Addr val0, IPAddr val1) => val1 > val0;
    509         public static bool operator <=(IPv6Addr val0, IPv6Addr val1) => val0.Value <= val1.Value;
    510         public static bool operator <=(IPv6Addr val0, IPAddr val1) => val1 >= val0;
    511         public static bool operator ==(IPv6Addr val0, IPv6Addr val1) => val0.Value == val1.Value;
    512         public static bool operator ==(IPv6Addr val0, IPAddr val1) => val1 == val0;
    513         public static bool operator >(IPv6Addr val0, IPv6Addr val1) => val0.Value > val1.Value;
    514         public static bool operator >(IPv6Addr val0, IPAddr val1) => val1 < val0;
    515         public static bool operator >=(IPv6Addr val0, IPv6Addr val1) => val0.Value >= val1.Value;
    516         public static bool operator >=(IPv6Addr val0, IPAddr val1) => val1 <= val0;
    517         #endregion
    518 
    519         #region Types
    520         #endregion
    521     }
    522     static class Functions {
    523 
    524         #region Type-level Constructors
    525         #endregion
    526 
    527         #region Instance Constructors
    528         #endregion
    529 
    530         #region Type-level Fields
    531         internal static readonly IPv6Addr _unspecified = new(U128.MinValue);
    532         internal static readonly IPv6Addr _loopback = new(new U128(0x1ul, ulong.MinValue));
    533         internal static readonly IPv6Addr _portControlAnycast = new(new U128(0x1ul, 0x2001000100000000ul));
    534         internal static readonly IPv6Addr _traversalRelaysNATAnycast = new(new U128(0x2ul, 0x2001000100000000ul));
    535         internal static readonly Prod<IPv6Addr, IPv6Addr> _6To4 = new(new IPv6Addr(new U128(ulong.MinValue, 0x2002000000000000ul)), new IPv6Addr(new U128(ulong.MinValue, 0x2003000000000000ul)));
    536         internal static readonly Prod<IPv6Addr, IPv6Addr> _IPv4MappedRange = new(new IPv6Addr(new U128(0xffff00000000ul, ulong.MinValue)), new IPv6Addr(new U128(0x1000000000000ul, ulong.MinValue)));
    537         internal static readonly Prod<IPv6Addr, IPv6Addr> _IPv4IPv6Translated = new(new IPv6Addr(new U128(ulong.MinValue, 0x64ff9b00010000ul)), new IPv6Addr(new U128(ulong.MinValue, 0x64ff9b00020000ul)));
    538         internal static readonly Prod<IPv6Addr, IPv6Addr> _IPv4IPv6TranslatedGlobal = new(new IPv6Addr(new U128(ulong.MinValue, 0x64ff9b00000000ul)), new IPv6Addr(new U128(0x100000000ul, 0x64ff9b00000000ul)));
    539         internal static readonly Prod<IPv6Addr, IPv6Addr> _discard = new(new IPv6Addr(new U128(ulong.MinValue, 0x100000000000000ul)), new IPv6Addr(new U128(ulong.MinValue, 0x100000000000001ul)));
    540         internal static readonly Prod<IPv6Addr, IPv6Addr> _benchmarking = new(new IPv6Addr(new U128(ulong.MinValue, 0x2001000200000000ul)), new IPv6Addr(new U128(ulong.MinValue, 0x2001000200010000ul)));
    541         internal static readonly Prod<IPv6Addr, IPv6Addr> _documentation = new(new IPv6Addr(new U128(ulong.MinValue, 0x20010db800000000ul)), new IPv6Addr(new U128(ulong.MinValue, 0x20010db800010000ul)));
    542         internal static readonly Prod<IPv6Addr, IPv6Addr> _linkLocal = new(new IPv6Addr(new U128(ulong.MinValue, 0xfe80000000000000ul)), new IPv6Addr(new U128(ulong.MinValue, 0xfec0000000000000ul)));
    543         internal static readonly Prod<IPv6Addr, IPv6Addr> _linkLocalStrict = new(new IPv6Addr(new U128(ulong.MinValue, 0xfe80000000000000ul)), new IPv6Addr(new U128(ulong.MinValue, 0xfe80000000000001ul)));
    544         internal static readonly Prod<IPv6Addr, IPv6Addr> _IETFProtocol = new(new IPv6Addr(new U128(ulong.MinValue, 0x2001000000000000ul)), new IPv6Addr(new U128(ulong.MinValue, 0x2001020000000000ul)));
    545         internal static readonly Prod<IPv6Addr, IPv6Addr> _uniqueLocal = new(new IPv6Addr(new U128(ulong.MinValue, 0xfc00000000000000ul)), new IPv6Addr(new U128(ulong.MinValue, 0xfe00000000000000ul)));
    546         internal static readonly Prod<IPv6Addr, IPv6Addr> _TEREDO = new(new IPv6Addr(new U128(ulong.MinValue, 0x2001000000000000ul)), new IPv6Addr(new U128(ulong.MinValue, 0x2001000100000000ul)));
    547         internal static readonly Prod<IPv6Addr, IPv6Addr> _AMT = new(new IPv6Addr(new U128(ulong.MinValue, 0x2001000300000000ul)), new IPv6Addr(new U128(ulong.MinValue, 0x2001000400000000ul)));
    548         internal static readonly Prod<IPv6Addr, IPv6Addr> _AS1122 = new(new IPv6Addr(new U128(ulong.MinValue, 0x2001000401120000ul)), new IPv6Addr(new U128(ulong.MinValue, 0x2001000401130000ul)));
    549         internal static readonly Prod<IPv6Addr, IPv6Addr> _ORCHID = new(new IPv6Addr(new U128(ulong.MinValue, 0x2001002000000000ul)), new IPv6Addr(new U128(ulong.MinValue, 0x2001003000000000ul)));
    550         internal static readonly Prod<IPv6Addr, IPv6Addr> _directDelegationAS112 = new(new IPv6Addr(new U128(ulong.MinValue, 0x2620004f80000000ul)), new IPv6Addr(new U128(ulong.MinValue, 0x2620004f80010000ul)));
    551         internal static readonly Prod<IPv6Addr, IPv6Addr> _multicast = new(new IPv6Addr(new U128(ulong.MinValue, 0xff00000000000000ul)), new IPv6Addr(U128.MaxValue));
    552         #endregion
    553 
    554         #region Instance Fields
    555         #endregion
    556 
    557         #region Type-level Properties
    558         #endregion
    559 
    560         #region Instance Properties
    561         #endregion
    562 
    563         #region Type-level Functions
    564         #endregion
    565 
    566         #region Instance Functions
    567         #endregion
    568 
    569         #region Operators
    570         #endregion
    571 
    572         #region Types
    573         #endregion
    574     }
    575     #endregion
    576 
    577     #region Namespaces
    578     #endregion
    579 }
    580 #endregion