1.3.0
This commit is contained in:
parent
6791f3b016
commit
0e7e161327
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
|
@ -2,19 +2,26 @@ name: ci
|
||||||
|
|
||||||
on: [push]
|
on: [push]
|
||||||
|
|
||||||
|
# Allow one run of this workflow per branch and cancel existing runs if triggered again
|
||||||
|
concurrency:
|
||||||
|
group: fruityfoundation-ci-${{ github.ref_name }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
dotnet-version: ['6.0.x']
|
dotnet-version: ['7.0.x', '6.0.x']
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-dotnet@v1
|
- uses: actions/setup-dotnet@v1
|
||||||
with:
|
with:
|
||||||
dotnet-version: "6.0.x"
|
dotnet-version: |
|
||||||
|
6.0.x
|
||||||
|
7.0.x
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|
2
.github/workflows/publish-release.yml
vendored
Executable file → Normal file
2
.github/workflows/publish-release.yml
vendored
Executable file → Normal file
|
@ -21,7 +21,7 @@ jobs:
|
||||||
fetch-depth: '0' # Load entire history
|
fetch-depth: '0' # Load entire history
|
||||||
- uses: actions/setup-dotnet@v3
|
- uses: actions/setup-dotnet@v3
|
||||||
with:
|
with:
|
||||||
dotnet-version: '6.x'
|
dotnet-version: '7.x'
|
||||||
- run: dotnet tool restore
|
- run: dotnet tool restore
|
||||||
- name: Generate Version
|
- name: Generate Version
|
||||||
id: generate-version
|
id: generate-version
|
||||||
|
|
4
Base.Tests/Base.Tests.csproj
Executable file → Normal file
4
Base.Tests/Base.Tests.csproj
Executable file → Normal file
|
@ -1,10 +1,11 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
|
||||||
|
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -21,4 +22,5 @@
|
||||||
<ProjectReference Include="..\Base\Base.csproj" />
|
<ProjectReference Include="..\Base\Base.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
using System.Linq;
|
|
||||||
using FruityFoundation.Base.Extensions;
|
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace Base.Tests.Extensions;
|
|
||||||
|
|
||||||
public class EnumerableExtensionTests
|
|
||||||
{
|
|
||||||
[TestCase(new object[] { 0, 1, 2 }, true, new object[] { 85 }, ExpectedResult = new object[] { 0, 1, 2, 85 })]
|
|
||||||
[TestCase(new object[] { "hi" }, false, new object[] { "there" }, ExpectedResult = new object[] { "hi" })]
|
|
||||||
public object[] TestConditionalConcat(object[] input, bool isConditionValid, object[] second) =>
|
|
||||||
input.ConditionalConcat(isConditionValid, second).ToArray();
|
|
||||||
|
|
||||||
[TestCase(new object[] { 0, 1, 2 }, true, 85, ExpectedResult = new object[0])]
|
|
||||||
[TestCase(new object[] { "hi", "there" }, false, "there", ExpectedResult = new object[] { "hi", "there" })]
|
|
||||||
public object[] TestConditionalWhere(object[] input, bool isConditionValid, object valueToKeep) =>
|
|
||||||
input.ConditionalWhere(isConditionValid, x => x.Equals(valueToKeep)).ToArray();
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestChooseWithRefType()
|
|
||||||
{
|
|
||||||
var input = new [] { "one", null, "two" };
|
|
||||||
|
|
||||||
var result = input.Choose(x => x).ToArray();
|
|
||||||
|
|
||||||
Assert.That(result.GetType(), Is.EqualTo(typeof(string[])));
|
|
||||||
Assert.That(result.Length, Is.EqualTo(2));
|
|
||||||
Assert.That(result[0], Is.EqualTo("one"));
|
|
||||||
Assert.That(result[1], Is.EqualTo("two"));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestChooseWithValueType()
|
|
||||||
{
|
|
||||||
var input = new int?[] { 1, null, 2 };
|
|
||||||
|
|
||||||
var result = input.Choose(x => x).ToArray();
|
|
||||||
|
|
||||||
Assert.That(result.GetType(), Is.EqualTo(typeof(int[])));
|
|
||||||
Assert.That(result.GetType(), Is.Not.EqualTo(typeof(int?[])));
|
|
||||||
Assert.That(result.Length, Is.EqualTo(2));
|
|
||||||
Assert.That(result[0], Is.EqualTo(1));
|
|
||||||
Assert.That(result[1], Is.EqualTo(2));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
using System;
|
|
||||||
using FruityFoundation.Base.Extensions;
|
|
||||||
using FruityFoundation.Base.Structures;
|
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace Base.Tests.Extensions;
|
|
||||||
|
|
||||||
public class MaybeExtensionTests
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public void EnumerableFirstOrEmptyTests()
|
|
||||||
{
|
|
||||||
Assert.AreEqual(Maybe<string>.Empty(), Array.Empty<string>().FirstOrEmpty());
|
|
||||||
Assert.AreEqual(Maybe<string>.Create("banana"), new[] { "banana" }.FirstOrEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestToMaybe()
|
|
||||||
{
|
|
||||||
Assert.AreEqual(Maybe<int>.Empty(), Maybe<int>.Empty());
|
|
||||||
Assert.AreEqual(Maybe<string>.Create("banana"), "banana".ToMaybe());
|
|
||||||
Assert.AreNotEqual(Maybe<int>.Create(293921), Maybe<int>.Create(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void MaybeNullableTests()
|
|
||||||
{
|
|
||||||
Assert.IsNull(Maybe<int>.Empty().ToNullable());
|
|
||||||
Assert.IsNull(Maybe<int>.Create(0, _ => false).ToNullable());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
using FruityFoundation.Base.Extensions;
|
|
||||||
using FruityFoundation.Base.Structures;
|
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace Base.Tests.Extensions;
|
|
||||||
|
|
||||||
public class NullableExtensionTests
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public void TestNullableStructOfNullToMaybe() =>
|
|
||||||
Assert.AreEqual(Maybe<int>.Empty(), ((int?)null).ToMaybe());
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestNullableStructOfValueToMaybe() =>
|
|
||||||
Assert.AreEqual(Maybe<int>.Create(25), ((int?)25).ToMaybe());
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestNullableRefOfNullToMaybe() =>
|
|
||||||
Assert.AreEqual(Maybe<object>.Empty(), ((object?)null).ToMaybe());
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestNullableRefOfValueToMaybe() =>
|
|
||||||
Assert.AreEqual(Maybe<object>.Create(new {}), ((object?)new {}).ToMaybe());
|
|
||||||
}
|
|
23
Base.Tests/Structures/EnumerableExtensionTests.cs
Normal file
23
Base.Tests/Structures/EnumerableExtensionTests.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System.Linq;
|
||||||
|
using FruityFoundation.Base.Structures;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Base.Tests.Structures;
|
||||||
|
|
||||||
|
public class EnumerableExtensionTests
|
||||||
|
{
|
||||||
|
[TestCase(new object[] { 0, 1, 2 }, true, new object[] { 85 }, ExpectedResult = new object[] { 0, 1, 2, 85 })]
|
||||||
|
[TestCase(new object[] { "hi" }, false, new object[] { "there" }, ExpectedResult = new object[] { "hi" })]
|
||||||
|
public object[] TestConditionalConcat(object[] input, bool condition, object[] second) =>
|
||||||
|
input.ConditionalConcat(condition, second).ToArray();
|
||||||
|
|
||||||
|
[TestCase(new object[] { 0, 1, 2 }, true, 3, ExpectedResult = new object[] { 0, 1, 2, 3 })]
|
||||||
|
[TestCase(new object[] { 0, 1, 2 }, false, 3, ExpectedResult = new object[] { 0, 1, 2 })]
|
||||||
|
public object[] TestConditionalAppend(object[] input, bool condition, object second) =>
|
||||||
|
input.ConditionalAppend(condition, second).ToArray();
|
||||||
|
|
||||||
|
[TestCase(new object[] { 0, 1, 2 }, true, 85, ExpectedResult = new object[0])]
|
||||||
|
[TestCase(new object[] { "hi", "there" }, false, "there", ExpectedResult = new object[] { "hi", "there" })]
|
||||||
|
public object[] TestConditionalWhere(object[] input, bool condition, object valueToKeep) =>
|
||||||
|
input.ConditionalWhere(condition, x => x.Equals(valueToKeep)).ToArray();
|
||||||
|
}
|
29
Base.Tests/Structures/MaybeExtensionTests.cs
Normal file
29
Base.Tests/Structures/MaybeExtensionTests.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using System;
|
||||||
|
using FruityFoundation.Base.Structures;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Base.Tests.Structures;
|
||||||
|
|
||||||
|
public class MaybeExtensionTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void EnumerableFirstOrEmptyTests()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(Maybe.Empty<string>(), Array.Empty<string>().FirstOrEmpty());
|
||||||
|
Assert.AreEqual(Maybe.Just<string>("banana"), new[] { "banana" }.FirstOrEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestToMaybe()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(Maybe.Empty<int>(), Maybe.Empty<int>());
|
||||||
|
Assert.AreNotEqual(Maybe.Just(293921), Maybe.Just(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void MaybeNullableTests()
|
||||||
|
{
|
||||||
|
Assert.IsNull(Maybe.Empty<int>().ToNullable());
|
||||||
|
Assert.IsNull(Maybe.Just(0, hasValue: _ => false).ToNullable());
|
||||||
|
}
|
||||||
|
}
|
15
Base.Tests/Structures/NullableExtensionTests.cs
Normal file
15
Base.Tests/Structures/NullableExtensionTests.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using FruityFoundation.Base.Structures;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Base.Tests.Structures;
|
||||||
|
|
||||||
|
public class NullableExtensionTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestNullableStructOfNullToMaybe() =>
|
||||||
|
Assert.AreEqual(Maybe.Empty<int>(), ((int?)null).ToMaybe());
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNullableStructOfValueToMaybe() =>
|
||||||
|
Assert.AreEqual(Maybe.Just(25), ((int?)25).ToMaybe());
|
||||||
|
}
|
|
@ -1,8 +1,7 @@
|
||||||
using FruityFoundation.Base.Extensions;
|
using FruityFoundation.Base.Structures;
|
||||||
using FruityFoundation.Base.Structures;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace Base.Tests.Extensions;
|
namespace Base.Tests.Structures;
|
||||||
|
|
||||||
public class StringExtensionTests
|
public class StringExtensionTests
|
||||||
{
|
{
|
||||||
|
@ -20,15 +19,6 @@ public class StringExtensionTests
|
||||||
public bool ContainsIgnoreCaseTests(string haystack, string needle) =>
|
public bool ContainsIgnoreCaseTests(string haystack, string needle) =>
|
||||||
haystack.ContainsIgnoreCase(needle);
|
haystack.ContainsIgnoreCase(needle);
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void StringToCouldBeTests()
|
|
||||||
{
|
|
||||||
#pragma warning disable CS8604
|
|
||||||
Assert.AreEqual(Maybe<string>.Empty(), (null as string).ToMaybe());
|
|
||||||
#pragma warning restore CS8604
|
|
||||||
Assert.AreEqual(Maybe<string>.Create("banana"), "banana".ToMaybe());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
[TestCase("banana", 1, ExpectedResult = "b")]
|
[TestCase("banana", 1, ExpectedResult = "b")]
|
||||||
[TestCase("This is a longer sentence. I would like it capped at 30 characters.", 30, ExpectedResult = "This is a longer sentence. I w")]
|
[TestCase("This is a longer sentence. I would like it capped at 30 characters.", 30, ExpectedResult = "This is a longer sentence. I w")]
|
2
Base/Base.csproj
Executable file → Normal file
2
Base/Base.csproj
Executable file → Normal file
|
@ -15,6 +15,8 @@
|
||||||
<Version>1.2.2</Version>
|
<Version>1.2.2</Version>
|
||||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||||
|
<AssemblyName>FruityFoundation.Base</AssemblyName>
|
||||||
|
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\LICENSE" Pack="true" PackagePath="" />
|
<None Include="..\LICENSE" Pack="true" PackagePath="" />
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace FruityFoundation.Base.Extensions;
|
|
||||||
|
|
||||||
public static class EnumerableExtensions
|
|
||||||
{
|
|
||||||
public static IEnumerable<T> ConditionalConcat<T>(this IEnumerable<T> enumerable, bool isConditionValid, IEnumerable<T> second) =>
|
|
||||||
!isConditionValid ? enumerable : enumerable.Concat(second);
|
|
||||||
|
|
||||||
public static IEnumerable<T> ConditionalWhere<T>(this IEnumerable<T> enumerable, bool isConditionValid, Func<T, bool> pred) =>
|
|
||||||
!isConditionValid ? enumerable : enumerable.Where(pred);
|
|
||||||
|
|
||||||
public static IEnumerable<TOutput> Choose<TInput, TOutput>(this IEnumerable<TInput> enumerable, Func<TInput, TOutput?> mapper)
|
|
||||||
where TOutput : class? =>
|
|
||||||
enumerable
|
|
||||||
.Select(mapper)
|
|
||||||
.Where(x => x is not null)
|
|
||||||
.Cast<TOutput>();
|
|
||||||
|
|
||||||
public static IEnumerable<TOutput> Choose<TInput, TOutput>(this IEnumerable<TInput> enumerable, Func<TInput, TOutput?> mapper)
|
|
||||||
where TOutput : struct =>
|
|
||||||
enumerable
|
|
||||||
.Select(mapper)
|
|
||||||
.Where(x => x.HasValue)
|
|
||||||
.Select(x => x!.Value);
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
using FruityFoundation.Base.Structures;
|
|
||||||
|
|
||||||
namespace FruityFoundation.Base.Extensions;
|
|
||||||
|
|
||||||
public static class NullableExtensions
|
|
||||||
{
|
|
||||||
public static Maybe<T> ToMaybe<T>(this T? item) where T : struct =>
|
|
||||||
item ?? Maybe<T>.Empty();
|
|
||||||
|
|
||||||
public static Maybe<T> ToMaybe<T>(this T? item) where T : class =>
|
|
||||||
item ?? Maybe<T>.Empty();
|
|
||||||
}
|
|
|
@ -1,8 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using FruityFoundation.Base.Structures;
|
|
||||||
|
|
||||||
namespace FruityFoundation.Base.Extensions;
|
namespace FruityFoundation.Base.Structures;
|
||||||
|
|
||||||
public static class DataReaderExtensions
|
public static class DataReaderExtensions
|
||||||
{
|
{
|
||||||
|
@ -42,6 +41,6 @@ public static class DataReaderExtensions
|
||||||
public static Maybe<string> TryGetString(this IDataReader reader, int ord) =>
|
public static Maybe<string> TryGetString(this IDataReader reader, int ord) =>
|
||||||
TryGet(reader, ord, reader.GetString);
|
TryGet(reader, ord, reader.GetString);
|
||||||
|
|
||||||
private static Maybe<T> TryGet<T>(IDataReader reader, int ord, Func<int, T> valueGetter) =>
|
private static Maybe<T> TryGet<T>(IDataRecord reader, int ord, Func<int, T> valueGetter) =>
|
||||||
reader.IsDBNull(ord) ? Maybe<T>.Empty() : valueGetter(ord);
|
reader.IsDBNull(ord) ? Maybe.Empty<T>() : valueGetter(ord);
|
||||||
}
|
}
|
20
Base/Structures/EnumerableExtensions.cs
Normal file
20
Base/Structures/EnumerableExtensions.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace FruityFoundation.Base.Structures;
|
||||||
|
|
||||||
|
public static class EnumerableExtensions
|
||||||
|
{
|
||||||
|
public static IEnumerable<T> ConditionalConcat<T>(this IEnumerable<T> enumerable, bool condition, IEnumerable<T> second) =>
|
||||||
|
!condition ? enumerable : enumerable.Concat(second);
|
||||||
|
|
||||||
|
public static IEnumerable<T> ConditionalAppend<T>(this IEnumerable<T> enumerable, bool condition, T second) =>
|
||||||
|
condition ? enumerable.Append(second) : enumerable;
|
||||||
|
|
||||||
|
public static IEnumerable<T> ConditionalWhere<T>(this IEnumerable<T> enumerable, bool condition, Func<T, bool> pred) =>
|
||||||
|
!condition ? enumerable : enumerable.Where(pred);
|
||||||
|
|
||||||
|
public static IEnumerable<TOutput> Choose<TInput, TOutput>(this IEnumerable<TInput> enumerable, Func<TInput, Maybe<TOutput>> chooser) =>
|
||||||
|
enumerable.Select(chooser).Where(x => x.HasValue).Select(x => x.Value);
|
||||||
|
}
|
|
@ -1,18 +1,20 @@
|
||||||
// Normally we wouldn't want to disable Nullable references, but in this case we want to.
|
namespace FruityFoundation.Base.Structures;
|
||||||
// We're assuming that if you're following Maybe conventions, you won't be hitting null ref exceptions.
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
#pragma warning disable CS8601
|
public static class Maybe
|
||||||
namespace FruityFoundation.Base.Structures;
|
{
|
||||||
|
public static Maybe<T> Just<T>(T value) => new(value, hasValue: true);
|
||||||
|
public static Maybe<T> Just<T>(T value, Func<T, bool> hasValue) => new(value, hasValue: hasValue(value));
|
||||||
|
public static Maybe<T> Empty<T>() => new(val: default!, hasValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
[Serializable]
|
public readonly struct Maybe<T>
|
||||||
public struct Maybe<T>
|
|
||||||
{
|
{
|
||||||
private readonly T _value;
|
private readonly T _value;
|
||||||
public readonly bool HasValue;
|
public readonly bool HasValue;
|
||||||
|
|
||||||
private Maybe(T val = default!, bool hasValue = true)
|
internal Maybe(T val = default!, bool hasValue = true)
|
||||||
{
|
{
|
||||||
_value = val;
|
_value = val;
|
||||||
HasValue = hasValue;
|
HasValue = hasValue;
|
||||||
|
@ -29,12 +31,13 @@ public struct Maybe<T>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public T OrValue(T orVal) =>
|
public T OrValue(T orVal) => HasValue ? Value : orVal;
|
||||||
HasValue ? Value : orVal;
|
|
||||||
|
public T OrEval(Func<T> valueFactory) => HasValue ? Value : valueFactory();
|
||||||
|
|
||||||
public bool Try(out T val)
|
public bool Try(out T val)
|
||||||
{
|
{
|
||||||
val = HasValue ? Value : default;
|
val = HasValue ? Value : default!;
|
||||||
|
|
||||||
return HasValue;
|
return HasValue;
|
||||||
}
|
}
|
||||||
|
@ -42,23 +45,34 @@ public struct Maybe<T>
|
||||||
public T OrThrow(string msg) =>
|
public T OrThrow(string msg) =>
|
||||||
HasValue ? Value : throw new Exception(msg);
|
HasValue ? Value : throw new Exception(msg);
|
||||||
|
|
||||||
|
public T OrThrow(Func<string> messageFactory) =>
|
||||||
|
HasValue ? Value : throw new Exception(messageFactory());
|
||||||
|
|
||||||
|
public T OrThrow(Func<Exception> exFactory) =>
|
||||||
|
HasValue ? Value : throw exFactory();
|
||||||
|
|
||||||
public Maybe<TOutput> Map<TOutput>(Func<T, TOutput> transformer) =>
|
public Maybe<TOutput> Map<TOutput>(Func<T, TOutput> transformer) =>
|
||||||
HasValue
|
HasValue ? Maybe.Just(transformer(Value)) : Maybe.Empty<TOutput>();
|
||||||
? Maybe<TOutput>.Create(transformer(Value))
|
|
||||||
: Maybe<TOutput>.Empty();
|
|
||||||
|
|
||||||
public object ToDbValue() =>
|
public Maybe<TOutput> Bind<TOutput>(Func<T, TOutput> binder) =>
|
||||||
HasValue && Value is not null
|
HasValue ? binder(Value) : Maybe.Empty<TOutput>();
|
||||||
? Value
|
|
||||||
: DBNull.Value;
|
|
||||||
|
|
||||||
public static Maybe<T> Create(T val, bool hasValue = true) => new(val, hasValue);
|
public Maybe<TOutput> Cast<TOutput>()
|
||||||
|
{
|
||||||
|
if (!HasValue)
|
||||||
|
return Maybe.Empty<TOutput>();
|
||||||
|
|
||||||
public static Maybe<T> Create(T val, Func<T, bool> hasValue) => new(val, hasValue(val));
|
try
|
||||||
|
{
|
||||||
|
return (TOutput)Convert.ChangeType(Value, typeof(TOutput))!;
|
||||||
|
}
|
||||||
|
catch (InvalidCastException)
|
||||||
|
{
|
||||||
|
return Maybe.Empty<TOutput>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Maybe<T> Empty() => new(default!, hasValue: false);
|
public static implicit operator Maybe<T>(T val) => Maybe.Just(val);
|
||||||
|
|
||||||
public static implicit operator Maybe<T>(T val) => Create(val);
|
|
||||||
|
|
||||||
public static explicit operator T(Maybe<T> val) => val.Value;
|
public static explicit operator T(Maybe<T> val) => val.Value;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ public static class MaybeExtensions
|
||||||
{
|
{
|
||||||
using var enumerator = collection.GetEnumerator();
|
using var enumerator = collection.GetEnumerator();
|
||||||
|
|
||||||
return !enumerator.MoveNext() ? Maybe<T>.Empty() : enumerator.Current;
|
return !enumerator.MoveNext() ? Maybe.Empty<T>() : enumerator.Current;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Maybe<T> FirstOrEmpty<T>(this IEnumerable<T> collection, Func<T, bool> pred)
|
public static Maybe<T> FirstOrEmpty<T>(this IEnumerable<T> collection, Func<T, bool> pred)
|
||||||
|
@ -19,9 +19,12 @@ public static class MaybeExtensions
|
||||||
if (pred(item))
|
if (pred(item))
|
||||||
return item;
|
return item;
|
||||||
|
|
||||||
return Maybe<T>.Empty();
|
return Maybe.Empty<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Maybe<TValue> TryGet<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dict, TKey key) =>
|
||||||
|
dict.TryGetValue(key, out var value) ? Maybe.Just(value) : Maybe.Empty<TValue>();
|
||||||
|
|
||||||
public static T? ToNullable<T>(this Maybe<T> item) where T : struct =>
|
public static T? ToNullable<T>(this Maybe<T> item) where T : struct =>
|
||||||
item.HasValue ? item.Value : null;
|
item.HasValue ? item.Value : null;
|
||||||
|
|
||||||
|
|
7
Base/Structures/NullableExtensions.cs
Normal file
7
Base/Structures/NullableExtensions.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace FruityFoundation.Base.Structures;
|
||||||
|
|
||||||
|
public static class NullableExtensions
|
||||||
|
{
|
||||||
|
public static Maybe<T> ToMaybe<T>(this T? item) where T : struct =>
|
||||||
|
item ?? Maybe.Empty<T>();
|
||||||
|
}
|
49
Base/Structures/Result.cs
Normal file
49
Base/Structures/Result.cs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FruityFoundation.Base.Structures;
|
||||||
|
|
||||||
|
public readonly struct Result<TSuccess, TFailure>
|
||||||
|
{
|
||||||
|
private readonly Maybe<TSuccess> _successVal;
|
||||||
|
private readonly Maybe<TFailure> _failureVal;
|
||||||
|
|
||||||
|
private Result(Maybe<TSuccess> successVal, Maybe<TFailure> failureVal)
|
||||||
|
{
|
||||||
|
_successVal = successVal;
|
||||||
|
_failureVal = failureVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result<TSuccess, TFailure> CreateSuccess(TSuccess val) =>
|
||||||
|
new(successVal: val, failureVal: Maybe.Empty<TFailure>());
|
||||||
|
|
||||||
|
public static Result<TSuccess, TFailure> CreateFailure(TFailure val) =>
|
||||||
|
new(successVal: Maybe.Empty<TSuccess>(), failureVal: val);
|
||||||
|
|
||||||
|
public bool IsSuccess => _successVal.HasValue;
|
||||||
|
public bool IsFailure => _failureVal.HasValue;
|
||||||
|
|
||||||
|
public bool TrySuccess(out TSuccess output)
|
||||||
|
{
|
||||||
|
if (!_successVal.Try(out output))
|
||||||
|
{
|
||||||
|
output = default!;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryFailure(out TFailure output)
|
||||||
|
{
|
||||||
|
if (!_failureVal.Try(out output))
|
||||||
|
{
|
||||||
|
output = default!;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Merge<T>(Func<TSuccess, T> onSuccess, Func<TFailure, T> onFailure) =>
|
||||||
|
IsSuccess ? onSuccess(_successVal.Value) : onFailure(_failureVal.Value);
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace FruityFoundation.Base.Extensions;
|
namespace FruityFoundation.Base.Structures;
|
||||||
|
|
||||||
public static class StringExtensions
|
public static class StringExtensions
|
||||||
{
|
{
|
||||||
|
@ -16,5 +16,5 @@ public static class StringExtensions
|
||||||
/// <param name="str"></param>
|
/// <param name="str"></param>
|
||||||
/// <param name="maxLength">The maximum number of characters. If <paramref name="str"/> has fewer characters, it will be truncated to the length of <paramref name="str"/>.</param>
|
/// <param name="maxLength">The maximum number of characters. If <paramref name="str"/> has fewer characters, it will be truncated to the length of <paramref name="str"/>.</param>
|
||||||
public static string Truncate(this string str, int maxLength) =>
|
public static string Truncate(this string str, int maxLength) =>
|
||||||
str.Substring(0, Math.Min(str.Length, maxLength));
|
str[..Math.Min(str.Length, maxLength)];
|
||||||
}
|
}
|
0
Db/Db.fsproj
Executable file → Normal file
0
Db/Db.fsproj
Executable file → Normal file
|
@ -3,7 +3,7 @@ open FruityFoundation.Base.Structures
|
||||||
|
|
||||||
module Option =
|
module Option =
|
||||||
let toMaybe : 'a option -> Maybe<'a> = function
|
let toMaybe : 'a option -> Maybe<'a> = function
|
||||||
| Some x -> x |> Maybe.Create
|
| Some x -> x |> Maybe.Just
|
||||||
| None -> Maybe.Empty ()
|
| None -> Maybe.Empty ()
|
||||||
|
|
||||||
let fromMaybe : Maybe<'a> -> 'a option = function
|
let fromMaybe : Maybe<'a> -> 'a option = function
|
||||||
|
|
2
FsBase/FsBase.fsproj
Executable file → Normal file
2
FsBase/FsBase.fsproj
Executable file → Normal file
|
@ -29,7 +29,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Update="FSharp.Core" Version="7.0.0" />
|
<PackageReference Update="FSharp.Core" Version="7.0.300" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user