Skip to content

Commit

Permalink
funcattr adjustments for usage with rest module
Browse files Browse the repository at this point in the history
1) Add new calling overload in AttributedFunction so that it won't
try merging parameter and attribute type tuples when incoming and
target parameter type tuples match exactly. In that cases relevant
parameters are simply overwritten by attached attribute functions.

2) Add diagnostic that all attached InputAttribute functions conform
to stored argument list.

3) static imports added for qualified symbols
  • Loading branch information
Dicebot committed Oct 18, 2013
1 parent 971a0b7 commit 361005b
Showing 1 changed file with 88 additions and 13 deletions.
101 changes: 88 additions & 13 deletions source/vibe/utils/meta/funcattr.d
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ private {
int index;
// fully qualified return type of attached function
string type;
// for non-basic types - module to import
string origin;
}

/**
Expand All @@ -243,7 +245,7 @@ private {
{
import std.typetuple : Filter, staticMap, staticIndexOf;
import std.traits : ParameterIdentifierTuple, ReturnType,
fullyQualifiedName;
fullyQualifiedName, moduleName;

private alias attributes = Filter!(
isInputAttribute,
Expand All @@ -265,11 +267,19 @@ private {
"hook functions attached for usage with `AttributedFunction` " ~
"must have a return type"
);

static if (is(typeof(moduleName!(ReturnType!(attribute.evaluator))))) {
enum origin = moduleName!(ReturnType!(attribute.evaluator));
}
else {
enum origin = "";
}

enum BuildParameter = Parameter(
name,
staticIndexOf!(name, parameter_names),
fullyQualifiedName!(ReturnType!(attribute.evaluator))
fullyQualifiedName!(ReturnType!(attribute.evaluator)),
origin
);

import std.string : format;
Expand Down Expand Up @@ -354,6 +364,9 @@ private {
enum Parameter meta = ParameterMeta.expand[0];

static assert (meta.index <= ParameterList.expand.length);
static if (meta.origin.length) {
mixin("static import " ~ meta.origin ~ ";");
}
mixin("alias type = " ~ meta.type ~ ";");

alias PartialResult = Group!(
Expand Down Expand Up @@ -446,8 +459,11 @@ private {
*/
struct AttributedFunction(alias Function, alias StoredArgTypes)
{
import std.traits : isSomeFunction, ReturnType, FunctionTypeOf;
import vibe.utils.meta.typetuple : Group, isGroup;
import std.traits : isSomeFunction, ReturnType, FunctionTypeOf,
ParameterTypeTuple, ParameterIdentifierTuple;
import vibe.utils.meta.typetuple : Group, isGroup, Compare;
import std.functional : toDelegate;
import std.typetuple : Filter;

static assert (isGroup!StoredArgTypes);
static assert (is(FunctionTypeOf!Function));
Expand Down Expand Up @@ -486,6 +502,23 @@ struct AttributedFunction(alias Function, alias StoredArgTypes)
ReturnType!Function result;
}

// check that all attached functions have conforming argument lists
foreach (uda; input_attributes) {
static assert (
Compare!(
Group!(ParameterTypeTuple!(uda.evaluator)),
StoredArgTypes
),
format(
"Input attribute function '%s%s' argument list " ~
"does not match provided argument list %s",
fullyQualifiedName!(uda.evaluator),
ParameterTypeTuple!(uda.evaluator).stringof,
StoredArgTypes.expand.stringof
)
);
}

static if (hasReturnType) {
result = prepareInputAndCall(dg, args);
}
Expand All @@ -499,8 +532,7 @@ struct AttributedFunction(alias Function, alias StoredArgTypes)
);

static if (output_attributes.length) {
import vibe.utils.meta.typetuple : Compare;
import std.traits : fullyQualifiedName, ParameterTypeTuple;
import std.traits : fullyQualifiedName;
import std.string : format;
import std.typetuple : TypeTuple;

Expand Down Expand Up @@ -544,10 +576,6 @@ struct AttributedFunction(alias Function, alias StoredArgTypes)
}

private {
import std.functional : toDelegate;
import std.traits : ParameterTypeTuple, ParameterIdentifierTuple;
import std.typetuple : Filter;

// used as an argument tuple when function attached
// to InputAttribute is called
StoredArgTypes.expand m_storedArgs;
Expand Down Expand Up @@ -582,6 +610,7 @@ struct AttributedFunction(alias Function, alias StoredArgTypes)
proxies return value of dg
*/
ReturnType!Function prepareInputAndCall(T...)(FunctionDg dg, T args)
if (!Compare!(Group!T, Group!(ParameterTypeTuple!Function)))
{
alias attributed_parameters = AttributedParameterMetadata!Function;
// calculated combined input type list
Expand All @@ -590,7 +619,6 @@ struct AttributedFunction(alias Function, alias StoredArgTypes)
Group!T
);

import vibe.utils.meta.typetuple : Compare;
import std.traits : fullyQualifiedName;
import std.string : format;

Expand All @@ -608,8 +636,7 @@ struct AttributedFunction(alias Function, alias StoredArgTypes)
// this value tuple will be used to assemble argument list
Input input;

foreach (i, uda; input_attributes)
{
foreach (i, uda; input_attributes) {
// each iteration cycle is responsible for initialising `input`
// tuple from previous spot to current attributed parameter index
// (including)
Expand Down Expand Up @@ -650,6 +677,24 @@ struct AttributedFunction(alias Function, alias StoredArgTypes)

return dg(input);
}

/**
`prepareInputAndCall` overload that operates on argument tuple that exactly
matches attributed function argument list and thus gets updated by
attached function instead of being merged with it
*/
ReturnType!Function prepareInputAndCall(T...)(FunctionDg dg, T args)
if (Compare!(Group!T, Group!(ParameterTypeTuple!Function)))
{
alias attributed_parameters = AttributedParameterMetadata!Function;

foreach (i, uda; input_attributes) {
enum index = attributed_parameters[i].index;
args[index] = uda.evaluator(m_storedArgs);
}

return dg(args);
}
}
}

Expand Down Expand Up @@ -685,6 +730,36 @@ unittest
assert(result == (1020 + 42 + 1020 + to!int(13.5)) * 2);
}

// testing other prepareInputAndCall overload
unittest
{
import std.conv;

static string evaluator(string left, string right)
{
return left ~ right;
}

// all attribute function must accept same stored parameters
static int modificator(int result, string unused1, string unused2)
{
return result * 2;
}

@before!evaluator("a") @before!evaluator("c") @after!modificator()
static int sum(string a, int b, string c, double d)
{
return to!int(a) + to!int(b) + to!int(c) + to!int(d);
}

auto funcattr = createAttributedFunction!sum("10", "20");

// `a` and `c` are expected to be simply overwritten
int result = funcattr("1000", 42, "1000", 13.5);

assert(result == (1020 + 42 + 1020 + to!int(13.5)) * 2);
}

/**
Syntax sugar in top of AttributedFunction
Expand Down

0 comments on commit 361005b

Please sign in to comment.