
// Written in the D programming language.

/**
 * Templates with which to extract information about
 * types at compile time.
 *
 * Source: $(PHOBOSSRC std/_traits.d)
 * Macros:
 *      WIKI = Phobos/StdTraits
 * Copyright:
 *      Public Domain
 */

/*
 * Authors:
 *      Walter Bright, Digital Mars, www.digitalmars.com
 *      Tomasz Stachowiak (isStaticArray, isExpressionTuple)
 */

module std.traits;

/***
 * Get the type of the return value from a function,
 * a pointer to function, or a delegate.
 * Example:
 * ---
 * import std.traits;
 * int foo();
 * ReturnType!(foo) x;   // x is declared as int
 * ---
 */
template ReturnType(alias dg)
{
    alias ReturnType!(typeof(dg)) ReturnType;
}

/** ditto */
template ReturnType(dg)
{
    static if (is(dg R == return))
        alias R ReturnType;
    else
        static assert(0, "argument has no return type");
}

/***
 * Get the types of the paramters to a function,
 * a pointer to function, or a delegate as a tuple.
 * Example:
 * ---
 * import std.traits;
 * int foo(int, long);
 * void bar(ParameterTypeTuple!(foo));      // declares void bar(int, long);
 * void abc(ParameterTypeTuple!(foo)[1]);   // declares void abc(long);
 * ---
 */
template ParameterTypeTuple(alias dg)
{
    alias ParameterTypeTuple!(typeof(dg)) ParameterTypeTuple;
}

/** ditto */
template ParameterTypeTuple(dg)
{
    static if (is(dg P == function))
        alias P ParameterTypeTuple;
    else static if (is(dg P == delegate))
        alias ParameterTypeTuple!(P) ParameterTypeTuple;
    else static if (is(dg P == P*))
        alias ParameterTypeTuple!(P) ParameterTypeTuple;
    else
        static assert(0, "argument has no parameters");
}


/***
 * Get the types of the fields of a struct or class.
 * This consists of the fields that take up memory space,
 * excluding the hidden fields like the virtual function
 * table pointer.
 */

template FieldTypeTuple(S)
{
    static if (is(S == struct) || is(S == class))
        alias typeof(S.tupleof) FieldTypeTuple;
    else
        static assert(0, "argument is not struct or class");
}


/***
 * Get a TypeTuple of the base class and base interfaces of
 * this class or interface.
 * Example:
 * ---
 * import std.traits, std.typetuple, std.stdio;
 * interface I { }
 * class A { }
 * class B : A, I { }
 *
 * void main()
 * {
 *     alias BaseTypeTuple!(B) TL;
 *     writefln(typeid(TL));    // prints: (A,I)
 * }
 * ---
 */

template BaseTypeTuple(A)
{
    static if (is(A P == super))
        alias P BaseTypeTuple;
    else
        static assert(0, "argument is not a class or interface");
}

unittest
{
    interface I { }
    class A { }
    class B : A, I { }

    alias BaseTypeTuple!(B) TL;
    assert(TL.length == 2);
    assert(is (TL[0] == A));
    assert(is (TL[1] == I));
}

/* *******************************************
 */
template isStaticArray_impl(T)
{
    const T inst = void;

    static if (is(typeof(T.length)))
    {
        static if (!is(T == typeof(T.init)))
        {                       // abuses the fact that int[5].init == int
            static if (is(T == typeof(T[0])[inst.length]))
            {   // sanity check. this check alone isn't enough because dmd complains about dynamic arrays
                const bool res = true;
            }
            else
                const bool res = false;
        }
        else
            const bool res = false;
    }
    else
    {
            const bool res = false;
    }
}
/**
 * Detect whether type T is a static array.
 */
template isStaticArray(T)
{
    const bool isStaticArray = isStaticArray_impl!(T).res;
}


static assert (isStaticArray!(int[51]));
static assert (isStaticArray!(int[][2]));
static assert (isStaticArray!(char[][int][11]));
static assert (!isStaticArray!(int[]));
static assert (!isStaticArray!(int[char]));
static assert (!isStaticArray!(int[1][]));

/**
 * Tells whether the tuple T is an expression tuple.
 */
template isExpressionTuple(T ...)
{
    static if (is(void function(T)))
        const bool isExpressionTuple = false;
    else
        const bool isExpressionTuple = true;
}



