# # # Nim's Runtime Library # (c) Copyright 2012 Nim Contributors # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## This module defines compile-time reflection procs for ## working with types. ## ## Unstable API. import std/private/since export system.`$` # for backward compatibility type HoleyEnum* = (not Ordinal) and enum ## Enum with holes. type OrdinalEnum* = Ordinal and enum ## Enum without holes. runnableExamples: type A = enum a0 = 2, a1 = 4, a2 type B = enum b0 = 2, b1, b2 assert A is enum assert A is HoleyEnum assert A isnot OrdinalEnum assert B isnot HoleyEnum assert B is OrdinalEnum assert int isnot HoleyEnum type C[T] = enum h0 = 2, h1 = 4 assert C[float] is HoleyEnum proc name*(t: typedesc): string {.magic: "TypeTrait".} = ## Returns the name of the given type. ## ## Alias for `system.\`$\`(t) `_ since Nim v0.20. runnableExamples: doAssert name(int) == "int" doAssert name(seq[string]) == "seq[string]" proc arity*(t: typedesc): int {.magic: "TypeTrait".} = ## Returns the arity of the given type. This is the number of "type" ## components or the number of generic parameters a given type `t` has. runnableExamples: doAssert arity(int) == 0 doAssert arity(seq[string]) == 1 doAssert arity(array[3, int]) == 2 doAssert arity((int, int, float, string)) == 4 proc genericHead*(t: typedesc): typedesc {.magic: "TypeTrait".} = ## Accepts an instantiated generic type and returns its ## uninstantiated form. ## A compile-time error will be produced if the supplied type ## is not generic. ## ## **See also:** ## * `stripGenericParams proc <#stripGenericParams,typedesc>`_ runnableExamples: type Foo[T] = object FooInst = Foo[int] Foo2 = genericHead(FooInst) doAssert Foo2 is Foo and Foo is Foo2 doAssert genericHead(Foo[seq[string]]) is Foo doAssert not compiles(genericHead(int)) type Generic = concept f type _ = genericHead(typeof(f)) proc bar(a: Generic): typeof(a) = a doAssert bar(Foo[string].default) == Foo[string]() doAssert not compiles bar(string.default) when false: # these don't work yet doAssert genericHead(Foo[int])[float] is Foo[float] doAssert seq[int].genericHead is seq proc stripGenericParams*(t: typedesc): typedesc {.magic: "TypeTrait".} = ## This trait is similar to `genericHead <#genericHead,typedesc>`_, but ## instead of producing an error for non-generic types, it will just return ## them unmodified. runnableExamples: type Foo[T] = object doAssert stripGenericParams(Foo[string]) is Foo doAssert stripGenericParams(int) is int proc supportsCopyMem*(t: typedesc): bool {.magic: "TypeTrait".} ## This trait returns true if the type `t` is safe to use for ## `copyMem`:idx:. ## ## Other languages name a type like these `blob`:idx:. proc isNamedTuple*(T: typedesc): bool {.magic: "TypeTrait".} = ## Returns true for named tuples, false for any other type. runnableExamples: doAssert not isNamedTuple(int) doAssert not isNamedTuple((string, int)) doAssert isNamedTuple(tuple[name: string, age: int]) proc distinctBase*(T: typedesc): typedesc {.magic: "TypeTrait".} = ## Returns the base type for distinct types, or the type itself otherwise. ## ## **See also:** ## * `distinctBase template <#distinctBase.t,T>`_ runnableExamples: type MyInt = distinct int doAssert distinctBase(MyInt) is int doAssert distinctBase(int) is int since (1, 1): template distinctBase*[T](a: T): untyped = ## Overload of `distinctBase <#distinctBase,typedesc>`_ for values. runnableExamples: type MyInt = distinct int doAssert 12.MyInt.distinctBase == 12 doAssert 12.distinctBase == 12 when T is distinct: distinctBase(typeof(a))(a) else: # avoids hint ConvFromXtoItselfNotNeeded a proc tupleLen*(T: typedesc[tuple]): int {.magic: "TypeTrait".} = ## Returns the number of elements of the tuple type `T`. ## ## **See also:** ## * `tupleLen template <#tupleLen.t>`_ runnableExamples: doAssert tupleLen((int, int, float, string)) == 4 doAssert tupleLen(tuple[name: string, age: int]) == 2 template tupleLen*(t: tuple): int = ## Returns the number of elements of the tuple `t`. ## ## **See also:** ## * `tupleLen proc <#tupleLen,typedesc>`_ runnableExamples: doAssert tupleLen((1, 2)) == 2 tupleLen(typeof(t)) template get*(T: typedesc[tuple], i: static int): untyped = ## Returns the `i`-th element of `T`. # Note: `[]` currently gives: `Error: no generic parameters allowed for ...` runnableExamples: doAssert get((int, int, float, string), 2) is float typeof(default(T)[i]) type StaticParam*[value: static type] = object ## Used to wrap a static value in `genericParams <#genericParams.t,typedesc>`_. since (1, 3, 5): template elementType*(a: untyped): typedesc = ## Returns the element type of `a`, which can be any iterable (over which you ## can iterate). runnableExamples: iterator myiter(n: int): auto = for i in 0 ..< n: yield i doAssert elementType(@[1,2]) is int doAssert elementType("asdf") is char doAssert elementType(myiter(3)) is int typeof(block: (for ai in a: ai)) import macros macro enumLen*(T: typedesc[enum]): int = ## Returns the number of items in the enum `T`. runnableExamples: type Foo = enum fooItem1 fooItem2 doAssert Foo.enumLen == 2 let bracketExpr = getType(T) expectKind(bracketExpr, nnkBracketExpr) let enumTy = bracketExpr[1] expectKind(enumTy, nnkEnumTy) result = newLit(enumTy.len - 1) macro genericParamsImpl(T: typedesc): untyped = # auxiliary macro needed, can't do it directly in `genericParams` result = newNimNode(nnkTupleConstr) var impl = getTypeImpl(T) expectKind(impl, nnkBracketExpr) impl = impl[1] while true: case impl.kind of nnkSym: impl = impl.getImpl of nnkTypeDef: impl = impl[2] of nnkTypeOfExpr: impl = getTypeInst(impl[0]) of nnkBracketExpr: for i in 1..