difftreelog
feat exp-bigint
in: master
16 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -298,6 +298,7 @@
"jrsonnet-macros",
"jrsonnet-parser",
"jrsonnet-types",
+ "num-bigint",
"pathdiff",
"rustc-hash",
"serde",
@@ -370,6 +371,7 @@
"jrsonnet-macros",
"jrsonnet-parser",
"md5",
+ "num-bigint",
"serde",
"serde_json",
"serde_yaml_with_quirks",
@@ -449,6 +451,37 @@
]
[[package]]
+name = "num-bigint"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+ "serde",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
name = "once_cell"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
[workspace]
-package.version = "0.5.0"
+package.version = "0.5.0-pre7"
members = ["crates/*", "bindings/jsonnet", "cmds/jrsonnet", "tests"]
default-members = ["cmds/jrsonnet"]
cmds/jrsonnet/Cargo.tomldiffbeforeafterboth--- a/cmds/jrsonnet/Cargo.toml
+++ b/cmds/jrsonnet/Cargo.toml
@@ -19,6 +19,8 @@
exp-destruct = ["jrsonnet-evaluator/exp-destruct"]
# Iteration over objects yields [key, value] elements
exp-object-iteration = ["jrsonnet-evaluator/exp-object-iteration"]
+# Bigint type
+exp-bigint = ["jrsonnet-evaluator/exp-bigint", "jrsonnet-cli/exp-bigint"]
# std.thisFile support
legacy-this-file = ["jrsonnet-cli/legacy-this-file"]
crates/jrsonnet-cli/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-cli/Cargo.toml
+++ b/crates/jrsonnet-cli/Cargo.toml
@@ -11,6 +11,10 @@
"jrsonnet-evaluator/exp-preserve-order",
"jrsonnet-stdlib/exp-preserve-order",
]
+exp-bigint = [
+ "jrsonnet-evaluator/exp-bigint",
+ "jrsonnet-stdlib/exp-bigint",
+]
legacy-this-file = ["jrsonnet-stdlib/legacy-this-file"]
[dependencies]
crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -24,6 +24,8 @@
exp-destruct = ["jrsonnet-parser/exp-destruct"]
# Iteration over objects yields [key, value] elements
exp-object-iteration = []
+# Bigint type
+exp-bigint = ["num-bigint"]
# Improves performance, and implements some useful things using nightly-only features
nightly = ["hashbrown/nightly"]
@@ -54,3 +56,5 @@
annotate-snippets = { version = "0.9.1", features = ["color"], optional = true }
# Async imports
async-trait = { version = "0.1.60", optional = true }
+# Bigint
+num-bigint = { version = "0.4.3", features = ["serde"], optional = true }
crates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/operator.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/operator.rs
@@ -47,6 +47,8 @@
(Arr(a), Arr(b)) => Val::Arr(ArrValue::extended(a.clone(), b.clone())),
(Num(v1), Num(v2)) => Val::new_checked_num(v1 + v2)?,
+ #[cfg(feature = "exp-bigint")]
+ (BigInt(a), BigInt(b)) => BigInt(Box::new((&**a).clone() + (&**b).clone())),
_ => throw!(BinaryOperatorDoesNotOperateOnValues(
BinaryOpType::Add,
a.value_type(),
@@ -95,6 +97,8 @@
Ok(match (a, b) {
(Str(a), Str(b)) => a.cmp(b),
(Num(a), Num(b)) => a.partial_cmp(b).expect("jsonnet numbers are non NaN"),
+ #[cfg(feature = "exp-bigint")]
+ (BigInt(a), BigInt(b)) => a.cmp(b),
(Arr(a), Arr(b)) => {
if let (Some(ai), Some(bi)) = (a.iter_cheap(), b.iter_cheap()) {
for (a, b) in ai.zip(bi) {
@@ -174,6 +178,12 @@
Num(f64::from((*v1 as i32) >> (*v2 as i32)))
}
+ // Bigint X Bigint
+ #[cfg(feature = "exp-bigint")]
+ (BigInt(a), Mul, BigInt(b)) => BigInt(Box::new((&**a).clone() * (&**b).clone())),
+ #[cfg(feature = "exp-bigint")]
+ (BigInt(a), Sub, BigInt(b)) => BigInt(Box::new((&**a).clone() - (&**b).clone())),
+
_ => throw!(BinaryOperatorDoesNotOperateOnValues(
op,
a.value_type(),
crates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/integrations/serde.rs
+++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs
@@ -162,6 +162,8 @@
Val::Null => serializer.serialize_none(),
Val::Str(s) => serializer.serialize_str(&s.clone().into_flat()),
Val::Num(n) => serializer.serialize_f64(*n),
+ #[cfg(feature = "exp-bigint")]
+ Val::BigInt(b) => b.serialize(serializer),
Val::Arr(arr) => {
let mut seq = serializer.serialize_seq(Some(arr.len()))?;
for (i, element) in arr.iter().enumerate() {
crates/jrsonnet-evaluator/src/manifest.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/manifest.rs
+++ b/crates/jrsonnet-evaluator/src/manifest.rs
@@ -149,6 +149,8 @@
Val::Null => buf.push_str("null"),
Val::Str(s) => escape_string_json_buf(&s.clone().into_flat(), buf),
Val::Num(n) => write!(buf, "{n}").unwrap(),
+ #[cfg(feature = "exp-bigint")]
+ Val::BigInt(n) => write!(buf, "{n}").unwrap(),
Val::Arr(items) => {
buf.push('[');
if !items.is_empty() {
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -311,6 +311,9 @@
/// Should be finite, and not NaN
/// This restriction isn't enforced by enum, as enum field can't be marked as private
Num(f64),
+ /// Experimental bigint
+ #[cfg(feature = "exp-bigint")]
+ BigInt(#[trace(skip)] Box<num_bigint::BigInt>),
/// Represents a Jsonnet array.
Arr(ArrValue),
/// Represents a Jsonnet object.
@@ -389,6 +392,8 @@
match self {
Self::Str(..) => ValType::Str,
Self::Num(..) => ValType::Num,
+ #[cfg(feature = "exp-bigint")]
+ Self::BigInt(..) => ValType::BigInt,
Self::Arr(..) => ValType::Arr,
Self::Obj(..) => ValType::Obj,
Self::Bool(_) => ValType::Bool,
crates/jrsonnet-stdlib/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-stdlib/Cargo.toml
+++ b/crates/jrsonnet-stdlib/Cargo.toml
@@ -17,6 +17,8 @@
exp-preserve-order = ["jrsonnet-evaluator/exp-preserve-order"]
# Add nonstandard `std.sha256` function
exp-more-hashes = ["dep:sha2"]
+# Bigint type
+exp-bigint = ["num-bigint", "jrsonnet-evaluator/exp-bigint"]
[dependencies]
jrsonnet-evaluator.workspace = true
@@ -39,6 +41,7 @@
serde_yaml_with_quirks = "0.8.24"
sha2 = { version = "0.10.6", optional = true }
+num-bigint = { version = "0.4.3", optional = true }
[build-dependencies]
jrsonnet-parser.workspace = true
crates/jrsonnet-stdlib/src/expr.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/expr.rs
+++ b/crates/jrsonnet-stdlib/src/expr.rs
@@ -83,7 +83,7 @@
pub(super) use std::{option::Option, rc::Rc, vec};
pub(super) use jrsonnet_parser::*;
- };
+ }
include!(concat!(env!("OUT_DIR"), "/stdlib.rs"))
}
crates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/lib.rs
+++ b/crates/jrsonnet-stdlib/src/lib.rs
@@ -143,6 +143,8 @@
("asciiLower", builtin_ascii_lower::INST),
("findSubstr", builtin_find_substr::INST),
("parseInt", builtin_parse_int::INST),
+ #[cfg(feature = "exp-bigint")]
+ ("bigint", builtin_bigint::INST),
("parseOctal", builtin_parse_octal::INST),
("parseHex", builtin_parse_hex::INST),
// Misc
crates/jrsonnet-stdlib/src/manifest/toml.rsdiffbeforeafterboth1use std::borrow::Cow;23use jrsonnet_evaluator::{4 manifest::{escape_string_json_buf, ManifestFormat},5 throw,6 val::ArrValue,7 IStr, ObjValue, Result, Val,8};910pub struct TomlFormat<'s> {11 /// Padding before fields, i.e12 /// ```toml13 /// [a]14 /// b = 115 /// ## <- this16 /// ```17 padding: Cow<'s, str>,18 /// Do not emit sections for objects, consisting only from sections:19 /// ```toml20 /// # false21 /// [a]22 /// [a.b]23 ///24 /// # true25 /// [a.b]26 /// ```27 skip_empty_sections: bool,28 /// If true - then order of fields is preserved as written,29 /// instead of sorting alphabetically30 #[cfg(feature = "exp-preserve-order")]31 preserve_order: bool,32}33impl TomlFormat<'_> {34 pub fn cli(35 padding: usize,36 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,37 ) -> Self {38 let padding = " ".repeat(padding);39 Self {40 padding: Cow::Owned(padding),41 skip_empty_sections: true,42 #[cfg(feature = "exp-preserve-order")]43 preserve_order,44 }45 }46 pub fn std_to_toml(47 padding: String,48 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,49 ) -> Self {50 Self {51 padding: Cow::Owned(padding),52 skip_empty_sections: false,53 #[cfg(feature = "exp-preserve-order")]54 preserve_order,55 }56 }57}5859fn bare_allowed(s: &str) -> bool {60 s.bytes()61 .all(|c| matches!(c, b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'_' | b'-'))62}6364fn escape_key_toml_buf(key: &str, buf: &mut String) {65 if bare_allowed(key) {66 buf.push_str(key);67 } else {68 escape_string_json_buf(key, buf);69 }70}7172fn is_section(val: &Val) -> Result<bool> {73 Ok(match val {74 Val::Arr(a) => {75 if a.is_empty() {76 return Ok(false);77 }78 for e in a.iter() {79 let e = e?;80 if !matches!(e, Val::Obj(_)) {81 return Ok(false);82 }83 }84 true85 }86 Val::Obj(_) => true,87 _ => false,88 })89}9091fn manifest_value(92 val: &Val,93 inline: bool,94 buf: &mut String,95 cur_padding: &str,96 options: &TomlFormat<'_>,97) -> Result<()> {98 use std::fmt::Write;99 match val {100 Val::Bool(true) => buf.push_str("true"),101 Val::Bool(false) => buf.push_str("false"),102 Val::Str(s) => {103 escape_string_json_buf(&s.clone().into_flat(), buf);104 }105 Val::Num(n) => write!(buf, "{n}").unwrap(),106 Val::Arr(a) => {107 if a.is_empty() {108 buf.push_str("[]");109 return Ok(());110 }111 for (i, e) in a.iter().enumerate() {112 let e = e?;113 if i != 0 {114 buf.push(',');115 } else {116 buf.push('[');117 }118 if inline {119 buf.push(' ');120 } else {121 buf.push('\n');122 buf.push_str(cur_padding);123 buf.push_str(&options.padding);124 }125 manifest_value(&e, true, buf, "", options)?;126 }127 if inline {128 buf.push(' ');129 } else {130 buf.push('\n');131 buf.push_str(cur_padding);132 }133 buf.push(']');134 }135 Val::Obj(o) => {136 if o.is_empty() {137 buf.push_str("{}");138 }139 buf.push_str("{ ");140 for (i, (k, v)) in o141 .iter(142 #[cfg(feature = "exp-preserve-order")]143 options.preserve_order,144 )145 .enumerate()146 {147 let v = v?;148 if i != 0 {149 buf.push_str(", ");150 }151 escape_key_toml_buf(&k, buf);152 buf.push_str(" = ");153 manifest_value(&v, true, buf, "", options)?;154 }155 buf.push_str(" }");156 }157 Val::Null => {158 throw!("tried to manifest null")159 }160 Val::Func(_) => {161 throw!("tried to manifest function")162 }163 }164 Ok(())165}166167fn manifest_table_internal(168 obj: &ObjValue,169 path: &mut Vec<IStr>,170 buf: &mut String,171 cur_padding: &mut String,172 options: &TomlFormat<'_>,173) -> Result<()> {174 let mut sections = Vec::new();175 let mut first = true;176 for (key, value) in obj.iter(177 #[cfg(feature = "exp-preserve-order")]178 options.preserve_order,179 ) {180 let value = value?;181 if !is_section(&value)? {182 if !first {183 buf.push('\n');184 }185 first = false;186 buf.push_str(cur_padding);187 escape_key_toml_buf(&key, buf);188 buf.push_str(" = ");189 manifest_value(&value, false, buf, cur_padding, options)?;190 } else {191 sections.push((key, value));192 }193 }194 for (k, v) in sections {195 if !first {196 buf.push_str("\n\n");197 }198 first = false;199 path.push(k);200 match v {201 Val::Obj(obj) => manifest_table(&obj, path, buf, cur_padding, options)?,202 Val::Arr(arr) => manifest_table_array(&arr, path, buf, cur_padding, options)?,203 _ => unreachable!("iterating over sections"),204 }205 path.pop();206 }207 Ok(())208}209210fn manifest_table(211 obj: &ObjValue,212 path: &mut Vec<IStr>,213 buf: &mut String,214 cur_padding: &mut String,215 options: &TomlFormat<'_>,216) -> Result<()> {217 if options.skip_empty_sections218 && !obj.is_empty()219 && obj220 .iter(221 #[cfg(feature = "exp-preserve-order")]222 false,223 )224 .try_fold(true, |c, (_, v)| Ok(c && is_section(&v?)?) as Result<bool>)?225 {226 manifest_table_internal(obj, path, buf, cur_padding, options)?;227 return Ok(());228 }229 buf.push_str(cur_padding);230 buf.push('[');231 for (i, k) in path.iter().enumerate() {232 if i != 0 {233 buf.push('.');234 }235 escape_key_toml_buf(k, buf);236 }237 buf.push(']');238 if obj.is_empty() {239 return Ok(());240 }241 buf.push('\n');242 let prev_len = cur_padding.len();243 cur_padding.push_str(&options.padding);244 manifest_table_internal(obj, path, buf, cur_padding, options)?;245 cur_padding.truncate(prev_len);246 Ok(())247}248fn manifest_table_array(249 arr: &ArrValue,250 path: &mut Vec<IStr>,251 buf: &mut String,252 cur_padding: &mut String,253 options: &TomlFormat<'_>,254) -> Result<()> {255 let mut formatted_path = String::new();256 {257 formatted_path.push_str(cur_padding);258 formatted_path.push_str("[[");259 for (i, k) in path.iter().enumerate() {260 if i != 0 {261 formatted_path.push('.');262 }263 escape_key_toml_buf(k, &mut formatted_path);264 }265 formatted_path.push_str("]]");266 }267 let prev_len = cur_padding.len();268 cur_padding.push_str(&options.padding);269 for (i, e) in arr.iter().enumerate() {270 let obj = e.expect("already tested").as_obj().expect("already tested");271 if i != 0 {272 buf.push_str("\n\n");273 }274 buf.push_str(&formatted_path);275 if obj.is_empty() {276 continue;277 }278 buf.push('\n');279 manifest_table_internal(&obj, path, buf, cur_padding, options)?;280 }281 cur_padding.truncate(prev_len);282 Ok(())283}284285impl ManifestFormat for TomlFormat<'_> {286 fn manifest_buf(&self, val: Val, buf: &mut String) -> jrsonnet_evaluator::Result<()> {287 match val {288 Val::Obj(obj) => {289 manifest_table_internal(&obj, &mut Vec::new(), buf, &mut String::new(), self)290 }291 _ => throw!("toml body should be object"),292 }293 }294}1use std::borrow::Cow;23use jrsonnet_evaluator::{4 manifest::{escape_string_json_buf, ManifestFormat},5 throw,6 val::ArrValue,7 IStr, ObjValue, Result, Val,8};910pub struct TomlFormat<'s> {11 /// Padding before fields, i.e12 /// ```toml13 /// [a]14 /// b = 115 /// ## <- this16 /// ```17 padding: Cow<'s, str>,18 /// Do not emit sections for objects, consisting only from sections:19 /// ```toml20 /// # false21 /// [a]22 /// [a.b]23 ///24 /// # true25 /// [a.b]26 /// ```27 skip_empty_sections: bool,28 /// If true - then order of fields is preserved as written,29 /// instead of sorting alphabetically30 #[cfg(feature = "exp-preserve-order")]31 preserve_order: bool,32}33impl TomlFormat<'_> {34 pub fn cli(35 padding: usize,36 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,37 ) -> Self {38 let padding = " ".repeat(padding);39 Self {40 padding: Cow::Owned(padding),41 skip_empty_sections: true,42 #[cfg(feature = "exp-preserve-order")]43 preserve_order,44 }45 }46 pub fn std_to_toml(47 padding: String,48 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,49 ) -> Self {50 Self {51 padding: Cow::Owned(padding),52 skip_empty_sections: false,53 #[cfg(feature = "exp-preserve-order")]54 preserve_order,55 }56 }57}5859fn bare_allowed(s: &str) -> bool {60 s.bytes()61 .all(|c| matches!(c, b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'_' | b'-'))62}6364fn escape_key_toml_buf(key: &str, buf: &mut String) {65 if bare_allowed(key) {66 buf.push_str(key);67 } else {68 escape_string_json_buf(key, buf);69 }70}7172fn is_section(val: &Val) -> Result<bool> {73 Ok(match val {74 Val::Arr(a) => {75 if a.is_empty() {76 return Ok(false);77 }78 for e in a.iter() {79 let e = e?;80 if !matches!(e, Val::Obj(_)) {81 return Ok(false);82 }83 }84 true85 }86 Val::Obj(_) => true,87 _ => false,88 })89}9091fn manifest_value(92 val: &Val,93 inline: bool,94 buf: &mut String,95 cur_padding: &str,96 options: &TomlFormat<'_>,97) -> Result<()> {98 use std::fmt::Write;99 match val {100 Val::Bool(true) => buf.push_str("true"),101 Val::Bool(false) => buf.push_str("false"),102 Val::Str(s) => {103 escape_string_json_buf(&s.clone().into_flat(), buf);104 }105 Val::Num(n) => write!(buf, "{n}").unwrap(),106 #[cfg(feature = "exp-bigint")]107 Val::BigInt(n) => write!(buf, "{n}").unwrap(),108 Val::Arr(a) => {109 if a.is_empty() {110 buf.push_str("[]");111 return Ok(());112 }113 for (i, e) in a.iter().enumerate() {114 let e = e?;115 if i != 0 {116 buf.push(',');117 } else {118 buf.push('[');119 }120 if inline {121 buf.push(' ');122 } else {123 buf.push('\n');124 buf.push_str(cur_padding);125 buf.push_str(&options.padding);126 }127 manifest_value(&e, true, buf, "", options)?;128 }129 if inline {130 buf.push(' ');131 } else {132 buf.push('\n');133 buf.push_str(cur_padding);134 }135 buf.push(']');136 }137 Val::Obj(o) => {138 if o.is_empty() {139 buf.push_str("{}");140 }141 buf.push_str("{ ");142 for (i, (k, v)) in o143 .iter(144 #[cfg(feature = "exp-preserve-order")]145 options.preserve_order,146 )147 .enumerate()148 {149 let v = v?;150 if i != 0 {151 buf.push_str(", ");152 }153 escape_key_toml_buf(&k, buf);154 buf.push_str(" = ");155 manifest_value(&v, true, buf, "", options)?;156 }157 buf.push_str(" }");158 }159 Val::Null => {160 throw!("tried to manifest null")161 }162 Val::Func(_) => {163 throw!("tried to manifest function")164 }165 }166 Ok(())167}168169fn manifest_table_internal(170 obj: &ObjValue,171 path: &mut Vec<IStr>,172 buf: &mut String,173 cur_padding: &mut String,174 options: &TomlFormat<'_>,175) -> Result<()> {176 let mut sections = Vec::new();177 let mut first = true;178 for (key, value) in obj.iter(179 #[cfg(feature = "exp-preserve-order")]180 options.preserve_order,181 ) {182 let value = value?;183 if !is_section(&value)? {184 if !first {185 buf.push('\n');186 }187 first = false;188 buf.push_str(cur_padding);189 escape_key_toml_buf(&key, buf);190 buf.push_str(" = ");191 manifest_value(&value, false, buf, cur_padding, options)?;192 } else {193 sections.push((key, value));194 }195 }196 for (k, v) in sections {197 if !first {198 buf.push_str("\n\n");199 }200 first = false;201 path.push(k);202 match v {203 Val::Obj(obj) => manifest_table(&obj, path, buf, cur_padding, options)?,204 Val::Arr(arr) => manifest_table_array(&arr, path, buf, cur_padding, options)?,205 _ => unreachable!("iterating over sections"),206 }207 path.pop();208 }209 Ok(())210}211212fn manifest_table(213 obj: &ObjValue,214 path: &mut Vec<IStr>,215 buf: &mut String,216 cur_padding: &mut String,217 options: &TomlFormat<'_>,218) -> Result<()> {219 if options.skip_empty_sections220 && !obj.is_empty()221 && obj222 .iter(223 #[cfg(feature = "exp-preserve-order")]224 false,225 )226 .try_fold(true, |c, (_, v)| Ok(c && is_section(&v?)?) as Result<bool>)?227 {228 manifest_table_internal(obj, path, buf, cur_padding, options)?;229 return Ok(());230 }231 buf.push_str(cur_padding);232 buf.push('[');233 for (i, k) in path.iter().enumerate() {234 if i != 0 {235 buf.push('.');236 }237 escape_key_toml_buf(k, buf);238 }239 buf.push(']');240 if obj.is_empty() {241 return Ok(());242 }243 buf.push('\n');244 let prev_len = cur_padding.len();245 cur_padding.push_str(&options.padding);246 manifest_table_internal(obj, path, buf, cur_padding, options)?;247 cur_padding.truncate(prev_len);248 Ok(())249}250fn manifest_table_array(251 arr: &ArrValue,252 path: &mut Vec<IStr>,253 buf: &mut String,254 cur_padding: &mut String,255 options: &TomlFormat<'_>,256) -> Result<()> {257 let mut formatted_path = String::new();258 {259 formatted_path.push_str(cur_padding);260 formatted_path.push_str("[[");261 for (i, k) in path.iter().enumerate() {262 if i != 0 {263 formatted_path.push('.');264 }265 escape_key_toml_buf(k, &mut formatted_path);266 }267 formatted_path.push_str("]]");268 }269 let prev_len = cur_padding.len();270 cur_padding.push_str(&options.padding);271 for (i, e) in arr.iter().enumerate() {272 let obj = e.expect("already tested").as_obj().expect("already tested");273 if i != 0 {274 buf.push_str("\n\n");275 }276 buf.push_str(&formatted_path);277 if obj.is_empty() {278 continue;279 }280 buf.push('\n');281 manifest_table_internal(&obj, path, buf, cur_padding, options)?;282 }283 cur_padding.truncate(prev_len);284 Ok(())285}286287impl ManifestFormat for TomlFormat<'_> {288 fn manifest_buf(&self, val: Val, buf: &mut String) -> jrsonnet_evaluator::Result<()> {289 match val {290 Val::Obj(obj) => {291 manifest_table_internal(&obj, &mut Vec::new(), buf, &mut String::new(), self)292 }293 _ => throw!("toml body should be object"),294 }295 }296}crates/jrsonnet-stdlib/src/manifest/yaml.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/manifest/yaml.rs
+++ b/crates/jrsonnet-stdlib/src/manifest/yaml.rs
@@ -140,6 +140,8 @@
}
}
Val::Num(n) => write!(buf, "{}", *n).unwrap(),
+ #[cfg(feature = "exp-bigint")]
+ Val::BigInt(n) => write!(buf, "{}", *n).unwrap(),
Val::Arr(a) => {
if a.is_empty() {
buf.push_str("[]");
crates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/strings.rs
+++ b/crates/jrsonnet-stdlib/src/strings.rs
@@ -151,6 +151,20 @@
})
}
+#[cfg(feature = "exp-bigint")]
+#[builtin]
+pub fn builtin_bigint(v: Either![f64, IStr]) -> Result<Val> {
+ use Either2::*;
+ Ok(match v {
+ A(a) => Val::BigInt(Box::new((a as i64).into())),
+ B(b) => Val::BigInt(Box::new(
+ b.as_str()
+ .parse()
+ .map_err(|e| RuntimeError(format!("bad bigint: {e}").into()))?,
+ )),
+ })
+}
+
#[cfg(test)]
mod tests {
use super::*;
crates/jrsonnet-types/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-types/src/lib.rs
+++ b/crates/jrsonnet-types/src/lib.rs
@@ -88,6 +88,8 @@
Null,
Str,
Num,
+ #[cfg(feature = "exp-bigint")]
+ BigInt,
Arr,
Obj,
Func,
@@ -101,6 +103,8 @@
Null => "null",
Str => "string",
Num => "number",
+ #[cfg(feature = "exp-bigint")]
+ BigInt => "bigint",
Arr => "array",
Obj => "object",
Func => "function",