///
module drmi.core.helpers;

package template rmiFunctionName(alias func)
{
    string impl()
    {
        import std.meta : staticMap;
        import std.traits : Parameters;
        import std..string : join;
        import std.algorithm : canFind;

        checkFunction!func;

        template s4t(X) { enum s4t = X.stringof; }

        static if (Parameters!func.length)
            return __traits(identifier, func) ~ "(" ~ [staticMap!(s4t, Parameters!func)].join(",") ~ ")";
        else
            return __traits(identifier, func) ~ "()";
    }
    enum rmiFunctionName = impl();
}

package void checkFunction(alias func)()
{
    import std.algorithm : find;
    import std.traits : hasFunctionAttributes;
    enum funcstr = __traits(identifier, __traits(parent, __traits(parent, func))) ~ ":" ~ 
                    __traits(identifier, __traits(parent, func))
                    ~ "." ~ __traits(identifier, func);
    static assert(!hasFunctionAttributes!(func, "@safe"), "@safe not allowed: " ~ funcstr);
    static assert(!hasFunctionAttributes!(func,  "pure"), "pure not allowed: " ~ funcstr);
    static assert(!hasFunctionAttributes!(func, "@nogc"), "@nogc not allowed: " ~ funcstr);
}

unittest
{
    static auto i = [0];
    void foo(int a, double b, string c) @system { i ~= 1; }
    static assert(rmiFunctionName!foo == "foo(int,double,string)");
    void bar() @system { i ~= 2; }
    static assert(rmiFunctionName!bar == "bar()");
}