json/blueprint/number

Exact JSON numbers and their checked conversions to Int and Float.

A Number keeps the decimal value of a JSON number token exactly, with no rounding, so 1.10 equals 1.1 and 1e2 equals 100. parse reads a token within Limits on token bytes, significant digits and exponent size; default_limits() is 1,024 bytes, 800 digits and exponent 1,200, which admits the exact decimal expansion of every finite binary64 value.

to_int and to_float_exact return a native value only when it is exactly equal; to_float rounds to the nearest binary64. from_int, from_float (the shortest decimal that reads back as the same float) and from_float_exact (the float’s exact binary expansion) convert back. On JavaScript, integers outside the safe range (±9,007,199,254,740,991) are refused instead of rounded.

value.Number holds this type, and codec.number() decodes it.

import gleam/order
import json/blueprint/number

pub fn example() {
  let assert Ok(price) = number.parse("19.90", number.default_limits())
  let assert Ok(same) = number.parse("1.99e1", number.default_limits())
  let assert order.Eq = number.compare(price, same)
  let assert Ok(19.9) = number.to_float(price)
  number.to_string(price)
}

Types

Why from_float or from_float_exact refused a Float: on JavaScript, an infinity or NaN.

pub type FloatConstructionError {
  NonFiniteFloat
}

Constructors

  • NonFiniteFloat

Why to_float or to_float_exact refused a number.

pub type FloatProjectionError {
  FloatOverflow
  FloatUnderflow
  FloatInexact
  InvalidFloatCandidate
}

Constructors

  • FloatOverflow
  • FloatUnderflow
  • FloatInexact
  • InvalidFloatCandidate

Why from_int refused an Int. Only JavaScript produces these: a non-finite or fractional number, or one outside the safe integer range.

pub type IntegerConstructionError {
  NonFiniteInteger
  NonIntegerValue
  UnsafeNativeInteger
}

Constructors

  • NonFiniteInteger
  • NonIntegerValue
  • UnsafeNativeInteger

Why to_int refused a number.

pub type IntegerProjectionError {
  FractionalInteger
  IntegerDigitLimitExceeded
  UnsupportedNativeInteger
}

Constructors

  • FractionalInteger
  • IntegerDigitLimitExceeded
  • UnsupportedNativeInteger

Bounds for parse: token bytes, significant digits and the magnitude of the decimal exponent.

pub opaque type Limits

An exact JSON number.

The representation is canonical, so two Number values are equal exactly when they denote the same mathematical value.

pub opaque type Number

Why parse refused a token. InvalidSyntax is not a JSON number; the other variants exceed a bound of Limits or the target’s exact exponent representation.

pub type NumberError {
  InvalidSyntax
  TokenTooLong
  TooManySignificandDigits
  ExponentOutOfRange
}

Constructors

  • InvalidSyntax
  • TokenTooLong
  • TooManySignificandDigits
  • ExponentOutOfRange

Values

pub fn compare(left: Number, right: Number) -> order.Order

Compare two numbers by mathematical value.

pub fn default_limits() -> Limits

1,024 token bytes, 800 significant digits and exponent magnitude 1,200. These admit the exact decimal expansion of every finite binary64 value, including the smallest subnormal.

pub fn from_float(
  value: Float,
) -> Result(Number, FloatConstructionError)

The shortest decimal that reads back as the same float, such as 0.1 for 0.1. This is the number a JSON reader sees in the float’s usual printed form.

pub fn from_float_exact(
  value: Float,
) -> Result(Number, FloatConstructionError)

The exact decimal value of the float’s binary representation, such as 0.1000000000000000055511151231257827021181583404541015625 for 0.1.

pub fn from_int(
  value: Int,
) -> Result(Number, IntegerConstructionError)

The exact number of an Int. Fails only on JavaScript, for a value that is not a safe integer.

pub fn is_integer(number: Number) -> Bool

Whether the number has no fractional part.

pub fn limits(
  max_token_bytes max_token_bytes: Int,
  max_significant_digits max_significant_digits: Int,
  max_exponent max_exponent: Int,
) -> Limits

Build number limits. A token longer than max_token_bytes, with more than max_significant_digits digits as written, or whose normalized decimal exponent exceeds max_exponent in magnitude is refused. A token bound or digit bound below 1 refuses every token; a negative exponent bound refuses every number except zero.

pub fn parse(
  token: String,
  limits: Limits,
) -> Result(Number, NumberError)

Parse a JSON number token, such as -12.5e3, exactly. Leading or trailing whitespace, a leading +, leading zeros and a bare . are invalid, as in JSON. JavaScript refuses written exponents, normalized exponents, or decimal comparison magnitudes outside its safe integer range with ExponentOutOfRange, even when the supplied limits are larger. Erlang retains arbitrary integers.

pub fn to_float(
  number: Number,
) -> Result(Float, FloatProjectionError)

The nearest binary64 float. Fails with FloatOverflow when the magnitude is beyond the largest finite float; a magnitude below the smallest subnormal rounds to zero.

pub fn to_float_exact(
  number: Number,
) -> Result(Float, FloatProjectionError)

The float exactly equal to the number. Fails when the nearest float differs (FloatInexact), or the number is beyond the float range.

pub fn to_int(
  number: Number,
  max_digits: Int,
) -> Result(Int, IntegerProjectionError)

The number as an Int when it is an integer of at most max_digits decimal digits. max_digits bounds the work and memory of the conversion; on JavaScript the integer must also be within the safe range.

pub fn to_string(number: Number) -> String

The number as JSON number text: a plain integer when its normalized exponent is zero, otherwise one leading digit and an exponent, such as 1.25e1 for 12.5 or 1e3 for 1000.

✨ Search Document