serde-generate/runtime/csharp/Serde/Option.cs (60 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates
// SPDX-License-Identifier: MIT OR Apache-2.0
using System;
using System.Collections.Generic;
namespace Serde
{
public readonly struct Option<T> : IEquatable<Option<T>> where T : IEquatable<T>
{
public static Option<T> None => default;
public static Option<T> Some(T value)
{
if (value == null) throw new ArgumentNullException(nameof(value));
return new Option<T>(value);
}
readonly bool isSome;
readonly T value;
Option(T val)
{
isSome = val != null;
value = val;
}
public bool IsSome(out T value)
{
value = this.value;
return isSome;
}
public override bool Equals(object obj) => obj is Option<T> option && Equals(option);
public bool Equals(Option<T> other)
{
if (isSome != other.isSome) return false;
if (!isSome) return true;
return value.Equals(other.value);
}
public override int GetHashCode()
{
var hashCode = -934799437;
hashCode = hashCode * -1521134295 + isSome.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<T>.Default.GetHashCode(value);
return hashCode;
}
public static bool operator ==(Option<T> left, Option<T> right) => Equals(left, right);
public static bool operator !=(Option<T> left, Option<T> right) => !Equals(left, right);
}
public static class OptionExtensions
{
public static U Match<T, U>(this Option<T> option, Func<T, U> onIsSome, Func<U> onIsNone)
where T : IEquatable<T> where U : IEquatable<U> =>
option.IsSome(out var value) ? onIsSome(value) : onIsNone();
public static Option<U> Bind<T, U>(this Option<T> option, Func<T, Option<U>> binder)
where T : IEquatable<T> where U : IEquatable<U> =>
option.Match(onIsSome: binder, onIsNone: () => Option<U>.None);
public static Option<U> Map<T, U>(this Option<T> option, Func<T, U> mapper)
where T : IEquatable<T> where U : IEquatable<U> =>
option.Bind(value => Option<U>.Some(mapper(value)));
public static Option<T> Filter<T>(this Option<T> option, Predicate<T> predicate)
where T : IEquatable<T> =>
option.Bind(value => predicate(value) ? option : Option<T>.None);
public static T DefaultValue<T>(this Option<T> option, T defaultValue)
where T : IEquatable<T> =>
option.Match(onIsSome: value => value, onIsNone: () => defaultValue);
}
}