1 /** 2 * Copyright: © 2012-2014 Anton Gushcha 3 * License: Subject to the terms of the MIT license, as written in the included LICENSE file. 4 * Authors: NCrashed <ncrashed@gmail.com>, 5 * LeMarwin <lemarwin42@gmail.com>, 6 * Nazgull09 <nazgull90@gmail.com> 7 */ 8 module devol.type; 9 10 import std.array; 11 12 public 13 { 14 import devol.argument; 15 } 16 17 alias Argument delegate(Argument val) ConvertorFunc; 18 19 class ConvAddException : Exception 20 { 21 this(string s, ConvertorFunc conv, Type type) 22 { 23 super(s); 24 eConv = conv; 25 eType = type; 26 } 27 28 ConvertorFunc eConv; 29 Type eType; 30 } 31 32 class ConvException : Exception 33 { 34 this( string s, Type from, Type to) 35 { 36 super(s); 37 eFrom = from; 38 eTo = to; 39 } 40 41 Type eFrom; 42 Type eTo; 43 } 44 45 class Type 46 { 47 this(string name) 48 { 49 sName = name; 50 } 51 52 @property string name() 53 { 54 return sName; 55 } 56 57 Argument getNewArg() 58 { 59 throw new Exception("Pure type isn't allowed to generate args!"); 60 } 61 62 Argument getNewArg(string min, string max, string[] exVal) 63 { 64 throw new Exception("Pure type isn't allowed to generate args!"); 65 } 66 67 void registerConvertor( ConvertorFunc func, Type toType ) 68 { 69 if (toType is null) return; 70 71 if (toType in convs) 72 { 73 throw new ConvAddException("Convertor already exists!", convs[toType], toType); 74 } 75 76 convs[toType] = func; 77 } 78 79 Argument convert(Argument val) 80 { 81 Type type = val.type; 82 83 if(type.name == name ) return val; 84 85 if (this in type.convs) 86 { 87 return type.convs[this](val); 88 } 89 90 auto chain = findConvWay(type); 91 if (chain.empty) 92 { 93 throw new ConvException("Types uncovertable!", type, this); 94 } 95 96 foreach(conv; chain) 97 { 98 val = conv(val); 99 } 100 return val; 101 } 102 103 bool isConvertable(Type from) 104 { 105 if (from.name == name ) return true; 106 107 if (this in from.convs) 108 { 109 return true; 110 } 111 112 auto chain = findConvWay(from); 113 return !chain.empty; 114 } 115 116 private ConvertorFunc[] findConvWay(Type from) 117 { 118 class Node 119 { 120 Node parent; 121 Type type; 122 ConvertorFunc func; 123 } 124 125 Node[] stack = new Node[0]; 126 Type[] blackList = new Type[0]; 127 128 Node prevNode = new Node; 129 prevNode.parent = null; 130 prevNode.func = null; 131 bool finded = false; 132 133 finddo: do 134 { 135 blackList ~= from; 136 foreach(type,conv; from.convs) 137 { 138 Node node = new Node; 139 node.parent = prevNode; 140 node.func = conv; 141 142 bool isInBL(Type t, Type[] bl) 143 { 144 foreach( type; bl) 145 if (t == type) 146 return true; 147 return false; 148 } 149 150 if (!isInBL(type, blackList)) 151 stack ~= node; 152 153 if (type == this) 154 { 155 finded = true; 156 break finddo; 157 } 158 } 159 160 if (!stack.empty) 161 { 162 prevNode = stack[0]; 163 from = prevNode.type; 164 stack = stack[1..$]; 165 } 166 167 } while(!stack.empty); 168 169 auto chain = new ConvertorFunc[0]; 170 if (!finded) 171 return chain; 172 173 auto node = stack[$-1]; 174 while(node.parent !is null) 175 { 176 chain = node.func ~ chain; 177 node = node.parent; 178 } 179 return chain; 180 } 181 182 private ConvertorFunc[Type] convs; 183 private string sName; 184 }