Skip to content

Commit 168eb65

Browse files
committed
Move std.typecons.apply to std.experimental
1 parent 9e81b5a commit 168eb65

File tree

2 files changed

+105
-1
lines changed

2 files changed

+105
-1
lines changed

changelog/std-typecons-nullable-apply.dd

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
`apply` was added to `std.typecons`.
1+
`apply` was added to `std.experimental.typecons`.
22

33
`apply` is an operation for $(REF Nullable, std, typecons) values that "unpacks" the `Nullable`, performs some
44
operation (that is passed as a template parameter), then packs the result into another `Nullable` if necessary.
@@ -13,3 +13,5 @@ assert(n.isNull);
1313
n = 2;
1414
assert(n.apply!square.get == 4);
1515
-----
16+
17+
`apply` is currently in $(REF apply, std, experimental, typecons) and will be added to `std.typecons` once it stabilizes.

std/experimental/typecons.d

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,3 +1074,105 @@ pure nothrow @system unittest
10741074
arr.ptr++
10751075
));
10761076
}
1077+
1078+
/**
1079+
Unpacks the content of a `Nullable`, performs an operation and packs it again. Does nothing if isNull.
1080+
1081+
When called on a `Nullable`, `apply` will unpack the value contained in the `Nullable`,
1082+
pass it to the function you provide and wrap the result in another `Nullable` (if necessary).
1083+
If the Nullable is null, `apply` will return null itself.
1084+
1085+
Params:
1086+
t = a `Nullable`
1087+
fun = a function operating on the content of the nullable
1088+
1089+
Returns:
1090+
`fun(t.get).nullable` if `!t.isNull`, else `Nullable.init`.
1091+
1092+
See also:
1093+
$(HTTP en.wikipedia.org/wiki/Monad_(functional_programming)#The_Maybe_monad, The `Maybe` monad)
1094+
*/
1095+
template apply(alias fun)
1096+
{
1097+
import std.functional : unaryFun;
1098+
import std.typecons : Nullable, nullable;
1099+
1100+
auto apply(T)(T t)
1101+
if (isInstanceOf!(Nullable, T) && is(typeof(unaryFun!fun(T.init.get))))
1102+
{
1103+
alias FunType = typeof(unaryFun!fun(T.init.get));
1104+
1105+
enum MustWrapReturn = !isInstanceOf!(Nullable, FunType);
1106+
1107+
static if (MustWrapReturn)
1108+
{
1109+
alias ReturnType = Nullable!FunType;
1110+
}
1111+
else
1112+
{
1113+
alias ReturnType = FunType;
1114+
}
1115+
1116+
if (!t.isNull)
1117+
{
1118+
static if (MustWrapReturn)
1119+
{
1120+
return fun(t.get).nullable;
1121+
}
1122+
else
1123+
{
1124+
return fun(t.get);
1125+
}
1126+
}
1127+
else
1128+
{
1129+
return ReturnType.init;
1130+
}
1131+
}
1132+
}
1133+
1134+
///
1135+
nothrow pure @nogc @safe unittest
1136+
{
1137+
import std.typecons : Nullable;
1138+
1139+
alias toFloat = i => cast(float) i;
1140+
1141+
Nullable!int sample;
1142+
1143+
// apply(null) results in a null `Nullable` of the function's return type.
1144+
Nullable!float f = sample.apply!toFloat;
1145+
assert(sample.isNull && f.isNull);
1146+
1147+
sample = 3;
1148+
1149+
// apply(non-null) calls the function and wraps the result in a `Nullable`.
1150+
f = sample.apply!toFloat;
1151+
assert(!sample.isNull && !f.isNull);
1152+
assert(f.get == 3.0f);
1153+
}
1154+
1155+
///
1156+
nothrow pure @nogc @safe unittest
1157+
{
1158+
import std.typecons : Nullable, nullable;
1159+
1160+
alias greaterThree = i => (i > 3) ? i.nullable : Nullable!(typeof(i)).init;
1161+
1162+
Nullable!int sample;
1163+
1164+
// when the function already returns a `Nullable`, that `Nullable` is not wrapped.
1165+
auto result = sample.apply!greaterThree;
1166+
assert(sample.isNull && result.isNull);
1167+
1168+
// The function may decide to return a null `Nullable`.
1169+
sample = 3;
1170+
result = sample.apply!greaterThree;
1171+
assert(!sample.isNull && result.isNull);
1172+
1173+
// Or it may return a value already wrapped in a `Nullable`.
1174+
sample = 4;
1175+
result = sample.apply!greaterThree;
1176+
assert(!sample.isNull && !result.isNull);
1177+
assert(result.get == 4);
1178+
}

0 commit comments

Comments
 (0)