nim-stew/stew/objects.nim

117 lines
3.0 KiB
Nim
Raw Permalink Normal View History

import
macros
template init*(lvalue: var auto) =
mixin init
lvalue = init(type(lvalue))
template init*(lvalue: var auto, a1: auto)=
mixin init
lvalue = init(type(lvalue), a1)
template init*(lvalue: var auto, a1, a2: auto) =
mixin init
lvalue = init(type(lvalue), a1, a2)
template init*(lvalue: var auto, a1, a2, a3: auto) =
mixin init
lvalue = init(type(lvalue), a1, a2, a3)
2019-07-02 23:30:49 +00:00
when not declared(default):
proc default*(T: type): T = discard
proc toArray*[T](N: static int, data: openarray[T]): array[N, T] =
doAssert data.len == N
copyMem(addr result[0], unsafeAddr data[0], N)
2019-08-02 08:51:04 +00:00
template anonConst*(val: untyped): untyped =
const c = val
c
2019-10-02 13:24:59 +00:00
2020-04-22 12:41:42 +00:00
func declval*(T: type): T {.compileTime.} =
## `declval` denotes an anonymous expression of a particular
## type. It can be used in situations where you want to determine
## the type of an overloaded call in `typeof` expressions.
##
## Example:
## ```
## type T = typeof foo(declval(string), declval(var int))
## ```
##
## Please note that `declval` has two advantages over `default`:
##
2020-04-22 12:41:42 +00:00
## 1. It can return expressions with proper `var` or `lent` types.
##
2020-04-22 12:41:42 +00:00
## 2. It will work for types that lack a valid default value due
## to `not nil` or `requiresInit` requirements.
##
doAssert false,
2020-04-22 13:39:37 +00:00
"declval should be used only in `typeof` expressions and concepts"
2020-04-22 12:41:42 +00:00
default(ptr T)[]
2019-10-02 13:24:59 +00:00
when not compiles(len((1, 2))):
import typetraits
func len*(x: tuple): int =
arity(type(x))
2020-03-29 15:34:45 +00:00
# Get an object's base type, as a cstring. Ref objects will have an ":ObjectType"
# suffix.
# From: https://gist.github.com/stefantalpalaru/82dc71bb547d6f9178b916e3ed5b527d
proc baseType*(obj: RootObj): cstring =
when not defined(nimTypeNames):
raiseAssert("you need to compile this with '-d:nimTypeNames'")
else:
{.emit: "result = `obj`->m_type->name;".}
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
2021-09-13 16:02:32 +00:00
func isZeroMemory*[T](x: T): bool =
# TODO: iterate over words here
for b in cast[ptr array[sizeof(T), byte]](unsafeAddr x)[]:
if b != 0:
return false
return true