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;