public abstract record Option<T>()
{
internal T? Value { get; init; }
protected Option(T Value) : this()
{
this.Value = Value;
}
public static implicit operator Option<T>(T? value) =>
(value is not null) ? new Some<T>(value) : new None<T>();
}
public record Some<T>(T Value) : Option<T>(Value)
{
public new T Value { get; } = Value;
public static implicit operator T(Some<T> some) => some.Value!;
public static implicit operator Some<T>(T value) => new(value);
}
public sealed record None<T>() : Option<T>;
public static class Option
{
public static Option<T> From<T>(T? Value) => Value is null ? None<T>() : Some(Value);
public static Some<T> Some<T>(T Value) => new(Value);
public static None<T> None<T>() => new();
public static Option<T> Default<T>() => default(T);
public static bool IsSome<T>(this Option<T> option) => option is Some<T>;
public static bool IsNone<T>(this Option<T> option) => option is None<T>;
public static Option<U> Map<T, U>(this Option<T> option, Func<T, U> some) =>
option is { Value: T value }
? some(value)
: None<U>();
public static U? MapOrDefault<T, U>(this Option<T> option, Func<T, U> some) =>
option is { Value: T value }
? some(value)
: default;
public static Option<T> Filter<T>(this Option<T> option, Func<T, bool> predicate) =>
option is { Value: T value } && predicate(value)
? Some(value)
: None<T>();
public static void Then<T>(this Option<T> option, Action<T> some)
{
if (option is { Value: T value })
some(value);
}
public static void Match<T>(this Option<T> option, Action<T> some, Action none)
{
if (option is { Value: T value })
some(value);
else
none();
}
public static U Match<T, U>(this Option<T> option, Func<T, U> some, Func<U> none) =>
option is { Value: T value }
? some(value)
: none();
public static T Expect<T>(this Option<T> option) =>
Expect(option, $"Expect: {nameof(option)} to be {nameof(Some)} but found {nameof(None)}");
public static T Expect<T>(this Option<T> option, string message) =>
Expect(option, new Exception(message));
public static T Expect<T>(this Option<T> option, Exception ex) =>
option.Value ?? throw ex;
public static T UnwrapOr<T>(this Option<T> option, T @default) => option.Value ?? @default;
}
Last active
January 25, 2024 09:39
-
-
Save kallebysantos/0653a8298eaea9b40c3f43f3db3f9430 to your computer and use it in GitHub Desktop.
Rust types implementation in CSharp
public record Result<T, E>
{
internal Option<T> OkValue { get; init; } = Option.None<T>();
internal Option<E> ErrValue { get; init; } = Option.None<E>();
internal Result() {}
protected Result(T Value) : this()
{
OkValue = Option.Some(Value);
ErrValue = Option.None<E>();
}
protected Result(E Error) : this()
{
ErrValue = Option.Some(Error);
OkValue = Option.None<T>();
}
internal Result(Option<T> OkValue, Option<E> ErrValue) : this()
{
this.OkValue = OkValue;
this.ErrValue = ErrValue;
}
public static implicit operator Result<T, E>(T value) => new Ok<T, E>(value);
public static implicit operator Result<T, E>(E Error) => new Err<T, E>(Error);
}
public sealed record Ok<T, E>(T Value) : Result<T, E>(Value)
{
public static implicit operator T(Ok<T, E> ok) => ok.Value;
public static implicit operator Ok<T, E>(T value) => new(value);
}
public record Err<T,E>(E Value) : Result<T, E>(Value)
{
public static implicit operator E(Err<T, E> err) => err.Value;
public static implicit operator Err<T, E>(E err) => new(err);
}
public static class Result
{
public static Option<T> Ok<T, E>(this Result<T, E> result) => result.OkValue;
public static Option<E> Err<T, E>(this Result<T, E> result) => result.ErrValue;
public static Ok<T, E> Ok<T, E>(T Value) => new(Value);
public static Err<T, E> Err<T, E>(E Value) => new(Value);
public static bool IsOk<T, E>(this Result<T, E> result) => result is Ok<T, E>;
public static bool IsErr<T, E>(this Result<T, E> result) => result is Err<T, E>;
public static Result<U, E> Map<T, E, U>(this Result<T, E> result, Func<T, U> ok)
=> new(result.OkValue.Map(ok), result.ErrValue);
public static Result<T, F> MapErr<T, E, F>(this Result<T, E> result, Func<E, F> err)
=> new(result.OkValue, result.ErrValue.Map(err));
public static void Match<T, E>(this Result<T, E> result, Action<T> ok, Action<E> err)
{
if (result is { OkValue: Some<T> okValue })
ok(okValue);
if (result is { ErrValue: Some<E> errValue })
err(errValue);
}
public static U Match<T, E, U>(this Result<T, E> result, Func<T, U> ok, Func<E, U> err) =>
result switch
{
{ OkValue: T value } => ok(value),
{ ErrValue: E value } => err(value),
_ => default!,
};
public static T Expect<T, E>(this Result<T, E> result)
=> Expect(result, $"Expect: {nameof(result)} to be {nameof(Ok)} but found {nameof(Err)}");
public static T Expect<T, E>(this Result<T, E> result, string message)
=> Expect(result, new Exception(message));
public static T Expect<T, E>(this Result<T, E> result, Exception ex)
=> result.OkValue.Expect(ex);
public static E ExpectErr<T, E>(this Result<T, E> result)
=> ExpectErr(result, $"Expect: {nameof(result)} to be {nameof(Err)} but found {nameof(Ok)}");
public static E ExpectErr<T, E>(this Result<T, E> result, string message)
=> ExpectErr(result, new Exception(message));
public static E ExpectErr<T, E>(this Result<T, E> result, Exception ex)
=> result.ErrValue.Expect(ex);
public static T UnwrapOr<T, E>(this Result<T, E> result, T @default)
=> result.OkValue.UnwrapOr(@default);
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment