diff --git a/codex/utils/optionalcast.nim b/codex/utils/optionalcast.nim new file mode 100644 index 00000000..15830769 --- /dev/null +++ b/codex/utils/optionalcast.nim @@ -0,0 +1,16 @@ +import pkg/questionable +import pkg/questionable/operators + +export questionable + +proc `as`*[T](value: T, U: type): ?U = + ## Casts a value to another type, returns an Option. + ## When the cast succeeds, the option will contain the casted value. + ## When the cast fails, the option will have no value. + when value is U: + return some value + elif value is ref object: + if value of U: + return some U(value) + +Option.liftBinary `as` diff --git a/tests/codex/testutils.nim b/tests/codex/testutils.nim new file mode 100644 index 00000000..4ef7cee8 --- /dev/null +++ b/tests/codex/testutils.nim @@ -0,0 +1,3 @@ +import ./utils/testoptionalcast + +{.warning[UnusedImport]: off.} diff --git a/tests/codex/utils/testoptionalcast.nim b/tests/codex/utils/testoptionalcast.nim new file mode 100644 index 00000000..e945df40 --- /dev/null +++ b/tests/codex/utils/testoptionalcast.nim @@ -0,0 +1,30 @@ +import std/unittest +import codex/utils/optionalcast + +suite "optional casts": + + test "casting value to same type works": + check 42 as int == some 42 + + test "casting value to unrelated type evaluates to None": + check 42 as string == string.none + + test "casting value to subtype works": + type + BaseType = ref object of RootObj + SubType = ref object of BaseType + let x: BaseType = SubType() + check x as SubType == SubType(x).some + + test "casting to unrelated subtype evaluates to None": + type + BaseType = ref object of RootObj + SubType = ref object of BaseType + OtherType = ref object of BaseType + let x: BaseType = SubType() + check x as OtherType == OtherType.none + + test "casting works on optional types": + check 42.some as int == some 42 + check 42.some as string == string.none + check int.none as int == int.none diff --git a/tests/testCodex.nim b/tests/testCodex.nim index 0b563321..5ddd38da 100644 --- a/tests/testCodex.nim +++ b/tests/testCodex.nim @@ -10,6 +10,7 @@ import ./codex/testpurchasing import ./codex/testsales import ./codex/testerasure import ./codex/testproving +import ./codex/testutils # to check that everything compiles import ../codex