Skip to content

Commit

Permalink
#48 - Added ValueOrError<TValue,TError>
Browse files Browse the repository at this point in the history
STill a couple of tests missing, but the basic functionality is there.
  • Loading branch information
DavidArno committed Jul 20, 2018
1 parent c93a1c6 commit 9bb38e2
Show file tree
Hide file tree
Showing 19 changed files with 700 additions and 66 deletions.
1 change: 1 addition & 0 deletions SuccincT.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=analyser/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Succinc/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
5 changes: 0 additions & 5 deletions src/SuccincT.JSON/JSON/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,5 @@ namespace SuccincT.JSON
internal static class TypeExtensions
{
internal static bool IsGenericType(this Type type) => type.GetTypeInfo().IsGenericType;

internal static MethodInfo GetMethod(this Type type, string name) => type.GetTypeInfo().GetDeclaredMethod(name);

internal static PropertyInfo GetProperty(this Type type, string name) =>
type.GetTypeInfo().GetDeclaredProperty(name);
}
}
43 changes: 22 additions & 21 deletions src/SuccincT/Functional/ConsNodeEnumerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,29 @@ internal sealed class ConsNodeEnumerator<T> : IEnumerator<T>

public bool MoveNext()
{
if (!AdvanceToNextNode()) return false;

if (Node.State == HasEnumeration)
while (true)
{
Node.Enumerating(new ConsListBuilderEnumerator<T>(Node));
}
if (!AdvanceToNextNode()) return false;

if (Node.State == HasValue) return true;
if (Node.State == HasEnumeration)
{
Node.Enumerating(new ConsListBuilderEnumerator<T>(Node));
}

if (Node.Enumerator.MoveNext())
{
var newNode = new ConsNode<T> { Next = Node.Next };
newNode.Enumerating(Node.Enumerator);
if (Node.State == HasValue) return true;

Node.HasValue(Node.Enumerator.Current.Value);
Node.Next = newNode;
return true;
}
if (Node.Enumerator.MoveNext())
{
var newNode = new ConsNode<T> {Next = Node.Next};
newNode.Enumerating(Node.Enumerator);

Node.IgnoredNode();
return MoveNext();
Node.HasValue(Node.Enumerator.Current.Value);
Node.Next = newNode;
return true;
}

Node.IgnoredNode();
}
}

private bool AdvanceToNextNode()
Expand All @@ -46,11 +48,10 @@ private bool AdvanceToNextNode()
while (Node.State == IgnoredNode)
{
Node = Node.Next;
if (Node == null)
{
Dispose();
return false;
}
if (Node != null) continue;

Dispose();
return false;
}
return true;
}
Expand Down
18 changes: 18 additions & 0 deletions src/SuccincT/Options/IValueOrErrorActionMatcher{TV,TE}.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using SuccincT.Unions.PatternMatchers;

namespace SuccincT.Options
{
public interface IValueOrErrorActionMatcher<TValue, TError>
{
IUnionActionPatternCaseHandler<IValueOrErrorActionMatcher<TValue, TError>, TValue> Value();

IUnionActionPatternCaseHandler<IValueOrErrorActionMatcher<TValue, TError>, TError> Error();

IUnionActionPatternMatcherAfterElse Else(Action<ValueOrError<TValue, TError>> elseAction);

IUnionActionPatternMatcherAfterElse IgnoreElse();

void Exec();
}
}
18 changes: 18 additions & 0 deletions src/SuccincT/Options/IValueOrErrorFuncMatcher{TV,TE,TR}.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using SuccincT.Unions.PatternMatchers;

namespace SuccincT.Options
{
public interface IValueOrErrorFuncMatcher<TValue, TError, TResult>
{
IUnionFuncPatternCaseHandler<IValueOrErrorFuncMatcher<TValue, TError, TResult>, TValue, TResult> Value();

IUnionFuncPatternCaseHandler<IValueOrErrorFuncMatcher<TValue, TError, TResult>, TError, TResult> Error();

IUnionFuncPatternMatcherAfterElse<TResult> Else(Func<ValueOrError<TValue, TError>, TResult> elseAction);

IUnionFuncPatternMatcherAfterElse<TResult> Else(TResult value);

TResult Result();
}
}
18 changes: 7 additions & 11 deletions src/SuccincT/Options/Option{T}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ public readonly struct Option<T>
private static readonly Option<T> NoneInstance = new Option<T>();
private readonly T _value;

private Option(T value)
=> (HasValue, _value) = value != null
? (true, value)
: throw new ArgumentNullException(nameof(value));
private Option(T value)
=> (HasValue, _value) = value != null ? (true, value) : throw new ArgumentNullException(nameof(value));

/// <summary>
/// Creates an instance of an option with no value.
Expand Down Expand Up @@ -48,15 +46,13 @@ private Option(T value)
/// <summary>
/// The value held (if created by Some()). Will throw an InvalidOperationException if created via None().
/// </summary>
public T Value => HasValue
? _value
: throw new InvalidOperationException("Option contains no value.");
public T Value => HasValue ? _value : throw new InvalidOperationException("Option contains no value.");

