From 105d7156f8f9d95e16b3eefdf0fa97e5be7fbe5b Mon Sep 17 00:00:00 2001 From: Ana Gelez Date: Mon, 25 Mar 2024 17:51:35 +0100 Subject: [PATCH] Better handle large numbers from external data files (#3791) Co-authored-by: Martin Haug --- Cargo.lock | 2 +- Cargo.toml | 2 +- crates/typst/src/foundations/int.rs | 9 ++++++++- crates/typst/src/loading/cbor.rs | 3 +++ crates/typst/src/loading/json.rs | 17 +++++++++++------ crates/typst/src/loading/yaml.rs | 3 +++ tests/typ/bugs/3363-json-large-number.typ | 8 ++++++++ 7 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 tests/typ/bugs/3363-json-large-number.typ diff --git a/Cargo.lock b/Cargo.lock index 9c94d559c..8215e9e48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2630,7 +2630,7 @@ dependencies = [ [[package]] name = "typst-dev-assets" version = "0.11.0" -source = "git+https://github.com/typst/typst-dev-assets?tag=v0.11.0#e0ef7ad46f28a440c41bc8e78563ace86cc02678" +source = "git+https://github.com/typst/typst-dev-assets?rev=ee8ae61cca138dc92f9d818fc7f2fc046d0148c5#ee8ae61cca138dc92f9d818fc7f2fc046d0148c5" [[package]] name = "typst-docs" diff --git a/Cargo.toml b/Cargo.toml index 439d3edf4..cf0050487 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ typst-svg = { path = "crates/typst-svg", version = "0.11.0" } typst-syntax = { path = "crates/typst-syntax", version = "0.11.0" } typst-timing = { path = "crates/typst-timing", version = "0.11.0" } typst-assets = "0.11.0" -typst-dev-assets = { git = "https://github.com/typst/typst-dev-assets", tag = "v0.11.0" } +typst-dev-assets = { git = "https://github.com/typst/typst-dev-assets", rev = "ee8ae61cca138dc92f9d818fc7f2fc046d0148c5" } az = "1.2" base64 = "0.22" bitflags = { version = "2", features = ["serde"] } diff --git a/crates/typst/src/foundations/int.rs b/crates/typst/src/foundations/int.rs index ef21f7853..7b6c02638 100644 --- a/crates/typst/src/foundations/int.rs +++ b/crates/typst/src/foundations/int.rs @@ -261,7 +261,14 @@ macro_rules! unsigned_int { ($($ty:ty)*) => { $(cast! { $ty, - self => Value::Int(self as _), + self => if let Ok(int) = i64::try_from(self) { + Value::Int(int) + } else { + // Some u64 are too large to be cast as i64 + // In that case, we accept that there may be a + // precision loss, and use a floating point number + Value::Float(self as _) + }, v: i64 => v.try_into().map_err(|_| { if v < 0 { "number must be at least zero" diff --git a/crates/typst/src/loading/cbor.rs b/crates/typst/src/loading/cbor.rs index ddf559f33..bce092712 100644 --- a/crates/typst/src/loading/cbor.rs +++ b/crates/typst/src/loading/cbor.rs @@ -14,6 +14,9 @@ use crate::World; /// equivalents, null-values (`null`, `~` or empty ``) will be converted into /// `{none}`, and numbers will be converted to floats or integers depending on /// whether they are whole numbers. +/// +/// Be aware that integers larger than 263-1 will be converted to +/// floating point numbers, which may result in an approximative value. #[func(scope, title = "CBOR")] pub fn cbor( /// The engine. diff --git a/crates/typst/src/loading/json.rs b/crates/typst/src/loading/json.rs index aae1f4ad5..8e829594b 100644 --- a/crates/typst/src/loading/json.rs +++ b/crates/typst/src/loading/json.rs @@ -9,13 +9,18 @@ use crate::World; /// Reads structured data from a JSON file. /// -/// The file must contain a valid JSON object or array. JSON objects will be -/// converted into Typst dictionaries, and JSON arrays will be converted into -/// Typst arrays. Strings and booleans will be converted into the Typst -/// equivalents, `null` will be converted into `{none}`, and numbers will be -/// converted to floats or integers depending on whether they are whole numbers. +/// The file must contain a valid JSON value, such as object or array. JSON +/// objects will be converted into Typst dictionaries, and JSON arrays will be +/// converted into Typst arrays. Strings and booleans will be converted into the +/// Typst equivalents, `null` will be converted into `{none}`, and numbers will +/// be converted to floats or integers depending on whether they are whole +/// numbers. /// -/// The function returns a dictionary or an array, depending on the JSON file. +/// Be aware that integers larger than 263-1 will be converted to +/// floating point numbers, which may result in an approximative value. +/// +/// The function returns a dictionary, an array or, depending on the JSON file, +/// another JSON data type. /// /// The JSON files in the example contain objects with the keys `temperature`, /// `unit`, and `weather`. diff --git a/crates/typst/src/loading/yaml.rs b/crates/typst/src/loading/yaml.rs index 501e30666..d578eda4c 100644 --- a/crates/typst/src/loading/yaml.rs +++ b/crates/typst/src/loading/yaml.rs @@ -17,6 +17,9 @@ use crate::World; /// whether they are whole numbers. Custom YAML tags are ignored, though the /// loaded value will still be present. /// +/// Be aware that integers larger than 263-1 will be converted to +/// floating point numbers, which may give an approximative value. +/// /// The YAML files in the example contain objects with authors as keys, /// each with a sequence of their own submapping with the keys /// "title" and "published" diff --git a/tests/typ/bugs/3363-json-large-number.typ b/tests/typ/bugs/3363-json-large-number.typ new file mode 100644 index 000000000..57d37f1b9 --- /dev/null +++ b/tests/typ/bugs/3363-json-large-number.typ @@ -0,0 +1,8 @@ +// Big numbers (larger than what i64 can store) should just lose some precision +// but not overflow +// https://github.com/typst/typst/issues/3363 +// Ref: false + +#let bignum = json("/assets/data/big-number.json") + +#bignum \ No newline at end of file