From 3c095fcda79efbb447cc57fdf63d6432a5e08316 Mon Sep 17 00:00:00 2001 From: "Paul H. Liu" Date: Thu, 17 Jul 2025 21:35:28 -0700 Subject: [PATCH 1/2] fix: fix bug in casting numbers --- src/utils.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index 76236e1..8308843 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -41,17 +41,17 @@ pub fn stringify(v: &IDLValue) -> anyhow::Result> { fn num_cast_helper(v: IDLValue, truncate_float: bool) -> Result { Ok(match v { - IDLValue::Number(n) => n, + IDLValue::Number(n) => n.replace('_', ""), IDLValue::Int64(n) => n.to_string(), IDLValue::Int32(n) => n.to_string(), IDLValue::Int16(n) => n.to_string(), IDLValue::Int8(n) => n.to_string(), - IDLValue::Int(n) => n.to_string(), + IDLValue::Int(n) => n.to_string().replace('_', ""), IDLValue::Nat64(n) => n.to_string(), IDLValue::Nat32(n) => n.to_string(), IDLValue::Nat16(n) => n.to_string(), IDLValue::Nat8(n) => n.to_string(), - IDLValue::Nat(n) => n.to_string(), + IDLValue::Nat(n) => n.to_string().replace('_', ""), IDLValue::Float32(f) => if truncate_float { f.trunc() } else { f }.to_string(), IDLValue::Float64(f) => if truncate_float { f.trunc() } else { f }.to_string(), _ => return Err(anyhow!("{v} is not a number")), @@ -503,3 +503,46 @@ pub fn parse_state_path(paths: &[IDLValue]) -> anyhow::Result { result, }) } + +#[test] +fn test_cast_type_big_num() { + use candid::{Int, Nat}; + + // cast to Nat64 + assert!( + matches!(cast_type(IDLValue::Number("1_000_000".to_string()), &TypeInner::Nat64.into()), + Ok(v) if v == IDLValue::Nat64(1_000_000u64)) + ); + assert!( + matches!(cast_type(IDLValue::Nat(Nat::from(1_000_000u64)), &TypeInner::Nat64.into()), + Ok(v) if v == IDLValue::Nat64(1_000_000u64)) + ); + assert!( + matches!(cast_type(IDLValue::Int(Int::from(1_000_000i64)), &TypeInner::Nat64.into()), + Ok(v) if v == IDLValue::Nat64(1_000_000u64)) + ); + + fn pow + Clone>(base: T, n: i32) -> T { + let mut num = T::from(1u32); + for _ in 0..n { + num *= base.clone(); + } + num + } + + // cast to Float64 + for n in [0i32, 1, 10, 55] { + assert!( + matches!(cast_type(IDLValue::Number(pow(Nat::from(10u64), n).to_string()), &TypeInner::Float64.into()), + Ok(v) if v == IDLValue::Float64(10f64.powi(n))) + ); + assert!( + matches!(cast_type(IDLValue::Nat(pow(Nat::from(10u64), n)), &TypeInner::Float64.into()), + Ok(v) if v == IDLValue::Float64(10f64.powi(n))) + ); + assert!( + matches!(cast_type(IDLValue::Int(pow(Int::from(-10i64), n)), &TypeInner::Float64.into()), + Ok(v) if v == IDLValue::Float64((-10f64).powi(n))) + ); + } +} From c7b47cbdec6044524c1dfd1bbf8f1e1cff90ebcb Mon Sep 17 00:00:00 2001 From: "Paul H. Liu" Date: Thu, 17 Jul 2025 22:01:47 -0700 Subject: [PATCH 2/2] Clippy --- src/exp.rs | 2 +- src/helper.rs | 2 +- src/offline.rs | 4 ++-- src/utils.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/exp.rs b/src/exp.rs index e9958cb..13979e7 100644 --- a/src/exp.rs +++ b/src/exp.rs @@ -661,7 +661,7 @@ impl Exp { let args = input_args(&ctx, &func.args)?; // Ideally, we should store the args in helper and call editor.readline_with_initial to display // the full command in the editor. The tricky part is to know where to insert the args in text. - eprintln!("Generated arguments: {}", args); + eprintln!("Generated arguments: {args}"); eprintln!("Do you want to send this message? [y/N]"); let mut input = String::new(); std::io::stdin().read_line(&mut input)?; diff --git a/src/helper.rs b/src/helper.rs index a21486d..1d365b9 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -417,7 +417,7 @@ fn match_type(line: &str, helper: &MyHelper) -> Option<(usize, Vec)> { for (var, value) in helper.env.0.iter() { let ty = value.value_ty(); if candid::types::subtype::subtype(&mut gamma, env, &ty, expect_ty).is_ok() { - let value = format!("{:?}", value); + let value = format!("{value:?}"); // TODO use floor_char_boundary when available. let value = &value[..20.min(value.len())]; res.push(Pair { diff --git a/src/offline.rs b/src/offline.rs index e67115c..7e4ec8e 100644 --- a/src/offline.rs +++ b/src/offline.rs @@ -142,7 +142,7 @@ pub fn send(helper: &MyHelper, msg: &IngressWithStatus) -> Result { IDLArgs::from_bytes(&bytes)? }; println!("Sending {} call as {}:", message.call_type, sender); - println!(" call \"{}\".{}{};", canister_id, method_name, args); + println!(" call \"{canister_id}\".{method_name}{args};"); println!("Do you want to send this message? [y/N]"); let mut input = String::new(); std::io::stdin().read_line(&mut input)?; @@ -188,6 +188,6 @@ async fn send_internal( } else { IDLArgs::from_bytes(&response)? }; - println!("{}", res); + println!("{res}"); Ok(res) } diff --git a/src/utils.rs b/src/utils.rs index 8308843..6944107 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -278,7 +278,7 @@ pub async fn fetch_state_path(agent: &Agent, mut path: StatePath) -> anyhow::Res })? }; path.effective_id = Some(id); - eprintln!("Using {} as effective canister/subnet id. To change it, put the effective id as the first argument.", id); + eprintln!("Using {id} as effective canister/subnet id. To change it, put the effective id as the first argument."); } fetch_state_path_(agent, path).await }