From bacc4d5e24a993671486c61477f7ec8997fb5f77 Mon Sep 17 00:00:00 2001 From: Dicebot Date: Sun, 7 Oct 2012 03:11:11 +0300 Subject: [PATCH 1/2] Draft of improved parameter/return type generation for method overloading in REST interfaces. Restored from accidently deleted repo :) --- source/vibe/http/rest.d | 122 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 111 insertions(+), 11 deletions(-) diff --git a/source/vibe/http/rest.d b/source/vibe/http/rest.d index 0134c17d29..183336895e 100644 --- a/source/vibe/http/rest.d +++ b/source/vibe/http/rest.d @@ -226,6 +226,8 @@ void registerFormInterface(I)(UrlRouter router, I instance, string url_prefix, */ class RestInterfaceClient(I) : I { + mixin("static import "~(moduleName!I)~";"); + alias void delegate(HttpClientRequest req) RequestFilter; private { Url m_baseUrl; @@ -556,23 +558,117 @@ private @property string generateRestInterfaceMethods(I)() } /// private -private @property string getReturnTypeString(alias F)() +private @property string fullyQualifiedTypename(T)() { - static void testTempl(T)(){ mixin(T.stringof~" x;"); } + string result; + static if ( isBasicType!T ) + { + result = T.stringof; + } + else static if ( isAggregateType!T ) + { + result = fullyQualifiedName!T; + } + else static if ( isArray!T ) + { + result = fullyQualifiedTypename!(typeof(T.init[0])) ~ "[]"; + } + else static if ( isAssociativeArray!T ) + { + result = fullyQualifiedTypename!(ValueType!T) ~ "[" ~ fullyQualifiedTypename!(KeyType!T) ~ "]"; + } + else static if ( isSomeFunction!T ) + { + static assert(0, "Function types currently not supported"); + } + else + static assert(0, "Can't convert type to fully qualified string"); + + static if (is(T == const)) + { + result = "const(" ~ result ~ ")"; + } + static if (is(T == immutable)) + { + result = "immutable(" ~ result ~ ")"; + } + static if (is(T == shared)) + { + result = "shared(" ~ result ~ ")"; + } + + return result; +} + +/// private +// thanks to jerro@newsgroup for this snippet, should really be in phobos :( +private template returnsRef(alias f) +{ + enum bool returnsRef = is(typeof( + { + ParameterTypeTuple!f param; + auto ptr = &f(param); + })); +} + +/// private +private @property string getReturnTypeString(alias F)() +{ alias ReturnType!F T; - static if( is(T == void) || __traits(compiles, testTempl!T) ) - return T.stringof; - else return "ReturnType!(typeof(&BaseInterface."~__traits(identifier, F)~"))"; + static if (returnsRef!F) + return "ref " ~ fullyQualifiedTypename!T; + else + return fullyQualifiedTypename!T; } /// private private @property string getParameterTypeString(alias F, int i)() { - static void testTempl(T)(){ mixin(T.stringof~" x;"); } - alias ParameterTypeTuple!(F)[i] T; - static if( is(T == void) || __traits(compiles, testTempl!T) ) - return T.stringof; - else return "ParameterTypeTuple!(typeof(&BaseInterface."~__traits(identifier, F)~"))["~to!string(i)~"]"; + alias ParameterTypeTuple!(F) T; + alias ParameterStorageClassTuple!(F) storage_classes; + static assert(T.length > i); + static assert(storage_classes.length > i); + + enum is_ref = (storage_classes[i] & ParameterStorageClass.ref_); + enum is_out = (storage_classes[i] & ParameterStorageClass.out_); + enum is_lazy = (storage_classes[i] & ParameterStorageClass.lazy_); + enum is_scope = (storage_classes[i] & ParameterStorageClass.scope_); + + string prefix = ""; + if (is_ref) + prefix = "ref " ~ prefix; + if (is_out) + prefix = "out " ~ prefix; + if (is_lazy) + prefix = "lazy " ~ prefix; + if (is_scope) + prefix = "scope " ~ prefix; + + return prefix ~ fullyQualifiedTypename!(T[i]); +} + +version(unittest) +{ + struct Outer + { + struct Inner + { + } + + ref const(Inner[string]) func( ref Inner var1, lazy scope string var2 ) + { + return data; + } + + const(Inner[string]) data; + } +} + +unittest +{ + static assert(getReturnTypeString!(Outer.func) == "ref const(const(vibe.http.rest.Outer.Inner)[immutable(immutable(char))[]])"); + static assert(getParameterTypeString!(Outer.func, 0) == "ref vibe.http.rest.Outer.Inner"); + static assert(getParameterTypeString!(Outer.func, 1) == "scope lazy immutable(immutable(char))[]"); } /// private @@ -687,6 +783,10 @@ private string skipIdent(string str, ref size_t i) private void skipType(string str, ref size_t i) { + if (str[i..$].startsWith("ref")) { + i += 3; + skipWhitespace(str, i); + } skipIdent(str, i); if( i < str.length && (str[i] == '(' || str[i] == '[') ){ int depth = 1; @@ -748,4 +848,4 @@ private T fromRestString(T)(string value) deserializeJson(ret, parseJson(value)); return ret; } -} \ No newline at end of file +} From 1b83a8f5577a21a0fc65d88f3b28cd85cfd34eb4 Mon Sep 17 00:00:00 2001 From: Dicebot Date: Fri, 12 Oct 2012 01:51:13 +0300 Subject: [PATCH 2/2] More generic stuff, more tests etc. --- source/vibe/http/rest.d | 183 ++++++++++++++++++++++++++-------------- 1 file changed, 121 insertions(+), 62 deletions(-) diff --git a/source/vibe/http/rest.d b/source/vibe/http/rest.d index 183336895e..ec1e0e12d3 100644 --- a/source/vibe/http/rest.d +++ b/source/vibe/http/rest.d @@ -558,50 +558,7 @@ private @property string generateRestInterfaceMethods(I)() } /// private -private @property string fullyQualifiedTypename(T)() -{ - string result; - static if ( isBasicType!T ) - { - result = T.stringof; - } - else static if ( isAggregateType!T ) - { - result = fullyQualifiedName!T; - } - else static if ( isArray!T ) - { - result = fullyQualifiedTypename!(typeof(T.init[0])) ~ "[]"; - } - else static if ( isAssociativeArray!T ) - { - result = fullyQualifiedTypename!(ValueType!T) ~ "[" ~ fullyQualifiedTypename!(KeyType!T) ~ "]"; - } - else static if ( isSomeFunction!T ) - { - static assert(0, "Function types currently not supported"); - } - else - static assert(0, "Can't convert type to fully qualified string"); - - static if (is(T == const)) - { - result = "const(" ~ result ~ ")"; - } - static if (is(T == immutable)) - { - result = "immutable(" ~ result ~ ")"; - } - static if (is(T == shared)) - { - result = "shared(" ~ result ~ ")"; - } - - return result; -} - -/// private -// thanks to jerro@newsgroup for this snippet, should really be in phobos :( +// https://github.com/D-Programming-Language/phobos/pull/862 private template returnsRef(alias f) { enum bool returnsRef = is(typeof( @@ -615,7 +572,7 @@ private template returnsRef(alias f) private @property string getReturnTypeString(alias F)() { alias ReturnType!F T; - static if (returnsRef!F) + static if (returnsRef!F) return "ref " ~ fullyQualifiedTypename!T; else return fullyQualifiedTypename!T; @@ -647,28 +604,130 @@ private @property string getParameterTypeString(alias F, int i)() return prefix ~ fullyQualifiedTypename!(T[i]); } -version(unittest) +/// private +private template fullyQualifiedTypeNameImpl(T, + bool already_const, bool already_immutable, bool already_shared) { - struct Outer - { - struct Inner - { - } - - ref const(Inner[string]) func( ref Inner var1, lazy scope string var2 ) - { - return data; - } + import std.typetuple; + + // Convinience tags + enum { + _const = 0, + _immutable = 1, + _shared = 2 + } + + alias TypeTuple!(is(T == const), is(T == immutable), is(T == shared)) qualifiers; + alias TypeTuple!(false, false, false) no_qualifiers; + + template parametersTypeString(T) + { + import std.array; + import std.algorithm; + + alias ParameterTypeTuple!(T) parameters; + enum parametersTypeString = join([staticMap!(fullyQualifiedTypeName, parameters)], ", "); + } + + template addQualifiers(string type_string, + bool add_const, bool add_immutable, bool add_shared) + { + static if (add_const) + enum addQualifiers = addQualifiers!("const(" ~ type_string ~ ")", + false, add_immutable, add_shared); + else static if (add_immutable) + enum addQualifiers = addQualifiers!("immutable(" ~ type_string ~ ")", + add_const, false, add_shared); + else static if (add_shared) + enum addQualifiers = addQualifiers!("shared(" ~ type_string ~ ")", + add_const, add_immutable, false); + else + enum addQualifiers = type_string; + } + + // Convenience template to avoid copy-paste + template chain(string current) + { + enum chain = addQualifiers!(current, + qualifiers[_const] && !already_const, + qualifiers[_immutable] && !already_immutable, + qualifiers[_shared] && !already_shared); + } + + static if (isBasicType!T) + { + enum fullyQualifiedTypeNameImpl = chain!((Unqual!T).stringof); + } + else static if (isAggregateType!T) + { + enum fullyQualifiedTypeNameImpl = chain!(fullyQualifiedName!T); + } + else static if (isArray!T) + { + enum fullyQualifiedTypeNameImpl = chain!( + fullyQualifiedTypeNameImpl!(typeof(T.init[0]), qualifiers ) ~ "[]" + ); + } + else static if (isAssociativeArray!T) + { + enum fullyQualifiedTypeNameImpl = chain!( + fullyQualifiedTypeNameImpl!(ValueType!T, qualifiers) + ~ "[" + ~ fullyQualifiedTypeNameImpl!(KeyType!T, qualifiers) + ~ "]" + ); + } + else static if (isSomeFunction!T) + { + enum fullyQualifiedTypeNameImpl = chain!( + fullyQualifiedTypeNameImpl!(ReturnType!T, no_qualifiers) + ~ "(" + ~ parametersTypeString!(T) + ~ ")" + ); + } + else + // In case something is forgotten + static assert(0, "Unrecognized type" ~ T.stringof ~ ", can't convert to fully qualified string"); +} - const(Inner[string]) data; - } +/// private +// https://github.com/D-Programming-Language/phobos/pull/863 +private template fullyQualifiedTypeName(T) +{ + static assert(is(T), "Template parameter must be a type"); + enum fullyQualifiedTypeName = fullyQualifiedTypeNameImpl!(T, false, false, false); +} + +version(unittest) +{ + struct QualifiedNameTests + { + struct Inner + { + } + + ref const(Inner[string]) func( ref Inner var1, lazy scope string var2 ); + + shared(const(Inner[string])[]) data; + + Inner delegate(double, string) deleg; + } } unittest -{ - static assert(getReturnTypeString!(Outer.func) == "ref const(const(vibe.http.rest.Outer.Inner)[immutable(immutable(char))[]])"); - static assert(getParameterTypeString!(Outer.func, 0) == "ref vibe.http.rest.Outer.Inner"); - static assert(getParameterTypeString!(Outer.func, 1) == "scope lazy immutable(immutable(char))[]"); +{ + static assert(fullyQualifiedTypeName!(string) == "immutable(char)[]"); + static assert(fullyQualifiedTypeName!(QualifiedNameTests.Inner) + == "vibe.http.rest.QualifiedNameTests.Inner"); + static assert(fullyQualifiedTypeName!(ReturnType!(QualifiedNameTests.func)) + == "const(vibe.http.rest.QualifiedNameTests.Inner[immutable(char)[]])"); + static assert(fullyQualifiedTypeName!(typeof(QualifiedNameTests.func)) + == "const(vibe.http.rest.QualifiedNameTests.Inner[immutable(char)[]])(vibe.http.rest.QualifiedNameTests.Inner, immutable(char)[])"); + static assert(fullyQualifiedTypeName!(typeof(QualifiedNameTests.data)) + == "shared(const(vibe.http.rest.QualifiedNameTests.Inner[immutable(char)[]])[])"); + static assert(fullyQualifiedTypeName!(typeof(QualifiedNameTests.deleg)) + == "vibe.http.rest.QualifiedNameTests.Inner(double, immutable(char)[])"); } /// private