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 import devol.serializable; 12 import devol.typemng; 13 14 import dyaml.all; 15 16 public 17 { 18 import devol.argument; 19 } 20 21 alias Argument delegate(Argument val) ConvertorFunc; 22 23 class ConvAddException : Exception 24 { 25 this(string s, ConvertorFunc conv, Type type) 26 { 27 super(s); 28 eConv = conv; 29 eType = type; 30 } 31 32 ConvertorFunc eConv; 33 Type eType; 34 } 35 36 class ConvException : Exception 37 { 38 this( string s, Type from, Type to) 39 { 40 super(s); 41 eFrom = from; 42 eTo = to; 43 } 44 45 Type eFrom; 46 Type eTo; 47 } 48 49 abstract class Type : ISerializable 50 { 51 this(string name) 52 { 53 sName = name; 54 } 55 56 @property string name() 57 { 58 return sName; 59 } 60 61 Argument getNewArg() 62 { 63 throw new Exception("Pure type isn't allowed to generate args!"); 64 } 65 66 Argument getNewArg(string min, string max, string[] exVal) 67 { 68 throw new Exception("Pure type isn't allowed to generate args!"); 69 } 70 71 void registerConvertor( ConvertorFunc func, Type toType ) 72 { 73 if (toType is null) return; 74 75 if (toType in convs) 76 { 77 throw new ConvAddException("Convertor already exists!", convs[toType], toType); 78 } 79 80 convs[toType] = func; 81 } 82 83 Argument convert(Argument val) 84 { 85 Type type = val.type; 86 87 if(type.name == name ) return val; 88 89 if (this in type.convs) 90 { 91 return type.convs[this](val); 92 } 93 94 auto chain = findConvWay(type); 95 if (chain.empty) 96 { 97 throw new ConvException("Types uncovertable!", type, this); 98 } 99 100 foreach(conv; chain) 101 { 102 val = conv(val); 103 } 104 return val; 105 } 106 107 bool isConvertable(Type from) 108 { 109 if (from.name == name ) return true; 110 111 if (this in from.convs) 112 { 113 return true; 114 } 115 116 auto chain = findConvWay(from); 117 return !chain.empty; 118 } 119 120 private ConvertorFunc[] findConvWay(Type from) 121 { 122 class Node 123 { 124 Node parent; 125 Type type; 126 ConvertorFunc func; 127 } 128 129 Node[] stack = new Node[0]; 130 Type[] blackList = new Type[0]; 131 132 Node prevNode = new Node; 133 prevNode.parent = null; 134 prevNode.func = null; 135 bool finded = false; 136 137 finddo: do 138 { 139 blackList ~= from; 140 foreach(type,conv; from.convs) 141 { 142 Node node = new Node; 143 node.parent = prevNode; 144 node.func = conv; 145 146 bool isInBL(Type t, Type[] bl) 147 { 148 foreach( type; bl) 149 if (t == type) 150 return true; 151 return false; 152 } 153 154 if (!isInBL(type, blackList)) 155 stack ~= node; 156 157 if (type == this) 158 { 159 finded = true; 160 break finddo; 161 } 162 } 163 164 if (!stack.empty) 165 { 166 prevNode = stack[0]; 167 from = prevNode.type; 168 stack = stack[1..$]; 169 } 170 171 } while(!stack.empty); 172 173 auto chain = new ConvertorFunc[0]; 174 if (!finded) 175 return chain; 176 177 auto node = stack[$-1]; 178 while(node.parent !is null) 179 { 180 chain = node.func ~ chain; 181 node = node.parent; 182 } 183 return chain; 184 } 185 186 static Type loadBinary(InputStream stream) 187 { 188 char[] typename; 189 stream.read(typename); 190 191 return TypeMng.getSingleton().getType(typename.idup); 192 } 193 194 static Type loadYaml(Node node) 195 { 196 return TypeMng.getSingleton().getType(node.as!string); 197 } 198 199 /// Loading argument from input stream 200 /** 201 * Should be defined by all childs. 202 */ 203 Argument loadArgument(InputStream stream); 204 205 /// Loading argument from input stream 206 /** 207 * Should be defined by all childs. 208 */ 209 Argument loadArgument(Node node); 210 211 void saveBinary(OutputStream stream) 212 { 213 stream.write(sName); 214 } 215 216 Node saveYaml() 217 { 218 return Node(sName); 219 } 220 221 private ConvertorFunc[Type] convs; 222 private string sName; 223 }