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 (Exception ex) { 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 76 UniNode varargs = UniNode.emptyArray; 77 UniNode kwargs = UniNode.emptyObject; 78 79 bool isVarargs = false; 80 int varargsFilled = 0; 81 static foreach (int i; 0 .. PT.length) 82 { 83 static if (ParameterIdents[i] == "varargs" || ParameterIdents[i] == "kwargs") 84 { 85 isVarargs = true; 86 } 87 if (params["varargs"].length > i) 88 { 89 if (!isVarargs) 90 { 91 fillArg!(i, ParameterTypes[i])(ParameterIdents[i], params["varargs"][i]); 92 filled[ParameterIdents[i]] = true; 93 } 94 else 95 varargs ~= params["varargs"][i]; 96 varargsFilled++; 97 } 98 } 99 // Filled missed varargs 100 if (varargsFilled < params["varargs"].length) 101 foreach(i; varargsFilled .. params["varargs"].length) 102 varargs ~= params["varargs"][i]; 103 104 bool[string] kwargsFilled; 105 static foreach(i, key; ParameterIdents) 106 { 107 if (key in params["kwargs"]) 108 { 109 fillArg!(i, ParameterTypes[i])(key, params["kwargs"][key]); 110 filled[ParameterIdents[i]] = true; 111 kwargsFilled[key] = true; 112 } 113 } 114 // Filled missed kwargs 115 foreach (string key, ref UniNode val; params["kwargs"]) 116 { 117 if (key !in kwargsFilled) 118 kwargs[key] = val; 119 } 120 121 // Fill varargs/kwargs 122 foreach(i, key; ParameterIdents) 123 { 124 static if (key == "varargs") 125 args[i] = varargs; 126 else static if (key == "kwargs") 127 args[i] = kwargs; 128 } 129 130 string[] missedArgs = []; 131 foreach(key, val; filled) 132 if (!val) 133 missedArgs ~= key; 134 135 if (missedArgs.length) 136 assertTemplate(0, "Missed values for args `%s`".fmt(missedArgs.join(", "))); 137 138 static if (is (RT == void)) 139 { 140 F(args.expand); 141 return UniNode(null); 142 } 143 else 144 { 145 auto ret = F(args.expand); 146 return ret.serialize!RT; 147 } 148 } 149 150 return toDelegate(&func); 151 } 152 }