public T ValueOrDefault => HasValue ? _value : default;

public override bool Equals(object obj) => obj is Option<T> option && EqualsOption(option);

internal bool EqualsOption(Option<T> other)
private bool EqualsOption(Option<T> other)
=> other.HasValue && HasValue && Value.Equals(other.Value) || !(HasValue || other.HasValue);

public override int GetHashCode() => HasValue ? _value.GetHashCode() : 0;
Expand All @@ -65,10 +61,10 @@ internal bool EqualsOption(Option<T> other)

public static bool operator !=(Option<T> a, Option<T> b) => !a.EqualsOption(b);

public static implicit operator Option<T>(T value) => value == null ? None() : Some(value);
public static implicit operator Option<T>(T value) => value == null ? None() : Some(value);

public void Deconstruct(out bool hasValue, out T value) =>
(hasValue, value) = (HasValue, HasValue ? _value : default);
public void Deconstruct(out bool hasValue, out T value)
=> (hasValue, value) = (HasValue, HasValue ? _value : default);

private Union<T, None> CreateUnion() => HasValue ? new Union<T, None>(_value) : new Union<T, None>(none);
}
Expand Down
133 changes: 133 additions & 0 deletions src/SuccincT/Options/ValueOrErrorMatcher{TV,TE,TR}.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using SuccincT.Functional;
using SuccincT.PatternMatchers;
using SuccincT.Unions.PatternMatchers;
using System;
using System.Collections.Generic;

namespace SuccincT.Options
{
internal sealed class ValueOrErrorMatcher<TValue, TError, TResult> : IUnionFuncPatternMatcherAfterElse<TResult>,
IValueOrErrorFuncMatcher<TValue,
TError,
TResult>,
IValueOrErrorActionMatcher<TValue, TError>,
IUnionActionPatternMatcherAfterElse
{
private readonly ValueOrError<TValue, TError> _valueOrError;

private readonly MatchFunctionSelector<TValue, TValue, TResult> _valueFunctionSelector =
new MatchFunctionSelector<TValue, TValue, TResult>(
x => throw new NoMatchException("No match action defined for ValueOrError with value"));

private readonly MatchFunctionSelector<TError, TError, TResult> _errorFunctionSelector =
new MatchFunctionSelector<TError, TError, TResult>(
x => throw new NoMatchException("No match action defined for ValueOrError with value"));

private Func<ValueOrError<TValue, TError>, TResult> _elseAction;

internal ValueOrErrorMatcher(ValueOrError<TValue, TError> valueOrError) => _valueOrError = valueOrError;

IUnionFuncPatternCaseHandler<IValueOrErrorFuncMatcher<TValue, TError, TResult>, TValue, TResult>
IValueOrErrorFuncMatcher<TValue, TError, TResult>.Value()
{
return new UnionPatternCaseHandler<IValueOrErrorFuncMatcher<TValue, TError, TResult>, TValue, TResult>(
RecordValueAction,
this);
}

IUnionFuncPatternCaseHandler<IValueOrErrorFuncMatcher<TValue, TError, TResult>, TError, TResult>
IValueOrErrorFuncMatcher<TValue, TError, TResult>.Error()
{
return new UnionPatternCaseHandler<IValueOrErrorFuncMatcher<TValue, TError, TResult>, TError, TResult>(
RecordErrorAction,
this);
}

IUnionFuncPatternMatcherAfterElse<TResult> IValueOrErrorFuncMatcher<TValue, TError, TResult>.Else(TResult value)
{
_elseAction = _ => value;
return this;
}

IUnionFuncPatternMatcherAfterElse<TResult> IValueOrErrorFuncMatcher<TValue, TError, TResult>.Else(
Func<ValueOrError<TValue, TError>, TResult> elseAction)
{
_elseAction = elseAction;
return this;
}

TResult IValueOrErrorFuncMatcher<TValue, TError, TResult>.Result()
{
return _valueOrError.HasValue
? _valueFunctionSelector.DetermineResultUsingDefaultIfRequired(_valueOrError.Value)
: _errorFunctionSelector.DetermineResultUsingDefaultIfRequired(_valueOrError.Error);
}

IUnionActionPatternCaseHandler<IValueOrErrorActionMatcher<TValue, TError>, TValue>
IValueOrErrorActionMatcher<TValue, TError>.Value()
{
return new UnionPatternCaseHandler<IValueOrErrorActionMatcher<TValue, TError>, TValue, TResult>(
RecordValueAction,
this);
}


IUnionActionPatternCaseHandler<IValueOrErrorActionMatcher<TValue, TError>, TError>
IValueOrErrorActionMatcher<TValue, TError>.Error()
{
return new UnionPatternCaseHandler<IValueOrErrorActionMatcher<TValue, TError>, TError, TResult>(
RecordErrorAction,
this);
}

IUnionActionPatternMatcherAfterElse IValueOrErrorActionMatcher<TValue, TError>.Else(
Action<ValueOrError<TValue, TError>> elseAction)
{
_elseAction = elseAction.ToUnitFunc() as Func<ValueOrError<TValue, TError>, TResult>;
return this;
}

IUnionActionPatternMatcherAfterElse IValueOrErrorActionMatcher<TValue, TError>.IgnoreElse()
{
_elseAction = x => default;
return this;
}

void IValueOrErrorActionMatcher<TValue, TError>.Exec()
{
_ = _valueOrError.HasValue
? _valueFunctionSelector.DetermineResultUsingDefaultIfRequired(_valueOrError.Value)
: _errorFunctionSelector.DetermineResultUsingDefaultIfRequired(_valueOrError.Error);
}

TResult IUnionFuncPatternMatcherAfterElse<TResult>.Result()
{
var possibleResult = _valueOrError.HasValue
? _valueFunctionSelector.DetermineResult(_valueOrError.Value)
: _errorFunctionSelector.DetermineResult(_valueOrError.Error);

return possibleResult.HasValue ? possibleResult.Value : _elseAction(_valueOrError);
}

void IUnionActionPatternMatcherAfterElse.Exec()
{
var possibleResult = _valueOrError.HasValue
? _valueFunctionSelector.DetermineResult(_valueOrError.Value)
: _errorFunctionSelector.DetermineResult(_valueOrError.Error);

_ = possibleResult.HasValue ? possibleResult.Value : _elseAction(_valueOrError);
}

private void RecordValueAction(Func<TValue, IList<TValue>, bool> withTest,
Func<TValue, bool> whereTest,
IList<TValue> withValues,
Func<TValue, TResult> action)
=> _valueFunctionSelector.AddTestAndAction(withTest, withValues, whereTest, action);

private void RecordErrorAction(Func<TError, IList<TError>, bool> withTest,
Func<TError, bool> whereTest,
IList<TError> withValues,
Func<TError, TResult> action)
=> _errorFunctionSelector.AddTestAndAction(withTest, withValues, whereTest, action);
}
}
87 changes: 87 additions & 0 deletions src/SuccincT/Options/ValueOrError{TV,TE}.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System;
using SuccincT.Functional;

