From 54c38c6028dd0307c3ded51fdeb7a12b0bbf3428 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 19 Feb 2026 10:46:11 +0100 Subject: [PATCH 01/10] feat: configurable arbitrary precision --- core/engine/Cargo.toml | 6 ++- core/expression/Cargo.toml | 5 ++- core/types/Cargo.toml | 6 ++- core/types/src/constant.rs | 1 + core/types/src/rcvalue/conv.rs | 33 +++++++++++--- core/types/src/rcvalue/de.rs | 9 +++- core/types/src/rcvalue/ser.rs | 25 ++++++++++- core/types/src/variable/conv.rs | 79 ++++++++++++++++++++++++++++----- core/types/src/variable/de.rs | 9 +++- core/types/src/variable/ser.rs | 25 ++++++++++- 10 files changed, 171 insertions(+), 27 deletions(-) diff --git a/core/engine/Cargo.toml b/core/engine/Cargo.toml index 1500bb04..5bee67fc 100644 --- a/core/engine/Cargo.toml +++ b/core/engine/Cargo.toml @@ -15,7 +15,7 @@ ahash = { workspace = true } anyhow = { workspace = true } thiserror = { workspace = true } petgraph = { workspace = true } -serde_json = { workspace = true, features = ["arbitrary_precision"] } +serde_json = { workspace = true, features = [] } serde = { workspace = true, features = ["derive", "rc"] } strum = { workspace = true, features = ["derive"] } once_cell = { workspace = true } @@ -52,4 +52,6 @@ harness = false name = "engine" [features] -bindgen = ["rquickjs/bindgen"] \ No newline at end of file +default = ["arbitrary_precision"] +bindgen = ["rquickjs/bindgen"] +arbitrary_precision = ["serde_json/arbitrary_precision", "zen-expression/arbitrary_precision", "zen-types/arbitrary_precision"] \ No newline at end of file diff --git a/core/expression/Cargo.toml b/core/expression/Cargo.toml index da015734..a9ad854b 100644 --- a/core/expression/Cargo.toml +++ b/core/expression/Cargo.toml @@ -19,7 +19,7 @@ once_cell = { workspace = true } regex = { workspace = true, optional = true } regex-lite = { workspace = true, optional = true } serde = { workspace = true, features = ["rc", "derive"] } -serde_json = { workspace = true, features = ["arbitrary_precision"] } +serde_json = { workspace = true, features = [] } strum = { workspace = true } strum_macros = { workspace = true } thiserror = { workspace = true } @@ -41,9 +41,10 @@ serde_json5 = "0.2" recursive = { workspace = true } [features] -default = ["regex-deprecated"] +default = ["regex-deprecated", "arbitrary_precision"] regex-lite = ["dep:regex-lite"] regex-deprecated = ["dep:regex"] +arbitrary_precision = ["serde_json/arbitrary_precision", "zen-types/arbitrary_precision"] [[bench]] harness = false diff --git a/core/types/Cargo.toml b/core/types/Cargo.toml index 4318c4f5..e3b1b0d4 100644 --- a/core/types/Cargo.toml +++ b/core/types/Cargo.toml @@ -8,8 +8,12 @@ license = "MIT" [dependencies] ahash = { workspace = true } serde = { workspace = true, features = ["rc", "derive"] } -serde_json = { workspace = true, features = ["arbitrary_precision"] } +serde_json = { workspace = true, features = [] } rust_decimal = { workspace = true, features = ["maths-nopanic"] } rust_decimal_macros = { workspace = true } thiserror = { workspace = true } nohash-hasher = { workspace = true } + +[features] +default = ["arbitrary_precision"] +arbitrary_precision = ["serde_json/arbitrary_precision"] diff --git a/core/types/src/constant.rs b/core/types/src/constant.rs index d4ba663d..4e0eeedb 100644 --- a/core/types/src/constant.rs +++ b/core/types/src/constant.rs @@ -1 +1,2 @@ +#[cfg(feature = "arbitrary_precision")] pub(crate) const NUMBER_TOKEN: &str = "$serde_json::private::Number"; diff --git a/core/types/src/rcvalue/conv.rs b/core/types/src/rcvalue/conv.rs index 1cf1a758..ab6ffda1 100644 --- a/core/types/src/rcvalue/conv.rs +++ b/core/types/src/rcvalue/conv.rs @@ -1,5 +1,7 @@ use crate::rcvalue::RcValue; use crate::variable::{ToVariable, Variable}; +#[cfg(not(feature = "arbitrary_precision"))] +use rust_decimal::prelude::FromPrimitive; use rust_decimal::Decimal; use serde_json::Value; use std::rc::Rc; @@ -58,11 +60,32 @@ impl From<&Value> for RcValue { match value { Value::Null => RcValue::Null, Value::Bool(b) => RcValue::Bool(*b), - Value::Number(n) => RcValue::Number( - Decimal::from_str_exact(n.as_str()) - .or_else(|_| Decimal::from_scientific(n.as_str())) - .expect("Allowed number"), - ), + Value::Number(n) => { + #[cfg(feature = "arbitrary_precision")] + { + RcValue::Number( + Decimal::from_str_exact(n.as_str()) + .or_else(|_| Decimal::from_scientific(n.as_str())) + .expect("Allowed number"), + ) + } + + #[cfg(not(feature = "arbitrary_precision"))] + { + let decimal = match n.as_u64() { + Some(n) => Decimal::from_u64(n).expect("Allowed number"), + None => match n.as_i64() { + Some(n) => Decimal::from(n), + None => match n.as_f64() { + Some(n) => Decimal::from_f64(n).expect("Allowed number"), + None => panic!("Invalid number"), + }, + }, + }; + + RcValue::Number(decimal) + } + } Value::String(s) => RcValue::String(Rc::from(s.as_str())), Value::Array(arr) => RcValue::Array(arr.iter().map(RcValue::from).collect()), Value::Object(obj) => RcValue::Object( diff --git a/core/types/src/rcvalue/de.rs b/core/types/src/rcvalue/de.rs index 087ef1b7..2d52fcef 100644 --- a/core/types/src/rcvalue/de.rs +++ b/core/types/src/rcvalue/de.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "arbitrary_precision")] use crate::constant::NUMBER_TOKEN; use crate::rcvalue::RcValue; use ahash::{HashMap, HashMapExt}; @@ -7,6 +8,7 @@ use serde::de::{DeserializeSeed, Error, MapAccess, SeqAccess, Unexpected, Visito use serde::{Deserialize, Deserializer}; use std::fmt::Formatter; use std::marker::PhantomData; +#[cfg(feature = "arbitrary_precision")] use std::ops::Deref; use std::rc::Rc; @@ -84,11 +86,13 @@ impl<'de> Visitor<'de> for RcValueVisitor { A: MapAccess<'de>, { let mut m = HashMap::with_capacity(map.size_hint().unwrap_or_default()); + #[cfg(feature = "arbitrary_precision")] let mut first = true; while let Some((key, value)) = map.next_entry_seed(PhantomData::>, RcValueDeserializer)? { + #[cfg(feature = "arbitrary_precision")] if first && key.deref() == NUMBER_TOKEN { let str = match &value { RcValue::String(s) => s.as_ref(), @@ -103,7 +107,10 @@ impl<'de> Visitor<'de> for RcValueVisitor { } m.insert(key, value); - first = false; + #[cfg(feature = "arbitrary_precision")] + { + first = false; + } } Ok(RcValue::Object(m)) diff --git a/core/types/src/rcvalue/ser.rs b/core/types/src/rcvalue/ser.rs index 0cd6ca5a..0bad00ac 100644 --- a/core/types/src/rcvalue/ser.rs +++ b/core/types/src/rcvalue/ser.rs @@ -1,8 +1,13 @@ -use crate::constant::NUMBER_TOKEN; use crate::rcvalue::RcValue; -use serde::ser::SerializeStruct; +#[cfg(not(feature = "arbitrary_precision"))] +use rust_decimal::prelude::ToPrimitive; use serde::{Serialize, Serializer}; +#[cfg(feature = "arbitrary_precision")] +use crate::constant::NUMBER_TOKEN; +#[cfg(feature = "arbitrary_precision")] +use serde::ser::SerializeStruct; + impl Serialize for RcValue { fn serialize(&self, serializer: S) -> Result where @@ -11,6 +16,7 @@ impl Serialize for RcValue { match self { RcValue::Null => serializer.serialize_unit(), RcValue::Bool(v) => serializer.serialize_bool(*v), + #[cfg(feature = "arbitrary_precision")] RcValue::Number(v) => { let str = v.normalize().to_string(); @@ -18,6 +24,21 @@ impl Serialize for RcValue { s.serialize_field(NUMBER_TOKEN, &str)?; s.end() } + #[cfg(not(feature = "arbitrary_precision"))] + RcValue::Number(v) => { + if v.scale() == 0 { + if let Some(i) = v.to_i64() { + return serializer.serialize_i64(i); + } + if let Some(u) = v.to_u64() { + return serializer.serialize_u64(u); + } + } + let f = v + .to_f64() + .ok_or_else(|| serde::ser::Error::custom("cannot convert to f64"))?; + serializer.serialize_f64(f) + } RcValue::String(v) => serializer.serialize_str(v), RcValue::Array(v) => serializer.collect_seq(v.iter()), RcValue::Object(v) => serializer.collect_map(v.iter()), diff --git a/core/types/src/variable/conv.rs b/core/types/src/variable/conv.rs index b81137d1..f125d13e 100644 --- a/core/types/src/variable/conv.rs +++ b/core/types/src/variable/conv.rs @@ -1,18 +1,43 @@ use crate::variable::Variable; +#[cfg(not(feature = "arbitrary_precision"))] +use rust_decimal::prelude::FromPrimitive; use rust_decimal::Decimal; use serde_json::{Number, Value}; use std::rc::Rc; +#[cfg(not(feature = "arbitrary_precision"))] +use std::str::FromStr; impl From for Variable { fn from(value: Value) -> Self { match value { Value::Null => Variable::Null, Value::Bool(b) => Variable::Bool(b), - Value::Number(n) => Variable::Number( - Decimal::from_str_exact(n.as_str()) - .or_else(|_| Decimal::from_scientific(n.as_str())) - .expect("Allowed number"), - ), + Value::Number(n) => { + #[cfg(feature = "arbitrary_precision")] + { + Variable::Number( + Decimal::from_str_exact(n.as_str()) + .or_else(|_| Decimal::from_scientific(n.as_str())) + .expect("Allowed number"), + ) + } + + #[cfg(not(feature = "arbitrary_precision"))] + { + let decimal = match n.as_u64() { + Some(n) => Decimal::from_u64(n).expect("Allowed number"), + None => match n.as_i64() { + Some(n) => Decimal::from(n), + None => match n.as_f64() { + Some(n) => Decimal::from_f64(n).expect("Allowed number"), + None => panic!("Invalid number"), + }, + }, + }; + + Variable::Number(decimal) + } + } Value::String(s) => Variable::String(Rc::from(s.as_str())), Value::Array(arr) => { Variable::from_array(arr.into_iter().map(Variable::from).collect()) @@ -31,11 +56,32 @@ impl From<&Value> for Variable { match value { Value::Null => Variable::Null, Value::Bool(b) => Variable::Bool(*b), - Value::Number(n) => Variable::Number( - Decimal::from_str_exact(n.as_str()) - .or_else(|_| Decimal::from_scientific(n.as_str())) - .expect("Allowed number"), - ), + Value::Number(n) => { + #[cfg(feature = "arbitrary_precision")] + { + Variable::Number( + Decimal::from_str_exact(n.as_str()) + .or_else(|_| Decimal::from_scientific(n.as_str())) + .expect("Allowed number"), + ) + } + + #[cfg(not(feature = "arbitrary_precision"))] + { + let decimal = match n.as_u64() { + Some(n) => Decimal::from_u64(n).expect("Allowed number"), + None => match n.as_i64() { + Some(n) => Decimal::from(n), + None => match n.as_f64() { + Some(n) => Decimal::from_f64(n).expect("Allowed number"), + None => panic!("Invalid number"), + }, + }, + }; + + Variable::Number(decimal) + } + } Value::String(s) => Variable::String(Rc::from(s.as_str())), Value::Array(arr) => Variable::from_array(arr.iter().map(Variable::from).collect()), Value::Object(obj) => Variable::from_object( @@ -53,7 +99,18 @@ impl From for Value { Variable::Null => Value::Null, Variable::Bool(b) => Value::Bool(b), Variable::Number(n) => { - Value::Number(Number::from_string_unchecked(n.normalize().to_string())) + #[cfg(feature = "arbitrary_precision")] + { + Value::Number(Number::from_string_unchecked(n.normalize().to_string())) + } + #[cfg(not(feature = "arbitrary_precision"))] + { + Value::Number( + Number::from_str(n.normalize().to_string().as_str()) + .map_err(|_| "Invalid number") + .unwrap(), + ) + } } Variable::String(s) => Value::String(s.to_string()), Variable::Array(arr) => { diff --git a/core/types/src/variable/de.rs b/core/types/src/variable/de.rs index 6c3ad6fd..75b78c6d 100644 --- a/core/types/src/variable/de.rs +++ b/core/types/src/variable/de.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "arbitrary_precision")] use crate::constant::NUMBER_TOKEN; use crate::variable::Variable; use ahash::{HashMap, HashMapExt}; @@ -7,6 +8,7 @@ use serde::de::{DeserializeSeed, Error, MapAccess, SeqAccess, Unexpected, Visito use serde::{Deserialize, Deserializer}; use std::fmt::Formatter; use std::marker::PhantomData; +#[cfg(feature = "arbitrary_precision")] use std::ops::Deref; use std::rc::Rc; @@ -84,11 +86,13 @@ impl<'de> Visitor<'de> for VariableVisitor { A: MapAccess<'de>, { let mut m = HashMap::with_capacity(map.size_hint().unwrap_or_default()); + #[cfg(feature = "arbitrary_precision")] let mut first = true; while let Some((key, value)) = map.next_entry_seed(PhantomData::>, VariableDeserializer)? { + #[cfg(feature = "arbitrary_precision")] if first && key.deref() == NUMBER_TOKEN { let str = value .as_str() @@ -102,7 +106,10 @@ impl<'de> Visitor<'de> for VariableVisitor { } m.insert(key, value); - first = false; + #[cfg(feature = "arbitrary_precision")] + { + first = false; + } } Ok(Variable::from_object(m)) diff --git a/core/types/src/variable/ser.rs b/core/types/src/variable/ser.rs index 1f57b709..495b525f 100644 --- a/core/types/src/variable/ser.rs +++ b/core/types/src/variable/ser.rs @@ -1,8 +1,13 @@ -use crate::constant::NUMBER_TOKEN; use crate::variable::Variable; -use serde::ser::SerializeStruct; +#[cfg(not(feature = "arbitrary_precision"))] +use rust_decimal::prelude::ToPrimitive; use serde::{Serialize, Serializer}; +#[cfg(feature = "arbitrary_precision")] +use crate::constant::NUMBER_TOKEN; +#[cfg(feature = "arbitrary_precision")] +use serde::ser::SerializeStruct; + impl Serialize for Variable { fn serialize(&self, serializer: S) -> Result where @@ -11,6 +16,7 @@ impl Serialize for Variable { match self { Variable::Null => serializer.serialize_unit(), Variable::Bool(v) => serializer.serialize_bool(*v), + #[cfg(feature = "arbitrary_precision")] Variable::Number(v) => { let str = v.normalize().to_string(); @@ -18,6 +24,21 @@ impl Serialize for Variable { s.serialize_field(NUMBER_TOKEN, &str)?; s.end() } + #[cfg(not(feature = "arbitrary_precision"))] + Variable::Number(v) => { + if v.scale() == 0 { + if let Some(i) = v.to_i64() { + return serializer.serialize_i64(i); + } + if let Some(u) = v.to_u64() { + return serializer.serialize_u64(u); + } + } + let f = v + .to_f64() + .ok_or_else(|| serde::ser::Error::custom("cannot convert to f64"))?; + serializer.serialize_f64(f) + } Variable::String(v) => serializer.serialize_str(v), Variable::Array(v) => { let borrowed = v.borrow(); From 36da71d3bcdb8908e846baab7cd15773c4dad81b Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 19 Feb 2026 16:18:00 +0100 Subject: [PATCH 02/10] fix workflow --- .github/workflows/node.yaml | 55 ++++++++++++++------------------- core/types/src/rcvalue/conv.rs | 2 +- core/types/src/variable/conv.rs | 2 +- 3 files changed, 25 insertions(+), 34 deletions(-) diff --git a/.github/workflows/node.yaml b/.github/workflows/node.yaml index d2c6ae3f..931a600e 100644 --- a/.github/workflows/node.yaml +++ b/.github/workflows/node.yaml @@ -174,12 +174,15 @@ jobs: run: yarn install --immutable --mode=skip-build - name: Build in docker - uses: addnab/docker-run-action@v3 if: ${{ matrix.settings.docker }} - with: - image: ${{ matrix.settings.docker }} - options: --user 0:0 -v ${{ github.workspace }}/.cargo-cache/.cargo/git:/usr/local/cargo/git -v ${{ github.workspace }}/.cargo-cache/.cargo/registry:/usr/local/cargo/registry -v ${{ github.workspace }}:/build -w /build - run: ${{ matrix.settings.build }} + run: | + docker run --rm --user 0:0 \ + -v ${{ github.workspace }}/.cargo-cache/.cargo/git:/usr/local/cargo/git \ + -v ${{ github.workspace }}/.cargo-cache/.cargo/registry:/usr/local/cargo/registry \ + -v ${{ github.workspace }}:/build \ + -w /build \ + ${{ matrix.settings.docker }} \ + bash -c "${{ matrix.settings.build }}" - name: 'Build' run: ${{ matrix.settings.build }} @@ -315,15 +318,11 @@ jobs: shell: bash - name: Test bindings - uses: addnab/docker-run-action@v3 - with: - image: node:${{ matrix.node }}-slim - options: -v ${{ github.workspace }}:/workspace - run: | - cd workspace/bindings/nodejs - yarn install - yarn link - yarn test + run: | + docker run --rm \ + -v ${{ github.workspace }}:/workspace \ + node:${{ matrix.node }}-slim \ + bash -c "cd workspace/bindings/nodejs && yarn install && yarn link && yarn test" test-linux-x64-musl-binding: name: Test bindings on Linux-x64-musl - node@${{ matrix.node }} needs: @@ -370,15 +369,11 @@ jobs: shell: bash - name: Test bindings - uses: addnab/docker-run-action@v3 - with: - image: node:${{ matrix.node }}-alpine - options: -v ${{ github.workspace }}:/workspace - run: | - cd workspace/bindings/nodejs - yarn install - yarn link - yarn test + run: | + docker run --rm \ + -v ${{ github.workspace }}:/workspace \ + node:${{ matrix.node }}-alpine \ + sh -c "cd workspace/bindings/nodejs && yarn install && yarn link && yarn test" test-linux-aarch64-musl-binding: name: Test bindings on Linux-aarch64-musl - node@${{ matrix.node }} needs: @@ -432,15 +427,11 @@ jobs: shell: bash - name: Test bindings - uses: addnab/docker-run-action@v3 - with: - options: --platform linux/arm64 -v ${{ github.workspace }}:/workspace - image: node:${{ matrix.node }}-alpine - run: | - cd workspace/bindings/nodejs - yarn install - yarn link - yarn test + run: | + docker run --rm --platform linux/arm64 \ + -v ${{ github.workspace }}:/workspace \ + node:${{ matrix.node }}-alpine \ + sh -c "cd workspace/bindings/nodejs && yarn install && yarn link && yarn test" # test-linux-aarch64-gnu-binding: # name: Test bindings on aarch64-unknown-linux-gnu - node@${{ matrix.node }} # needs: diff --git a/core/types/src/rcvalue/conv.rs b/core/types/src/rcvalue/conv.rs index ab6ffda1..7f476510 100644 --- a/core/types/src/rcvalue/conv.rs +++ b/core/types/src/rcvalue/conv.rs @@ -1,8 +1,8 @@ use crate::rcvalue::RcValue; use crate::variable::{ToVariable, Variable}; +use rust_decimal::Decimal; #[cfg(not(feature = "arbitrary_precision"))] use rust_decimal::prelude::FromPrimitive; -use rust_decimal::Decimal; use serde_json::Value; use std::rc::Rc; diff --git a/core/types/src/variable/conv.rs b/core/types/src/variable/conv.rs index f125d13e..747e73a7 100644 --- a/core/types/src/variable/conv.rs +++ b/core/types/src/variable/conv.rs @@ -1,7 +1,7 @@ use crate::variable::Variable; +use rust_decimal::Decimal; #[cfg(not(feature = "arbitrary_precision"))] use rust_decimal::prelude::FromPrimitive; -use rust_decimal::Decimal; use serde_json::{Number, Value}; use std::rc::Rc; #[cfg(not(feature = "arbitrary_precision"))] From 3c0c6f9b5c97890ee882b67ca9d295f110c4d22d Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 19 Feb 2026 17:55:58 +0100 Subject: [PATCH 03/10] fix workflow --- .github/workflows/node.yaml | 57 +++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/.github/workflows/node.yaml b/.github/workflows/node.yaml index 931a600e..2107d47a 100644 --- a/.github/workflows/node.yaml +++ b/.github/workflows/node.yaml @@ -174,15 +174,12 @@ jobs: run: yarn install --immutable --mode=skip-build - name: Build in docker + uses: stefan-gorules/docker-run-action@main if: ${{ matrix.settings.docker }} - run: | - docker run --rm --user 0:0 \ - -v ${{ github.workspace }}/.cargo-cache/.cargo/git:/usr/local/cargo/git \ - -v ${{ github.workspace }}/.cargo-cache/.cargo/registry:/usr/local/cargo/registry \ - -v ${{ github.workspace }}:/build \ - -w /build \ - ${{ matrix.settings.docker }} \ - bash -c "${{ matrix.settings.build }}" + with: + image: ${{ matrix.settings.docker }} + options: --user 0:0 -v ${{ github.workspace }}/.cargo-cache/.cargo/git:/usr/local/cargo/git -v ${{ github.workspace }}/.cargo-cache/.cargo/registry:/usr/local/cargo/registry -v ${{ github.workspace }}:/build -w /build + run: ${{ matrix.settings.build }} - name: 'Build' run: ${{ matrix.settings.build }} @@ -318,11 +315,15 @@ jobs: shell: bash - name: Test bindings - run: | - docker run --rm \ - -v ${{ github.workspace }}:/workspace \ - node:${{ matrix.node }}-slim \ - bash -c "cd workspace/bindings/nodejs && yarn install && yarn link && yarn test" + uses: stefan-gorules/docker-run-action@main + with: + image: node:${{ matrix.node }}-slim + options: -v ${{ github.workspace }}:/workspace + run: | + cd workspace/bindings/nodejs + yarn install + yarn link + yarn test test-linux-x64-musl-binding: name: Test bindings on Linux-x64-musl - node@${{ matrix.node }} needs: @@ -369,11 +370,15 @@ jobs: shell: bash - name: Test bindings - run: | - docker run --rm \ - -v ${{ github.workspace }}:/workspace \ - node:${{ matrix.node }}-alpine \ - sh -c "cd workspace/bindings/nodejs && yarn install && yarn link && yarn test" + uses: stefan-gorules/docker-run-action@main + with: + image: node:${{ matrix.node }}-alpine + options: -v ${{ github.workspace }}:/workspace + run: | + cd workspace/bindings/nodejs + yarn install + yarn link + yarn test test-linux-aarch64-musl-binding: name: Test bindings on Linux-aarch64-musl - node@${{ matrix.node }} needs: @@ -427,11 +432,15 @@ jobs: shell: bash - name: Test bindings - run: | - docker run --rm --platform linux/arm64 \ - -v ${{ github.workspace }}:/workspace \ - node:${{ matrix.node }}-alpine \ - sh -c "cd workspace/bindings/nodejs && yarn install && yarn link && yarn test" + uses: stefan-gorules/docker-run-action@main + with: + options: --platform linux/arm64 -v ${{ github.workspace }}:/workspace + image: node:${{ matrix.node }}-alpine + run: | + cd workspace/bindings/nodejs + yarn install + yarn link + yarn test # test-linux-aarch64-gnu-binding: # name: Test bindings on aarch64-unknown-linux-gnu - node@${{ matrix.node }} # needs: @@ -473,7 +482,7 @@ jobs: # shell: bash # # - name: Setup and run tests - # uses: addnab/docker-run-action@v3 + # uses: stefan-gorules/docker-run-action@main # with: # image: ghcr.io/napi-rs/napi-rs/nodejs:aarch64-${{ matrix.node }} # options: -v ${{ github.workspace }}:/workspace -w /workspace From a3e602dc2fa5b6225afdb42decdefd1d460673b1 Mon Sep 17 00:00:00 2001 From: Stefan Date: Thu, 19 Feb 2026 23:46:46 +0100 Subject: [PATCH 04/10] set version of docker run action to v1 --- .github/workflows/node.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/node.yaml b/.github/workflows/node.yaml index 2107d47a..67109b6b 100644 --- a/.github/workflows/node.yaml +++ b/.github/workflows/node.yaml @@ -174,7 +174,7 @@ jobs: run: yarn install --immutable --mode=skip-build - name: Build in docker - uses: stefan-gorules/docker-run-action@main + uses: stefan-gorules/docker-run-action@v1 if: ${{ matrix.settings.docker }} with: image: ${{ matrix.settings.docker }} @@ -315,7 +315,7 @@ jobs: shell: bash - name: Test bindings - uses: stefan-gorules/docker-run-action@main + uses: stefan-gorules/docker-run-action@v1 with: image: node:${{ matrix.node }}-slim options: -v ${{ github.workspace }}:/workspace @@ -370,7 +370,7 @@ jobs: shell: bash - name: Test bindings - uses: stefan-gorules/docker-run-action@main + uses: stefan-gorules/docker-run-action@v1 with: image: node:${{ matrix.node }}-alpine options: -v ${{ github.workspace }}:/workspace @@ -432,7 +432,7 @@ jobs: shell: bash - name: Test bindings - uses: stefan-gorules/docker-run-action@main + uses: stefan-gorules/docker-run-action@v1 with: options: --platform linux/arm64 -v ${{ github.workspace }}:/workspace image: node:${{ matrix.node }}-alpine @@ -482,7 +482,7 @@ jobs: # shell: bash # # - name: Setup and run tests - # uses: stefan-gorules/docker-run-action@main + # uses: stefan-gorules/docker-run-action@v1 # with: # image: ghcr.io/napi-rs/napi-rs/nodejs:aarch64-${{ matrix.node }} # options: -v ${{ github.workspace }}:/workspace -w /workspace From f06e6fd07453de1a369a75c1de52053a632d653e Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 23 Feb 2026 12:41:28 +0100 Subject: [PATCH 05/10] set arbitrary_precision as opt-in --- bindings/c/Cargo.toml | 4 ++-- bindings/nodejs/Cargo.toml | 4 ++-- bindings/python/Cargo.toml | 4 ++-- bindings/uniffi/Cargo.toml | 4 ++-- core/engine/Cargo.toml | 6 +++--- core/expression/Cargo.toml | 2 +- core/types/Cargo.toml | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bindings/c/Cargo.toml b/bindings/c/Cargo.toml index 7641efc6..ffb31ade 100644 --- a/bindings/c/Cargo.toml +++ b/bindings/c/Cargo.toml @@ -12,8 +12,8 @@ serde = { workspace = true } serde_json = { workspace = true } strum = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["rt"] } -zen-engine = { path = "../../core/engine" } -zen-expression = { path = "../../core/expression" } +zen-engine = { path = "../../core/engine", features = ["arbitrary_precision"] } +zen-expression = { path = "../../core/expression", features = ["arbitrary_precision"] } zen-tmpl = { path = "../../core/template" } [lib] diff --git a/bindings/nodejs/Cargo.toml b/bindings/nodejs/Cargo.toml index f7488dd9..5bc273ee 100644 --- a/bindings/nodejs/Cargo.toml +++ b/bindings/nodejs/Cargo.toml @@ -15,8 +15,8 @@ napi-sys = "3" napi-derive = "3" tokio-util = { workspace = true, features = ["rt"] } serde_json = { workspace = true } -zen-engine = { path = "../../core/engine" } -zen-expression = { path = "../../core/expression" } +zen-engine = { path = "../../core/engine", features = ["arbitrary_precision"] } +zen-expression = { path = "../../core/expression", features = ["arbitrary_precision"] } zen-tmpl = { path = "../../core/template" } serde = { workspace = true, features = ["derive"] } json_dotpath = { workspace = true } diff --git a/bindings/python/Cargo.toml b/bindings/python/Cargo.toml index bd323e73..052a88b0 100644 --- a/bindings/python/Cargo.toml +++ b/bindings/python/Cargo.toml @@ -20,6 +20,6 @@ serde = { workspace = true } serde_json = { workspace = true } rust_decimal = { workspace = true, features = ["maths-nopanic"] } tokio-util = { version = "0.7", features = ["rt"] } -zen-engine = { path = "../../core/engine" } -zen-expression = { path = "../../core/expression" } +zen-engine = { path = "../../core/engine", features = ["arbitrary_precision"] } +zen-expression = { path = "../../core/expression", features = ["arbitrary_precision"] } zen-tmpl = { path = "../../core/template" } diff --git a/bindings/uniffi/Cargo.toml b/bindings/uniffi/Cargo.toml index 8315f77b..570b904c 100644 --- a/bindings/uniffi/Cargo.toml +++ b/bindings/uniffi/Cargo.toml @@ -15,8 +15,8 @@ path = "uniffi-bindgen.rs" [dependencies] uniffi = { version = "0.29", features = ["tokio", "cli"] } serde_json = { workspace = true } -zen-engine = { path = "../../core/engine" } -zen-expression = { path = "../../core/expression" } +zen-engine = { path = "../../core/engine", features = ["arbitrary_precision"] } +zen-expression = { path = "../../core/expression", features = ["arbitrary_precision"] } serde = { workspace = true, features = ["derive"] } async-trait = "0.1" tokio = "1.46" diff --git a/core/engine/Cargo.toml b/core/engine/Cargo.toml index 5bee67fc..3f553b06 100644 --- a/core/engine/Cargo.toml +++ b/core/engine/Cargo.toml @@ -24,8 +24,8 @@ rust_decimal = { workspace = true, features = ["maths-nopanic"] } fixedbitset = "0.5" tokio = { workspace = true, features = ["sync", "time"] } rquickjs = { version = "0.10", features = ["macro", "loader", "rust-alloc", "futures", "either", "properties"] } -zen-types = { path = "../types", version = "0.53.0" } -zen-expression = { path = "../expression", version = "0.53.0" } +zen-types = { path = "../types", version = "0.53.0", default-features = false } +zen-expression = { path = "../expression", version = "0.53.0", default-features = false } zen-tmpl = { path = "../template", version = "0.53.0" } nohash-hasher = { workspace = true } downcast-rs = { version = "2.0", features = ["std", "sync"] } @@ -52,6 +52,6 @@ harness = false name = "engine" [features] -default = ["arbitrary_precision"] +default = [] bindgen = ["rquickjs/bindgen"] arbitrary_precision = ["serde_json/arbitrary_precision", "zen-expression/arbitrary_precision", "zen-types/arbitrary_precision"] \ No newline at end of file diff --git a/core/expression/Cargo.toml b/core/expression/Cargo.toml index a9ad854b..17cc30a0 100644 --- a/core/expression/Cargo.toml +++ b/core/expression/Cargo.toml @@ -41,7 +41,7 @@ serde_json5 = "0.2" recursive = { workspace = true } [features] -default = ["regex-deprecated", "arbitrary_precision"] +default = ["regex-deprecated"] regex-lite = ["dep:regex-lite"] regex-deprecated = ["dep:regex"] arbitrary_precision = ["serde_json/arbitrary_precision", "zen-types/arbitrary_precision"] diff --git a/core/types/Cargo.toml b/core/types/Cargo.toml index e3b1b0d4..2da2fa56 100644 --- a/core/types/Cargo.toml +++ b/core/types/Cargo.toml @@ -15,5 +15,5 @@ thiserror = { workspace = true } nohash-hasher = { workspace = true } [features] -default = ["arbitrary_precision"] +default = [] arbitrary_precision = ["serde_json/arbitrary_precision"] From 42feb83cc1d8e75efbae5f492865ad0c03cfbd34 Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 23 Feb 2026 13:06:24 +0100 Subject: [PATCH 06/10] revert making arbitrary_precision non-default --- bindings/c/Cargo.toml | 4 ++-- bindings/nodejs/Cargo.toml | 4 ++-- bindings/python/Cargo.toml | 4 ++-- bindings/uniffi/Cargo.toml | 4 ++-- core/engine/Cargo.toml | 6 +++--- core/expression/Cargo.toml | 4 ++-- core/template/Cargo.toml | 7 ++++--- core/types/Cargo.toml | 2 +- 8 files changed, 18 insertions(+), 17 deletions(-) diff --git a/bindings/c/Cargo.toml b/bindings/c/Cargo.toml index ffb31ade..7641efc6 100644 --- a/bindings/c/Cargo.toml +++ b/bindings/c/Cargo.toml @@ -12,8 +12,8 @@ serde = { workspace = true } serde_json = { workspace = true } strum = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["rt"] } -zen-engine = { path = "../../core/engine", features = ["arbitrary_precision"] } -zen-expression = { path = "../../core/expression", features = ["arbitrary_precision"] } +zen-engine = { path = "../../core/engine" } +zen-expression = { path = "../../core/expression" } zen-tmpl = { path = "../../core/template" } [lib] diff --git a/bindings/nodejs/Cargo.toml b/bindings/nodejs/Cargo.toml index 5bc273ee..f7488dd9 100644 --- a/bindings/nodejs/Cargo.toml +++ b/bindings/nodejs/Cargo.toml @@ -15,8 +15,8 @@ napi-sys = "3" napi-derive = "3" tokio-util = { workspace = true, features = ["rt"] } serde_json = { workspace = true } -zen-engine = { path = "../../core/engine", features = ["arbitrary_precision"] } -zen-expression = { path = "../../core/expression", features = ["arbitrary_precision"] } +zen-engine = { path = "../../core/engine" } +zen-expression = { path = "../../core/expression" } zen-tmpl = { path = "../../core/template" } serde = { workspace = true, features = ["derive"] } json_dotpath = { workspace = true } diff --git a/bindings/python/Cargo.toml b/bindings/python/Cargo.toml index 052a88b0..bd323e73 100644 --- a/bindings/python/Cargo.toml +++ b/bindings/python/Cargo.toml @@ -20,6 +20,6 @@ serde = { workspace = true } serde_json = { workspace = true } rust_decimal = { workspace = true, features = ["maths-nopanic"] } tokio-util = { version = "0.7", features = ["rt"] } -zen-engine = { path = "../../core/engine", features = ["arbitrary_precision"] } -zen-expression = { path = "../../core/expression", features = ["arbitrary_precision"] } +zen-engine = { path = "../../core/engine" } +zen-expression = { path = "../../core/expression" } zen-tmpl = { path = "../../core/template" } diff --git a/bindings/uniffi/Cargo.toml b/bindings/uniffi/Cargo.toml index 570b904c..8315f77b 100644 --- a/bindings/uniffi/Cargo.toml +++ b/bindings/uniffi/Cargo.toml @@ -15,8 +15,8 @@ path = "uniffi-bindgen.rs" [dependencies] uniffi = { version = "0.29", features = ["tokio", "cli"] } serde_json = { workspace = true } -zen-engine = { path = "../../core/engine", features = ["arbitrary_precision"] } -zen-expression = { path = "../../core/expression", features = ["arbitrary_precision"] } +zen-engine = { path = "../../core/engine" } +zen-expression = { path = "../../core/expression" } serde = { workspace = true, features = ["derive"] } async-trait = "0.1" tokio = "1.46" diff --git a/core/engine/Cargo.toml b/core/engine/Cargo.toml index 3f553b06..0f8a5e3f 100644 --- a/core/engine/Cargo.toml +++ b/core/engine/Cargo.toml @@ -26,7 +26,7 @@ tokio = { workspace = true, features = ["sync", "time"] } rquickjs = { version = "0.10", features = ["macro", "loader", "rust-alloc", "futures", "either", "properties"] } zen-types = { path = "../types", version = "0.53.0", default-features = false } zen-expression = { path = "../expression", version = "0.53.0", default-features = false } -zen-tmpl = { path = "../template", version = "0.53.0" } +zen-tmpl = { path = "../template", version = "0.53.0", default-features = false } nohash-hasher = { workspace = true } downcast-rs = { version = "2.0", features = ["std", "sync"] } @@ -52,6 +52,6 @@ harness = false name = "engine" [features] -default = [] +default = ["arbitrary_precision"] bindgen = ["rquickjs/bindgen"] -arbitrary_precision = ["serde_json/arbitrary_precision", "zen-expression/arbitrary_precision", "zen-types/arbitrary_precision"] \ No newline at end of file +arbitrary_precision = ["serde_json/arbitrary_precision", "zen-expression/arbitrary_precision", "zen-types/arbitrary_precision", "zen-tmpl/arbitrary_precision"] \ No newline at end of file diff --git a/core/expression/Cargo.toml b/core/expression/Cargo.toml index 17cc30a0..14858f2b 100644 --- a/core/expression/Cargo.toml +++ b/core/expression/Cargo.toml @@ -30,7 +30,7 @@ strsim = "0.11" iana-time-zone = "0.1" zen-macros = { path = "../macros", version = "0.53.0" } -zen-types = { path = "../types", version = "0.53.0" } +zen-types = { path = "../types", version = "0.53.0", default-features = false } [dev-dependencies] criterion = { workspace = true } @@ -41,7 +41,7 @@ serde_json5 = "0.2" recursive = { workspace = true } [features] -default = ["regex-deprecated"] +default = ["regex-deprecated", "arbitrary_precision"] regex-lite = ["dep:regex-lite"] regex-deprecated = ["dep:regex"] arbitrary_precision = ["serde_json/arbitrary_precision", "zen-types/arbitrary_precision"] diff --git a/core/template/Cargo.toml b/core/template/Cargo.toml index eef066b1..c825e00c 100644 --- a/core/template/Cargo.toml +++ b/core/template/Cargo.toml @@ -8,13 +8,14 @@ edition = "2021" repository = "https://github.com/gorules/zen.git" [dependencies] -zen-expression = { path = "../expression", version = "0.53.0" } +zen-expression = { path = "../expression", version = "0.53.0", default-features = false } thiserror = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } [features] -default = ["regex-deprecated"] +default = ["regex-deprecated", "arbitrary_precision"] regex-lite = ["zen-expression/regex-lite"] -regex-deprecated = ["zen-expression/regex-deprecated"] \ No newline at end of file +regex-deprecated = ["zen-expression/regex-deprecated"] +arbitrary_precision = ["zen-expression/arbitrary_precision"] \ No newline at end of file diff --git a/core/types/Cargo.toml b/core/types/Cargo.toml index 2da2fa56..e3b1b0d4 100644 --- a/core/types/Cargo.toml +++ b/core/types/Cargo.toml @@ -15,5 +15,5 @@ thiserror = { workspace = true } nohash-hasher = { workspace = true } [features] -default = [] +default = ["arbitrary_precision"] arbitrary_precision = ["serde_json/arbitrary_precision"] From 1d423a05ed9fb2cedc661b73c07978195054d6e5 Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 23 Feb 2026 13:26:47 +0100 Subject: [PATCH 07/10] update cargo version action and add features in Cargo.toml for deps --- actions/cargo-version-action/dist/index.js | 11 ++------ actions/cargo-version-action/src/cargo.ts | 11 ++------ .../cargo-version-action/src/index.spec.ts | 28 +++++++++++++++++++ core/engine/Cargo.toml | 4 +-- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/actions/cargo-version-action/dist/index.js b/actions/cargo-version-action/dist/index.js index 06c946e0..f409ab22 100644 --- a/actions/cargo-version-action/dist/index.js +++ b/actions/cargo-version-action/dist/index.js @@ -34066,17 +34066,12 @@ var toml = __nccwpck_require__(2132); ;// CONCATENATED MODULE: ./src/cargo.ts const versionRegex = /version = "[0-9]+\.[0-9]+\.[0-9]+"$/im; -const expressionDep = /zen-expression =.*$/im; -const templateDep = /zen-tmpl =.*$/im; -const macroDep = /zen-macros =.*$/im; -const typesDep = /zen-types =.*$/im; +const zenDepLine = /^.*zen-(?:expression|tmpl|macros|types)\s*=\s*\{.*}.*$/gim; +const depVersionRegex = /version\s*=\s*"[0-9]+\.[0-9]+\.[0-9]+"/; const updateCargoContents = (contents, { version }) => { return contents .replace(versionRegex, `version = "${version}"`) - .replace(expressionDep, `zen-expression = { path = "../expression", version = "${version}" }`) - .replace(macroDep, `zen-macros = { path = "../macros", version = "${version}" }`) - .replace(typesDep, `zen-types = { path = "../types", version = "${version}" }`) - .replace(templateDep, `zen-tmpl = { path = "../template", version = "${version}" }`); + .replace(zenDepLine, (line) => line.replace(depVersionRegex, `version = "${version}"`)); }; const getCargoVersion = (contents) => { var _a; diff --git a/actions/cargo-version-action/src/cargo.ts b/actions/cargo-version-action/src/cargo.ts index 2ce55e92..278e9de0 100644 --- a/actions/cargo-version-action/src/cargo.ts +++ b/actions/cargo-version-action/src/cargo.ts @@ -5,18 +5,13 @@ type UpdateCargoOptions = { }; const versionRegex = /version = "[0-9]+\.[0-9]+\.[0-9]+"$/im; -const expressionDep = /zen-expression =.*$/im; -const templateDep = /zen-tmpl =.*$/im; -const macroDep = /zen-macros =.*$/im; -const typesDep = /zen-types =.*$/im; +const zenDepLine = /^.*zen-(?:expression|tmpl|macros|types)\s*=\s*\{.*}.*$/gim; +const depVersionRegex = /version\s*=\s*"[0-9]+\.[0-9]+\.[0-9]+"/; export const updateCargoContents = (contents: string, { version }: UpdateCargoOptions): string => { return contents .replace(versionRegex, `version = "${version}"`) - .replace(expressionDep, `zen-expression = { path = "../expression", version = "${version}" }`) - .replace(macroDep, `zen-macros = { path = "../macros", version = "${version}" }`) - .replace(typesDep, `zen-types = { path = "../types", version = "${version}" }`) - .replace(templateDep, `zen-tmpl = { path = "../template", version = "${version}" }`); + .replace(zenDepLine, (line) => line.replace(depVersionRegex, `version = "${version}"`)); }; export const getCargoVersion = (contents: string): string => { diff --git a/actions/cargo-version-action/src/index.spec.ts b/actions/cargo-version-action/src/index.spec.ts index 9603ba31..3fa4d478 100644 --- a/actions/cargo-version-action/src/index.spec.ts +++ b/actions/cargo-version-action/src/index.spec.ts @@ -53,6 +53,34 @@ describe('GitHub Action', () => { } }); + test('Preserves default-features and features flags', () => { + const tomlWithFlags = ` + [package] + name = "zen-engine" + version = "0.53.0" + + [dependencies] + zen-types = { path = "../types", version = "0.53.0", default-features = false } + zen-expression = { path = "../expression", version = "0.53.0", default-features = false } + zen-tmpl = { path = "../template", version = "0.53.0", default-features = false } + zen-macros = { path = "../macros", version = "0.53.0" } +`; + + const expected = ` + [package] + name = "zen-engine" + version = "1.0.0" + + [dependencies] + zen-types = { path = "../types", version = "1.0.0", default-features = false } + zen-expression = { path = "../expression", version = "1.0.0", default-features = false } + zen-tmpl = { path = "../template", version = "1.0.0", default-features = false } + zen-macros = { path = "../macros", version = "1.0.0" } +`; + + expect(updateCargoContents(tomlWithFlags, { version: '1.0.0' })).toEqual(expected); + }); + test('Points to right directory', async () => { const escapeDir = (count: number) => '../'.repeat(count); const coreDirectory = path.join(__dirname, escapeDir(3), 'core'); diff --git a/core/engine/Cargo.toml b/core/engine/Cargo.toml index 0f8a5e3f..57baee32 100644 --- a/core/engine/Cargo.toml +++ b/core/engine/Cargo.toml @@ -25,8 +25,8 @@ fixedbitset = "0.5" tokio = { workspace = true, features = ["sync", "time"] } rquickjs = { version = "0.10", features = ["macro", "loader", "rust-alloc", "futures", "either", "properties"] } zen-types = { path = "../types", version = "0.53.0", default-features = false } -zen-expression = { path = "../expression", version = "0.53.0", default-features = false } -zen-tmpl = { path = "../template", version = "0.53.0", default-features = false } +zen-expression = { path = "../expression", version = "0.53.0", default-features = false, features = ["regex-deprecated"] } +zen-tmpl = { path = "../template", version = "0.53.0", default-features = false, features = ["regex-deprecated"] } nohash-hasher = { workspace = true } downcast-rs = { version = "2.0", features = ["std", "sync"] } From 1cc362b2f657dbea2161744220a4baca527077e5 Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 23 Feb 2026 14:19:43 +0100 Subject: [PATCH 08/10] add tests for arbitrary precision and make it non default. add warnings for compilation when arbitrary precision not enabled --- .github/workflows/rust.yaml | 4 ++++ bindings/c/Cargo.toml | 4 ++-- bindings/nodejs/Cargo.toml | 4 ++-- bindings/python/Cargo.toml | 4 ++-- bindings/uniffi/Cargo.toml | 4 ++-- core/engine/Cargo.toml | 8 ++++---- core/expression/Cargo.toml | 4 ++-- core/template/Cargo.toml | 4 ++-- core/types/Cargo.toml | 2 +- core/types/build.rs | 7 +++++++ 10 files changed, 28 insertions(+), 17 deletions(-) create mode 100644 core/types/build.rs diff --git a/.github/workflows/rust.yaml b/.github/workflows/rust.yaml index dd7b6ee4..5b4907d7 100644 --- a/.github/workflows/rust.yaml +++ b/.github/workflows/rust.yaml @@ -54,6 +54,10 @@ jobs: run: rustup install 1.80 - run: cargo test --workspace --all-features --exclude zen-ffi --exclude zen-nodejs --exclude zen-python - run: cargo test --workspace --all-features --exclude zen-ffi --exclude zen-nodejs --exclude zen-python --release + - name: Test without arbitrary_precision + run: cargo test --workspace --exclude zen-ffi --exclude zen-nodejs --exclude zen-python + - name: Test without arbitrary_precision (release) + run: cargo test --workspace --exclude zen-ffi --exclude zen-nodejs --exclude zen-python --release build: name: cargo +${{ matrix.rust }} build diff --git a/bindings/c/Cargo.toml b/bindings/c/Cargo.toml index 7641efc6..ffb31ade 100644 --- a/bindings/c/Cargo.toml +++ b/bindings/c/Cargo.toml @@ -12,8 +12,8 @@ serde = { workspace = true } serde_json = { workspace = true } strum = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["rt"] } -zen-engine = { path = "../../core/engine" } -zen-expression = { path = "../../core/expression" } +zen-engine = { path = "../../core/engine", features = ["arbitrary_precision"] } +zen-expression = { path = "../../core/expression", features = ["arbitrary_precision"] } zen-tmpl = { path = "../../core/template" } [lib] diff --git a/bindings/nodejs/Cargo.toml b/bindings/nodejs/Cargo.toml index f7488dd9..5bc273ee 100644 --- a/bindings/nodejs/Cargo.toml +++ b/bindings/nodejs/Cargo.toml @@ -15,8 +15,8 @@ napi-sys = "3" napi-derive = "3" tokio-util = { workspace = true, features = ["rt"] } serde_json = { workspace = true } -zen-engine = { path = "../../core/engine" } -zen-expression = { path = "../../core/expression" } +zen-engine = { path = "../../core/engine", features = ["arbitrary_precision"] } +zen-expression = { path = "../../core/expression", features = ["arbitrary_precision"] } zen-tmpl = { path = "../../core/template" } serde = { workspace = true, features = ["derive"] } json_dotpath = { workspace = true } diff --git a/bindings/python/Cargo.toml b/bindings/python/Cargo.toml index bd323e73..052a88b0 100644 --- a/bindings/python/Cargo.toml +++ b/bindings/python/Cargo.toml @@ -20,6 +20,6 @@ serde = { workspace = true } serde_json = { workspace = true } rust_decimal = { workspace = true, features = ["maths-nopanic"] } tokio-util = { version = "0.7", features = ["rt"] } -zen-engine = { path = "../../core/engine" } -zen-expression = { path = "../../core/expression" } +zen-engine = { path = "../../core/engine", features = ["arbitrary_precision"] } +zen-expression = { path = "../../core/expression", features = ["arbitrary_precision"] } zen-tmpl = { path = "../../core/template" } diff --git a/bindings/uniffi/Cargo.toml b/bindings/uniffi/Cargo.toml index 8315f77b..570b904c 100644 --- a/bindings/uniffi/Cargo.toml +++ b/bindings/uniffi/Cargo.toml @@ -15,8 +15,8 @@ path = "uniffi-bindgen.rs" [dependencies] uniffi = { version = "0.29", features = ["tokio", "cli"] } serde_json = { workspace = true } -zen-engine = { path = "../../core/engine" } -zen-expression = { path = "../../core/expression" } +zen-engine = { path = "../../core/engine", features = ["arbitrary_precision"] } +zen-expression = { path = "../../core/expression", features = ["arbitrary_precision"] } serde = { workspace = true, features = ["derive"] } async-trait = "0.1" tokio = "1.46" diff --git a/core/engine/Cargo.toml b/core/engine/Cargo.toml index 57baee32..22e5c4ba 100644 --- a/core/engine/Cargo.toml +++ b/core/engine/Cargo.toml @@ -24,9 +24,9 @@ rust_decimal = { workspace = true, features = ["maths-nopanic"] } fixedbitset = "0.5" tokio = { workspace = true, features = ["sync", "time"] } rquickjs = { version = "0.10", features = ["macro", "loader", "rust-alloc", "futures", "either", "properties"] } -zen-types = { path = "../types", version = "0.53.0", default-features = false } -zen-expression = { path = "../expression", version = "0.53.0", default-features = false, features = ["regex-deprecated"] } -zen-tmpl = { path = "../template", version = "0.53.0", default-features = false, features = ["regex-deprecated"] } +zen-types = { path = "../types", version = "0.53.0" } +zen-expression = { path = "../expression", version = "0.53.0" } +zen-tmpl = { path = "../template", version = "0.53.0" } nohash-hasher = { workspace = true } downcast-rs = { version = "2.0", features = ["std", "sync"] } @@ -52,6 +52,6 @@ harness = false name = "engine" [features] -default = ["arbitrary_precision"] +default = [] bindgen = ["rquickjs/bindgen"] arbitrary_precision = ["serde_json/arbitrary_precision", "zen-expression/arbitrary_precision", "zen-types/arbitrary_precision", "zen-tmpl/arbitrary_precision"] \ No newline at end of file diff --git a/core/expression/Cargo.toml b/core/expression/Cargo.toml index 14858f2b..17cc30a0 100644 --- a/core/expression/Cargo.toml +++ b/core/expression/Cargo.toml @@ -30,7 +30,7 @@ strsim = "0.11" iana-time-zone = "0.1" zen-macros = { path = "../macros", version = "0.53.0" } -zen-types = { path = "../types", version = "0.53.0", default-features = false } +zen-types = { path = "../types", version = "0.53.0" } [dev-dependencies] criterion = { workspace = true } @@ -41,7 +41,7 @@ serde_json5 = "0.2" recursive = { workspace = true } [features] -default = ["regex-deprecated", "arbitrary_precision"] +default = ["regex-deprecated"] regex-lite = ["dep:regex-lite"] regex-deprecated = ["dep:regex"] arbitrary_precision = ["serde_json/arbitrary_precision", "zen-types/arbitrary_precision"] diff --git a/core/template/Cargo.toml b/core/template/Cargo.toml index c825e00c..bffc9830 100644 --- a/core/template/Cargo.toml +++ b/core/template/Cargo.toml @@ -8,13 +8,13 @@ edition = "2021" repository = "https://github.com/gorules/zen.git" [dependencies] -zen-expression = { path = "../expression", version = "0.53.0", default-features = false } +zen-expression = { path = "../expression", version = "0.53.0" } thiserror = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } [features] -default = ["regex-deprecated", "arbitrary_precision"] +default = ["regex-deprecated"] regex-lite = ["zen-expression/regex-lite"] regex-deprecated = ["zen-expression/regex-deprecated"] diff --git a/core/types/Cargo.toml b/core/types/Cargo.toml index e3b1b0d4..2da2fa56 100644 --- a/core/types/Cargo.toml +++ b/core/types/Cargo.toml @@ -15,5 +15,5 @@ thiserror = { workspace = true } nohash-hasher = { workspace = true } [features] -default = ["arbitrary_precision"] +default = [] arbitrary_precision = ["serde_json/arbitrary_precision"] diff --git a/core/types/build.rs b/core/types/build.rs new file mode 100644 index 00000000..ae4a0310 --- /dev/null +++ b/core/types/build.rs @@ -0,0 +1,7 @@ +fn main() { + #[cfg(not(feature = "arbitrary_precision"))] + println!("cargo:warning=zen: arbitrary_precision is now opt-in across all zen crates \ + (zen-engine, zen-expression, zen-types). \ + If you rely on precise decimal handling, add features = [\"arbitrary_precision\"]. \ + See CHANGELOG for details."); +} From 06ae6836ace602382beb22db9f4b90d0a0b9053b Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 23 Feb 2026 16:33:36 +0100 Subject: [PATCH 09/10] simplify conversion --- core/types/build.rs | 6 ++-- core/types/src/rcvalue/conv.rs | 25 +++++++++------- core/types/src/rcvalue/ser.rs | 23 +++++++------- core/types/src/variable/conv.rs | 53 ++++++++++++++++++--------------- core/types/src/variable/ser.rs | 23 +++++++------- 5 files changed, 71 insertions(+), 59 deletions(-) diff --git a/core/types/build.rs b/core/types/build.rs index ae4a0310..5b50aa68 100644 --- a/core/types/build.rs +++ b/core/types/build.rs @@ -1,7 +1,9 @@ fn main() { #[cfg(not(feature = "arbitrary_precision"))] - println!("cargo:warning=zen: arbitrary_precision is now opt-in across all zen crates \ + println!( + "cargo:warning=zen: arbitrary_precision is now opt-in across all zen crates \ (zen-engine, zen-expression, zen-types). \ If you rely on precise decimal handling, add features = [\"arbitrary_precision\"]. \ - See CHANGELOG for details."); + See CHANGELOG for details." + ); } diff --git a/core/types/src/rcvalue/conv.rs b/core/types/src/rcvalue/conv.rs index 7f476510..cf2f51ac 100644 --- a/core/types/src/rcvalue/conv.rs +++ b/core/types/src/rcvalue/conv.rs @@ -72,18 +72,21 @@ impl From<&Value> for RcValue { #[cfg(not(feature = "arbitrary_precision"))] { - let decimal = match n.as_u64() { - Some(n) => Decimal::from_u64(n).expect("Allowed number"), - None => match n.as_i64() { - Some(n) => Decimal::from(n), - None => match n.as_f64() { - Some(n) => Decimal::from_f64(n).expect("Allowed number"), - None => panic!("Invalid number"), - }, - }, - }; + if let Some(u) = n.as_u64() { + return RcValue::Number(Decimal::from(u)); + } - RcValue::Number(decimal) + if let Some(i) = n.as_i64() { + return RcValue::Number(Decimal::from(i)); + } + + if let Some(f) = n.as_f64() { + return RcValue::Number(Decimal::from_f64(f).expect("Allowed number")); + } + + unreachable!( + "serde_json::Number is always u64, i64, or f64 without arbitrary_precision" + ); } } Value::String(s) => RcValue::String(Rc::from(s.as_str())), diff --git a/core/types/src/rcvalue/ser.rs b/core/types/src/rcvalue/ser.rs index 0bad00ac..9e18f072 100644 --- a/core/types/src/rcvalue/ser.rs +++ b/core/types/src/rcvalue/ser.rs @@ -26,18 +26,19 @@ impl Serialize for RcValue { } #[cfg(not(feature = "arbitrary_precision"))] RcValue::Number(v) => { - if v.scale() == 0 { - if let Some(i) = v.to_i64() { - return serializer.serialize_i64(i); - } - if let Some(u) = v.to_u64() { - return serializer.serialize_u64(u); - } + if let Some(u) = v.to_u64() { + return serializer.serialize_u64(u); } - let f = v - .to_f64() - .ok_or_else(|| serde::ser::Error::custom("cannot convert to f64"))?; - serializer.serialize_f64(f) + + if let Some(i) = v.to_i64() { + return serializer.serialize_i64(i); + } + + if let Some(f) = v.to_f64() { + return serializer.serialize_f64(f); + } + + Err(serde::ser::Error::custom("cannot convert to f64")) } RcValue::String(v) => serializer.serialize_str(v), RcValue::Array(v) => serializer.collect_seq(v.iter()), diff --git a/core/types/src/variable/conv.rs b/core/types/src/variable/conv.rs index 747e73a7..284ce4ce 100644 --- a/core/types/src/variable/conv.rs +++ b/core/types/src/variable/conv.rs @@ -24,18 +24,21 @@ impl From for Variable { #[cfg(not(feature = "arbitrary_precision"))] { - let decimal = match n.as_u64() { - Some(n) => Decimal::from_u64(n).expect("Allowed number"), - None => match n.as_i64() { - Some(n) => Decimal::from(n), - None => match n.as_f64() { - Some(n) => Decimal::from_f64(n).expect("Allowed number"), - None => panic!("Invalid number"), - }, - }, - }; + if let Some(n) = n.as_u64() { + return Variable::Number(n.into()); + } - Variable::Number(decimal) + if let Some(n) = n.as_i64() { + return Variable::Number(n.into()); + } + + if let Some(n) = n.as_f64() { + return Variable::Number(Decimal::from_f64(n).expect("Allowed number")); + } + + unreachable!( + "serde_json::Number is always u64, i64, or f64 without arbitrary_precision" + ) } } Value::String(s) => Variable::String(Rc::from(s.as_str())), @@ -68,18 +71,21 @@ impl From<&Value> for Variable { #[cfg(not(feature = "arbitrary_precision"))] { - let decimal = match n.as_u64() { - Some(n) => Decimal::from_u64(n).expect("Allowed number"), - None => match n.as_i64() { - Some(n) => Decimal::from(n), - None => match n.as_f64() { - Some(n) => Decimal::from_f64(n).expect("Allowed number"), - None => panic!("Invalid number"), - }, - }, - }; + if let Some(u) = n.as_u64() { + return Variable::Number(u.into()); + } - Variable::Number(decimal) + if let Some(i) = n.as_i64() { + return Variable::Number(i.into()); + } + + if let Some(f) = n.as_f64() { + return Variable::Number(Decimal::from_f64(f).expect("Allowed number")); + } + + unreachable!( + "serde_json::Number is always u64, i64, or f64 without arbitrary_precision" + ); } } Value::String(s) => Variable::String(Rc::from(s.as_str())), @@ -107,8 +113,7 @@ impl From for Value { { Value::Number( Number::from_str(n.normalize().to_string().as_str()) - .map_err(|_| "Invalid number") - .unwrap(), + .expect("Allowed number"), ) } } diff --git a/core/types/src/variable/ser.rs b/core/types/src/variable/ser.rs index 495b525f..304f199b 100644 --- a/core/types/src/variable/ser.rs +++ b/core/types/src/variable/ser.rs @@ -26,18 +26,19 @@ impl Serialize for Variable { } #[cfg(not(feature = "arbitrary_precision"))] Variable::Number(v) => { - if v.scale() == 0 { - if let Some(i) = v.to_i64() { - return serializer.serialize_i64(i); - } - if let Some(u) = v.to_u64() { - return serializer.serialize_u64(u); - } + if let Some(u) = v.to_u64() { + return serializer.serialize_u64(u); } - let f = v - .to_f64() - .ok_or_else(|| serde::ser::Error::custom("cannot convert to f64"))?; - serializer.serialize_f64(f) + + if let Some(i) = v.to_i64() { + return serializer.serialize_i64(i); + } + + if let Some(f) = v.to_f64() { + return serializer.serialize_f64(f); + } + + Err(serde::ser::Error::custom("cannot convert to f64")) } Variable::String(v) => serializer.serialize_str(v), Variable::Array(v) => { From 70a26df6183dd936d5c95d1d774d357ee8812ed4 Mon Sep 17 00:00:00 2001 From: Stefan Date: Tue, 3 Mar 2026 14:00:31 +0100 Subject: [PATCH 10/10] remove build.rs --- core/types/build.rs | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 core/types/build.rs diff --git a/core/types/build.rs b/core/types/build.rs deleted file mode 100644 index 5b50aa68..00000000 --- a/core/types/build.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - #[cfg(not(feature = "arbitrary_precision"))] - println!( - "cargo:warning=zen: arbitrary_precision is now opt-in across all zen crates \ - (zen-engine, zen-expression, zen-types). \ - If you rely on precise decimal handling, add features = [\"arbitrary_precision\"]. \ - See CHANGELOG for details." - ); -}