module nxt.assuming;

import std.traits : isFunctionPointer, isDelegate, functionAttributes, FunctionAttribute, SetFunctionAttributes, functionLinkage;

/**
   * See_Also: http://forum.dlang.org/post/nq4eol$2h34$1@digitalmars.com
   * See_Also: https://dpaste.dzfl.pl/8c5ec90c5b39
   */
void assumeNogc(alias fun, T...)(T xs) @nogc
{
    static auto assumeNogcPtr(T)(T f)
    if (isFunctionPointer!T ||
        isDelegate!T)
    {
        enum attrs = functionAttributes!T | FunctionAttribute.nogc;
        return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) f;
    }
    assumeNogcPtr(&fun!T)(xs);
}

/** Return `T` assumed to be `pure`.
 *
 * Copied from: https://dlang.org/phobos/std_traits.html#SetFunctionAttributes.
 * See_Also: https://forum.dlang.org/post/hmucolyghbomttqpsili@forum.dlang.org
 */
auto assumePure(T)(T t)
if (isFunctionPointer!T ||
    isDelegate!T)
{
    enum attrs = functionAttributes!T | FunctionAttribute.pure_;
    return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
}

version(unittest)
{
    static int f(int x) => x + 1;

    static void g() pure
    {
        static assert(!__traits(compiles, { auto x = f(42); }));
        auto pureF = assumePure(&f);
        assert(pureF(42) == 43);
    }
}

auto assumePureNogc(T)(T t)
if (isFunctionPointer!T ||
    isDelegate!T)
{
    enum attrs = functionAttributes!T | FunctionAttribute.pure_ | FunctionAttribute.nogc;
    return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
}