1 module toml_foolery.decode.types.integer; 2 3 import std.algorithm : filter, all; 4 import std.ascii : isASCII, isHexDigit; 5 import std.conv; 6 7 import toml_foolery.decode.exceptions; 8 9 version(unittest) import dshould; 10 11 12 package(toml_foolery.decode) long parseTomlInteger(string value) 13 in ( 14 value.all!( 15 (e) => ( 16 (e.isASCII && ( 17 e.isHexDigit || 18 e == 'x' || 19 e == 'o' || 20 e == 'b' || 21 e == '-' || 22 e == '+' 23 )) || e == '_' 24 ) 25 ) 26 ) 27 { 28 int radix = value.length < 3 ? 10 : 29 value[0..2] == "0x" ? 16 : 30 value[0..2] == "0o" ? 8 : 31 value[0..2] == "0b" ? 2 : 32 10; 33 34 try 35 { 36 return (radix != 10 ? value[2..$] : value).filter!(e => e != '_').to!long(radix); 37 } 38 catch (ConvOverflowException e) 39 { 40 throw new TomlTypeException( 41 `Integer ` ~ value ~ 42 ` is outside permitted range for TOML integers [-2^⁶³, 2^⁶³ - 1]` 43 ); 44 } 45 } 46 47 @("Positive") 48 unittest 49 { 50 parseTomlInteger("123").should.equal(123); 51 } 52 53 @("Positive with leading +") 54 unittest 55 { 56 parseTomlInteger("+123").should.equal(123); 57 } 58 59 @("Negative") 60 unittest 61 { 62 parseTomlInteger("-123").should.equal(-123); 63 } 64 65 @("Zero") 66 unittest 67 { 68 parseTomlInteger("0").should.equal(0); 69 } 70 71 @("Underscores — Positive") 72 unittest 73 { 74 parseTomlInteger("525_600").should.equal(525_600); 75 } 76 77 @("Underscores — Negative") 78 unittest 79 { 80 parseTomlInteger("-189_912").should.equal(-189_912); 81 } 82 83 @("Hex — lowercase") 84 unittest 85 { 86 parseTomlInteger("0xbee").should.equal(0xbee); 87 } 88 89 @("Hex — uppercase") 90 unittest 91 { 92 parseTomlInteger("0xBEE").should.equal(0xbee); 93 } 94 95 @("Hex — mixed case") 96 unittest 97 { 98 parseTomlInteger("0xbEe").should.equal(0xbee); 99 } 100 101 @("Hex — long") 102 unittest 103 { 104 parseTomlInteger("0xbeadface").should.equal(0xBeadFace); 105 } 106 107 @("Hex — underscores") 108 unittest 109 { 110 parseTomlInteger("0xb_e_e").should.equal(0xbee); 111 } 112 113 @("Octal") 114 unittest 115 { 116 parseTomlInteger("0o777").should.equal(511); 117 } 118 119 @("Binary") 120 unittest 121 { 122 parseTomlInteger("0b11001101").should.equal(205); 123 }