diff --git a/src/DotNext/Optional.cs b/src/DotNext/Optional.cs index 25718a18a..745f62a31 100644 --- a/src/DotNext/Optional.cs +++ b/src/DotNext/Optional.cs @@ -8,6 +8,8 @@ namespace DotNext; +using System.Threading.Tasks; +using DotNext.Threading.Tasks; using Runtime.CompilerServices; using Intrinsics = Runtime.Intrinsics; @@ -79,6 +81,16 @@ public static async Task> Convert(this Task.None; } + /// + /// Creates from instance. + /// + /// The optional value. + /// The error code to apply if the value is not present. + /// The converted optional value. + public static Result ToResult(this in Optional optional, TError error) + where TError : struct, Enum + => optional.HasValue ? new(optional.Value) : new(error); + /// /// If a value is present, returns the value, otherwise throw exception. /// @@ -609,6 +621,32 @@ public Optional Convert(Converter> mapper public unsafe Optional Convert(delegate*> mapper) => ConvertOptional>>(mapper); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Task> ConvertOptionalTask(TConverter converter) + where TConverter : struct, ISupplier>> + => HasValue ? converter.Invoke(value) : Task.FromResult(Optional.None); + + /// + /// If a value is present, apply the provided mapping function to it, and if the result is + /// non-null, return an Optional describing the result. Otherwise, returns . + /// + /// The type of the result of the mapping function. + /// A mapping function to be applied to the value, if present. + /// An Optional describing the result of applying a mapping function to the value of this Optional, if a value is present, otherwise . + public Task> Convert(Converter>> mapper) + => ConvertOptionalTask>>>(mapper); + + /// + /// If a value is present, apply the provided mapping function to it, and if the result is + /// non-null, return an Optional describing the result. Otherwise returns . + /// + /// The type of the result of the mapping function. + /// A mapping function to be applied to the value, if present. + /// An Optional describing the result of applying a mapping function to the value of this Optional, if a value is present, otherwise . + [CLSCompliant(false)] + public unsafe Task> Convert(delegate*>> mapper) + => ConvertOptionalTask>>>(mapper); + /// Func IFunctional>.ToDelegate() => Func.Constant(kind is NotEmptyValue ? value : null); diff --git a/src/DotNext/Result.cs b/src/DotNext/Result.cs index 6985974d1..746c0cddd 100644 --- a/src/DotNext/Result.cs +++ b/src/DotNext/Result.cs @@ -7,6 +7,8 @@ namespace DotNext; +using System; +using DotNext.Threading.Tasks; using Runtime.CompilerServices; using Intrinsics = Runtime.Intrinsics; @@ -202,6 +204,53 @@ private Result Convert(TConverter converter) return result; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Result ConvertResult(TConverter converter) + where TConverter : struct, ISupplier> + { + Result result; + if (exception is null) + { + try + { + result = converter.Invoke(value); + } + catch (Exception e) + { + result = new(e); + } + } + else + { + result = new(exception); + } + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private AwaitableResult ConvertTask(Func> converter, CancellationToken token = default) + { + AwaitableResult result; + if (exception is null) + { + try + { + result = converter.Invoke(value, token).SuspendException(); + } + catch (Exception e) + { + result = new(Task.FromException(e)); + } + } + else + { + result = new(Task.FromException(exception.SourceException)); + } + + return result; + } + /// /// If the successful result is present, apply the provided mapping function hiding any exception /// caused by the converter. @@ -212,6 +261,27 @@ private Result Convert(TConverter converter) public Result Convert(Converter converter) => Convert>(converter); + /// + /// If successful result is present, apply the provided mapping function. If not, + /// forward the exception. + /// + /// A mapping function to be applied to the value, if present. + /// The type of the result of the mapping function. + /// The conversion result. + public Result Convert(Converter> converter) + => ConvertResult>>(converter); + + /// + /// If successful result is present, apply the provided mapping function. If not, + /// forward the exception. + /// + /// A mapping function to be applied to the value, if present. + /// The type of the result of the mapping function. + /// The token that can be used to cancel the operation. + /// The conversion result. + public AwaitableResult Convert(Func> converter, CancellationToken token = default) + => ConvertTask(converter, token); + /// /// If the successful result is present, apply the provided mapping function hiding any exception /// caused by the converter. @@ -223,6 +293,17 @@ public Result Convert(Converter converter) public unsafe Result Convert(delegate* converter) => Convert>(converter); + /// + /// If successful result is present, apply the provided mapping function. If not, + /// forward the exception. + /// + /// A mapping function to be applied to the value, if present. + /// The type of the result of the mapping function. + /// The conversion result. + [CLSCompliant(false)] + public unsafe Result Convert(delegate*> converter) + => ConvertResult>>(converter); + /// /// Attempts to extract value from the container if it is present. /// @@ -323,6 +404,13 @@ public ValueTask AsTask() { } error => ValueTask.FromException(error), }; + /// + /// Converts this result to . + /// + /// The awaitable Result representing the result. + public AwaitableResult ToAwaitable() + => IsSuccessful ? new(Task.FromResult(value)) : new(Task.FromException(Error)); + /// /// Converts the result to . /// @@ -534,6 +622,11 @@ private Result Convert(TConverter converte where TConverter : struct, ISupplier => IsSuccessful ? new(converter.Invoke(value)) : new(Error); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Result ConvertResult(TConverter converter) + where TConverter : struct, ISupplier> + => IsSuccessful ? converter.Invoke(value) : new(Error); + /// /// If the successful result is present, apply the provided mapping function hiding any exception /// caused by the converter. @@ -544,6 +637,16 @@ private Result Convert(TConverter converte public Result Convert(Converter converter) => Convert>(converter); + /// + /// If successful result is present, apply the provided mapping function. If not, + /// forward the error. + /// + /// A mapping function to be applied to the value, if present. + /// The type of the result of the mapping function. + /// The conversion result. + public Result Convert(Converter> converter) + => ConvertResult>>(converter); + /// /// If the successful result is present, apply the provided mapping function hiding any exception /// caused by the converter. @@ -555,6 +658,17 @@ public Result Convert(Converter converter) public unsafe Result Convert(delegate* converter) => Convert>(converter); + /// + /// If successful result is present, apply the provided mapping function. If not, + /// forward the error. + /// + /// A mapping function to be applied to the value, if present. + /// The type of the result of the mapping function. + /// The conversion result. + [CLSCompliant(false)] + public unsafe Result Convert(delegate*> converter) + => ConvertResult>>(converter); + [MethodImpl(MethodImplOptions.AggressiveInlining)] private T OrInvoke(TSupplier defaultFunc) where TSupplier : struct, ISupplier