Std

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

Maybe.cs (16867B)


      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.Iter;
      7 using Std.Ops;
      8 using static Std.Maybe.Maybe<Std.Cmp.Ordering>;
      9 using Std.Result;
     10 using System;
     11 using System.Runtime.CompilerServices;
     12 using System.Runtime.InteropServices;
     13 #region Namespaces
     14 namespace Std.Maybe {
     15     #region Types
     16     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 0)]
     17     public struct IntoIterator<T>: IDoubleEndedIterator<T>, IExactSizeIterator<T>, IFusedIterator<T>, IInto<IntoIterator<T>>, IIntoIterator<T, IntoIterator<T>> where T: notnull {
     18 
     19         #region Type-level Constructors
     20         #endregion
     21 
     22         #region Instance Constructors
     23         public IntoIterator() => throw new InvalidOperationException("Parameterless constructor is not allowed to be called!");
     24         internal IntoIterator(Maybe<T> maybe) => _maybe = maybe;
     25         #endregion
     26 
     27         #region Type-level Fields
     28         #endregion
     29 
     30         #region Instance Fields
     31         Maybe<T> _maybe;
     32         #endregion
     33 
     34         #region Type-level Properties
     35         #endregion
     36 
     37         #region Instance Properties
     38         #endregion
     39 
     40         #region Type-level Functions
     41         #endregion
     42 
     43         #region Instance Functions
     44         public Result<Unit, ulong> AdvanceBackBy(ulong n) => IDoubleEndedIterator<T>.AdvanceBackByDefault(ref this, n);
     45         public Result<Unit, ulong> AdvanceBy(ulong n) => IIterator<T>.AdvanceByDefault(ref this, n);
     46         public readonly ulong Count() => _maybe.IsSome ? 1ul : ulong.MinValue;
     47         public TInit Fold<TInit>(TInit init, Fn<TInit, T, TInit> f) where TInit: notnull => IIterator<T>.FoldDefault(ref this, init, f);
     48         public override readonly bool Equals(object? _) => false;
     49         public override readonly int GetHashCode() => 0;
     50         public readonly IntoIterator<T> Into() => this;
     51         public readonly IntoIterator<T> IntoIter() => this;
     52         public Maybe<T> Last() => IIterator<T>.LastDefault(ref this);
     53         public readonly ulong Len() => _maybe.IsSome ? 1ul : ulong.MinValue;
     54         public Maybe<T> Next() {
     55 
     56             var val = _maybe;
     57             _maybe = Maybe<T>.None();
     58             return val;
     59         }
     60         public Maybe<T> NextBack() => Next();
     61         public TInit RFold<TInit>(TInit init, Fn<TInit, T, TInit> f) where TInit: notnull => IDoubleEndedIterator<T>.RFoldDefault(ref this, init, f);
     62         public readonly Prod<ulong, Maybe<ulong>> SizeHint() => _maybe.IsSome ? new(1ul, new(1ul)) : new(ulong.MinValue, new(ulong.MinValue));
     63         public override readonly string ToString() => string.Empty;
     64         public Result<TInit, TErr> TryFold<TInit, TErr>(TInit init, Fn<TInit, T, Result<TInit, TErr>> f) where TInit: notnull where TErr: notnull => IIterator<T>.TryFoldDefault(ref this, init, f);
     65         public Result<TInit, TErr> TryRFold<TInit, TErr>(TInit init, Fn<TInit, T, Result<TInit, TErr>> f) where TInit: notnull where TErr: notnull => IDoubleEndedIterator<T>.TryRFoldDefault(ref this, init, f);
     66         readonly Result<IntoIterator<T>, Bottom> ITryInto<IntoIterator<T>, Bottom>.TryInto() => new(this);
     67         #endregion
     68 
     69         #region Operators
     70         #endregion
     71 
     72         #region Types
     73         #endregion
     74     }
     75     // Even though TSome can be a non-readonly struct, we can still make Maybe readonly without any performance hit so long
     76     // as we never access any members of _some.
     77     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 0)]
     78     public readonly struct Maybe<TSome>: ISum<TSome, Unit>, IInto<Maybe<TSome>>, IIntoIterator<TSome, IntoIterator<TSome>> where TSome: notnull {
     79 
     80         #region Type-level Constructors
     81         #endregion
     82 
     83         #region Instance Constructors
     84         [MethodImpl(MethodImplOptions.AggressiveInlining)]
     85         public Maybe() => (_some, Var) = (default!, Tag.None);
     86         [MethodImpl(MethodImplOptions.AggressiveInlining)]
     87         public Maybe(TSome val) => (Var, _some) = (Tag.Some, val);
     88         #endregion
     89 
     90         #region Type-level Fields
     91         #endregion
     92 
     93         #region Instance Fields
     94         // This is the "standard library"; so it is important that code is quick.
     95         // Due to the pervasive usage of Maybes, we decide to expose this field to the rest of the shared library.
     96         // This allows code to avoid overhead from calling the monadic API or even functions like Unwrap.
     97         // It is imperative that code manually verify IsSome is true first though.
     98         internal readonly TSome _some;
     99         public readonly Tag Var;
    100         #endregion
    101 
    102         #region Type-level Properties
    103         #endregion
    104 
    105         #region Instance Properties
    106         public readonly bool IsNone => Var == Tag.None;
    107         public readonly bool IsSome => Var == Tag.Some;
    108         public readonly Var2 Variant => Var == Tag.Some ? Var2.V0 : Var2.V1;
    109         public readonly TSome Variant0 => Var == Tag.Some ? _some : throw new InvalidOperationException($"The Maybe variant, {Var.ToString()} is not Some!");
    110         public readonly Unit Variant1 => Var == Tag.None ? new Unit() : throw new InvalidOperationException($"The Maybe variant, {Var.ToString()} is not None!");
    111         #endregion
    112 
    113         #region Type-level Functions
    114         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    115         public static Maybe<TSome> None() => new();
    116         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    117         public static Maybe<TSome> Some(TSome val) => new(val);
    118         #endregion
    119 
    120         #region Instance Functions
    121         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    122         public readonly Maybe<T> And<T>(Maybe<T> val) where T: notnull => IsSome ? val : Maybe<T>.None();
    123         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    124         public readonly Maybe<T> AndThen<T>(Fn<TSome, Maybe<T>> f) where T: notnull => IsSome ? f(_some) : Maybe<T>.None();
    125         public override readonly bool Equals(object? _) => false;
    126         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    127         public readonly TSome Expect(string msg) => IsSome ? _some : throw new InvalidOperationException(msg);
    128         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    129         public readonly Unit ExpectNone(string msg) => !IsSome ? new Unit() : throw new InvalidOperationException($"{msg}: {_some.ToString()}");
    130         public readonly Maybe<TSome> Filter(FnIn<TSome, bool> f) => (IsSome && f(in _some)) ? this : new Maybe<TSome>();
    131         public override readonly int GetHashCode() => 0;
    132         public readonly Maybe<TSome> Into() => this;
    133         public readonly IntoIterator<TSome> IntoIter() => new(this);
    134         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    135         public readonly Maybe<T> Map<T>(Fn<TSome, T> f) where T: notnull => IsSome ? new(f(_some)) : Maybe<T>.None();
    136         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    137         public readonly T MapOr<T>(T Default, Fn<TSome, T> f) where T: notnull => IsSome ? f(_some) : Default;
    138         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    139         public readonly T MapOrElse<T>(Fn<T> Default, Fn<TSome, T> f) where T: notnull => IsSome ? f(_some) : Default();
    140         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    141         public readonly Result<TSome, TErr> OKOr<TErr>(TErr err) where TErr: notnull => IsSome ? new(_some) : new(err);
    142         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    143         public readonly Result<TSome, TErr> OKOrElse<TErr>(Fn<TErr> err) where TErr: notnull => IsSome ? new(_some) : new(err());
    144         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    145         public readonly Maybe<TSome> Or(Maybe<TSome> val) => IsSome ? this : val;
    146         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    147         public readonly Maybe<TSome> OrElse(Fn<Maybe<TSome>> f) => IsSome ? this : f();
    148         public override readonly string ToString() => IsSome ? $"Some({_some.ToString()})" : "None";
    149         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    150         public readonly TSome Unwrap() => IsSome ? _some : throw new InvalidOperationException("None");
    151         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    152         public readonly Unit UnwrapNone() => !IsSome ? new Unit() : throw new InvalidOperationException($"OK{_some.ToString()}");
    153         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    154         public readonly TSome UnwrapOr(TSome Default) => IsSome ? _some : Default;
    155         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    156         public readonly TSome UnwrapOrElse(Fn<TSome> f) => IsSome ? _some : f();
    157         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    158         public readonly Maybe<TSome> Xor(Maybe<TSome> val) => !IsSome ? val : val.IsSome ? new Maybe<TSome>() : this;
    159         public readonly Maybe<Prod<TSome, T>> Zip<T>(Maybe<T> other) where T: notnull => IsSome && other.IsSome ? new(new(_some, other._some)) : new Maybe<Prod<TSome, T>>();
    160         public readonly Maybe<TVal> ZipWith<T, TVal>(Maybe<T> other, Fn<TSome, T, TVal> f) where T: notnull where TVal: notnull => IsSome && other.IsSome ? new(f(_some, other._some)) : new Maybe<TVal>();
    161         readonly Result<Maybe<TSome>, Bottom> ITryInto<Maybe<TSome>, Bottom>.TryInto() => new(this);
    162         #endregion
    163 
    164         #region Operators
    165         #endregion
    166 
    167         #region Types
    168         public enum Tag: byte {
    169             None = byte.MinValue,
    170             Some = byte.MaxValue,
    171         }
    172         #endregion
    173     }
    174     public static class Functions {
    175 
    176         #region Type-level Constructors
    177         #endregion
    178 
    179         #region Instance Constructors
    180         #endregion
    181 
    182         #region Type-level Fields
    183         #endregion
    184 
    185         #region Instance Fields
    186         #endregion
    187 
    188         #region Type-level Properties
    189         #endregion
    190 
    191         #region Instance Properties
    192         #endregion
    193 
    194         #region Type-level Functions
    195         public static Maybe<TSome> Clamp<TSome>(this Maybe<TSome> self, Maybe<TSome> min, Maybe<TSome> max) where TSome: notnull, IOrd<TSome> {
    196 
    197             System.Diagnostics.Trace.Assert(min.Cmp(in max).Var != Ord.Greater);
    198             return self.Cmp(in min).Var switch {
    199                 Ord.Less => min,
    200                 Ord.Equivalent => self,
    201                 _ => self.Cmp(in max).Var == Ord.Greater ? max : self,
    202             };
    203         }
    204         public static Maybe<TSome> Clone<TSome>(in this Maybe<TSome> self) where TSome: notnull, IClone<TSome> => self.IsSome ? new(self._some.Clone()) : new Maybe<TSome>();
    205         public static Ordering Cmp<TSome>(in this Maybe<TSome> self, in Maybe<TSome> other) where TSome: notnull, IOrd<TSome> => (self.IsSome, other.IsSome) switch {
    206             (true, true) => self._some.Cmp(in other._some),
    207             (true, false) => Greater,
    208             (false, true) => Less,
    209             _ => Equivalent,
    210         };
    211         public static int CompareToComparable<TSome>(in this Maybe<TSome> self, in Maybe<TSome> other) where TSome: notnull, IComparable<TSome> => (self.IsSome, other.IsSome) switch {
    212             (true, true) => self._some.CompareTo(other._some),
    213             (true, false) => 1,
    214             (false, true) => -1,
    215             _ => 0,
    216         };
    217         public static bool Contains<TSome, T>(in this Maybe<TSome> self, in T val) where TSome: notnull, IPartialEq<TSome, T> where T: notnull, IPartialEq<T, TSome> => self.IsSome && self._some == val;
    218         public static bool Eq<T0, T1>(in this Maybe<T0> self, in Maybe<T1> other) where T0: notnull, IPartialEq<T0, T1> where T1: notnull, IPartialEq<T1, T0> => (self.IsSome, other.IsSome) switch {
    219             (true, true) => self._some == other._some,
    220             (false, false) => true,
    221             _ => false,
    222         };
    223         public static bool EqualsEquality<TSome>(in this Maybe<TSome> self, in Maybe<TSome> other) where TSome: notnull, IEquality<TSome> => (self.IsSome, other.IsSome) switch {
    224             (true, true) => self._some.Equals(in other._some),
    225             (false, false) => true,
    226             _ => false,
    227         };
    228         public static bool EqualsEquatable<T>(in this Maybe<T> self, in Maybe<T> other) where T: notnull, IEquatable<T> => (self.IsSome, other.IsSome) switch {
    229             (true, true) => self._some.Equals(other._some),
    230             (false, false) => true,
    231             _ => false,
    232         };
    233         public static Maybe<TSome> Flatten<TSome>(this Maybe<Maybe<TSome>> self) where TSome: notnull => self.AndThen(Convert.Functions.Identity);
    234         public static Maybe<TSome> FromIter<TSome, T, TIter>(TIter iter) where T: notnull where TIter: notnull, IIterator<Maybe<T>> where TSome: notnull, IFromIterator<TSome, T> {
    235 
    236             var mbe = new Maybe<Unit>();
    237             var v = TSome.FromIter(iter.Scan(new Unit(), (ref Unit _, ref Maybe<T> item) => {
    238                 if (item.IsNone) { mbe = new(new Unit()); }
    239                 return item;
    240             }));
    241             return mbe.IsSome ? new Maybe<TSome>() : new(v);
    242         }
    243         public static bool Ge<T0, T1>(in this Maybe<T0> self, in Maybe<T1> other) where T0: notnull, IPartialOrd<T0, T1> where T1: notnull, IPartialOrd<T1, T0> => (self.IsSome, other.IsSome) switch {
    244             (true, true) => self._some >= other._some,
    245             (true, false) => true,
    246             (false, true) => false,
    247             _ => true,
    248         };
    249         public static int GetHashCodeEquatable<TSome>(in this Maybe<TSome> self) where TSome: notnull, IEquatable<TSome> => self.IsSome ? HashCode.Combine(1, self._some) : 0;
    250         public static bool Gt<T0, T1>(in this Maybe<T0> self, in Maybe<T1> other) where T0: notnull, IPartialOrd<T0, T1> where T1: notnull, IPartialOrd<T1, T0> => (self.IsSome, other.IsSome) switch {
    251             (true, true) => self._some > other._some,
    252             (true, false) => true,
    253             (false, true) => false,
    254             _ => false,
    255         };
    256         public static Unit Hash<TSome, THasher>(in this Maybe<TSome> self, ref THasher hasher) where TSome: notnull, IHashable where THasher: notnull, IHasher {
    257 
    258             if (self.IsSome) {
    259                 _ = hasher.WriteByte(byte.MaxValue);
    260                 return self._some.Hash(ref hasher);
    261             } else {
    262                 return hasher.WriteByte(byte.MinValue);
    263             }
    264         }
    265         public static string IntoString<TSome>(in this Maybe<TSome> self) where TSome: notnull, IInto<string> => self.IsSome ? $"Some({self._some.Into()})" : "None";
    266         public static bool Le<T0, T1>(in this Maybe<T0> self, in Maybe<T1> other) where T0: notnull, IPartialOrd<T0, T1> where T1: notnull, IPartialOrd<T1, T0> => (self.IsSome, other.IsSome) switch {
    267             (true, true) => self._some <= other._some,
    268             (true, false) => false,
    269             (false, true) => true,
    270             _ => true,
    271         };
    272         public static bool Lt<T0, T1>(in this Maybe<T0> self, in Maybe<T1> other) where T0: notnull, IPartialOrd<T0, T1> where T1: notnull, IPartialOrd<T1, T0> => (self.IsSome, other.IsSome) switch {
    273             (true, true) => self._some < other._some,
    274             (true, false) => false,
    275             (false, true) => true,
    276             _ => false,
    277         };
    278         public static bool Ne<T0, T1>(in this Maybe<T0> self, in Maybe<T1> other) where T0: notnull, IPartialEq<T0, T1> where T1: notnull, IPartialEq<T1, T0> => (self.IsSome, other.IsSome) switch {
    279             (true, true) => self._some != other._some,
    280             (false, false) => false,
    281             _ => true,
    282         };
    283         public static Maybe<Ordering> PartialCmp<T0, T1>(in this Maybe<T0> self, in Maybe<T1> other) where T0: notnull, IPartialOrd<T0, T1> where T1: notnull, IPartialOrd<T1, T0> => (self.IsSome, other.IsSome) switch {
    284             (true, true) => self._some.PartialCmp(in other._some),
    285             (true, false) => Some(Greater),
    286             (false, true) => Some(Less),
    287             _ => Some(Equivalent),
    288         };
    289         public static Result<Maybe<TOK>, TErr> Transpose<TOK, TErr>(this Maybe<Result<TOK, TErr>> self) where TOK: notnull where TErr: notnull => self.IsSome ? self._some.IsOK ? new(new Maybe<TOK>(self._some._ok)) : new(self._some._err) : new(new Maybe<TOK>());
    290         public static Result<string, TErr> TryIntoString<TSome, TErr>(in this Maybe<TSome> self) where TSome: notnull, ITryInto<string, TErr> where TErr: notnull {
    291 
    292             if (self.IsSome) {
    293                 var val = self._some.TryInto();
    294                 return val.IsErr ? val : new($"Some({val._ok})");
    295             } else {
    296                 return new("None");
    297             }
    298         }
    299         public static TSome UnwrapOrDefault<TSome>(this Maybe<TSome> self) where TSome: notnull, new() => self.Var == Maybe<TSome>.Tag.Some ? self._some : new TSome();
    300         #endregion
    301 
    302         #region Instance Functions
    303         #endregion
    304 
    305         #region Operators
    306         #endregion
    307 
    308         #region Types
    309         #endregion
    310     }
    311     #endregion
    312 
    313     #region Namespaces
    314     #endregion
    315 }
    316 #endregion