namespace SuccincT.Options
{
public readonly struct ValueOrError<TValue, TError>
{
private readonly TValue _value;
private readonly TError _error;

private ValueOrError(TValue value, TError error, bool hasValue)
=> (_value, _error, HasValue) = (value, error, hasValue);

/// <summary>
/// Creates a new instance with a value (and no error)
/// </summary>
public static ValueOrError<TValue, TError> WithValue(TValue value)
=> new ValueOrError<TValue, TError>(value, default, true);

/// <summary>
/// Creates a new instance with an error (and no value)
/// </summary>
public static ValueOrError<TValue, TError> WithError(TError error)
=> new ValueOrError<TValue, TError>(default, error, false);

/// <summary>
/// Provides a fluent matcher that ultimately (upon Result() being called) returns a TResult value
/// by invoking the function associated with the match.
/// </summary>
public IValueOrErrorFuncMatcher<TValue, TError, TResult> Match<TResult>()
=> new ValueOrErrorMatcher<TValue, TError, TResult>(this);

/// <summary>
/// Provides a fluent matcher that ultimately (upon Exec() being called) invokes the Action
/// associated with the match.
/// </summary>
public IValueOrErrorActionMatcher<TValue, TError> Match()
=> new ValueOrErrorMatcher<TValue, TError, Unit>(this);

/// <summary>
/// True if created via WithValue(), else false.
/// </summary>
public bool HasValue { get; }

/// <summary>
/// The value held (if created by WithValue()). Will throw an InvalidOperationException if created via
/// WithError().
/// </summary>
public TValue Value
=> HasValue ? _value : throw new InvalidOperationException("ValueOrError doesn't contain a value");

/// <summary>
/// The error held (if created by WithError()). Will throw an InvalidOperationException if created via
/// WithValue().
/// </summary>
public TError Error
=> !HasValue ? _error : throw new InvalidOperationException("ValueOrError doesn't contain an error");

public override string ToString() => HasValue ? $"Value of {_value}" : $"Error of {_error}";

public override bool Equals(object obj)
{
switch (obj)
{
case ValueOrError<TValue, TError> other: return other.HasValue == HasValue && ValueOrErrorsEqual(other);
case null: return HasValue && _value == null || !HasValue && _error == null;
}

return false;
}

private bool ValueOrErrorsEqual(in ValueOrError<TValue, TError> other)
{
return HasValue
? _value == null && other.HasValue && other.Value == null ||
_value != null && _value.Equals(other.Value)
: _error == null && !other.HasValue && other.Error == null ||
_error != null && _error.Equals(other.Error);
}

public override int GetHashCode() => HasValue ? _value.GetHashCode() : _error.GetHashCode();

public static bool operator ==(ValueOrError<TValue, TError> a, ValueOrError<TValue, TError> b) => a.Equals(b);

public static bool operator !=(ValueOrError<TValue, TError> a, ValueOrError<TValue, TError> b) => !a.Equals(b);
}
}
Loading

0 comments on commit 9bb38e2

Please sign in to comment.