taler-rust

GNU Taler code in Rust. Largely core banking integrations.
Log | Files | Refs | Submodules | README | LICENSE

commit 4f7dd68d2d0d34f7c10486e4779ddf1b9e6274c8
parent aeb633aa5bfae3373fc8dba312840d94aee3eeaf
Author: Antoine A <>
Date:   Sat, 15 Feb 2025 12:29:32 +0100

common: clean code

Diffstat:
MCargo.lock | 41+++++++++++++++++------------------------
Mcommon/taler-common/src/types/amount.rs | 24++++++++++++++----------
Mcommon/taler-common/src/types/iban.rs | 6+++---
Mcommon/taler-common/src/types/payto.rs | 42+++++++++++++++++++++---------------------
Mcommon/taler-common/src/types/utils.rs | 6+++++-
Mcommon/taler-test-utils/src/routine.rs | 42+++++++++++++++++++++++-------------------
Mtaler-magnet-bank/src/lib.rs | 1+
7 files changed, 84 insertions(+), 78 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -304,9 +304,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.13" +version = "1.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" +checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" dependencies = [ "shlex", ] @@ -759,9 +759,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" @@ -1791,9 +1791,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944" dependencies = [ "cfg_aliases", "libc", @@ -1831,7 +1831,7 @@ checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.0", - "zerocopy 0.8.17", + "zerocopy 0.8.18", ] [[package]] @@ -1870,7 +1870,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" dependencies = [ "getrandom 0.3.1", - "zerocopy 0.8.17", + "zerocopy 0.8.18", ] [[package]] @@ -1996,15 +1996,14 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.8" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24" dependencies = [ "cc", "cfg-if", "getrandom 0.2.15", "libc", - "spin", "untrusted", "windows-sys 0.52.0", ] @@ -2300,9 +2299,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" dependencies = [ "serde", ] @@ -2318,12 +2317,6 @@ dependencies = [ ] [[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] name = "spki" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3384,11 +3377,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.17" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713" +checksum = "79386d31a42a4996e3336b0919ddb90f81112af416270cff95b5f5af22b839c2" dependencies = [ - "zerocopy-derive 0.8.17", + "zerocopy-derive 0.8.18", ] [[package]] @@ -3404,9 +3397,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.17" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626" +checksum = "76331675d372f91bf8d17e13afbd5fe639200b73d01f0fc748bb059f9cca2db7" dependencies = [ "proc-macro2", "quote", diff --git a/common/taler-common/src/types/amount.rs b/common/taler-common/src/types/amount.rs @@ -129,7 +129,7 @@ impl Decimal { Some(self) } - pub fn add(mut self, rhs: &Self) -> Option<Self> { + pub fn try_add(mut self, rhs: &Self) -> Option<Self> { self.val = self.val.checked_add(rhs.val)?; self.frac = self .frac @@ -249,9 +249,9 @@ impl Amount { Some((self.currency, decimal).into()) } - pub fn add(self, rhs: &Self) -> Option<Self> { + pub fn try_add(self, rhs: &Self) -> Option<Self> { assert_eq!(self.currency, rhs.currency); - let decimal = self.decimal().add(&rhs.decimal())?.normalize()?; + let decimal = self.decimal().try_add(&rhs.decimal())?.normalize()?; Some((self.currency, decimal).into()) } } @@ -366,29 +366,33 @@ fn test_amount_parse() { #[test] fn test_amount_add() { assert_eq!( - Amount::max("EUR").add(&Amount::zero("EUR")), + Amount::max("EUR").try_add(&Amount::zero("EUR")), Some(Amount::max("EUR")) ); assert_eq!( - Amount::zero("EUR").add(&Amount::zero("EUR")), + Amount::zero("EUR").try_add(&Amount::zero("EUR")), Some(Amount::zero("EUR")) ); assert_eq!( - amount("EUR:6.41").add(&amount("EUR:4.69")), + amount("EUR:6.41").try_add(&amount("EUR:4.69")), Some(amount("EUR:11.1")) ); assert_eq!( - amount(format!("EUR:{MAX_VALUE}")).add(&amount("EUR:0.99999999")), + amount(format!("EUR:{MAX_VALUE}")).try_add(&amount("EUR:0.99999999")), Some(Amount::max("EUR")) ); assert_eq!( - amount(format!("EUR:{}", MAX_VALUE - 5)).add(&amount("EUR:6")), + amount(format!("EUR:{}", MAX_VALUE - 5)).try_add(&amount("EUR:6")), None ); - assert_eq!(Amount::new("EUR", u64::MAX, 0).add(&amount("EUR:1")), None); assert_eq!( - amount(format!("EUR:{}.{}", MAX_VALUE - 5, FRAC_BASE - 1)).add(&amount("EUR:5.00000002")), + Amount::new("EUR", u64::MAX, 0).try_add(&amount("EUR:1")), + None + ); + assert_eq!( + amount(format!("EUR:{}.{}", MAX_VALUE - 5, FRAC_BASE - 1)) + .try_add(&amount("EUR:5.00000002")), None ); } diff --git a/common/taler-common/src/types/iban.rs b/common/taler-common/src/types/iban.rs @@ -65,7 +65,7 @@ impl IBAN { pub fn from_parts(country: &str, bban: &str) -> Self { assert_eq!(country.len(), 2); // Create a iban with an empty digit check - let mut iban = InlineStr::from_iter( + let mut iban = InlineStr::try_from_iter( country .as_bytes() .iter() @@ -140,7 +140,7 @@ impl FromStr for IBAN { .all(|b| b.is_ascii_whitespace() || b.is_ascii_alphanumeric()) { Err(IbanErrorKind::Invalid) - } else if let Some(inlined) = InlineStr::from_iter( + } else if let Some(inlined) = InlineStr::try_from_iter( bytes .iter() .filter_map(|b| (!b.is_ascii_whitespace()).then_some(b.to_ascii_uppercase())), @@ -243,7 +243,7 @@ impl FromStr for BIC { Err(BicErrorKind::Invalid) } else { Ok(Self( - InlineStr::from_iter(bytes.iter().copied().map(|b| b.to_ascii_uppercase())) + InlineStr::try_from_iter(bytes.iter().copied().map(|b| b.to_ascii_uppercase())) .unwrap(), )) } diff --git a/common/taler-common/src/types/payto.rs b/common/taler-common/src/types/payto.rs @@ -235,6 +235,18 @@ impl<P: PaytoImpl> TryFrom<&PaytoURI> for Payto<P> { } } +impl<P: PaytoImpl> From<FullPayto<P>> for Payto<P> { + fn from(value: FullPayto<P>) -> Payto<P> { + Payto(value.inner) + } +} + +impl<P: PaytoImpl> From<TransferPayto<P>> for Payto<P> { + fn from(value: TransferPayto<P>) -> Payto<P> { + Payto(value.inner) + } +} + impl<P: PaytoImpl> std::fmt::Display for Payto<P> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.as_payto(), f) @@ -278,12 +290,6 @@ impl<P: PaytoImpl> FullPayto<P> { } } -impl<P: PaytoImpl> Into<Payto<P>> for FullPayto<P> { - fn into(self) -> Payto<P> { - Payto(self.inner) - } -} - impl<P: PaytoImpl> TryFrom<&PaytoURI> for FullPayto<P> { type Error = PaytoErr; @@ -297,6 +303,15 @@ impl<P: PaytoImpl> TryFrom<&PaytoURI> for FullPayto<P> { } } +impl<P: PaytoImpl> From<TransferPayto<P>> for FullPayto<P> { + fn from(value: TransferPayto<P>) -> FullPayto<P> { + FullPayto { + inner: value.inner, + name: value.name, + } + } +} + impl<P: PaytoImpl> std::fmt::Display for FullPayto<P> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(&self.as_payto(), f) @@ -348,21 +363,6 @@ impl<P: PaytoImpl> TransferPayto<P> { } } -impl<P: PaytoImpl> Into<Payto<P>> for TransferPayto<P> { - fn into(self) -> Payto<P> { - Payto(self.inner) - } -} - -impl<P: PaytoImpl> Into<FullPayto<P>> for TransferPayto<P> { - fn into(self) -> FullPayto<P> { - FullPayto { - inner: self.inner, - name: self.name, - } - } -} - impl<P: PaytoImpl> TryFrom<&PaytoURI> for TransferPayto<P> { type Error = PaytoErr; diff --git a/common/taler-common/src/types/utils.rs b/common/taler-common/src/types/utils.rs @@ -42,7 +42,7 @@ impl<const LEN: usize> InlineStr<LEN> { /// Create an inlined string from a string /// Return none if too long #[inline] - pub fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Option<Self> { + pub fn try_from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Option<Self> { let mut len = 0; let mut buf = [0; LEN]; for byte in iter { @@ -56,6 +56,9 @@ impl<const LEN: usize> InlineStr<LEN> { }) } + /// # Safety + /// You must only write valid ASCII chars + #[inline] pub unsafe fn deref_mut(&mut self) -> &mut [u8] { // SAFETY: len <= LEN unsafe { self.buf.get_unchecked_mut(..self.len as usize) } @@ -79,6 +82,7 @@ impl<const LEN: usize> Debug for InlineStr<LEN> { impl<const LEN: usize> Deref for InlineStr<LEN> { type Target = [u8]; + #[inline] fn deref(&self) -> &Self::Target { // SAFETY: len <= LEN unsafe { self.buf.get_unchecked(..self.len as usize) } diff --git a/common/taler-test-utils/src/routine.rs b/common/taler-test-utils/src/routine.rs @@ -97,15 +97,19 @@ pub async fn routine_history< mut ignore: impl FnMut(&'a TestServer, usize) -> FI, ) { // Check history is following specs - let assert_history = |args: String, size: usize| async move { - let resp = server.get(&format!("{url}?{args}")).await; - assert_history_ids(&resp, ids, size) - }; + macro_rules! assert_history { + ($args:expr, $size:expr) => { + async { + let resp = server.get(&format!("{url}?{}", $args)).await; + assert_history_ids(&resp, ids, $size) + } + }; + } // Get latest registered id - let latest_id = || async { assert_history(format!("limit=-1"), 1).await[0] }; + let latest_id = || async { assert_history!("limit=-1", 1).await[0] }; // Check error when no transactions - assert_history(format!("limit=7"), 0).await; + assert_history!("limit=7".to_owned(), 0).await; let mut register_iter = (0..nb_register).peekable(); let mut ignore_iter = (0..nb_ignore).peekable(); @@ -120,25 +124,25 @@ pub async fn routine_history< let nb_total = nb_register + nb_ignore; // Check ignored - assert_history(format!("limit={nb_total}"), nb_register).await; + assert_history!(format_args!("limit={nb_total}"), nb_register).await; // Check skip ignored - assert_history(format!("limit={nb_register}"), nb_register).await; + assert_history!(format_args!("limit={nb_register}"), nb_register).await; // Check no polling when we cannot have more transactions assert_time( 0..100, - assert_history( - format!("limit=-{}&timeout_ms=1000", nb_register + 1), - nb_register, + assert_history!( + format_args!("limit=-{}&timeout_ms=1000", nb_register + 1), + nb_register ), ) .await; // Check no polling when already find transactions even if less than delta assert_time( 0..100, - assert_history( - format!("limit={}&timeout_ms=1000", nb_register + 1), - nb_register, + assert_history!( + format_args!("limit={}&timeout_ms=1000", nb_register + 1), + nb_register ), ) .await; @@ -149,12 +153,12 @@ pub async fn routine_history< // Check polling succeed assert_time( 100..300, - assert_history(format!("limit=2&offset={id}&timeout_ms=1000"), 1) + assert_history!(format_args!("limit=2&offset={id}&timeout_ms=1000"), 1) ), assert_time( 200..300, - assert_history( - format!( + assert_history!( + format_args!( "limit=1&offset={}&timeout_ms=200", id as usize + nb_total * 3 ), @@ -174,7 +178,7 @@ pub async fn routine_history< // Check polling succeed assert_time( 100..300, - assert_history(format!("limit=7&offset={id}&timeout_ms=1000"), 1) + assert_history!(format_args!("limit=7&offset={id}&timeout_ms=1000"), 1) ), async { sleep(Duration::from_millis(100)).await; @@ -189,7 +193,7 @@ pub async fn routine_history< // Check polling succeed assert_time( 200..300, - assert_history(format!("limit=7&offset={id}&timeout_ms=200"), 0) + assert_history!(format_args!("limit=7&offset={id}&timeout_ms=200"), 0) ), async { sleep(Duration::from_millis(100)).await; diff --git a/taler-magnet-bank/src/lib.rs b/taler-magnet-bank/src/lib.rs @@ -41,6 +41,7 @@ pub const MAX_MAGNET_BBAN_SIZE: usize = 24; pub struct HuIban(IBAN); impl HuIban { + #[allow(clippy::identity_op)] pub fn checksum(b: &[u8]) -> Result<(), (u8, u8)> { let expected_digit = b[7] - b'0'; let sum = ((b[0] - b'0') * 9) as u16