Tutorial

Text and JSON

Deliberate text parsing

Start with Integer("123") to read a decimal integer. By default, the parser accepts a sign and leading zeros, but rejects surrounding whitespace, underscores, prefixes, and trailing characters. You can choose the same parsing options in the constructor and in Integer.parse.

base=0 detects 0b, 0o, and 0x prefixes, using decimal when none is present. With an explicit base, allow_prefix=True permits its matching prefix. allow_whitespace=True accepts surrounding ASCII whitespace, and allow_underscores=True permits separators between digits.

Keep every digit in storage

Integers print in decimal, and rationals as reduced fractions or whole numbers. Floats and complex components print the shortest decimal that reads back as the same value in its format, such as 0.1 or 3.0. to_string() offers the formatting options for each type: for Floats, positional or scientific notation, a digit count, and the exact hexadecimal form for tests and interchange.

JSON preserves both values and format metadata for integers, rationals, floats, complex numbers, and their batches. Large numeric fields are strings, so a reader can preserve them even if its native number type is too small. Decode with the matching from_json() method. Real and complex balls also have scalar JSON formats; ball batches currently support text output only. ExactComplex saves its two rational parts exactly; see the complex-fraction example.

conversion.mojo Download
"""Decimal text, JSON and conversion limits for Integers."""

from apn_mojo import Batch, Integer, ConversionLimits


def main() raises:
    var limits = ConversionLimits(
        max_input_bytes=4096,
        max_output_bytes=4096,
        max_digits=1000,
        max_values=100,
        max_allocated_bytes=65536,
    )
    var value = Integer(
        " -0xFF_FF ", base=0, allow_whitespace=True,
        allow_underscores=True, limits=limits,
    )
    print("decimal:", value)
    print("hex:", value.to_string(16, prefix=True, uppercase=True, limits=limits))
    var document = value.to_json(limits=limits)
    print("JSON:", document)
    print("round trip:", Integer.from_json(document, limits=limits) == value)
    var batch = Batch[Integer]([value, Integer(2) ** 80])
    var restored = Batch[Integer].from_json(batch[::-1].to_json(), limits=limits)
    print("restored:", restored[0], restored[1])

Run from the repository root pixi run mojo run -I src docs/examples/conversion.mojo

Output

decimal: -65535
hex: -0XFFFF
JSON: {"version":1,"family":"integer","value":"-65535"}
round trip: True
restored: 1208925819614629174706176 -65535

For native Mojo numbers instead of serialized text, see native batch output. That conversion can round values or discard interval bounds; it serves a different purpose from saving an APN value and its metadata.

Bounding conversions

To bound the work a conversion can do, pass limits=ConversionLimits(...). You can reuse the limits object: each call gets a fresh budget, and the resulting value does not retain it. An unset field (None) is unlimited; zero allows none of that resource.

Setting What it bounds
max_input_bytes Raw input bytes before trimming or unescaping
max_output_bytes Bytes in the returned text
max_digits Numeric digits parsed or written, as defined by the format
max_values Logical values, including batch elements
max_allocated_bytes Cumulative allocation requests during conversion

Apply transport or file-size limits before buffering large payloads, since conversion limits cannot recover memory already used to receive the input. Reject an oversized record; truncating it could change its value. The policy does not cap later arithmetic, retained snapshots, or process execution time.

See the conversion reference for grammars, JSON records, and exactly what each limit counts.