1 /* 2 * Hunt - A high-level D Programming Language Web framework that encourages rapid development and clean, pragmatic design. 3 * 4 * Copyright (C) 2015-2019, HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.framework.view.algo.Wrapper; 13 14 private 15 { 16 import std.algorithm : min; 17 import std.format : fmt = format; 18 import std.functional : toDelegate; 19 import std.traits; 20 import std.typecons : Tuple; 21 import std.string : join; 22 23 import hunt.framework.view.Exception : assertTemplate = assertTemplateException; 24 import hunt.framework.view.Uninode; 25 } 26 27 28 alias Function = UniNode delegate(UniNode); 29 30 31 template wrapper(alias F) 32 if (isSomeFunction!F) 33 { 34 alias ParameterIdents = ParameterIdentifierTuple!F; 35 alias ParameterTypes = Parameters!F; 36 alias ParameterDefs = ParameterDefaults!F; 37 alias RT = ReturnType!F; 38 alias PT = Tuple!ParameterTypes; 39 40 41 Function wrapper() 42 { 43 UniNode func (UniNode params) 44 { 45 assertTemplate(params.kind == UniNode.Kind.object, "Non object params"); 46 assertTemplate(cast(bool)("varargs" in params), "Missing varargs in params"); 47 assertTemplate(cast(bool)("kwargs" in params), "Missing kwargs in params"); 48 49 bool[string] filled; 50 PT args; 51 52 foreach(i, def; ParameterDefs) 53 { 54 alias key = ParameterIdents[i]; 55 static if (key == "varargs") 56 args[i] = UniNode.emptyArray; 57 else static if (key == "kwargs") 58 args[i] = UniNode.emptyObject; 59 else static if (!is(def == void)) 60 args[i] = def; 61 else 62 filled[key] = false; 63 } 64 65 void fillArg(size_t idx, PType)(string key, UniNode val) 66 { 67 // TODO toBoolType, toStringType 68 try 69 args[idx] = val.deserialize!PType; 70 catch 71 assertTemplate(0, "Can't deserialize param `%s` from `%s` to `%s` in function `%s`" 72 .fmt(key, val.kind, PType.stringof, fullyQualifiedName!F)); 73 } 74 75 UniNode varargs = UniNode.emptyArray; 76 UniNode kwargs = UniNode.emptyObject; 77 78 bool isVarargs = false; 79 int varargsFilled = 0; 80 static foreach (int i; 0 .. PT.length) 81 { 82 static if (ParameterIdents[i] == "varargs" || ParameterIdents[i] == "kwargs") 83 { 84 isVarargs = true; 85 } 86 if (params["varargs"].length > i) 87 { 88 if (!isVarargs) 89 { 90 fillArg!(i, ParameterTypes[i])(ParameterIdents[i], params["varargs"][i]); 91 filled[ParameterIdents[i]] = true; 92 } 93 else 94 varargs ~= params["varargs"][i]; 95 varargsFilled++; 96 } 97 } 98 // Filled missed varargs 99 if (varargsFilled < params["varargs"].length) 100 foreach(i; varargsFilled .. params["varargs"].length) 101 varargs ~= params["varargs"][i]; 102 103 bool[string] kwargsFilled; 104 static foreach(i, key; ParameterIdents) 105 { 106 if (key in params["kwargs"]) 107 { 108 fillArg!(i, ParameterTypes[i])(key, params["kwargs"][key]); 109 filled[ParameterIdents[i]] = true; 110 kwargsFilled[key] = true; 111 } 112 } 113 // Filled missed kwargs 114 foreach (string key, ref UniNode val; params["kwargs"]) 115 { 116 if (key !in kwargsFilled) 117 kwargs[key] = val; 118 } 119 120 // Fill varargs/kwargs 121 foreach(i, key; ParameterIdents) 122 { 123 static if (key == "varargs") 124 args[i] = varargs; 125 else static if (key == "kwargs") 126 args[i] = kwargs; 127 } 128 129 string[] missedArgs = []; 130 foreach(key, val; filled) 131 if (!val) 132 missedArgs ~= key; 133 134 if (missedArgs.length) 135 assertTemplate(0, "Missed values for args `%s`".fmt(missedArgs.join(", "))); 136 137 static if (is (RT == void)) 138 { 139 F(args.expand); 140 return UniNode(null); 141 } 142 else 143 { 144 auto ret = F(args.expand); 145 return ret.serialize!RT; 146 } 147 } 148 149 return toDelegate(&func); 150 } 151 }