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