-- c = Scientific.coefficient s

parseIntegral :: Integral a => String -> Value -> Parser a

-parseIntegral expected = withScientific expected $ pure . ~~scientificToIntegral~~

+parseIntegral expected = withScientific expected $ pure . floor

{-# INLINE parseIntegral #-}

--- | Safely convert an /untrusted/ scientific value to an integral.

--- This function is safe in the sense that the amount of space used is

--- bounded by the size of the target type.

-scientificToIntegral :: Integral a => Scientific -> a

- -- When the exponent is positive (we're dealing with an integer)

- -- we convert the coefficient to the desired integral type and

- -- multiply it by the magnitude (10^e). Note that the magnitude is

- -- also represented in the target type which means that the space

- -- usage is bounded by the size of that type (8/16/32/64

- -- bits). Computing the magnitude could take a long time but it's

- -- easy to protect against that by using a timeout.

- | e >= 0 = fromInteger c * 10 ^ e

- -- When the exponent is negative we divide the Integer coefficient

- -- by the magnitude (10^(-e)) and convert the resulting Integer to

- -- the target integral type.

- -- Do note that the magnitude (which is an Integer) will consume

- -- lots of space if the exponent is a big negative number. If left

- -- unguarded this allows an attacker to supply a scientific number

- -- with a big negative exponent like 1e-1000000000 and crash the

- -- target system by filling up all memory.

- -- We guard against this by only computing the magnitude when the

- -- exponent is between -limit and 0 (in which case the magnitude

- -- doesn't consume much space). If the exponent is smaller than

- -- -limit we return 0 but only when it's smaller than

- -- -nrOfCoefficientDigits (the number of decimal digits in the

- -- Note that this still allows an attacker to trigger the unsafe

- -- magnitude computation. However, he can only trigger it by

- -- supplying a coefficient consisting of more decimal digits than

- -- 10^(-e). It's easy to protect against this by limiting the

- -- amount of bytes read from an untrusted source.

- -- Also note that nrOfCoefficientDigits is only computed when the

- -- exponent is smaller than -limit.

- | e < (-limit) && e < (-nrOfCoefficientDigits) = 0

- | otherwise = fromInteger (c `div` (10^(-e)))

- e = Scientific.base10Exponent s

- c = Scientific.coefficient s

- -- The number of decimal digits of the coefficient.

- nrOfCoefficientDigits = integerLogBase 10 (abs c)

--- | Calculate the integer logarithm for an arbitrary base.

--- The base must be greater than 1, the second argument, the number

--- whose logarithm is sought, should be positive, otherwise the

--- result is meaningless.

--- > base ^ integerLogBase base m <= m < base ^ (integerLogBase base m + 1)

--- for @base > 1@ and @m > 0@.

--- TODO: Use integerLogBase# from integer-gmp which is probably more efficient!

-integerLogBase :: Integer -> Integer -> Int

-integerLogBase b m = case step b of (_, e) -> e

- step pw | m < pw = (m, 0)

- | otherwise = (q `quot` pw, 2 * e + 1)

- (q, e) = step (pw * pw)