1 /**
2  * This module provides a templated function that performs value-preserving
3  * conversions between arbitrary types.  This function's behaviour can be
4  * extended for user-defined types as needed.
5  *
6  * Copyright:   Copyright © 2007 Daniel Keep.
7  * License:     BSD style: $(LICENSE)
8  * Authors:     Daniel Keep
9  * Credits:     Inspired in part by Andrei Alexandrescu's work on std.conv.
10  */
11 
12 module tango.util.Convert;
13 
14 private import tango.core.Exception;
15 private import tango.core.Traits;
16 private import tango.core.Tuple : Tuple;
17 
18 private import tango.math.Math;
19 private import tango.text.convert.Utf;
20 private import tango.text.convert.Float;
21 private import tango.text.convert.Integer;
22 
23 private import Ascii = tango.text.Ascii;
24 
25 version( TangoDoc )
26 {
27     /**
28      * Attempts to perform a value-preserving conversion of the given value
29      * from type S to type D.  If the conversion cannot be performed in any
30      * context, a compile-time error will be issued describing the types
31      * involved.  If the conversion fails at run-time because the destination
32      * type could not represent the value being converted, a
33      * ConversionException will be thrown.
34      *
35      * For example, to convert the string "123" into an equivalent integer
36      * value, you would use:
37      *
38      * -----
39      * auto v = to!(int)("123");
40      * -----
41      *
42      * You may also specify a default value which should be returned in the
43      * event that the conversion cannot take place:
44      *
45      * -----
46      * auto v = to!(int)("abc", 456);
47      * -----
48      *
49      * The function will attempt to preserve the input value as exactly as
50      * possible, given the limitations of the destination format.  For
51      * instance, converting a floating-point value to an integer will cause it
52      * to round the value to the nearest integer value.
53      *
54      * Below is a complete list of conversions between built-in types and
55      * strings.  Capitalised names indicate classes of types.  Conversions
56      * between types in the same class are also possible.
57      *
58      * -----
59      * bool         <-- Integer (0/!0), Char ('t'/'f'), String ("true"/"false")
60      * Integer      <-- bool, Real, Char ('0'-'9'), String
61      * Real         <-- Integer, String
62      * Imaginary    <-- Complex
63      * Complex      <-- Integer, Real, Imaginary
64      * Char         <-- bool, Integer (0-9)
65      * String       <-- bool, Integer, Real, Char
66      * -----
67      *
68      * Conversions between arrays and associative arrays are also supported,
69      * and are done element-by-element.
70      *
71      * You can add support for value conversions to your types by defining
72      * appropriate static and instance member functions.  Given a type
73      * the_type, any of the following members of a type T may be used:
74      *
75      * -----
76      * the_type to_the_type();
77      * static T from_the_type(the_type);
78      * -----
79      *
80      * You may also use "camel case" names:
81      *
82      * -----
83      * the_type toTheType();
84      * static T fromTheType(the_type);
85      * -----
86      *
87      * Arrays and associative arrays can also be explicitly supported:
88      *
89      * -----
90      * the_type[] to_the_type_array();
91      * the_type[] toTheTypeArray();
92      *
93      * static T from_the_type_array(the_type[]);
94      * static T fromTheTypeArray(the_type[]);
95      *
96      * the_type[int] to_int_to_the_type_map();
97      * the_type[int] toIntToTheTypeMap();
98      *
99      * static T from_int_to_the_type_map(the_type[int]);
100      * static T fromIntToTheTypeMap(the_type[int]);
101      * -----
102      *
103      * If you have more complex requirements, you can also use the generic to
104      * and from templated members:
105      *
106      * -----
107      * the_type to(the_type)();
108      * static T from(the_type)(the_type);
109      * -----
110      *
111      * These templates will have the_type explicitly passed to them in the
112      * template instantiation.
113      *
114      * Finally, strings are given special support.  The following members will
115      * be checked for:
116      *
117      * -----
118      * char[]  toString();
119      * wchar[] toString16();
120      * dchar[] toString32();
121      * char[]  toString();
122      * -----
123      *
124      * The "toString_" method corresponding to the destination string type will be
125      * tried first.  If this method does not exist, then the function will
126      * look for another "toString_" method from which it will convert the result.
127      * Failing this, it will try "toString" and convert the result to the
128      * appropriate encoding.
129      *
130      * The rules for converting to a user-defined type are much the same,
131      * except it makes use of the "fromUtf8", "fromUtf16", "fromUtf32" and
132      * "fromString" static methods.
133      *
134      * Note: This module contains imports to other Tango modules that needs
135      * semantic analysis to be discovered. If your build tool doesn't do this
136      * properly, causing compile or link time problems, import the relevant
137      * module explicitly.
138      */
139     D to(D,S)(S value);
140     D to(D,S)(S value, D default_); /// ditto
141 }
142 else
143 {
144     D to(D, S)(S value)
145     {
146         return toImpl!(D,S)(value);
147     }
148     
149     D to(D, S, Def)(S value, Def def=Def.init)
150     {
151         try
152         {
153             return toImpl!(D,S)(value);
154         }
155         catch( ConversionException e )
156             {}
157 
158         return def;
159     }
160 }
161 
162 /**
163  * This exception is thrown when the to template is unable to perform a
164  * conversion at run-time.  This typically occurs when the source value cannot
165  * be represented in the destination type.  This exception is also thrown when
166  * the conversion would cause an over- or underflow.
167  */
168 class ConversionException : Exception
169 {
170     this( immutable(char)[] msg )
171     {
172         super( msg );
173     }
174 }
175 
176 private:
177 
178 /*
179  * So, how is this module structured?
180  *
181  * Firstly, we need a bunch of support code.  The first block of this contains
182  * some CTFE functions for string manipulation (to cut down on the number of
183  * template symbols we generate.)
184  *
185  * The next contains a boat-load of templates.  Most of these are trait
186  * templates (things like isPOD, isObject, etc.)  There are also a number of
187  * mixins, and some switching templates (like toString_(n).)
188  *
189  * Another thing to mention is intCmp, which performs a safe comparison
190  * between two integers of arbitrary size and signage.
191  *
192  * Following all this are the templated to* implementations.
193  *
194  * The actual toImpl template is the second last thing in the module, with the
195  * module unit tests coming last.
196  */
197 
198 char ctfe_upper(char c)
199 {
200     if( 'a' <= c && c <= 'z' )
201         return cast(char)((c - 'a') + 'A');
202     else
203         return c;
204 }
205 
206 char[] ctfe_camelCase(const(char[]) s)
207 {
208     char[] result;
209 
210     bool nextIsCapital = true;
211 
212     foreach( c ; s )
213     {
214         if( nextIsCapital )
215         {
216             if( c == '_' )
217                 result ~= c;
218             else
219             {
220                 result ~= ctfe_upper(c);
221                 nextIsCapital = false;
222             }
223         }
224         else
225         {
226             if( c == '_' )
227                 nextIsCapital = true;
228             else
229                 result ~= c;
230         }
231     }
232 
233     return result;
234 }
235 
236 bool ctfe_isSpace(T)(T c)
237 {
238     static if (T.sizeof is 1)
239         return (c <= 32 && (c is ' ' || c is '\t' || c is '\r'
240                     || c is '\n' || c is '\v' || c is '\f'));
241     else
242         return (c <= 32 && (c is ' ' || c is '\t' || c is '\r'
243                     || c is '\n' || c is '\v' || c is '\f'))
244             || (c is '\u2028' || c is '\u2029');
245 }
246 
247 T[] ctfe_triml(T)(T[] source)
248 {
249     if( source.length == 0 )
250         return null;
251 
252     foreach( i,c ; source )
253         if( !ctfe_isSpace(c) )
254             return source[i..$];
255 
256     return null;
257 }
258 
259 T[] ctfe_trimr(T)(T[] source)
260 {
261     if( source.length == 0 )
262         return null;
263 
264     foreach_reverse( i,c ; source )
265         if( !ctfe_isSpace(c) )
266             return source[0..i+1];
267 
268     return null;
269 }
270 
271 T[] ctfe_trim(T)(T[] source)
272 {
273     return ctfe_trimr(ctfe_triml(source));
274 }
275 
276 template isPOD(T)
277 {
278     static if( is( T == struct ) || is( T == union ) )
279         enum isPOD = true;
280     else
281         enum isPOD = false;
282 }
283 
284 template isObject(T)
285 {
286     static if( is( T == class ) || is( T == interface ) )
287         enum isObject = true;
288     else
289         enum isObject = false;
290 }
291 
292 template isUDT(T)
293 {
294     enum isUDT = isPOD!(T) || isObject!(T);
295 }
296 
297 template isString(T)
298 {
299     static if( is( T : const(char[]) )
300             || is( T : const(wchar[]) )
301             || is( T : const(dchar[]) ) )
302         enum isString = true;
303     else
304         enum isString = false;
305 }
306 
307 static assert(isString!(string));
308 
309 template isMutableString(T)
310 {
311     static if( is( T == char[] )
312             || is( T == wchar[] )
313             || is( T == dchar[] ) )
314         enum isMutableString = true;
315     else
316         enum isMutableString = false;
317 }
318 
319 template isImmutableString(T)
320 {
321     static if( is( T == immutable(char)[] )
322             || is( T == immutable(wchar)[] )
323             || is( T == immutable(dchar)[] ) )
324         enum isImmutableString = true;
325     else
326         enum isImmutableString = false;
327 }
328 
329 template isArrayType(T)
330 {
331     enum isArrayType = isDynamicArrayType!(T) || isStaticArrayType!(T);
332 }
333 
334 /*
335  * Determines which signed integer type of T and U is larger.
336  */
337 template sintSuperType(T,U)
338 {
339     static if( is( T == long ) || is( U == long ) )
340         alias long sintSuperType;
341     else static if( is( T == int ) || is( U == int ) )
342         alias int sintSuperType;
343     else static if( is( T == short ) || is( U == short ) )
344         alias short sintSuperType;
345     else static if( is( T == byte ) || is( U == byte ) )
346         alias byte sintSuperType;
347 }
348 
349 /*
350  * Determines which unsigned integer type of T and U is larger.
351  */
352 template uintSuperType(T,U)
353 {
354     static if( is( T == ulong ) || is( U == ulong ) )
355         alias ulong uintSuperType;
356     else static if( is( T == uint ) || is( U == uint ) )
357         alias uint uintSuperType;
358     else static if( is( T == ushort ) || is( U == ushort ) )
359         alias ushort uintSuperType;
360     else static if( is( T == ubyte ) || is( U == ubyte ) )
361         alias ubyte uintSuperType;
362 }
363 
364 template uintOfSize(uint bytes)
365 {
366     static if( bytes == 1 )
367         alias ubyte uintOfSize;
368     else static if( bytes == 2 )
369         alias ushort uintOfSize;
370     else static if( bytes == 4 )
371         alias uint uintOfSize;
372 }
373 
374 /*
375  * Safely performs a comparison between two integer values, taking into
376  * account different sizes and signages.
377  */
378 int intCmp(T,U)(T lhs, U rhs)
379 {
380     static if( isSignedIntegerType!(T) && isSignedIntegerType!(U) )
381     {
382         alias sintSuperType!(T,U) S;
383         auto l = cast(S) lhs;
384         auto r = cast(S) rhs;
385         if( l < r ) return -1;
386         else if( l > r ) return 1;
387         else return 0;
388     }
389     else static if( isUnsignedIntegerType!(T) && isUnsignedIntegerType!(U) )
390     {
391         alias uintSuperType!(T,U) S;
392         auto l = cast(S) lhs;
393         auto r = cast(S) rhs;
394         if( l < r ) return -1;
395         else if( l > r ) return 1;
396         else return 0;
397     }
398     else
399     {
400         static if( isSignedIntegerType!(T) )
401         {
402             if( lhs < 0 )
403                 return -1;
404             else
405             {
406                 static if( U.sizeof >= T.sizeof )
407                 {
408                     auto l = cast(U) lhs;
409                     if( l < rhs ) return -1;
410                     else if( l > rhs ) return 1;
411                     else return 0;
412                 }
413                 else
414                 {
415                     auto l = cast(ulong) lhs;
416                     auto r = cast(ulong) rhs;
417                     if( l < r ) return -1;
418                     else if( l > r ) return 1;
419                     else return 0;
420                 }
421             }
422         }
423         else static if( isSignedIntegerType!(U) )
424         {
425             if( rhs < 0 )
426                 return 1;
427             else
428             {
429                 static if( T.sizeof >= U.sizeof )
430                 {
431                     auto r = cast(T) rhs;
432                     if( lhs < r ) return -1;
433                     else if( lhs > r ) return 1;
434                     else return 0;
435                 }
436                 else
437                 {
438                     auto l = cast(ulong) lhs;
439                     auto r = cast(ulong) rhs;
440                     if( l < r ) return -1;
441                     else if( l > r ) return 1;
442                     else return 0;
443                 }
444             }
445         }
446     }
447 }
448 
449 template unsupported(immutable(char)[] desc="")
450 {
451     static assert(false, "Unsupported conversion: cannot convert to "
452             ~ctfe_trim(D.stringof)~" from "
453             ~(desc!="" ? desc~" " : "")~ctfe_trim(S.stringof)~".");
454 }
455 
456 template unsupported_backwards(immutable(char)[] desc="")
457 {
458     static assert(false, "Unsupported conversion: cannot convert to "
459             ~(desc!="" ? desc~" " : "")~ctfe_trim(D.stringof)
460             ~" from "~ctfe_trim(S.stringof)~".");
461 }
462 
463 // TN works out the c_case name of the given type.
464 template TN(T:const(T[]))
465 {
466     static if( is( T == char ) )
467         enum TN = "string";
468     else static if( is( T == wchar ) )
469         enum TN = "wstring";
470     else static if( is( T == dchar ) )
471         enum TN = "dstring";
472     else
473         enum TN = TN!(T)~"_array";
474 }
475 
476 // ditto
477 template TN(T:T*)
478 {
479     enum TN = TN!(T)~"_pointer";
480 }
481 
482 // ditto
483 template TN(T)
484 {
485     static if( isAssocArrayType!(T) )
486         enum TN = TN!(typeof(T.keys[0]))~"_to_"
487             ~TN!(typeof(T.values[0]))~"_map";
488     else
489         enum TN = ctfe_trim(T.stringof);
490 }
491 
492 // Takes care of converting between mutable and immutable strings
493 D convertString_(D, C)(C[] ret)
494 {
495     static if(isImmutableString!(C))
496     {
497         static if(isMutableString!(D))
498             return cast(D) ret.dup;
499         else
500             return cast(D) ret;
501     }
502     else
503     {
504         static if(isImmutableString!(D))
505             return cast(D) ret.idup;
506         else
507             return cast(D) ret;
508     }
509 }
510 
511 // Picks an appropriate toString* method from t.text.convert.Utf.
512 T toString_(T, C)(C[] str)
513 {
514     static if( is( T : const(char[]) ) )
515         return convertString_!(T)(tango.text.convert.Utf.toString(str));
516 
517     else static if( is( T : const(wchar[]) ) )
518         return convertString_!(T)(tango.text.convert.Utf.toString16(str));
519 
520     else
521         return convertString_!(T)(tango.text.convert.Utf.toString32(str));
522 }
523 
524 template UtfNum(T)
525 {
526     enum UtfNum = is(ElementTypeOfArray!(T) : const(char)) ? "8" : (
527             is(ElementTypeOfArray!(T) : const(wchar)) ? "16" : "32");
528 }
529 
530 template StringNum(T)
531 {
532     enum StringNum = is(ElementTypeOfArray!(T) : const(char)) ? "" : (
533             is(ElementTypeOfArray!(T) : const(wchar)) ? "16" : "32");
534 }
535 
536 // Decodes a single dchar character from a string.  Yes, I know they're
537 // actually code points, but I can't be bothered to type that much.  Although
538 // I suppose I just typed MORE than that by writing this comment.  Meh.
539 dchar firstCharOf(T)(T s, out size_t used)
540 {
541     static if( is( T : const(char[]) ) || is( T : const(wchar[]) ) )
542     {
543         return tango.text.convert.Utf.decode(s, used);
544     }
545     else
546     {
547         used = 1;
548         return s[0];
549     }
550 }
551 
552 // This mixin defines a general function for converting to a UDT.
553 template toUDT()
554 {
555     D toDfromS()
556     {
557         static if( isString!(S) )
558         {
559             static if( is( typeof(mixin("D.fromUtf"
560                                 ~UtfNum!(S)~"(value)")) : D ) )
561                 return mixin("D.fromUtf"~UtfNum!(S)~"(value)");
562 
563             else static if( is( typeof(D.fromUtf8(""c)) : D ) )
564                 return D.fromUtf8(toString_!(char[])(value));
565 
566             else static if( is( typeof(D.fromUtf16(""w)) : D ) )
567                 return D.fromUtf16(toString_!(wchar[])(value));
568 
569             else static if( is( typeof(D.fromUtf32(""d)) : D ) )
570                 return D.fromUtf32(toString_!(dchar[])(value));
571 
572             else static if( is( typeof(D.fromString(""c)) : D ) )
573             {
574                 static if( is( S == char[] ) )
575                     return D.fromString(value);
576 
577                 else
578                     return D.fromString(toString_!(char[])(value));
579             }
580 
581             // Default fallbacks
582 
583             else static if( is( typeof(D.from!(S)(value)) : D ) )
584                 return D.from!(S)(value);
585 
586             else
587                 mixin unsupported!("user-defined type");
588         }
589         else
590         {
591             // TODO: Check for templates.  Dunno what to do about them.
592 
593             static if( is( typeof(mixin("D.from_"~TN!(S)~"()")) : D ) )
594                 return mixin("D.from_"~TN!(S)~"()");
595 
596             else static if( is( typeof(mixin("D.from"
597                                 ~ctfe_camelCase(TN!(S))~"()")) : D ) )
598                 return mixin("D.from"~ctfe_camelCase(TN!(S))~"()");
599 
600             else static if( is( typeof(D.from!(S)(value)) : D ) )
601                 return D.from!(S)(value);
602 
603             else
604                 mixin unsupported!("user-defined type");
605         }
606     }
607 }
608 
609 // This mixin defines a general function for converting from a UDT.
610 template fromUDT(immutable(char)[] fallthrough="")
611 {
612     D toDfromS()
613     {
614         static if( isString!(D) )
615         {
616             static if( is( typeof(convertString_!(D)(mixin("value.toString"
617                                 ~StringNum!(D)~"()"))) : D ) )
618                 return convertString_!(D)(mixin("value.toString"~StringNum!(D)~"()"));
619 
620             else static if( is( typeof(value.toString()) : const(char[]) ) )
621                 return toString_!(D)(value.toString());
622 
623             else static if( is( typeof(value.toString16()) : const(wchar[]) ) )
624                 return toString_!(D)(value.toString16);
625 
626             else static if( is( typeof(value.toString32()) : const(dchar[]) ) )
627                 return toString_!(D)(value.toString32);
628 
629             else static if( is( typeof(value.toString()) : const(char[]) ) )
630             {
631                 static if( is( D : const(char[]) ) )
632                     return value.toString();
633 
634                 else
635                 {
636                     return toString_!(D)(value.toString());
637                 }
638             }
639 
640             // Default fallbacks
641 
642             else static if( is( typeof(value.to!(D)()) : D ) )
643                 return value.to!(D)();
644 
645             else static if( fallthrough != "" )
646                 mixin(fallthrough);
647 
648             else
649                 mixin unsupported!("user-defined type");
650         }
651         else
652         {
653             // TODO: Check for templates.  Dunno what to do about them.
654 
655             static if( is( typeof(mixin("value.to_"~TN!(D)~"()")) : D ) )
656                 return mixin("value.to_"~TN!(D)~"()");
657 
658             else static if( is( typeof(mixin("value.to"
659                                 ~ctfe_camelCase(TN!(D))~"()")) : D ) )
660                 return mixin("value.to"~ctfe_camelCase(TN!(D))~"()");
661 
662             else static if( is( typeof(value.to!(D)()) : D ) )
663                 return value.to!(D)();
664 
665             else static if( fallthrough != "" )
666                 mixin(fallthrough);
667 
668             else
669                 mixin unsupported!("user-defined type");
670         }
671     }
672 }
673 
674 template convError()
675 {
676     void throwConvError()
677     {
678         // Since we're going to use to!(T) to convert the value to a string,
679         // we need to make sure we don't end up in a loop...
680         static if( isString!(D) || !is( typeof(to!(immutable(char)[])(value)) == immutable(char)[] ) )
681         {
682             throw new ConversionException("Could not convert a value of type "
683                     ~S.stringof~" to type "~D.stringof~".");
684         }
685         else
686         {
687             throw new ConversionException("Could not convert `"
688                     ~to!(immutable(char)[])(value)~"` of type "
689                     ~S.stringof~" to type "~D.stringof~".");
690         }
691     }
692 }
693 
694 D toBool(D,S)(S value)
695 {
696     static assert(is(D==bool));
697 
698     static if( isIntegerType!(S) /+|| isRealType!(S) || isImaginaryType!(S)
699                 || isComplexType!(S)+/ )
700         // The weird comparison is to support NaN as true
701         return !(value == 0);
702 
703     else static if( isCharType!(S) )
704     {
705         switch( value )
706         {
707             case 'F': case 'f':
708                 return false;
709 
710             case 'T': case 't':
711                 return true;
712 
713             default:
714                 mixin convError;
715                 throwConvError();
716                 assert(0);
717         }
718     }
719 
720     else static if( isString!(S) )
721     {
722         if(value.length == 5 || value.length == 4)
723         {
724             char[5] buf;
725             buf[0..value.length] = value[];
726             switch( Ascii.toLower(buf[0..value.length]) )
727             {
728                 case "false":
729                     return false;
730 
731                 case "true":
732                     return true;
733 
734                 default:
735             }
736         }
737         mixin convError;
738         throwConvError();
739         assert(0);
740     }
741     /+
742     else static if( isDynamicArrayType!(S) || isStaticArrayType!(S) )
743     {
744         mixin unsupported!("array type");
745     }
746     else static if( isAssocArrayType!(S) )
747     {
748         mixin unsupported!("associative array type");
749     }
750     else static if( isPointerType!(S) )
751     {
752         mixin unsupported!("pointer type");
753     }
754     else static if( is( S == alias ) )
755     {
756         mixin unsupported!("alias'ed type");
757     }
758     // +/
759     else static if( isPOD!(S) || isObject!(S) )
760     {
761         mixin fromUDT;
762         return toDfromS();
763     }
764     else
765     {
766         mixin unsupported;
767     }
768 }
769 
770 D toIntegerFromInteger(D,S)(S value)
771 {
772     static if( (cast(ulong) D.max) < (cast(ulong) S.max)
773             || (cast(long) D.min) > (cast(long) S.min) )
774     {
775         mixin convError; // TODO: Overflow error
776 
777         if( intCmp(value,D.min)<0 || intCmp(value,D.max)>0 )
778         {
779             throwConvError();
780         }
781     }
782     return cast(D) value;
783 }
784 
785 D toIntegerFromReal(D,S)(S value)
786 {
787     auto v = tango.math.Math.round(value);
788     if( (cast(real) D.min) <= v && v <= (cast(real) D.max) )
789     {
790         return cast(D) v;
791     }
792     else
793     {
794         mixin convError; // TODO: Overflow error
795         throwConvError();
796         assert(0);
797     }
798 }
799 
800 D toIntegerFromString(D,S)(S value)
801 {
802     static if( is( S charT : charT[] ) )
803     {
804         mixin convError;
805 
806         static if( is( D == ulong ) )
807         {
808             // Check for sign
809             S s = value;
810 
811             if( s.length == 0 )
812                 throwConvError();
813 
814             else if( s[0] == '-' )
815                 throwConvError();
816 
817             else if( s[0] == '+' )
818                 s = s[1..$];
819 
820             size_t len;
821             auto result = tango.text.convert.Integer.convert(s, 10, &len);
822 
823             if( len < s.length || len == 0 )
824                 throwConvError();
825 
826             return result;
827         }
828         else
829         {
830             size_t len;
831             auto result = tango.text.convert.Integer.parse(value, 10, &len);
832 
833             if( len < value.length || len == 0 )
834                 throwConvError();
835 
836             return toIntegerFromInteger!(D,long)(result);
837         }
838     }
839 }
840 
841 D toInteger(D,S)(S value)
842 {
843     static if( is( S == bool ) )
844         return (value ? 1 : 0);
845 
846     else static if( isIntegerType!(S) )
847     {
848         return toIntegerFromInteger!(D,S)(value);
849     }
850     else static if( isCharType!(S) )
851     {
852         if( value >= '0' && value <= '9' )
853         {
854             return cast(D)(value - '0');
855         }
856         else
857         {
858             mixin convError;
859             throwConvError();
860             assert(0);
861         }
862     }
863     else static if( isRealType!(S) )
864     {
865         return toIntegerFromReal!(D,S)(value);
866     }
867     else static if( isString!(S) )
868     {
869         return toIntegerFromString!(D,S)(value);
870     }
871     else static if( isPOD!(S) || isObject!(S) )
872     {
873         mixin fromUDT;
874         return toDfromS();
875     }
876     else
877         mixin unsupported;
878 }
879 
880 D toReal(D,S)(S value)
881 {
882     /+static if( is( S == bool ) )
883         return (value ? 1.0 : 0.0);
884 
885     else+/ static if( isIntegerType!(S) || isRealType!(S) )
886         return cast(D) value;
887 
888     /+else static if( isCharType!(S) )
889         return cast(D) to!(uint)(value);+/
890 
891     else static if( isString!(S) )
892     {
893         /+
894         try
895         {
896             return tango.text.convert.Float.toFloat(value);
897         }
898         catch( IllegalArgumentException e )
899         {
900             mixin convError;
901             throwConvError();
902         }
903         +/
904 
905         mixin convError;
906 
907         size_t len;
908         auto r = tango.text.convert.Float.parse(value, &len);
909         if( len < value.length || len == 0 )
910             throwConvError();
911 
912         return r;
913     }
914 
915     else static if( isPOD!(S) || isObject!(S) )
916     {
917         mixin fromUDT;
918         return toDfromS();
919     }
920     else
921         mixin unsupported;
922 }
923 
924 D toImaginary(D,S)(S value)
925 {
926     /+static if( is( S == bool ) )
927         return (value ? 1.0i : 0.0i);
928 
929     else+/ static if( isComplexType!(S) )
930     {
931         if( value.re == 0.0 )
932             return value.im * cast(D)1.0i;
933 
934         else
935         {
936             mixin convError;
937             throwConvError();
938             assert(0);
939         }
940     }
941     else static if( isPOD!(S) || isObject!(S) )
942     {
943         mixin fromUDT;
944         return toDfromS();
945     }
946     else
947         mixin unsupported;
948 }
949 
950 D toComplex(D,S)(S value)
951 {
952     static if( isIntegerType!(S) || isRealType!(S) || isImaginaryType!(S)
953             || isComplexType!(S) )
954         return cast(D) value;
955 
956     /+else static if( isCharType!(S) )
957         return cast(D) to!(uint)(value);+/
958 
959     else static if( isPOD!(S) || isObject!(S) )
960     {
961         mixin fromUDT;
962         return toDfromS();
963     }
964     else
965         mixin unsupported;
966 }
967 
968 D toChar(D,S)(S value)
969 {
970     static if( is( S == bool ) )
971         return (value ? 't' : 'f');
972 
973     else static if( isIntegerType!(S) )
974     {
975         if( value >= 0 && value <= 9 )
976             return cast(D) (value+'0');
977 
978         else
979         {
980             mixin convError; // TODO: Overflow error
981             throwConvError();
982             assert(0);
983         }
984     }
985     else static if( isString!(S) )
986     {
987         void fail()
988         {
989             mixin convError;
990             throwConvError();
991         }
992 
993         if( value.length == 0 )
994         {
995             fail();
996             assert(0);
997         }
998 
999         else
1000         {
1001             size_t used;
1002             dchar c = firstCharOf(value, used);
1003 
1004             if( used < value.length )
1005             {
1006                 fail(); // TODO: Overflow error
1007                 assert(0);
1008             }
1009 
1010             if( (cast(size_t) c) > (cast(size_t) D.max) )
1011             {
1012                 fail(); // TODO: Overflow error
1013                 assert(0);
1014             }
1015 
1016             return cast(D) c;
1017         }
1018     }
1019     else static if( isPOD!(S) || isObject!(S) )
1020     {
1021         mixin fromUDT;
1022         return toDfromS();
1023     }
1024     else
1025         mixin unsupported;
1026 }
1027 
1028 D toStringFromString(D,S)(S value)
1029 {
1030     return toString_!(D)(value);
1031 }
1032 
1033 __gshared immutable immutable(char)[] CHARS =
1034 "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
1035 "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
1036 "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
1037 "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
1038 "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
1039 "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e";
1040 
1041 D toStringFromChar(D,S)(S value)
1042 {
1043     static if( is( D : S[] ) )
1044     {
1045         static if( is( S == char ) )
1046         {
1047             if( 0x20 <= value && value <= 0x7e )
1048             {
1049                 return convertString_!(D)((&CHARS[value-0x20])[0..1]);
1050             }
1051         }
1052         auto r = new S[1];
1053         r[0] = value;
1054         return convertString_!(D)(r);
1055     }
1056     else
1057     {
1058         S[1] temp;
1059         temp[0] = value;
1060         return toStringFromString!(D,S[])(temp);
1061     }
1062 }
1063 
1064 D toString(D,S)(S value)
1065 {
1066     static if( is( S == bool ) )
1067     {
1068         return convertString_!(D)(value ? "true" : "false");
1069     }
1070     else static if( isCharType!(S) )
1071         return toStringFromChar!(D,S)(value);
1072 
1073     else static if( isIntegerType!(S) )
1074     {
1075         // TODO: Make sure this works with ulongs.
1076         return convertString_!(D)(mixin("tango.text.convert.Integer.toString"~StringNum!(D)~"(value)"));
1077     }
1078 
1079     else static if( isRealType!(S) )
1080         return convertString_!(D)(mixin("tango.text.convert.Float.toString"~StringNum!(D)~"(value)"));
1081 
1082     else static if( isDynamicArrayType!(S) || isStaticArrayType!(S) )
1083         mixin unsupported!("array type");
1084 
1085     else static if( isAssocArrayType!(S) )
1086         mixin unsupported!("associative array type");
1087 
1088     else static if( isPOD!(S) || isObject!(S) )
1089     {
1090         mixin fromUDT;
1091         return toDfromS();
1092     }
1093     else
1094         mixin unsupported;
1095 }
1096 
1097 D fromString(D,S)(D value)
1098 {
1099     static if( isDynamicArrayType!(S) || isStaticArrayType!(S) )
1100         mixin unsupported_backwards!("array type");
1101 
1102     else static if( isAssocArrayType!(S) )
1103         mixin unsupported_backwards!("associative array type");
1104 
1105     else static if( isPOD!(S) || isObject!(S) )
1106     {
1107         mixin toUDT;
1108         return toDfromS();
1109     }
1110     else
1111         mixin unsupported_backwards;
1112 }
1113 
1114 D toArrayFromArray(D,S)(S value)
1115 {
1116     alias BaseTypeOf!(ElementTypeOfArray!(D)) De;
1117 
1118     De[] result; result.length = value.length;
1119     scope(failure) delete result;
1120 
1121     foreach( i,e ; value )
1122         result[i] = to!(De)(e);
1123 
1124     /* Safe because it is newly allocated */
1125     return cast(D)result;
1126 }
1127 
1128 D toMapFromMap(D,S)(S value)
1129 {
1130     alias typeof(D.init.keys[0])   Dk;
1131     alias typeof(D.init.values[0]) Dv;
1132 
1133     D result;
1134 
1135     foreach( k,v ; value )
1136         result[ to!(Dk)(k) ] = to!(Dv)(v);
1137 
1138     return result;
1139 }
1140 
1141 D toFromUDT(D,S)(S value)
1142 {
1143     // Try value.to* first
1144     static if( is( typeof(mixin("value.to_"~TN!(D)~"()")) : D ) )
1145         return mixin("value.to_"~TN!(D)~"()");
1146 
1147     else static if( is( typeof(mixin("value.to"
1148                         ~ctfe_camelCase(TN!(D))~"()")) : D ) )
1149         return mixin("value.to"~ctfe_camelCase(TN!(D))~"()");
1150 
1151     else static if( is( typeof(value.to!(D)()) : D ) )
1152         return value.to!(D)();
1153 
1154     // Ok, try D.from* now
1155     else static if( is( typeof(mixin("D.from_"~TN!(S)~"(value)")) : D ) )
1156         return mixin("D.from_"~TN!(S)~"(value)");
1157 
1158     else static if( is( typeof(mixin("D.from"
1159                         ~ctfe_camelCase(TN!(S))~"(value)")) : D ) )
1160         return mixin("D.from"~ctfe_camelCase(TN!(S))~"(value)");
1161 
1162     else static if( is( typeof(D.from!(S)(value)) : D ) )
1163         return D.from!(S)(value);
1164 
1165     // Give up
1166     else
1167         mixin unsupported;
1168 }
1169 
1170 D toImpl(D,S)(S value)
1171 {
1172     static if( is( D == S ) )
1173         return value;
1174 
1175     else static if( is( S BaseType == enum ) )
1176         return toImpl!(D,BaseType)(value);
1177 
1178     else static if( isArrayType!(D) && isArrayType!(S)
1179             && is( typeof(D[0]) == typeof(S[0]) ) )
1180         // Special-case which catches to!(T[])!(T[n]).
1181         return value;
1182 
1183     else static if( is( D == bool ) )
1184         return toBool!(D,S)(value);
1185 
1186     else static if( isIntegerType!(D) )
1187         return toInteger!(D,S)(value);
1188 
1189     else static if( isRealType!(D) )
1190         return toReal!(D,S)(value);
1191 
1192     else static if( isImaginaryType!(D) )
1193         return toImaginary!(D,S)(value);
1194 
1195     else static if( isComplexType!(D) )
1196         return toComplex!(D,S)(value);
1197 
1198     else static if( isCharType!(D) )
1199         return toChar!(D,S)(value);
1200 
1201     else static if( isString!(D) && isString!(S) )
1202         return toStringFromString!(D,S)(value);
1203 
1204     else static if( isString!(D) )
1205         return toString!(D,S)(value);
1206 
1207     else static if( isString!(S) )
1208         return fromString!(D,S)(value);
1209 
1210     else static if( isArrayType!(D) && isArrayType!(S) )
1211         return toArrayFromArray!(D,S)(value);
1212 
1213     else static if( isAssocArrayType!(D) && isAssocArrayType!(S) )
1214         return toMapFromMap!(D,S)(value);
1215 
1216     else static if( isUDT!(D) || isUDT!(S) )
1217         return toFromUDT!(D,S)(value);
1218 
1219     else
1220         mixin unsupported;
1221 }
1222 
1223 debug ( ConvertTest )
1224 {
1225     void main() {}
1226 }
1227 
1228 debug( UnitTest ):
1229 
1230 
1231 bool ex(T)(lazy T v)
1232 {
1233     bool result = false;
1234     try
1235     {
1236         v();
1237     }
1238     catch( ConversionException _ )
1239     {
1240         result = true;
1241     }
1242     return result;
1243 }
1244 
1245 bool nx(T)(lazy T v)
1246 {
1247     bool result = true;
1248     try
1249     {
1250         v();
1251     }
1252     catch( ConversionException _ )
1253     {
1254         result = false;
1255     }
1256     return result;
1257 }
1258 
1259 struct Foo
1260 {
1261     int toInt() { return 42; }
1262 
1263     immutable(char)[] toString() { return "string foo"; }
1264 
1265     int[] toIntArray() { return [1,2,3]; }
1266 
1267     Bar toBar()
1268     {
1269         Bar result; return result;
1270     }
1271 
1272     T to(T)()
1273     {
1274         static if( is( T == bool ) )
1275             return true;
1276         else
1277             static assert( false );
1278     }
1279 }
1280 
1281 struct Bar
1282 {
1283     real toReal()
1284     {
1285         return 3.14159;
1286     }
1287 
1288     ireal toIreal()
1289     {
1290         return 42.0i;
1291     }
1292 }
1293 
1294 struct Baz
1295 {
1296     static Baz fromFoo(Foo foo)
1297     {
1298         Baz result; return result;
1299     }
1300 
1301     Bar toBar()
1302     {
1303         Bar result; return result;
1304     }
1305 }
1306 
1307 unittest
1308 {
1309     /*
1310      * bool
1311      */
1312     static assert( !is( typeof(to!(bool)(1.0)) ) );
1313     static assert( !is( typeof(to!(bool)(1.0i)) ) );
1314     static assert( !is( typeof(to!(bool)(1.0+1.0i)) ) );
1315 
1316     assert( to!(bool)(0) == false );
1317     assert( to!(bool)(1) == true );
1318     assert( to!(bool)(-1) == true );
1319 
1320     assert( to!(bool)('t') == true );
1321     assert( to!(bool)('T') == true );
1322     assert( to!(bool)('f') == false );
1323     assert( to!(bool)('F') == false );
1324     assert(ex( to!(bool)('x') ));
1325 
1326     assert( to!(bool)("true") == true );
1327     assert( to!(bool)("false") == false );
1328     assert( to!(bool)("TrUe") == true );
1329     assert( to!(bool)("fAlSe") == false );
1330 
1331     /*
1332      * Integer
1333      */
1334     assert( to!(int)(42L) == 42 );
1335     assert( to!(byte)(42) == cast(byte)42 );
1336     assert( to!(short)(-1701) == cast(short)-1701 );
1337     assert( to!(long)(cast(ubyte)72) == 72L );
1338 
1339     assert(nx( to!(byte)(127) ));
1340     assert(ex( to!(byte)(128) ));
1341     assert(nx( to!(byte)(-128) ));
1342     assert(ex( to!(byte)(-129) ));
1343 
1344     assert(nx( to!(ubyte)(255) ));
1345     assert(ex( to!(ubyte)(256) ));
1346     assert(nx( to!(ubyte)(0) ));
1347     assert(ex( to!(ubyte)(-1) ));
1348 
1349     assert(nx( to!(long)(9_223_372_036_854_775_807UL) ));
1350     assert(ex( to!(long)(9_223_372_036_854_775_808UL) ));
1351     assert(nx( to!(ulong)(0L) ));
1352     assert(ex( to!(ulong)(-1L) ));
1353 
1354     assert( to!(int)(3.14159) == 3 );
1355     assert( to!(int)(2.71828) == 3 );
1356 
1357     assert( to!(int)("1234") == 1234 );
1358 
1359     assert( to!(int)(true) == 1 );
1360     assert( to!(int)(false) == 0 );
1361 
1362     assert( to!(int)('0') == 0 );
1363     assert( to!(int)('9') == 9 );
1364 
1365     /*
1366      * Real
1367      */
1368     assert( to!(real)(3) == 3.0 );
1369     assert( to!(real)("1.125") == 1.125 );
1370 
1371     /*
1372      * Imaginary
1373      */
1374     static assert( !is( typeof(to!(ireal)(3.0)) ) );
1375 
1376     assert( to!(ireal)(0.0+1.0i) == 1.0i );
1377     assert(nx( to!(ireal)(0.0+1.0i) ));
1378     assert(ex( to!(ireal)(1.0+0.0i) ));
1379 
1380     /*
1381      * Complex
1382      */
1383     assert( to!(creal)(1) == (1.0+0.0i) );
1384     assert( to!(creal)(2.0) == (2.0+0.0i) );
1385     assert( to!(creal)(3.0i) == (0.0+3.0i) );
1386 
1387     /*
1388      * Char
1389      */
1390     assert( to!(char)(true) == 't' );
1391     assert( to!(char)(false) == 'f' );
1392 
1393     assert( to!(char)(0) == '0' );
1394     assert( to!(char)(9) == '9' );
1395 
1396     assert(ex( to!(char)(-1) ));
1397     assert(ex( to!(char)(10) ));
1398 
1399     assert( to!(char)("a"d) == 'a' );
1400     assert( to!(dchar)("ε"c) == 'ε' );
1401 
1402     assert(ex( to!(char)("ε"d) ));
1403 
1404     /*
1405      * String-string
1406      */
1407     assert( to!(char[])("Í love to æt "w) == "Í love to æt "c );
1408     assert( to!(char[])("them smûrƒies™,"d) == "them smûrƒies™,"c );
1409     assert( to!(wchar[])("Smûrfies™ I love"c) == "Smûrfies™ I love"w );
1410     assert( to!(wchar[])("2 食い散らす"d) == "2 食い散らす"w );
1411     assert( to!(dchar[])("bite đey µgly"c) == "bite đey µgly"d );
1412     assert( to!(dchar[])("headž ㍳ff"w) == "headž ㍳ff"d );
1413     // ... nibble on they bluish feet.
1414 
1415     /*
1416      * String
1417      */
1418     assert( to!(char[])(true) == "true" );
1419     assert( to!(char[])(false) == "false" );
1420 
1421     assert( to!(char[])(12345678) == "12345678" );
1422     assert( to!(char[])(1234.567800) == "1234.57");
1423 
1424     assert( to!( char[])(cast(char) 'a') == "a"c );
1425     assert( to!(wchar[])(cast(char) 'b') == "b"w );
1426     assert( to!(dchar[])(cast(char) 'c') == "c"d );
1427     assert( to!( char[])(cast(wchar)'d') == "d"c );
1428     assert( to!(wchar[])(cast(wchar)'e') == "e"w );
1429     assert( to!(dchar[])(cast(wchar)'f') == "f"d );
1430     assert( to!( char[])(cast(dchar)'g') == "g"c );
1431     assert( to!(wchar[])(cast(dchar)'h') == "h"w );
1432     assert( to!(dchar[])(cast(dchar)'i') == "i"d );
1433 
1434     /*
1435      * Array-array
1436      */
1437     assert( to!(ubyte[])([1,2,3]) == [cast(ubyte)1, 2, 3] );
1438     assert( to!(bool[])(["true"[], "false"]) == [true, false] );
1439 
1440     /*
1441      * Map-map
1442      */
1443     {
1444         immutable(char)[][int] src = [1:"true"[], 2:"false"];
1445         bool[ubyte] dst = to!(bool[ubyte])(src);
1446         assert( dst.keys.length == 2 );
1447         assert( dst[1] == true );
1448         assert( dst[2] == false );
1449     }
1450 
1451     /*
1452      * UDT
1453      */
1454     {
1455         Foo foo;
1456 
1457         assert( to!(bool)(foo) == true );
1458         assert( to!(int)(foo) == 42 );
1459         assert( to!(char[])(foo) == "string foo" );
1460         assert( to!(wchar[])(foo) == "string foo"w );
1461         assert( to!(dchar[])(foo) == "string foo"d );
1462         assert( to!(int[])(foo) == [1,2,3] );
1463         assert( to!(ireal)(to!(Bar)(foo)) == 42.0i );
1464         assert( to!(real)(to!(Bar)(to!(Baz)(foo))) == 3.14159 );
1465     }
1466 
1467     /*
1468      * Default values
1469      */
1470     {
1471         assert( to!(int)("123", 456) == 123,
1472                 `to!(int)("123", 456) == "` ~ to!(char[])(
1473                     to!(int)("123", 456)) ~ `"` );
1474         assert( to!(int)("abc", 456) == 456,
1475                 `to!(int)("abc", 456) == "` ~ to!(char[])(
1476                     to!(int)("abc", 456)) ~ `"` );
1477     }
1478 
1479     /*
1480      * Ticket #1486
1481      */
1482     {
1483         assert(ex( to!(int)("") ));
1484 
1485         assert(ex( to!(real)("Foo") ));
1486         assert(ex( to!(real)("") ));
1487         assert(ex( to!(real)("0x1.2cp+9") ));
1488 
1489         // From d0c's patch
1490         assert(ex( to!(int)("0x20") ));
1491         assert(ex( to!(int)("0x") ));
1492         assert(ex( to!(int)("-") ));
1493         assert(ex( to!(int)("-0x") ));
1494 
1495         assert( to!(real)("0x20") == cast(real) 0x20 );
1496         assert(ex( to!(real)("0x") ));
1497         assert(ex( to!(real)("-") ));
1498     }
1499 
1500     /*
1501      * Const and immutable
1502      */
1503     {
1504             assert( to!(immutable(char)[])("Í love to æt "w.dup) == "Í love to æt "c );
1505             assert( to!(immutable(char)[])("them smûrƒies™,"d.dup) == "them smûrƒies™,"c );
1506             assert( to!(immutable(wchar)[])("Smûrfies™ I love"c.dup) == "Smûrfies™ I love"w );
1507             assert( to!(immutable(wchar)[])("2 食い散らす"d.dup) == "2 食い散らす"w );
1508             assert( to!(immutable(dchar)[])("bite đey µgly"c.dup) == "bite đey µgly"d );
1509             assert( to!(immutable(dchar)[])("headž ㍳ff"w.dup) == "headž ㍳ff"d );
1510             // ... nibble on they bluish feet.
1511 
1512             assert( to!(immutable(char)[])("食い散らす"c.dup) == "食い散らす"c );
1513             assert( to!(immutable(wchar)[])("食い散らす"w.dup) == "食い散らす"w );
1514             assert( to!(immutable(dchar)[])("食い散らす"d.dup) == "食い散らす"d );
1515             
1516             assert( to!(immutable(char)[])(true) == "true" );
1517             assert( to!(immutable(char)[])(false) == "false" );
1518 
1519             assert( to!(immutable(char)[])(12345678) == "12345678" );
1520             assert( to!(immutable(char)[])(1234.567800) == "1234.57");
1521 
1522             assert( to!(immutable( char)[])(cast(char) 'a') == "a"c );
1523             assert( to!(immutable(wchar)[])(cast(char) 'b') == "b"w );
1524             assert( to!(immutable(dchar)[])(cast(char) 'c') == "c"d );
1525             assert( to!(immutable( char)[])(cast(wchar)'d') == "d"c );
1526             assert( to!(immutable(wchar)[])(cast(wchar)'e') == "e"w );
1527             assert( to!(immutable(dchar)[])(cast(wchar)'f') == "f"d );
1528             assert( to!(immutable( char)[])(cast(dchar)'g') == "g"c );
1529             assert( to!(immutable(wchar)[])(cast(dchar)'h') == "h"w );
1530             assert( to!(immutable(dchar)[])(cast(dchar)'i') == "i"d );
1531 
1532             assert( to!(immutable(ubyte)[])([1,2,3]) == [cast(ubyte)1, 2, 3] );
1533             
1534             assert( to!(const(char)[])("Í love to æt "w) == "Í love to æt "c );
1535 
1536             Foo foo;
1537 
1538             assert( to!(immutable(char)[])(foo) == "string foo" );
1539             assert( to!(immutable(wchar)[])(foo) == "string foo"w );
1540             assert( to!(immutable(dchar)[])(foo) == "string foo"d );
1541             /* assert( to!(immutable(int)[])(foo) == [1,2,3] ); */
1542     }
1543     
1544     /*
1545      * Pass through
1546      */
1547     {
1548         assert( to!(int)(cast(int)1) == 1 );
1549         assert( to!(char[])("abc".dup) == "abc" );
1550         assert( to!(immutable(char)[])("abc") == "abc" );
1551         assert( to!(immutable(dchar)[])("abc"d) == "abc"d );
1552     }
1553 }
1554