1 /** 2 Provides value conversion functionality, supplemental to [std.conv]. 3 4 Authors: Tony J. Hudgins 5 Copyright: Copyright © 2019, Tony J. Hudgins 6 License: MIT 7 */ 8 module dext.conv; 9 10 import std.traits : isIntegral, isStaticArray, isDynamicArray; 11 import std.range : ElementType; 12 13 version( unittest ) import std.system : Endian, endian; 14 15 private template isByteArray( N, A ) 16 { 17 static if( isStaticArray!A ) 18 enum isByteArray = A.length == N.sizeof && is( ElementType!A : ubyte ); 19 else static if( isDynamicArray!A ) 20 enum isByteArray = is( ElementType!A : ubyte ); 21 else 22 enum isByteArray = false; 23 } 24 25 /++ 26 Converts an integral number to a static or dynamic array of [ubyte]. 27 28 Authors: Tony J. Hudgins 29 Copyright: Copyright © 2019, Tony J. Hudgins 30 License: MIT 31 32 Examples: 33 --------- 34 int num = 10; 35 ubyte[4] bytes = num.to!( ubyte[4] ); 36 --------- 37 +/ 38 A to( A, N )( N x ) if( isByteArray!( N, A ) && isIntegral!N ) 39 { 40 static union Numeric 41 { 42 N num; 43 ubyte[N.sizeof] bytes; 44 } 45 46 static if( isDynamicArray!A ) 47 return Numeric( x ).bytes.dup; 48 else static if( isStaticArray!A ) 49 { 50 auto num = Numeric( x ); 51 A copy; 52 copy[] = num.bytes[]; 53 54 return copy; 55 } else static assert( false ); 56 } 57 58 @system unittest 59 { 60 // dynamic array 61 enum int five = 5; 62 63 static if( endian == Endian.littleEndian ) 64 { 65 enum ubyte[] expectedDynamic = [ 5, 0, 0, 0 ]; 66 enum ubyte[int.sizeof] expectedStatic = [ 5, 0, 0, 0 ]; 67 } 68 else static if( endian == Endian.bigEndian ) 69 { 70 enum ubyte[] expectedDynamic = [ 0, 0, 0, 5 ]; 71 enum ubyte[int.sizeof] expectedStatic = [ 0, 0, 0, 5 ]; 72 } 73 74 auto x = five.to!( ubyte[] ); 75 assert( x == expectedDynamic, "num -> ubyte[]" ); 76 77 auto y = five.to!( ubyte[4] ); 78 assert( x == expectedStatic, "num -> ubyte[4]" ); 79 } 80 81 /++ 82 Converts an array (either static or dynamic, but not associative) of [ubyte] to an integral number. 83 84 Authors: Tony J. Hudgins 85 Copyright: Copyright © 2019, Tony J. Hudgins 86 License: MIT 87 88 Examples: 89 --------- 90 import std.system : Endian, endian; 91 92 static if( endian == Endian.littleEndian ) 93 auto bytes = [ 10, 0, 0, 0 ]; 94 else 95 auto bytes = [ 0, 0, 0, 10 ]; 96 97 int num = bytes.to!int; // 10 98 --------- 99 +/ 100 N to( N, A )( A arr ) if( isByteArray!( N, A ) && isIntegral!N ) 101 { 102 static union Numeric 103 { 104 ubyte[N.sizeof] bytes; 105 N num; 106 } 107 108 static if( isStaticArray!A ) 109 return Numeric( arr ).num; 110 else 111 { 112 if( arr.length != N.sizeof ) 113 { 114 import std.format : format; 115 import std.conv : ConvException; 116 117 throw new ConvException( 118 "byte array must be equal to %s.sizeof (%s). actual length: %s" 119 .format( 120 N.stringof, 121 N.sizeof, 122 arr.length 123 ) 124 ); 125 } 126 127 Numeric num; 128 num.bytes[] = arr[]; 129 130 return num.num; 131 } 132 } 133 134 @system unittest 135 { 136 static if( endian == Endian.littleEndian ) 137 { 138 enum ubyte[] dynamicArray = [ 5, 0, 0, 0 ]; 139 enum ubyte[int.sizeof] staticArray = [ 5, 0, 0, 0 ]; 140 } 141 else static if( endian == Endian.bigEndian ) 142 { 143 enum ubyte[] dynamicArray = [ 0, 0, 0, 5 ]; 144 enum ubyte[int.sizeof] staticArray = [ 0, 0, 0, 5 ]; 145 } 146 147 enum int expected = 5; 148 149 auto x = dynamicArray.to!int; 150 assert( x == expected, "ubyte[] -> int" ); 151 152 auto y = staticArray.to!int; 153 assert( x == expected, "ubyte[4] -> int" ); 154 }