avr_progmem/wrapper.rs
1//! Best-effort safe wrapper for progmem.
2//!
3//! This module offers the [`ProgMem`] struct that wraps pointers into progmem,
4//! and only gives access to that value via methods that first load the value
5//! into the normal data memory domain.
6//! This is also the reason why the value must be `Copy` and is always returned
7//! by-value instead of by-reference (since the value is not in the data memory
8//! where it could be referenced).
9//!
10//! Since the `ProgMem` struct loads the value using special instructions,
11//! it really must be in progmem, otherwise it would be **undefined behavior**
12//! to use any of its methods.
13//! Therefore, its constructor is `unsafe` where the
14//! caller must guarantee that the given pointer truly points to a valid value
15//! stored in progmem.
16//!
17//! As convenience, the [`progmem`] macro is offered that will create
18//! a `static` in progmem with the given value and wrap a pointer to it in the
19//! [`ProgMem`] struct for you.
20
21
22use derivative::Derivative;
23
24#[cfg(doc)]
25use crate::progmem;
26use crate::raw::read_value;
27
28
29
30/// Best-effort safe wrapper around a value in program memory.
31///
32/// This type wraps a pointer to a value that is stored in program memory,
33/// and offers safe functions to [`load`](ProgMem::load) that value from
34/// program memory into the data memory domain from where it can be normally
35/// used.
36///
37/// Since its constructor is the single most critical point in its API,
38/// it is `unsafe`, despite it is supposed to be a safe wrapper (hence the
39/// 'best-effort' notation).
40/// The caller of the constructor therefore must ensure that the supplied
41/// pointer points to a valid value stored in program memory.
42///
43/// Consequently, the only way to use this struct soundly is to define a
44/// `static` with the `#[link_section = ".progmem.data"]` attribute on it and
45/// pass a pointer to that `static` to `ProgMem::new`.
46/// However, having an accessible `static` around that is stored in progmem
47/// is a very dangerous endeavor.
48///
49/// In order to make working with progmem safer and more convenient,
50/// consider using the [`progmem`] macro, that will put the given data
51/// into a hidden `static` in progmem and provide you with an accessible static
52/// containing the pointer to it wrapped in `ProgMem`.
53///
54/// Since this is just a fancy immutable pointer type, it can always be
55/// copied/cloned (just copies the address). It also implements `Debug`,
56/// which simply prints the address (into progmem) of the wrapped value.
57/// And you can even coerce the pointed-to type e.g. from an statically sized
58/// array to a dynamically sized slice type (it also allow to coerce to a trait
59/// object, but those will not be useful at all), either using the
60/// [`as_slice`][ProgMem::as_slice] method, or by enabling the "unsize" crate
61/// feature that allows normal Rust coercing.
62///
63///
64/// # Safety
65///
66/// The `target` pointer in this struct must point to a valid object of type
67/// `T` that is stored in the program memory domain.
68/// The object must be initialized, readable, and immutable (i.e. it must not
69/// be changed).
70/// Also the `target` pointer must be valid for the `'static` lifetime.
71///
72/// However, the requirement about the program memory domain only applies
73/// to the AVR architecture (`#[cfg(target_arch = "avr")]`),
74/// otherwise normal data access primitives are used.
75/// This means that the value must be stored in the
76/// regular data memory domain for ALL OTHER architectures! This still
77/// holds, even if such other architecture is of the Harvard architecture,
78/// because this is an AVR-only crate, not a general Harvard architecture
79/// crate!
80///
81//
82//
83// SAFETY: Must not be publicly creatable
84#[non_exhaustive]
85//
86// We use Derivative here to get rid of the constraint on the impls, which
87// a normal derive would add.
88#[derive(Derivative)]
89// This is just a pointer type/wrapper thus it is safe & sound to just copy it.
90// Notice, it will just copy the pointer (i.e. the address), thus `T` doesn't
91// even need to implement any of these traits.
92#[derivative(Copy(bound = ""), Clone(bound = ""), Debug(bound = ""))]
93pub struct ProgMem<T: ?Sized> {
94 /// Points to some `T` in progmem.
95 ///
96 /// # Safety
97 ///
98 /// See the struct doc.
99 target: *const T,
100}
101
102
103/// Implement `uDebug` by hand, because the derive variant adds a sized constraint.
104///
105#[cfg(feature = "ufmt")]
106impl<T: ?Sized> ufmt::uDebug for ProgMem<T> {
107 fn fmt<W>(&self, fmt: &mut ufmt::Formatter<'_, W>) -> Result<(), W::Error>
108 where
109 W: ufmt::uWrite + ?Sized,
110 {
111 fmt.debug_struct("ProgMem")?
112 // It be better to just pass the pointer as is,
113 // however `ufmt` has - for what ever reason - a size constraint,
114 // so we first cast it down to a sized type.
115 .field("target", &self.target.cast::<()>())?
116 .finish()
117 }
118}
119
120unsafe impl<T: ?Sized> Send for ProgMem<T> {
121 // SAFETY: pointers per-se are sound to send & share.
122 // Further more, we will never mutate the underling value, thus `ProgMem`
123 // can be considered as some sort of sharable `'static` "reference".
124 // Thus it can be shared and transferred between threads.
125}
126
127unsafe impl<T: ?Sized> Sync for ProgMem<T> {
128 // SAFETY: pointers per-se are sound to send & share.
129 // Further more, we will never mutate the underling value, thus `ProgMem`
130 // can be considered as some sort of sharable `'static` "reference".
131 // Thus it can be shared and transferred between threads.
132}
133
134impl<T: ?Sized> ProgMem<T> {
135 /// Return the raw pointer to the inner value.
136 ///
137 /// Notice that the returned pointer is indeed a pointer into the progmem
138 /// domain! It may **never** be dereferenced via the default Rust operations.
139 /// That means a `unsafe{*pm.as_ptr()}` is **undefined behavior**!
140 ///
141 /// Instead, if you want to use the pointer, you may want to use one of
142 /// the "raw" functions, see the [raw](crate::raw) module.
143 ///
144 pub fn as_ptr(&self) -> *const T {
145 self.target
146 }
147}
148
149impl<T> ProgMem<T> {
150 /// Construct a new instance of this type.
151 ///
152 /// This struct is a pointer wrapper for data in the program memory domain.
153 /// Therefore when constructing this struct, it must be guaranteed
154 /// that the pointed data is stored in progmem!
155 /// This contract is expressed by the fact that this function is `unsafe`.
156 /// See the Safety section for details.
157 ///
158 /// You should not need to call this function directly.
159 /// It is recommended to use the [`progmem`] macro instead (which calls
160 /// this constructor for you, while enforcing its contract.
161 ///
162 ///
163 /// # Safety
164 ///
165 /// The `ProgMem` wrapper is build around the invariant that the wrapped
166 /// pointer is stored in the program code memory domain (on the AVR
167 /// architecture).
168 ///
169 /// That means that this function is only sound to call, if the value to
170 /// which `target` points is stored in a `static` that is stored in progmem,
171 /// e.g. by using the attribute `#[link_section = ".progmem.data"]`.
172 ///
173 /// However, the above requirement about the program memory domain only
174 /// applies to the AVR architecture (`#[cfg(target_arch = "avr")]`),
175 /// otherwise normal data access primitives are used,
176 /// and thus the `target` pointer needs to point to normal data on those
177 /// architectures.
178 ///
179 pub const unsafe fn new(target: *const T) -> Self {
180 ProgMem {
181 target,
182 }
183 }
184}
185
186impl<T: Copy> ProgMem<T> {
187 /// Read the inner value from progmem and return a regular value.
188 ///
189 /// # Panics
190 ///
191 /// This method panics, if the size of the value (i.e. `size_of::<T>()`)
192 /// is beyond 255 bytes.
193 /// However, this is currently just a implementation limitation, which may
194 /// be lifted in the future.
195 ///
196 /// Also notice, if you really hit this limit, you would need 256+ bytes on
197 /// your stack, on the Arduino Uno (at least) that means that you might be
198 /// close to a stack overflow. Thus it might be better to restructure your
199 /// data, so you can store it as an array of something, than you can use
200 /// the [`load_at`] and [`load_sub_array`] methods instead.
201 ///
202 /// [`load_at`]: struct.ProgMem.html#method.load_at
203 /// [`load_sub_array`]: struct.ProgMem.html#method.load_sub_array
204 ///
205 pub fn load(&self) -> T {
206 // This is safe, because the invariant of this struct guarantees that
207 // this value (i.e. target) is stored in the progmem domain,
208 // which is what `read_value` requires from us.
209 unsafe { read_value(self.target) }
210 }
211}
212
213/// Utilities to work with an array in progmem.
214impl<T, const N: usize> ProgMem<[T; N]> {
215 /// Get a reference to an element from the array, without loading it.
216 ///
217 /// # Panics
218 ///
219 /// This method panics, if the given index `idx` is grater or equal to the
220 /// length `N` of the array.
221 pub fn at(&self, idx: usize) -> ProgMem<T> {
222 // Just use the slice impl
223 let slice: ProgMem<[T]> = self.as_slice();
224 slice.at(idx)
225 }
226
227 /// Iterate over all elements as wrappers.
228 ///
229 /// Returns an iterator, which yields each element as a `ProgMem<T>`,
230 /// which can be subsequently loaded.
231 pub fn wrapper_iter(&self) -> PmWrapperIter<T> {
232 PmWrapperIter::new(self.as_slice())
233 }
234
235 /// Returns the length of the array (i.e. `N`)
236 pub fn len(&self) -> usize {
237 N
238 }
239
240 /// Coerce this array wrapper into a slice wrapper.
241 ///
242 /// Notice, if you enable the "unsize" crate feature, you can directly
243 /// coerce the `ProgMem` struct, otherwise you have to use this function
244 /// instead.
245 ///
246 /// This analog to normal Rust coercing of arrays to slices.
247 /// Indeed, if you enable the crate feature "unsize", you can use normal
248 /// Rust coercing to get the same result.
249 ///
250 /// # Examples
251 ///
252 /// ```rust
253 /// use avr_progmem::wrapper::ProgMem;
254 /// use avr_progmem::progmem;
255 ///
256 /// progmem!{
257 /// static progmem ARR: [u8; 3] = [1,2,3];
258 /// }
259 ///
260 /// // The array wrapper
261 /// let arr: ProgMem<[u8; 3]> = ARR;
262 /// // Coerced to a slice wrapper.
263 /// let s: ProgMem<[u8]> = arr.as_slice();
264 ///
265 /// // If you enable the "unsize" crate feature, you can just coerce like that:
266 /// #[cfg(feature = "unsize")]
267 /// let s: ProgMem<[u8]> = arr;
268 /// ```
269 ///
270 pub fn as_slice(&self) -> ProgMem<[T]> {
271 ProgMem {
272 target: self.target,
273 }
274 }
275}
276
277/// Loading elements of an array in progmem.
278impl<T: Copy, const N: usize> ProgMem<[T; N]> {
279 /// Load a single element from the inner array.
280 ///
281 /// This method is analog to a slice indexing `self.load()[idx]`, so the
282 /// same requirements apply, like the index `idx` should be less then the
283 /// length `N` of the array, otherwise a panic will be risen.
284 ///
285 ///
286 /// # Panics
287 ///
288 /// This method panics, if the given index `idx` is grater or equal to the
289 /// length `N` of the inner type.
290 ///
291 /// This method also panics, if the size of the value (i.e. `size_of::<T>()`)
292 /// is beyond 255 bytes.
293 /// However, this is currently just a implementation limitation, which may
294 /// be lifted in the future.
295 ///
296 /// Notice, that here `T` is the type of the elements not the entire array
297 /// as it would be with [`load`](Self::load).
298 ///
299 pub fn load_at(&self, idx: usize) -> T {
300 // Just get the element wrapper and load it
301 self.at(idx).load()
302 }
303
304 /// Loads a sub array from the inner array.
305 ///
306 /// This method is analog to a sub-slicing `self.load()[idx..(idx+M)]` but
307 /// returning an owned array instead of a slice, simply because it has to
308 /// copy the data anyway from the progmem into the data domain (i.e. the
309 /// stack).
310 ///
311 /// Also notice, that since this crate is intended for AVR
312 /// micro-controllers, static arrays are generally preferred over
313 /// dynamically allocated types such as a `Vec`.
314 ///
315 ///
316 /// # Panics
317 ///
318 /// This method panics, if the given index `idx` is grater or equal to the
319 /// length `N` of the inner array, or the end index `idx+M` is grater than
320 /// the length `N` of the inner array.
321 ///
322 /// This method also panics, if the size of the value
323 /// (i.e. `size_of::<[T;M]>()`) is beyond 255 bytes.
324 /// However, this is currently just a implementation limitation, which may
325 /// be lifted in the future.
326 ///
327 pub fn load_sub_array<const M: usize>(&self, start_idx: usize) -> [T; M] {
328 // Just a check to give a nicer panic message
329 assert!(
330 M <= N,
331 "The sub array can not be grater than the source array"
332 );
333
334 // SAFETY: bounds check, the last element of the sub array must
335 // still be within the source array (i.e. self)
336 assert!(
337 start_idx + M <= N,
338 "The sub array goes beyond the end of the source array"
339 );
340
341 let first_source_element_ptr: *const T = self.target.cast();
342
343 // Get a point to the selected element
344 let first_output_element_ptr = first_source_element_ptr.wrapping_add(start_idx);
345
346 // Pointer into as sub array into the source
347 let sub_array_ptr: *const [T; M] = first_output_element_ptr.cast();
348
349 // SAFETY: This is safe, because the invariant of this struct demands
350 // that this value (i.e. self and thus also its inner value) are stored
351 // in the progmem domain, which is what `read_value` requires from us.
352 unsafe { read_value(sub_array_ptr) }
353 }
354
355 /// Lazily iterate over all elements
356 ///
357 /// Returns an iterator which lazily loads the elements one at a time
358 /// from progmem.
359 /// This means this iterator can be used to access huge arrays while
360 /// only requiring `size_of::<T>()` amount of stack memory.
361 ///
362 /// # Panics
363 ///
364 /// The returned iterator will panic, if the size of an element (i.e. `size_of::<T>()`)
365 /// is beyond 255 bytes.
366 /// However, this is currently just a implementation limitation, which may
367 /// be lifted in the future.
368 ///
369 /// Notice, that here `T` is the type of the elements not the entire array
370 /// as it would be with [`load`](Self::load).
371 ///
372 pub fn iter(&self) -> PmIter<T, N> {
373 PmIter::new(self)
374 }
375}
376
377/// Utilities to work with an slice wrapper.
378///
379/// You can obtain a slice wrapper by coercing an array wrapper.
380impl<T> ProgMem<[T]> {
381 /// Get a reference to an element from the array, without loading it.
382 ///
383 /// # Panics
384 ///
385 /// This method panics, if the given index `idx` is grater or equal to the
386 /// length of the slice.
387 pub fn at(&self, idx: usize) -> ProgMem<T> {
388 // SAFETY: check that `idx` is in bounds
389 assert!(idx < self.target.len(), "Given index is out of bounds");
390
391 let first_element_ptr: *const T = self.target.cast();
392
393 // Get a point to the selected element
394 let element_ptr = first_element_ptr.wrapping_add(idx);
395
396 // This sound, because `self.target` is in program domain and we checked
397 // above that `idx` is in bound, thus that element pointer is also
398 // valid and pointing into the program domain.
399 ProgMem {
400 target: element_ptr,
401 }
402 }
403
404 /// Iterate over all elements as wrappers.
405 ///
406 /// Returns an iterator, which yields each element as a `ProgMem<T>`,
407 /// which can be subsequently loaded.
408 pub fn wrapper_iter(&self) -> PmWrapperIter<T> {
409 PmWrapperIter::new(*self)
410 }
411
412 /// Returns the length of the slice
413 pub fn len(&self) -> usize {
414 self.target.len()
415 }
416}
417
418/// Loading elements of an array in progmem.
419impl<T: Copy> ProgMem<[T]> {
420 /// Load a single element from the slice.
421 ///
422 /// This method is analog to a slice indexing, thus the same requirements
423 /// apply: the index `idx` should be less then the length of the slice,
424 /// otherwise a panic will be risen.
425 ///
426 ///
427 /// # Panics
428 ///
429 /// This method panics, if the given index `idx` is grater or equal to the
430 /// length of the slice.
431 ///
432 /// This method also panics, if the size of the value (i.e. `size_of::<T>()`)
433 /// is beyond 255 bytes.
434 /// However, this is currently just a implementation limitation, which may
435 /// be lifted in the future.
436 ///
437 /// Notice, that here `T` is the type of the elements not the entire slice.
438 ///
439 pub fn load_at(&self, idx: usize) -> T {
440 // Just get the element wrapper and load it
441 self.at(idx).load()
442 }
443}
444
445
446/// Allows coercing a `ProgMem<T>` to a `ProgMem<U>`, where U might be unsized.
447///
448/// A classic example of this is coercing an array `ProgMem<[T; N]>` into a
449/// slice `ProgMem<[T]>`. Thus this impl is a generalization of the
450/// [`as_slice`][ProgMem::as_slice] method.
451///
452/// # Examples
453///
454/// ```rust
455/// use avr_progmem::wrapper::ProgMem;
456/// use avr_progmem::progmem;
457///
458/// progmem!{
459/// static progmem ARR: [u8; 3] = [1,2,3];
460/// }
461///
462/// // The array wrapper
463/// let arr: ProgMem<[u8; 3]> = ARR;
464/// // Coerced to a slice wrapper, just like that.
465/// let s: ProgMem<[u8]> = arr;
466/// ```
467#[cfg(feature = "unsize")]
468impl<T: ?Sized, U: ?Sized> core::ops::CoerceUnsized<ProgMem<U>> for ProgMem<T> where
469 T: core::marker::Unsize<U>
470{
471}
472
473/// An iterator over an array in progmem.
474///
475/// Can be acquired via [`ProgMem::iter`].
476pub struct PmIter<'a, T, const N: usize> {
477 progmem: &'a ProgMem<[T; N]>,
478 current_idx: usize,
479}
480
481impl<'a, T, const N: usize> PmIter<'a, T, N> {
482 /// Creates a new iterator over the given progmem array.
483 pub const fn new(pm: &'a ProgMem<[T; N]>) -> Self {
484 Self {
485 progmem: pm,
486 current_idx: 0,
487 }
488 }
489}
490
491impl<'a, T: Copy, const N: usize> Iterator for PmIter<'a, T, N> {
492 type Item = T;
493
494 fn next(&mut self) -> Option<Self::Item> {
495 // Check for iterator end
496 if self.current_idx < N {
497 // Load next item from progmem
498 let b = self.progmem.load_at(self.current_idx);
499 self.current_idx += 1;
500
501 Some(b)
502 } else {
503 None
504 }
505 }
506}
507
508/// Same as [`ProgMem::iter`]
509impl<'a, T: Copy, const N: usize> IntoIterator for &'a ProgMem<[T; N]> {
510 type IntoIter = PmIter<'a, T, N>;
511 type Item = T;
512
513 fn into_iter(self) -> Self::IntoIter {
514 self.iter()
515 }
516}
517
518/// An iterator over an array in progmem, without loading elements
519///
520/// Can be acquired via [`ProgMem::wrapper_iter`].
521pub struct PmWrapperIter<T> {
522 progmem: ProgMem<[T]>,
523 current_idx: usize,
524}
525
526impl<T> PmWrapperIter<T> {
527 /// Creates a new iterator over the given progmem array.
528 pub const fn new(pm: ProgMem<[T]>) -> Self {
529 Self {
530 progmem: pm,
531 current_idx: 0,
532 }
533 }
534}
535
536impl<T> Iterator for PmWrapperIter<T> {
537 type Item = ProgMem<T>;
538
539 fn next(&mut self) -> Option<Self::Item> {
540 // Check for iterator end
541 if self.current_idx < self.progmem.len() {
542 // Get next element wrapper
543 let b = self.progmem.at(self.current_idx);
544 self.current_idx += 1;
545
546 Some(b)
547 } else {
548 None
549 }
550 }
551}
552
553
554
555/// Define a static in progmem.
556///
557/// This is a helper macro to simplify the definition of statics that are valid
558/// to be wrapped in the `ProgMem` struct thus providing a safe way to work
559/// with data in progmem.
560///
561/// Thus this macro essentially takes a user static definition and emits a
562/// definition that is defined to be stored in the progmem section and then is
563/// wrap in the `ProgMem` wrapper for safe access.
564///
565/// There are essentially three types of statics that you can created:
566///
567/// * ordinary fixed-size data, e.g. a `u8`, `(u16,u32)`, or your own struct.
568/// * "auto-sized" arrays, essentially any kind of array `[T; N]`
569/// * strings, i.e. anything `str`-ish such as string literals
570///
571///
572/// # Ordinary Data
573///
574/// You can store any `Copy + Sized` data in progmem and load it at your
575/// leisure.
576///
577/// ## Example
578///
579/// ```
580/// use avr_progmem::progmem;
581///
582/// #[derive(Copy, Clone)]
583/// struct Foo {
584/// a: u16,
585/// b: u32,
586/// }
587///
588/// progmem!{
589/// /// Static data stored in progmem!
590/// pub static progmem BYTE: u8 = b'a';
591///
592/// /// Anything that is `Copy + Sized`
593/// pub static progmem FOO: Foo = Foo { a: 42, b: 42 * 42 };
594/// }
595///
596/// // Loading the byte from progmem onto the stack
597/// let data: u8 = BYTE.load();
598/// assert_eq!(b'a', data);
599///
600/// // Loading the arbitrary data
601/// let foo: Foo = FOO.load();
602/// assert_eq!(42, foo.a);
603/// assert_eq!(1764, foo.b);
604/// ```
605///
606///
607/// # Arrays
608///
609/// Notice, that to access ordinary data from the progmem you have to load it
610/// as whole before you can do anything with it.
611/// In other words you can't just load `foo.a`, you have to first load the
612/// entire struct into RAM.
613///
614/// When we have arrays, stuff can get hugh quickly, therefore,
615/// specifically for arrays, we have additionally accessors to access elements
616/// individually, without the burden to load the entire array first.
617///
618/// ```
619/// use avr_progmem::progmem;
620///
621/// progmem!{
622/// /// A simple array using ordinary syntax
623/// pub static progmem ARRAY: [u16; 4] = [1, 2, 3, 4];
624/// }
625///
626/// // We can still load the entire array (but you shouldn't do this with
627/// // big arrays)
628/// let array: [u16; 4] = ARRAY.load();
629/// assert_eq!([1,2,3,4], array);
630///
631/// // We can also load individual elements
632/// let last_elem: u16 = ARRAY.load_at(3);
633/// assert_eq!(4, last_elem);
634///
635/// // And even arbitrary sub-arrays (tho they need to be statically sized)
636/// let middle_stuff: [u16; 2] = ARRAY.load_sub_array(1);
637/// assert_eq!([2, 3], middle_stuff);
638///
639/// // Finally, we can iterate the array lazily loading one byte after another
640/// // so we need only just enough RAM for to handle a single element
641/// let mut elem_iter = ARRAY.iter();
642/// assert_eq!(Some(1), elem_iter.next());
643/// assert_eq!(Some(2), elem_iter.next());
644/// assert_eq!(Some(3), elem_iter.next());
645/// assert_eq!(Some(4), elem_iter.next());
646/// assert_eq!(None, elem_iter.next());
647/// ```
648///
649/// ## Auto-Sizing
650///
651/// While we could use arrays with the syntax from above, we get also use an
652/// alternative syntax, where the array size is gets inferred which is
653/// particularly useful if you include external data (e.g. form a file).
654///
655/// ```
656/// use avr_progmem::progmem;
657///
658/// progmem!{
659/// /// An "auto-sized" array (the size is inferred and made accessible by
660/// /// a constant named `DATA_LEN`, tho any name would do)
661/// pub static progmem<const DATA_LEN: usize> DATA: [u8; DATA_LEN] =
662/// *include_bytes!("../examples/test_text.txt"); // assume it's binary
663/// }
664///
665/// // "auto-sized" array can be accessed in the exactly same way as ordinary
666/// // arrays, we just don't need to hardcode the size, and even get this nice
667/// // constant at our disposal.
668/// let middle: u8 = DATA.load_at(DATA_LEN / 2);
669/// assert_eq!(32, middle);
670/// ```
671///
672/// # Strings
673///
674/// Strings are complicated, partially, because in Rust strings such as `str`
675/// are unsized making storing them a nightmare (normally the compiler somehow
676/// manages to automagically put all your string literals into static memory,
677/// but you can't have a `static` that stores a `str` by-value, that is without
678/// the `&`).
679/// The next best thing that one can do to store a "string" is to store some
680/// fix-size array either of `char`s or of UTF-8 encoded `u8`s, which aren't
681/// exactly `str` and thus much more cumbersome to use.
682/// Therefore, this crate has dedicated an entire
683/// [module to strings](crate::string).
684///
685/// Consequently, this macro also has some special syntax to make string
686/// literals, which are given as some `&str` and are automagically converted
687/// into something more manageable
688/// (i.e. a [`PmString`](crate::string::PmString)) and are put in this format
689/// into a progmem `static`.
690///
691/// ## Examples
692///
693/// ```rust
694/// use avr_progmem::progmem;
695///
696/// progmem! {
697/// /// A static string stored in program memory as a `PmString`.
698/// /// Notice the `string` keyword.
699/// static progmem string TEXT = "Unicode text: 大賢者";
700/// }
701///
702/// let text = TEXT.load();
703/// assert_eq!("Unicode text: 大賢者", &*text);
704/// ```
705///
706#[macro_export]
707macro_rules! progmem {
708 // Special string rule
709 (
710 $( #[ $attr:meta ] )*
711 $vis:vis static progmem string $name:ident = $value:expr ;
712
713 $($rest:tt)*
714 ) => {
715 // Just forward to internal rule
716 $crate::progmem_internal!{
717 $(#[$attr])*
718 $vis static progmem string $name = $value ;
719 }
720
721 // Recursive call to allow multiple items in macro invocation
722 $crate::progmem!{
723 $($rest)*
724 }
725 };
726
727 // Catch "hand" strings rule, use the above special rule instead
728 (
729 $( #[ $attr:meta ] )*
730 $vis:vis static progmem $name:ident : $( avr_progmem::string:: )? LoadedString < $ty:literal > = $( avr_progmem::string:: )? LoadedString :: new ( $value:expr ) $( . unwrap () $(@ $unwrapped:ident)? )? ;
731
732 $($rest:tt)*
733 ) => {
734 // Make this a hard compile-time error.
735 ::core::compile_error!("Prefer using the special `PmString` rule with the `string` keyword.");
736 ::core::compile_error!(concat!("Use instead: ", stringify!($vis), " static progmem string ", stringify!($name), " = ..."));
737
738 // Emit a dummy to suppress errors where `$name` is used
739 static $name : $crate::wrapper::ProgMem< $crate::string::LoadedString< $ty > > = todo!();
740
741 // Recursive call to allow multiple items in macro invocation
742 $crate::progmem!{
743 $($rest)*
744 }
745 };
746
747 // Catch references rule, reference are evil!
748 // (well actually they are not, but most likely using them *is* a mistake)
749 (
750 $( #[ $attr:meta ] )*
751 $vis:vis static progmem $name:ident : & $ty:ty = $value:expr ;
752
753 $($rest:tt)*
754 ) => {
755 // Make this a hard compile-time error
756 ::core::compile_error!("Do not use a reference type for progmem, because this way only the reference itself would be in progmem, whereas the underlying data would still be in the normal data domain!");
757
758 // Emit a dummy to suppress errors where `$name` is used
759 static $name : & $ty = todo!();
760
761 // Recursive call to allow multiple items in macro invocation
762 $crate::progmem!{
763 $($rest)*
764 }
765 };
766
767 // Standard rule
768 (
769 $( #[ $attr:meta ] )*
770 $vis:vis static progmem $( < const $size_name:ident : usize > )? $name:ident : $ty:ty = $value:expr ;
771
772 $($rest:tt)*
773 ) => {
774 // Crate the progmem static via internal macro
775 $crate::progmem_internal!{
776 $(#[$attr])* $vis static progmem $( < const $size_name : usize > )? $name : $ty = $value;
777 }
778
779 // Recursive call to allow multiple items in macro invocation
780 $crate::progmem!{
781 $($rest)*
782 }
783 };
784
785 // Empty rule
786 () => ()
787}
788
789
790#[doc(hidden)]
791pub const fn array_from_str<const N: usize>(s: &str) -> [u8; N] {
792 let array_ref = crate::string::from_slice::array_ref_try_from_slice(s.as_bytes());
793 match array_ref {
794 Ok(r) => *r,
795 Err(_) => panic!("Invalid array size"),
796 }
797}
798
799
800/// Only for internal use. Use the `progmem!` macro instead.
801#[doc(hidden)]
802#[macro_export]
803macro_rules! progmem_internal {
804 // The string rule creating the progmem string static via `PmString`
805 {
806 $( #[ $attr:meta ] )*
807 $vis:vis static progmem string $name:ident = $value:expr ;
808 } => {
809 // User attributes
810 $(#[$attr])*
811 // The facade static definition, this only contains a pointer and thus
812 // is NOT in progmem, which in turn makes it safe & sound to access this
813 // facade.
814 $vis static $name: $crate::string::PmString<{
815 // This bit runs at compile-time
816 let s: &str = $value;
817 s.len()
818 }> = {
819 // This inner hidden static contains the actual real raw value.
820 //
821 // SAFETY: it must be stored in the progmem or text section!
822 // The `link_section` lets us define that:
823 #[cfg_attr(target_arch = "avr", link_section = ".progmem.data")]
824 static VALUE: [u8; {
825 // This bit runs at compile-time
826 let s: &str = $value;
827 s.len()
828 }] = $crate::wrapper::array_from_str( $value );
829
830 let pm = unsafe {
831 // SAFETY: This call is sound because we ensure with the above
832 // `link_section` attribute on `VALUE` that it is indeed
833 // in the progmem section.
834 $crate::wrapper::ProgMem::new(
835 ::core::ptr::addr_of!(VALUE)
836 )
837 };
838
839 // Just return the PmString wrapper around the local static
840 unsafe {
841 // SAFETY: This call is sound, because we started out with a
842 // `&str` thus the conent of `VALUE` must be valid UTF-8
843 $crate::string::PmString::new(
844 pm
845 )
846 }
847 };
848 };
849
850 // The rule creating an auto-sized progmem static via `ProgMem`
851 {
852 $( #[ $attr:meta ] )*
853 $vis:vis static progmem < const $size_name:ident : usize > $name:ident : $ty:ty = $value:expr ;
854 } => {
855 // Create a constant with the size of the value, which is retrieved
856 // via `SizedOwned` on the value, assuming it is an array of sorts.
857 //#[doc = concat!("Size of [", stringify!( $name ))]
858 $vis const $size_name : usize = {
859 // This bit is a bit hacky, we just hope that the type of `$value`
860 // has some `len` method.
861 $value.len()
862 };
863
864 // Just a normal prgomem static, `$ty` may use the above constant
865 $crate::progmem_internal!{
866 $( #[ $attr ] )*
867 $vis static progmem $name : $ty = $value ;
868 }
869 };
870
871 // The normal rule creating a progmem static via `ProgMem`
872 {
873 $( #[ $attr:meta ] )*
874 $vis:vis static progmem $name:ident : $ty:ty = $value:expr ;
875 } => {
876 // User attributes
877 $(#[$attr])*
878 // The facade static definition, this only contains a pointer and thus
879 // is NOT in progmem, which in turn makes it safe & sound to access this
880 // facade.
881 $vis static $name: $crate::wrapper::ProgMem<$ty> = {
882 // This inner hidden static contains the actual real raw value.
883 //
884 // SAFETY: it must be stored in the progmem or text section!
885 // The `link_section` lets us define that:
886 #[cfg_attr(target_arch = "avr", link_section = ".progmem.data")]
887 static VALUE: $ty = $value;
888
889 unsafe {
890 // SAFETY: This call is sound because we ensure with the above
891 // `link_section` attribute on `VALUE` that it is indeed
892 // in the progmem section.
893 $crate::wrapper::ProgMem::new(
894 ::core::ptr::addr_of!(VALUE)
895 )
896 }
897 };
898 };
899}
900
901
902/// ```compile_fail
903/// use avr_progmem::progmem;
904/// progmem! {
905/// static progmem AREF: &str = "Sometext";
906/// }
907/// ```
908#[cfg(doctest)]
909pub struct ProgMemReferenceTest;
910
911
912/// ```compile_fail
913/// use avr_progmem::progmem;
914/// progmem! {
915/// // Should notify that we should use the `progmem string` rule instead
916/// static progmem HAND_STRING: LoadedString<34> =
917/// LoadedString::new("hand crafted progmem loaded string").unwrap();
918/// }
919/// ```
920#[cfg(doctest)]
921pub struct HandStringTest;