//
/*
The MIT License (MIT)
Copyright (c) 2016-2020 Maksim Volkau
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// ReSharper disable once InconsistentNaming
#if !NET35 && !PCL
#define SUPPORTS_SPIN_WAIT
#endif
namespace ImTools
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Runtime.CompilerServices; // For [MethodImpl(AggressiveInlining)]
/// Helpers for functional composition
public static class Fun
{
///
/// Always a true condition.
///
public static bool Always(T _) => true;
///
/// Identity function returning passed argument as result.
///
public static T Id(T x) => x;
///
/// Forward pipe operator (`|>` in F#)
///
public static R To(this T x, Func map) => map(x);
///
/// Forward pipe operator (`|>` in F#) with the additional state A for two arguments function
///
public static R To(this T x, S state, Func map) => map(x, state);
///
/// Cast to the R type with the forward pipe operator (`|>` in F#)
///
public static R To(this object x) => (R)x;
///
/// Forward pipe operator (`|>` in F#) but with side effect propagating the original `x` value
///
public static T Do(this T x, Action effect)
{
effect(x);
return x;
}
///
/// Forward pipe operator (`|>` in F#) but with side effect propagating the original `x` value and the state object
///
public static T Do(this T x, S state, Action effect)
{
effect(x, state);
return x;
}
///
/// Lifts argument to Func without allocations ignoring the first argument.
/// For example if you have `Func{T, R} = _ => instance`,
/// you may rewrite it without allocations as `instance.ToFunc{A, R}`
///
public static R ToFunc(this R result, T ignoredArg) => result;
}
/// Helpers for lazy instantiations
public static class Lazy
{
/// Provides result type inference for creation of lazy.
public static Lazy Of(Func valueFactory) => new Lazy(valueFactory);
}
/// Replacement for `Void` type which can be used as a type argument and value.
/// In traditional functional languages this type is a singleton empty record type,
/// e.g. `()` in Haskell https://en.wikipedia.org/wiki/Unit_type
public struct Unit : IEquatable
{
/// Singleton unit value - making it a lower-case so you could import `using static ImTools.Unit;` and write `return unit;`
public static readonly Unit unit = new Unit();
///
public override string ToString() => "(unit)";
/// Equals to any other Unit
public bool Equals(Unit other) => true;
///
public override bool Equals(object obj) => obj is Unit;
/// Using type hash code for the value
public override int GetHashCode() => typeof(Unit).GetHashCode();
}
/// Simple value provider interface - useful for the type pattern matching via `case I{T} x: ...`
public interface I
{
/// The value in this case ;)
T Value { get; }
}
/// Helpers for `Is` and `Union`
public static class UnionTools
{
/// Pretty prints the Union using the type information
internal static string ToString(T value, string prefix = "case(", string suffix = ")")
{
if (typeof(TName) == typeof(Unit))
return prefix + value + suffix;
var typeName = typeof(TName).Name;
var i = typeName.IndexOf('`');
var name = i == -1 ? typeName : typeName.Substring(0, i);
return name + prefix + value + suffix;
}
}
/// Wraps the `T` in a typed `TData` struct value in a one-line declaration,
/// so the ]]>
/// is different from the ]]>
public abstract class Item where TItem : Item
{
/// Creation method for the consistency with other types
public static item Of(T x) => new item(x);
/// Nested structure that hosts a value.
/// All nested types by convention here are lowercase
public readonly struct item : IEquatable- , I
{
///
public T Value { [MethodImpl((MethodImplOptions)256)] get => Item; }
/// The value
public readonly T Item;
/// Constructor
public item(T x) => Item = x;
///
public bool Equals(item other) => EqualityComparer.Default.Equals(Value, other.Value);
///
public override bool Equals(object obj) => obj is item c && Equals(c);
///
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Value);
///
public override string ToString() => UnionTools.ToString(Value);
}
}
/// Item without the data payload
public abstract class Item where TItem : Item
{
/// Single item value
public static readonly item Single = new item();
/// Nested structure that hosts a value.
/// All nested types by convention here are lowercase
public readonly struct item : IEquatable
-
{
///
public bool Equals(item other) => true;
///
public override bool Equals(object obj) => obj is item;
///
public override int GetHashCode() => typeof(TItem).GetHashCode();
///
public override string ToString() => "(" + typeof(TItem).Name + ")";
}
}
/// Wraps the `T` in a named `TBox` class in a one-line declaration,
/// so the ]]>
/// is different from the ]]>
public abstract class Box : I, IEquatable>
where TBox : Box, new()
{
/// Wraps the value
public static TBox Of(T x) => new TBox { Value = x };
///
public T Value { get; private set; }
///
public bool Equals(Box other) =>
other != null && EqualityComparer.Default.Equals(Value, other.Value);
///
public override bool Equals(object obj) => obj is Box c && Equals(c);
// ReSharper disable once NonReadonlyMemberInGetHashCode
///
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Value);
///
public override string ToString() => UnionTools.ToString(Value, "data(");
}
/// Unnamed discriminated union (with Empty name), shorter name for simplified inline usage
public class U : Union { }
/// Discriminated union
public abstract class Union
{
/// To tag the cases with enum value for efficient pattern matching of required -
/// otherwise we need to use `is CaseN` pattern or similar which is less efficient
public enum Tag : byte
{
/// Tags Case1
Case1,
/// Tags Case2
Case2
}
/// The base interface for the cases to operate.
/// The naming is selected to start from the lower letter, cause we need to use the nested type.
/// It is an unusual case, that's why using the __union__ will be fine to highlight this.
// ReSharper disable once InconsistentNaming
public interface union
{
/// The tag
Tag Tag { get; }
/// Matches the union cases to the R value
R Match(Func map1, Func map2);
}
/// Creates the respective case
public static union Of(T1 x) => new case1(x);
/// Creates the respective case
public static union Of(T2 x) => new case2(x);
/// Wraps the respective case
public readonly struct case1 : union, IEquatable, I
{
/// Implicit conversion
public static implicit operator case1(T1 x) => new case1(x);
///
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case1; }
///
public R Match(Func map1, Func map2) => map1(Case);
///
public T1 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
/// The case value
public readonly T1 Case;
/// Wraps the value
public case1(T1 x) => Case = x;
///
public bool Equals(case1 other) => EqualityComparer.Default.Equals(Value, other.Value);
///
public override bool Equals(object obj) => obj is case1 x && Equals(x);
///
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Value);
///
public override string ToString() => UnionTools.ToString(Value);
}
/// Wraps the respective case
public readonly struct case2 : union, IEquatable, I
{
/// Conversion
public static implicit operator case2(T2 x) => new case2(x);
///
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case2; }
///
public R Match(Func map1, Func map2) => map2(Value);
///
public T2 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
/// The case value
public readonly T2 Case;
/// Wraps the value
public case2(T2 x) => Case = x;
///
public bool Equals(case2 other) => EqualityComparer.Default.Equals(Value, other.Value);
///
public override bool Equals(object obj) => obj is case2 x && Equals(x);
///
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Value);
///
public override string ToString() => UnionTools.ToString(Value);
}
}
#pragma warning disable 1591
public class U : Union { }
public abstract class Union
{
public enum Tag : byte { Case1, Case2, Case3 }
public interface union
{
Tag Tag { get; }
R Match(Func map1, Func map2, Func map3);
}
public static union Of(T1 x) => new case1(x);
public static union Of(T2 x) => new case2(x);
public static union Of(T3 x) => new case3(x);
public struct case1 : union, IEquatable, I
{
public static implicit operator case1(T1 x) => new case1(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case1; }
[MethodImpl((MethodImplOptions)256)]
public R Match(Func map1, Func map2, Func map3) => map1(Case);
public T1 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T1 Case;
public case1(T1 x) => Case = x;
public bool Equals(case1 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case1 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
public struct case2 : union, IEquatable, I
{
public static implicit operator case2(T2 x) => new case2(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case2; }
public R Match(Func map1, Func map2, Func map3) => map2(Case);
public T2 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T2 Case;
public case2(T2 x) => Case = x;
public bool Equals(case2 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case2 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
public struct case3 : union, IEquatable, I
{
public static implicit operator case3(T3 x) => new case3(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case3; }
public R Match(Func map1, Func map2, Func map3) => map3(Case);
public T3 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T3 Case;
public case3(T3 x) => Case = x;
public bool Equals(case3 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case3 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
}
public class U : Union { }
public abstract class Union
{
public enum Tag : byte { Case1, Case2, Case3, Case4 }
public interface union
{
Tag Tag { get; }
R Match(Func map1, Func map2, Func map3, Func map4);
}
public static union Of(T1 x) => new case1(x);
public static union Of(T2 x) => new case2(x);
public static union Of(T3 x) => new case3(x);
public static union Of(T4 x) => new case4(x);
public struct case1 : union, IEquatable, I
{
public static implicit operator case1(T1 x) => new case1(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case1; }
[MethodImpl((MethodImplOptions)256)]
public R Match(Func map1, Func map2, Func map3, Func map4) => map1(Case);
public T1 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T1 Case;
public case1(T1 x) => Case = x;
public bool Equals(case1 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case1 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
public struct case2 : union, IEquatable, I
{
public static implicit operator case2(T2 x) => new case2(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case2; }
public R Match(Func map1, Func map2, Func map3, Func map4) => map2(Case);
public T2 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T2 Case;
public case2(T2 x) => Case = x;
public bool Equals(case2 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case2 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
public struct case3 : union, IEquatable, I
{
public static implicit operator case3(T3 x) => new case3(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case3; }
public R Match(Func map1, Func map2, Func map3, Func map4) => map3(Case);
public T3 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T3 Case;
public case3(T3 x) => Case = x;
public bool Equals(case3 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case3 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
public struct case4 : union, IEquatable, I
{
public static implicit operator case4(T4 x) => new case4(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case4; }
public R Match(Func map1, Func map2, Func map3, Func map4) => map4(Case);
public T4 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T4 Case;
public case4(T4 x) => Case = x;
public bool Equals(case4 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case4 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
}
public class U : Union { }
public abstract class Union
{
public enum Tag : byte { Case1, Case2, Case3, Case4, Case5 }
public interface union
{
Tag Tag { get; }
R Match(Func map1, Func map2, Func map3, Func map4, Func map5);
}
public static union Of(T1 x) => new case1(x);
public static union Of(T2 x) => new case2(x);
public static union Of(T3 x) => new case3(x);
public static union Of(T4 x) => new case4(x);
public static union Of(T5 x) => new case5(x);
public struct case1 : union, IEquatable, I
{
public static implicit operator case1(T1 x) => new case1(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case1; }
[MethodImpl((MethodImplOptions)256)]
public R Match(Func map1, Func map2, Func map3, Func map4, Func map5) => map1(Case);
public T1 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T1 Case;
public case1(T1 x) => Case = x;
public bool Equals(case1 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case1 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
public struct case2 : union, IEquatable, I
{
public static implicit operator case2(T2 x) => new case2(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case2; }
public R Match(Func map1, Func map2, Func map3, Func map4, Func map5) => map2(Case);
public T2 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T2 Case;
public case2(T2 x) => Case = x;
public bool Equals(case2 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case2 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
public struct case3 : union, IEquatable, I
{
public static implicit operator case3(T3 x) => new case3(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case3; }
public R Match(Func map1, Func map2, Func map3, Func map4, Func map5) => map3(Case);
public T3 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T3 Case;
public case3(T3 x) => Case = x;
public bool Equals(case3 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case3 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
public struct case4 : union, IEquatable, I
{
public static implicit operator case4(T4 x) => new case4(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case4; }
public R Match(Func map1, Func map2, Func map3, Func map4, Func map5) => map4(Case);
public T4 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T4 Case;
public case4(T4 x) => Case = x;
public bool Equals(case4 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case4 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
public struct case5 : union, IEquatable, I
{
public static implicit operator case5(T5 x) => new case5(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case5; }
public R Match(Func map1, Func map2, Func map3, Func map4, Func map5) => map5(Case);
public T5 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T5 Case;
public case5(T5 x) => Case = x;
public bool Equals(case5 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case5 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
}
public class U : Union { }
public abstract class Union
{
public enum Tag : byte { Case1, Case2, Case3, Case4, Case5, Case6 }
public interface union
{
Tag Tag { get; }
R Match(Func map1, Func map2, Func map3, Func map4, Func map5, Func map6);
}
public static union Of(T1 x) => new case1(x);
public static union Of(T2 x) => new case2(x);
public static union Of(T3 x) => new case3(x);
public static union Of(T4 x) => new case4(x);
public static union Of(T5 x) => new case5(x);
public static union Of(T6 x) => new case6(x);
public struct case1 : union, IEquatable, I
{
public static implicit operator case1(T1 x) => new case1(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case1; }
[MethodImpl((MethodImplOptions)256)]
public R Match(Func map1, Func map2, Func map3, Func map4, Func map5, Func map6) => map1(Case);
public T1 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T1 Case;
public case1(T1 x) => Case = x;
public bool Equals(case1 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case1 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
public struct case2 : union, IEquatable, I
{
public static implicit operator case2(T2 x) => new case2(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case2; }
public R Match(Func map1, Func map2, Func map3, Func map4, Func map5, Func map6) => map2(Case);
public T2 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T2 Case;
public case2(T2 x) => Case = x;
public bool Equals(case2 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case2 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
public struct case3 : union, IEquatable, I
{
public static implicit operator case3(T3 x) => new case3(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case3; }
public R Match(Func map1, Func map2, Func map3, Func map4, Func map5, Func map6) => map3(Case);
public T3 Value { [MethodImpl((MethodImplOptions)256)] get => Case; }
public readonly T3 Case;
public case3(T3 x) => Case = x;
public bool Equals(case3 other) => EqualityComparer.Default.Equals(Case, other.Case);
public override bool Equals(object obj) => obj is case3 x && Equals(x);
public override int GetHashCode() => EqualityComparer.Default.GetHashCode(Case);
public override string ToString() => UnionTools.ToString(Case);
}
public struct case4 : union, IEquatable, I
{
public static implicit operator case4(T4 x) => new case4(x);
public Tag Tag { [MethodImpl((MethodImplOptions)256)] get => Tag.Case4; }
public R Match