diff --git a/src/libanvl.Opt/Opt.cs b/src/libanvl.Opt/Opt.cs
index a906566..d94099a 100644
--- a/src/libanvl.Opt/Opt.cs
+++ b/src/libanvl.Opt/Opt.cs
@@ -33,6 +33,14 @@ public static class Opt
/// An containing the value if not null, otherwise .
public static Opt From(T? value) where T : notnull => value is null ? Opt.None : Some(value);
+ ///
+ /// Creates an from a nullable value.
+ ///
+ /// The type of the value.
+ /// The nullable value to wrap.
+ /// An containing the value if not null, otherwise .
+ public static Opt From(T? value) where T : struct => value.HasValue ? Some(value.Value) : Opt.None;
+
///
/// Combines two options into an option containing a tuple of their values if both are present.
///
@@ -41,7 +49,7 @@ public static class Opt
/// The first option.
/// The second option.
/// An option containing a tuple of the values if both are present, otherwise none.
- public static Opt<(T, U)> Zip(Opt opt1, Opt opt2)
+ public static Opt<(T, U)> Zip(this Opt opt1, Opt opt2)
where T : notnull
where U : notnull
{
@@ -55,7 +63,7 @@ public static class Opt
///
/// The option to flatten.
/// The flattened option.
- public static Opt Flatten(Opt> opt)
+ public static Opt Flatten(this Opt> opt)
where T : notnull => opt.IsSome ? opt.Unwrap() : Opt.None;
///
@@ -102,7 +110,7 @@ public static Opt AndThen(this Opt opt, Func> fn) where T
///
/// The value to wrap.
/// Thrown if the value is null.
- public Opt(T value)
+ internal Opt(T value)
{
OptException.ThrowIfNull(value);
_value = value;
@@ -248,10 +256,29 @@ public TResult Match(Func some, Func none) => IsSo
/// The type of the result.
/// The function to transform the value.
/// An containing the transformed value or none.
- public Opt Select(Func fn) where U : notnull => IsSome
- ? new(fn(OptException.ThrowInternalErrorIfNull(_value)))
+ public Opt Select(Func fn) where U : notnull => IsSome
+ ? Opt.From(fn(OptException.ThrowInternalErrorIfNull(_value)))
: Opt.None;
+ ///
+ /// Transforms the value if present using the specified function.
+ ///
+ /// The type of the result.
+ /// The function to transform the value.
+ /// An containing the transformed value or none.
+ public Opt Select(Func fn) where U: struct => IsSome
+ ? Opt.From(fn(OptException.ThrowInternalErrorIfNull(_value)))
+ : Opt.None;
+
+ ///
+ /// Filters the option based on a predicate.
+ ///
+ /// The predicate to apply.
+ /// The option if the predicate is true, otherwise none.
+ public Opt Where(Func predicate) => IsSome && predicate(OptException.ThrowInternalErrorIfNull(_value))
+ ? this
+ : None;
+
///
/// Casts the value to the specified type if present.
///
diff --git a/test/libanvl.Opt.Test/OptTests.cs b/test/libanvl.Opt.Test/OptTests.cs
index 8a18b21..bf141e7 100644
--- a/test/libanvl.Opt.Test/OptTests.cs
+++ b/test/libanvl.Opt.Test/OptTests.cs
@@ -268,4 +268,78 @@ public void GetHashCode_ReturnsSameHashCode_ForNone()
var opt2 = Opt.None;
Assert.Equal(opt1.GetHashCode(), opt2.GetHashCode());
}
+
+ [Fact]
+ public void Select_ReturnsTransformedOption_WhenSome()
+ {
+ var opt = Opt.Some(5);
+ var result = opt.Select(x => x * 2);
+ Assert.True(result.IsSome);
+ Assert.Equal(10, result.Unwrap());
+ }
+
+ [Fact]
+ public void Select_ReturnsNone_WhenTransformedValueIsNull()
+ {
+ var opt = Opt.Some("Hello");
+ var result = opt.Select(x => null);
+ Assert.True(result.IsNone);
+ }
+
+ [Fact]
+ public void Select_ReturnsNone_WhenTransformedValueIsNullValueType()
+ {
+ Opt opt = 5;
+ var result = opt.Select(_ => null);
+ Assert.True(result.IsNone);
+ }
+
+ [Fact]
+ public void Select_ReturnsNone_WhenNone()
+ {
+ var opt = Opt.None;
+ var result = opt.Select(x => x * 2);
+ Assert.True(result.IsNone);
+ }
+
+ [Fact]
+ public void Where_ReturnsSome_WhenPredicateIsTrue()
+ {
+ var opt = Opt.Some(5);
+ var result = opt.Where(x => x > 3);
+ Assert.True(result.IsSome);
+ }
+
+ [Fact]
+ public void Where_ReturnsNone_WhenPredicateIsFalse()
+ {
+ var opt = Opt.Some(5);
+ var result = opt.Where(x => x < 3);
+ Assert.True(result.IsNone);
+ }
+
+ [Fact]
+ public void Where_ReturnsNone_WhenOptionIsNone()
+ {
+ var opt = Opt.None;
+ var result = opt.Where(x => x > 3);
+ Assert.True(result.IsNone);
+ }
+
+ [Fact]
+ public void Cast_ReturnsSome_WhenCastIsValid()
+ {
+ var opt = Opt.Some((object)5);
+ var result = opt.Cast();
+ Assert.True(result.IsSome);
+ Assert.Equal(5, result.Unwrap());
+ }
+
+ [Fact]
+ public void Cast_ReturnsNone_WhenCastIsInvalid()
+ {
+ var opt = Opt.Some((object)"string");
+ var result = opt.Cast();
+ Assert.True(result.IsNone);
+ }
}