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 exceeds_expectations; 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 expect(parseTomlInteger("123")).toEqual(123); 51 } 52 53 @("Positive with leading +") 54 unittest 55 { 56 expect(parseTomlInteger("+123")).toEqual(123); 57 } 58 59 @("Negative") 60 unittest 61 { 62 expect(parseTomlInteger("-123")).toEqual(-123); 63 } 64 65 @("Zero") 66 unittest 67 { 68 expect(parseTomlInteger("0")).toEqual(0); 69 } 70 71 @("Underscores — Positive") 72 unittest 73 { 74 expect(parseTomlInteger("525_600")).toEqual(525_600); 75 } 76 77 @("Underscores — Negative") 78 unittest 79 { 80 expect(parseTomlInteger("-189_912")).toEqual(-189_912); 81 } 82 83 @("Hex — lowercase") 84 unittest 85 { 86 expect(parseTomlInteger("0xbee")).toEqual(0xbee); 87 } 88 89 @("Hex — uppercase") 90 unittest 91 { 92 expect(parseTomlInteger("0xBEE")).toEqual(0xbee); 93 } 94 95 @("Hex — mixed case") 96 unittest 97 { 98 expect(parseTomlInteger("0xbEe")).toEqual(0xbee); 99 } 100 101 @("Hex — long") 102 unittest 103 { 104 expect(parseTomlInteger("0xbeadface")).toEqual(0xBeadFace); 105 } 106 107 @("Hex — underscores") 108 unittest 109 { 110 expect(parseTomlInteger("0xb_e_e")).toEqual(0xbee); 111 } 112 113 @("Octal") 114 unittest 115 { 116 expect(parseTomlInteger("0o777")).toEqual(511); 117 } 118 119 @("Binary") 120 unittest 121 { 122 expect(parseTomlInteger("0b11001101")).toEqual(205); 123 }