diff --git a/stew/objects.nim b/stew/objects.nim index 54eed36..788c1a6 100644 --- a/stew/objects.nim +++ b/stew/objects.nim @@ -1,3 +1,6 @@ +import + macros + template init*(lvalue: var auto) = mixin init lvalue = init(type(lvalue)) @@ -36,9 +39,9 @@ func declval*(T: type): T {.compileTime.} = ## ``` ## ## Please note that `declval` has two advantages over `default`: - ## + ## ## 1. It can return expressions with proper `var` or `lent` types. - ## + ## ## 2. It will work for types that lack a valid default value due ## to `not nil` or `requiresInit` requirements. ## @@ -64,3 +67,43 @@ proc baseType*(obj: RootObj): cstring = proc baseType*(obj: ref RootObj): cstring = obj[].baseType +when false: + # TODO: Implementing this doesn't seem possible at the moment. + # + # When given enum like: + # + # type WithoutHoles2 = enum + # A2 = 2, B2 = 3, C2 = 4 + # + # ...the code below will print: + # + # EnumTy + # Empty + # Sym "A2" + # Sym "B2" + # Sym "C2" + # + macro hasHoles*(T: type[enum]): bool = + let t = getType(T)[1] + echo t.treeRepr + return newLit(true) + +func checkedEnumAssign*[E: enum, I: SomeInteger](res: var E, value: I): bool = + ## This function can be used to safely assign a tainted integer value (coming + ## from untrusted source) to an enum variable. The function will return `true` + ## if the integer value is within the acceped values of the enum and `false` + ## otherwise. + + # TODO: Enums with holes are not supported yet + # static: doAssert(not hasHoles(E)) + + when I is SomeSignedInt or low(E).int > 0: + if value < I(low(E)): + return false + + if value > I(high(E)): + return false + + res = E value + return true + diff --git a/tests/test_objects.nim b/tests/test_objects.nim index d6ae887..e5209c1 100644 --- a/tests/test_objects.nim +++ b/tests/test_objects.nim @@ -70,3 +70,65 @@ suite "Objects": T6 is DistinctBar T6 isnot Bar + when false: + # TODO: Not possible yet (see objects.nim) + test "hasHoles": + type + WithoutHoles = enum + A1, B1, C1 + + WithoutHoles2 = enum + A2 = 2, B2 = 3, C2 = 4 + + WithHoles = enum + A3, B3 = 2, C3 + + check: + hasHoles(WithoutHoles2) == false + hasHoles(WithoutHoles) == false + hasHoles(WithHoles) == true + + test "checkedEnumAssign": + type + SomeEnum = enum + A1, B1, C1 + + AnotherEnum = enum + A2 = 2, B2, C2 + + var + e1 = A1 + e2 = A2 + + check: + checkedEnumAssign(e1, 2) + e1 == C1 + + check: + not checkedEnumAssign(e1, 5) + e1 == C1 + + check: + checkedEnumAssign(e1, 0) + e1 == A1 + + check: + not checkedEnumAssign(e1, -1) + e1 == A1 + + check: + checkedEnumAssign(e2, 2) + e2 == A2 + + check: + not checkedEnumAssign(e2, 5) + e2 == A2 + + check: + checkedEnumAssign(e2, 4) + e2 == C2 + + check: + not checkedEnumAssign(e2, 1) + e2 == C2 +