From e0acf36e29a24bfd09b11535ceba9c7f2f0a2c7d Mon Sep 17 00:00:00 2001 From: TimLuq Date: Tue, 7 Jan 2025 03:01:30 +0100 Subject: [PATCH] add `format_shared` and `format_queue` macros --- src/macros.rs | 55 +++++++++++++++++++++++++++++++++++++++ src/queue/string_queue.rs | 9 +++++++ src/test/macros.rs | 26 ++++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/src/macros.rs b/src/macros.rs index 60fb4a2..a26ad40 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -41,3 +41,58 @@ macro_rules! concat_str_static { } }; } + +#[cfg(feature = "alloc")] +#[doc(hidden)] +#[inline] +pub fn __format_shared<'a>(args: core::fmt::Arguments<'_>) -> crate::StringData<'a> { + if let Some(args2) = args.as_str() { + return crate::StringData::from_static(args2); + } + let mut me = crate::SharedStrBuilder::new(); + core::fmt::Write::write_fmt(&mut me, args).unwrap(); + me.build_str() +} + +/// Formats a format string with arguments into a shared `StringData`. +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "macros")))] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +#[macro_export] +macro_rules! format_shared { + ($fmt:expr) => { + $crate::__format_shared(core::format_args!($fmt)) + }; + ($fmt:expr, $($args:tt)*) => { + $crate::__format_shared(core::format_args!($fmt, $($args)*)) + }; +} + +#[cfg(feature = "queue")] +#[doc(hidden)] +#[inline] +#[allow(clippy::unwrap_used)] +pub fn __format_queue<'a>(args: core::fmt::Arguments<'_>) -> crate::StringQueue<'a> { + if let Some(args2) = args.as_str() { + return crate::StringQueue::with_item(crate::StringData::from_static(args2)); + } + let mut me = crate::StringQueue::new(); + core::fmt::Write::write_fmt(&mut me, args).unwrap(); + me +} + +/// Formats a format string with arguments into an owned `StringQueue`. +/// +/// There is currently no way to optimize shallow clones of `StringData` or `StringQueue` instances, so prefer to use [`StringQueue::push_back`] or [`StringQueue::append`] to build a queue of prepared strings. +#[cfg(feature = "queue")] +#[cfg_attr(docsrs, doc(cfg(feature = "macros")))] +#[cfg_attr(docsrs, doc(cfg(feature = "queue")))] +#[macro_export] +macro_rules! format_queue { + ($fmt:expr) => { + $crate::__format_queue(core::format_args!($fmt)) + }; + ($fmt:expr, $($args:tt)*) => { + $crate::__format_queue(core::format_args!($fmt, $($args)*)) + }; +} diff --git a/src/queue/string_queue.rs b/src/queue/string_queue.rs index d2ad779..45618fa 100644 --- a/src/queue/string_queue.rs +++ b/src/queue/string_queue.rs @@ -537,6 +537,15 @@ impl core::fmt::Debug for crate::StringQueue<'_> { } } +impl core::fmt::Write for crate::StringQueue<'_> { + #[inline] + #[allow(clippy::min_ident_chars)] + fn write_str(&mut self, s: &str) -> core::fmt::Result { + self.push_back(StringData::from_borrowed(s).into_shared()); + Ok(()) + } +} + impl Default for crate::StringQueue<'_> { #[inline] fn default() -> Self { diff --git a/src/test/macros.rs b/src/test/macros.rs index a37f90d..8e16b93 100644 --- a/src/test/macros.rs +++ b/src/test/macros.rs @@ -9,3 +9,29 @@ fn test_macros_str() { static HW: &str = crate::concat_str_static!("hello", " ", "world"); assert_eq!(HW, "hello world"); } + +#[cfg(feature = "alloc")] +#[test] +fn test_macros_format_shared() { + static CHOICES: &[&str] = &[" you", " world", "... hello... hello", "oooooooo!"]; + static CHOICE_ATOM: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); + let choice = CHOICES + [CHOICE_ATOM.fetch_add(1, core::sync::atomic::Ordering::Relaxed) as usize % CHOICES.len()]; + let hw = crate::format_shared!("{}{}", "hello", choice); + assert_eq!(hw.len(), 5 + choice.len()); + assert!(hw.starts_with("hello")); + assert!(hw.ends_with(choice)); +} + +#[cfg(feature = "queue")] +#[test] +fn test_macros_format_queue() { + static CHOICES: &[&str] = &[" you", " world", "... hello... hello", "oooooooo!"]; + static CHOICE_ATOM: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); + let choice = CHOICES + [CHOICE_ATOM.fetch_add(1, core::sync::atomic::Ordering::Relaxed) as usize % CHOICES.len()]; + let hw = crate::format_queue!("{}{}", "hello", choice); + assert_eq!(hw.len(), 5 + choice.len()); + assert!(hw.starts_with("hello")); + assert!(hw.ends_with(choice)); +}