Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stew/enums and enumStrValues{Array,Seq} #122

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ jobs:
fi
nim --version
nimble --version
nimble install -y --depsOnly
env TEST_LANG=c nimble test
env TEST_LANG=cpp nimble test

Expand All @@ -173,5 +174,6 @@ jobs:
- name: Test using VCC
if: runner.os == 'Windows'
run: |
export NIMFLAGS="-d:nimRawSetjmp"
env TEST_LANG=c nimble testvcc
env TEST_LANG=cpp nimble testvcc
3 changes: 2 additions & 1 deletion stew.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ description = "Backports, standard library candidates and small utilities that
license = "Apache License 2.0"
skipDirs = @["tests"]

requires "nim >= 1.2.0"
requires "nim >= 1.2.0",
"unittest2"

### Helper functions
proc test(args, path: string) =
Expand Down
58 changes: 58 additions & 0 deletions stew/enums.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import
macros, sequtils

macro enumRangeInt64*(a: type[enum]): untyped =
## This macro returns an array with all the ordinal values of an enum
let
values = a.getType[1][1..^1]
valuesOrded = values.mapIt(newCall("int64", it))
newNimNode(nnkBracket).add(valuesOrded)

macro enumStrValuesArrayImpl(a: type[enum]): untyped =
## This macro returns an array with all the ordinal values of an enum
let
values = a.getType[1][1..^1]
valuesOrded = values.mapIt(newCall("$", it))
newNimNode(nnkBracket).add(valuesOrded)

# TODO: This should be a proc returning a lent view over the
# const value. This will ensure only a single instace
# of the array is generated.
template enumStrValuesArray*(E: type[enum]): auto =
const values = enumStrValuesArrayImpl E
values

# TODO: This should be a proc returning a lent view over the
# const value. This will ensure only a single instace
# of the sequence is generated.
template enumStrValuesSeq*(E: type[enum]): seq[string] =
const values = @(enumStrValuesArray E)
values

macro hasHoles*(T: type[enum]): bool =
# As an enum is always sorted, just substract the first and the last ordinal value
# and compare the result to the number of element in it will do the trick.
let len = T.getType[1].len - 2

quote: `T`.high.ord - `T`.low.ord != `len`

proc contains*[I: SomeInteger](e: type[enum], v: I): bool =
when I is uint64:
if v > int.high.uint64:
return false
when e.hasHoles():
v.int64 in enumRangeInt64(e)
else:
v.int64 in e.low.int64 .. e.high.int64

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.

if value notin E:
return false

res = E value
return true
44 changes: 7 additions & 37 deletions stew/objects.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import
macros,
sequtils
macros, sequtils

import
enums

export
enums

template init*(lvalue: var auto) =
mixin init
Expand Down Expand Up @@ -68,41 +73,6 @@ proc baseType*(obj: RootObj): cstring =
proc baseType*(obj: ref RootObj): cstring =
obj[].baseType

macro enumRangeInt64*(a: type[enum]): untyped =
## This macro returns an array with all the ordinal values of an enum
let
values = a.getType[1][1..^1]
valuesOrded = values.mapIt(newCall("int64", it))
newNimNode(nnkBracket).add(valuesOrded)

macro hasHoles*(T: type[enum]): bool =
# As an enum is always sorted, just substract the first and the last ordinal value
# and compare the result to the number of element in it will do the trick.
let len = T.getType[1].len - 2

quote: `T`.high.ord - `T`.low.ord != `len`

proc contains*[I: SomeInteger](e: type[enum], v: I): bool =
when I is uint64:
if v > int.high.uint64:
return false
when e.hasHoles():
v.int64 in enumRangeInt64(e)
else:
v.int64 in e.low.int64 .. e.high.int64

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.

if value notin E:
return false

res = E value
return true

func isZeroMemory*[T](x: T): bool =
# TODO: iterate over words here
for b in cast[ptr array[sizeof(T), byte]](unsafeAddr x)[]:
Expand Down
1 change: 1 addition & 0 deletions tests/all_tests.nim
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import
test_byteutils,
test_ctops,
test_endians2,
test_enums,
test_io2,
test_keyed_queue,
test_sorted_set,
Expand Down
3 changes: 2 additions & 1 deletion tests/ranges/tbitranges.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import
random, unittest,
random,
unittest2,
../../stew/ranges/bitranges, ../../stew/bitseqs

proc randomBytes(n: int): seq[byte] =
Expand Down
3 changes: 2 additions & 1 deletion tests/ranges/tstackarrays.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import
unittest, math,
math,
unittest2,
../../stew/ptrops,
../../stew/ranges/[stackarrays]

Expand Down
3 changes: 2 additions & 1 deletion tests/ranges/ttypedranges.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import
unittest, sets,
sets,
unittest2,
../../stew/ranges/[typedranges, ptr_arith]

suite "Typed ranges":
Expand Down
2 changes: 1 addition & 1 deletion tests/test_arrayops.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{.used.}

import
std/unittest,
unittest2,
../stew/arrayops

suite "arrayops":
Expand Down
2 changes: 1 addition & 1 deletion tests/test_assign2.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import
std/unittest,
unittest2,
../stew/assign2

suite "assign2":
Expand Down
5 changes: 3 additions & 2 deletions tests/test_base10.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
import ../stew/base10
import
unittest2,
../stew/base10

when defined(nimHasUsed): {.used.}

Expand Down
5 changes: 3 additions & 2 deletions tests/test_base32.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
import ../stew/base32
import
unittest2,
../stew/base32

when defined(nimHasUsed): {.used.}

Expand Down
5 changes: 3 additions & 2 deletions tests/test_base58.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
import ../stew/base58
import
unittest2,
../stew/base58

when defined(nimHasUsed): {.used.}

Expand Down
5 changes: 3 additions & 2 deletions tests/test_base64.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
import ../stew/[base64, byteutils]
import
unittest2,
../stew/[base64, byteutils]

when defined(nimHasUsed): {.used.}

Expand Down
6 changes: 3 additions & 3 deletions tests/test_bitops2.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import unittest

import ../stew/bitops2
import
unittest2,
../stew/bitops2

template test() =
doAssert bitsof(8'u8) == 8
Expand Down
3 changes: 2 additions & 1 deletion tests/test_bitseqs.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import
unittest, strformat,
strformat,
unittest2,
../stew/[bitseqs]

suite "Bit fields":
Expand Down
2 changes: 1 addition & 1 deletion tests/test_byteutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.

import
std/unittest,
unittest2,
../stew/byteutils

proc compilationTest {.exportc: "compilationTest".} =
Expand Down
5 changes: 3 additions & 2 deletions tests/test_ctops.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
import ../stew/ctops
import
unittest2,
../stew/ctops

suite "Constant-time operations test suite":
test "isEqual() test":
Expand Down
6 changes: 3 additions & 3 deletions tests/test_endians2.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import unittest

import ../stew/endians2
import
unittest2,
../stew/endians2

template test() =
doAssert 0x01'u8.toBytesBE == [0x01'u8]
Expand Down
Loading