Skip to content

Commit 8c720f5

Browse files
committed
Add another in-line string macro exposing the lazy [u]Display impl.
Refs #3
1 parent f332679 commit 8c720f5

File tree

1 file changed

+164
-37
lines changed

1 file changed

+164
-37
lines changed

src/string.rs

+164-37
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,28 @@
2323
//! * [`PmString`] a UTF-8 encoded sized byte array in progmem similar to [`ProgMem`].
2424
//!
2525
//! Also the [`progmem`](crate::progmem) macro offers a special syntax for
26-
//! converting a normal string literal into a [`PmString`]:
26+
//! converting a normal string literal into a [`PmString`].
27+
//!
28+
//!
29+
//! # Examples
30+
//!
31+
//! Using [`PmString`] directly via the [`progmem`] macro:
2732
//!
2833
//! ```rust
2934
//! #![feature(const_option)]
3035
//!
3136
//! # use std::iter::FromIterator;
3237
//! use avr_progmem::progmem;
38+
//! use avr_progmem::string::LoadedString;
3339
//!
3440
//! progmem! {
3541
//! // A simple Unicode string in progmem, internally stored as fix-sized
36-
//! // byte array.
42+
//! // byte array, i.e. a `PmString<18>`.
3743
//! static progmem string TEXT = "Hello 大賢者";
3844
//! }
3945
//!
4046
//! // You can load it all at once (like a `ProgMem`)
41-
//! let buffer = TEXT.load();
47+
//! let buffer: LoadedString<15> = TEXT.load();
4248
//! // and use that as `&str`
4349
//! assert_eq!("Hello 大賢者", &*buffer);
4450
//!
@@ -47,6 +53,54 @@
4753
//! let chars_iter = TEXT.chars(); // impl Iterator<Item=char>
4854
//! let exp = ['H', 'e', 'l', 'l', 'o', ' ', '大', '賢', '者'];
4955
//! assert_eq!(&exp, &*Vec::from_iter(chars_iter));
56+
//!
57+
//! // Or you use directly the `Display`/`uDisplay` impl on `PmString`
58+
//! // which uses the chars-iterator internally
59+
//! use ufmt::uWrite;
60+
//! #
61+
//! # struct MyWriter;
62+
//! # impl uWrite for MyWriter {
63+
//! # type Error = ();
64+
//! # fn write_str(&mut self, _s: &str) -> Result<(),()> {
65+
//! # Ok(()) // ignore input
66+
//! # }
67+
//! # }
68+
//! let mut writer =
69+
//! # MyWriter
70+
//! /* SNIP */;
71+
//! #[cfg(feature = "ufmt")] // requires the `ufmt` crate feature
72+
//! ufmt::uwrite!(&mut writer, "{}", TEXT);
73+
//! ```
74+
//!
75+
//! Using the special literal in-line string macros [`progmem_str`] and
76+
//! [`progmem_display`]:
77+
//!
78+
//! ```rust
79+
//! #![feature(const_option)]
80+
//!
81+
//! use avr_progmem::progmem_str as F;
82+
//! use avr_progmem::progmem_display as D;
83+
//!
84+
//! // Or you use directly the `Display`/`uDisplay` impl on `PmString`
85+
//! // which uses the chars-iterator internally
86+
//! use ufmt::uWrite;
87+
//! # struct MyWriter;
88+
//! # impl uWrite for MyWriter {
89+
//! # type Error = ();
90+
//! # fn write_str(&mut self, _s: &str) -> Result<(),()> {
91+
//! # Ok(()) // ignore input
92+
//! # }
93+
//! # }
94+
//! let mut writer =
95+
//! # MyWriter
96+
//! /* SNIP */;
97+
//!
98+
//! // In-line string as temporary `&str`
99+
//! writer.write_str(F!("Hello 大賢者"));
100+
//!
101+
//! // In-line string as some `impl Display + uDisplay`
102+
//! #[cfg(feature = "ufmt")] // requires the `ufmt` crate feature
103+
//! ufmt::uwrite!(&mut writer, "{}", D!("Hello 大賢者"));
50104
//! ```
51105
//!
52106
@@ -78,28 +132,6 @@ pub struct InvalidLengthError;
78132
///
79133
/// This type is particularly useful to store string literals in progmem.
80134
///
81-
/// # Example
82-
///
83-
/// ```rust
84-
/// #![feature(const_option)]
85-
///
86-
/// use avr_progmem::progmem;
87-
/// use avr_progmem::string::PmString;
88-
/// use avr_progmem::string::LoadedString;
89-
///
90-
/// progmem! {
91-
/// // Stores a string as a byte array, i.e. `[u8;19]`, but makes it usable
92-
/// // as `&str` (via `Deref`)
93-
/// static progmem string TEXT = "dai 大賢者 kenja";
94-
/// }
95-
///
96-
/// // The static has type `PmString`
97-
/// let text: &PmString<19> = &TEXT;
98-
/// // The loaded RAM string has type `LoadedString`
99-
/// let loaded: LoadedString<19> = text.load();
100-
/// // Which derefs to `&str`
101-
/// assert_eq!("dai 大賢者 kenja", &*loaded)
102-
/// ```
103135
///
104136
/// # Safety
105137
///
@@ -243,6 +275,7 @@ impl<const N: usize> ufmt::uDisplay for LoadedString<N> {
243275
/// This allows `chars` to be used on very large strings that do not fit into
244276
/// the RAM as whole.
245277
///
278+
///
246279
/// # Safety
247280
///
248281
/// This type is a wrapper around [`ProgMem`], thus it any value of this type
@@ -252,6 +285,30 @@ impl<const N: usize> ufmt::uDisplay for LoadedString<N> {
252285
/// Additionally to the [`ProgMem`] contract, the byte array wrapped by this
253286
/// struct must be valid UTF-8.
254287
///
288+
///
289+
/// # Example
290+
///
291+
/// ```rust
292+
/// #![feature(const_option)]
293+
///
294+
/// use avr_progmem::progmem;
295+
/// use avr_progmem::string::PmString;
296+
/// use avr_progmem::string::LoadedString;
297+
///
298+
/// progmem! {
299+
/// // Stores a string as a byte array, i.e. `[u8;19]`, but makes it usable
300+
/// // as `&str` (via `Deref`)
301+
/// static progmem string TEXT = "dai 大賢者 kenja";
302+
/// }
303+
///
304+
/// // The static has type `PmString`
305+
/// let text: &PmString<19> = &TEXT;
306+
/// // The loaded RAM string has type `LoadedString`
307+
/// let loaded: LoadedString<19> = text.load();
308+
/// // Which derefs to `&str`
309+
/// assert_eq!("dai 大賢者 kenja", &*loaded)
310+
/// ```
311+
///
255312
#[repr(transparent)]
256313
#[non_exhaustive] // SAFETY: this struct must not be publicly constructible
257314
pub struct PmString<const N: usize> {
@@ -450,7 +507,7 @@ impl<'a, const N: usize> Iterator for PmChars<'a, N> {
450507

451508

452509

453-
/// Define a string in progmem
510+
/// Define a string in progmem usable as temporary `&str`
454511
///
455512
/// This is a short-cut macro to create an ad-hoc static storing the given
456513
/// string literal as by [`LoadedString`] and load it here from progmem into a
@@ -460,36 +517,106 @@ impl<'a, const N: usize> Iterator for PmChars<'a, N> {
460517
/// Similar to the C marco, this will load the full string into RAM at once
461518
/// and thus the string should be of limited size, to not exceed the space
462519
/// available in RAM.
520+
/// Also see the [progmem_display] macro which does not have this limitation.
463521
///
464-
/// This macro allows to conveniently put literal string into progmem exactly,
465-
/// where they are used. However, since they are directly loaded into a
466-
/// temporary you don't get a `&'static str` back, and must use the `&str`
467-
/// immediately (i.e. pass it as a function parameter).
522+
/// This macro allows to conveniently put a literal string into progmem
523+
/// right where it is used.
524+
/// However, since they are directly loaded into a temporary you don't get a
525+
/// `&'static str` back, and must use the `&str` immediately (i.e. pass it as a
526+
/// function parameter).
468527
/// You can't even store the returned `&str` in a local `let` assignment.
469528
///
470529
///
471530
/// # Example
472531
///
473532
/// ```rust
474533
/// #![feature(const_option)]
475-
///
476534
/// use avr_progmem::progmem_str as F;
535+
/// use ufmt::uWrite;
477536
///
478-
/// fn print(s: &str) {
479-
/// // -- snip --
480-
/// # assert_eq!(s, "dai 大賢者 kenja")
481-
/// }
537+
/// # struct MyWriter;
538+
/// # impl uWrite for MyWriter {
539+
/// # type Error = ();
540+
/// # fn write_str(&mut self, _s: &str) -> Result<(),()> {
541+
/// # Ok(()) // ignore input
542+
/// # }
543+
/// # }
544+
/// #
545+
/// let mut writer = // impl uWrite
546+
/// # MyWriter;
547+
/// /* SNIP */;
482548
///
483549
/// // Put the literal `str` into progmem and load it here as `&str`
484-
/// print(F!("dai 大賢者 kenja"));
550+
/// writer.write_str(F!("dai 大賢者 kenja"));
485551
/// ```
486552
///
487553
#[macro_export]
488554
macro_rules! progmem_str {
489-
($text:literal) => {{
555+
($text:expr) => {{
490556
$crate::progmem! {
491557
static progmem string TEXT = $text;
492558
}
493559
&*TEXT.load()
494560
}};
495561
}
562+
563+
564+
/// Define a string in progmem usable as `impl Display + uDisplay`
565+
///
566+
/// This is a short-cut macro to create an ad-hoc static storing the given
567+
/// string literal as a [`PmString`] and return it.
568+
/// This is somewhat similar to the `F` macro available in Arduino IDE, but
569+
/// different.
570+
/// For a macro more in line with the `F` macro, see [progmem_str].
571+
///
572+
/// Unlike the `F` macro, this macro neither loads the string here, nor, can
573+
/// it be use as a `&str`.
574+
/// However, the returned value implements [Display](fmt::Display) as well as
575+
/// [ufmt::uDisplay] (if the `ufmt` crate feature is enabled).
576+
///
577+
/// This macro allows to conveniently put a literal string into progmem
578+
/// right where it is used.
579+
/// However, since it is not loaded (yet) into RAM it is not a `&str`, it only
580+
/// exposes a [Display](fmt::Display) and [ufmt::uDisplay] (if the `ufmt` crate
581+
/// feature is enabled) implementation,
582+
/// which will load it char-by-char when used, thus limiting the RAM usage,
583+
/// and allowing arbitrarily large strings to be wrapped.
584+
///
585+
///
586+
/// # Example
587+
///
588+
/// ```rust
589+
/// #![feature(const_option)]
590+
/// use avr_progmem::progmem_display as D;
591+
/// use ufmt::uWrite;
592+
///
593+
/// # struct MyWriter;
594+
/// # impl uWrite for MyWriter {
595+
/// # type Error = ();
596+
/// # fn write_str(&mut self, _s: &str) -> Result<(),()> {
597+
/// # Ok(()) // ignore input
598+
/// # }
599+
/// # }
600+
/// #
601+
/// let mut writer = // impl uWrite
602+
/// # MyWriter;
603+
/// /* SNIP */;
604+
///
605+
/// // Put the literal `str` into progmem and use it as `impl uDisplay`
606+
/// #[cfg(feature = "ufmt")] // requires the `ufmt` crate feature
607+
/// ufmt::uwrite!(&mut writer, "{}", D!("dai 大賢者 kenja"));
608+
///
609+
/// // Huge strings are fine
610+
/// #[cfg(feature = "ufmt")] // requires the `ufmt` crate feature
611+
/// ufmt::uwrite!(&mut writer, "{}", D!(include_str!("../examples/test_text.txt")));
612+
/// ```
613+
///
614+
#[macro_export]
615+
macro_rules! progmem_display {
616+
($text:expr) => {{
617+
$crate::progmem! {
618+
static progmem string TEXT = $text;
619+
}
620+
&TEXT
621+
}};
622+
}

0 commit comments

Comments
 (0)