#[non_exhaustive]pub struct ProgMem<T: ?Sized> { /* private fields */ }
Expand description
Best-effort safe wrapper around a value in program memory.
This type wraps a pointer to a value that is stored in program memory,
and offers safe functions to load
that value from
program memory into the data memory domain from where it can be normally
used.
Since its constructor is the single most critical point in its API,
it is unsafe
, despite it is supposed to be a safe wrapper (hence the
‘best-effort’ notation).
The caller of the constructor therefore must ensure that the supplied
pointer points to a valid value stored in program memory.
Consequently, the only way to use this struct soundly is to define a
static
with the #[link_section = ".progmem.data"]
attribute on it and
pass a pointer to that static
to ProgMem::new
.
However, having an accessible static
around that is stored in progmem
is a very dangerous endeavor.
In order to make working with progmem safer and more convenient,
consider using the progmem
macro, that will put the given data
into a hidden static
in progmem and provide you with an accessible static
containing the pointer to it wrapped in ProgMem
.
Since this is just a fancy immutable pointer type, it can always be
copied/cloned (just copies the address). It also implements Debug
,
which simply prints the address (into progmem) of the wrapped value.
And you can even coerce the pointed-to type e.g. from an statically sized
array to a dynamically sized slice type (it also allow to coerce to a trait
object, but those will not be useful at all), either using the
as_slice
method, or by enabling the “unsize” crate
feature that allows normal Rust coercing.
§Safety
The target
pointer in this struct must point to a valid object of type
T
that is stored in the program memory domain.
The object must be initialized, readable, and immutable (i.e. it must not
be changed).
Also the target
pointer must be valid for the 'static
lifetime.
However, the requirement about the program memory domain only applies
to the AVR architecture (#[cfg(target_arch = "avr")]
),
otherwise normal data access primitives are used.
This means that the value must be stored in the
regular data memory domain for ALL OTHER architectures! This still
holds, even if such other architecture is of the Harvard architecture,
because this is an AVR-only crate, not a general Harvard architecture
crate!
Implementations§
Source§impl<T: ?Sized> ProgMem<T>
impl<T: ?Sized> ProgMem<T>
Sourcepub fn as_ptr(&self) -> *const T
pub fn as_ptr(&self) -> *const T
Return the raw pointer to the inner value.
Notice that the returned pointer is indeed a pointer into the progmem
domain! It may never be dereferenced via the default Rust operations.
That means a unsafe{*pm.as_ptr()}
is undefined behavior!
Instead, if you want to use the pointer, you may want to use one of the “raw” functions, see the raw module.
Source§impl<T> ProgMem<T>
impl<T> ProgMem<T>
Sourcepub const unsafe fn new(target: *const T) -> Self
pub const unsafe fn new(target: *const T) -> Self
Construct a new instance of this type.
This struct is a pointer wrapper for data in the program memory domain.
Therefore when constructing this struct, it must be guaranteed
that the pointed data is stored in progmem!
This contract is expressed by the fact that this function is unsafe
.
See the Safety section for details.
You should not need to call this function directly.
It is recommended to use the progmem
macro instead (which calls
this constructor for you, while enforcing its contract.
§Safety
The ProgMem
wrapper is build around the invariant that the wrapped
pointer is stored in the program code memory domain (on the AVR
architecture).
That means that this function is only sound to call, if the value to
which target
points is stored in a static
that is stored in progmem,
e.g. by using the attribute #[link_section = ".progmem.data"]
.
However, the above requirement about the program memory domain only
applies to the AVR architecture (#[cfg(target_arch = "avr")]
),
otherwise normal data access primitives are used,
and thus the target
pointer needs to point to normal data on those
architectures.
Source§impl<T: Copy> ProgMem<T>
impl<T: Copy> ProgMem<T>
Sourcepub fn load(&self) -> T
pub fn load(&self) -> T
Read the inner value from progmem and return a regular value.
§Panics
This method panics, if the size of the value (i.e. size_of::<T>()
)
is beyond 255 bytes.
However, this is currently just a implementation limitation, which may
be lifted in the future.
Also notice, if you really hit this limit, you would need 256+ bytes on
your stack, on the Arduino Uno (at least) that means that you might be
close to a stack overflow. Thus it might be better to restructure your
data, so you can store it as an array of something, than you can use
the load_at
and load_sub_array
methods instead.
Source§impl<T, const N: usize> ProgMem<[T; N]>
Utilities to work with an array in progmem.
impl<T, const N: usize> ProgMem<[T; N]>
Utilities to work with an array in progmem.
Sourcepub fn at(&self, idx: usize) -> ProgMem<T>
pub fn at(&self, idx: usize) -> ProgMem<T>
Get a reference to an element from the array, without loading it.
§Panics
This method panics, if the given index idx
is grater or equal to the
length N
of the array.
Sourcepub fn wrapper_iter(&self) -> PmWrapperIter<T> ⓘ
pub fn wrapper_iter(&self) -> PmWrapperIter<T> ⓘ
Iterate over all elements as wrappers.
Returns an iterator, which yields each element as a ProgMem<T>
,
which can be subsequently loaded.
Sourcepub fn as_slice(&self) -> ProgMem<[T]>
pub fn as_slice(&self) -> ProgMem<[T]>
Coerce this array wrapper into a slice wrapper.
Notice, if you enable the “unsize” crate feature, you can directly
coerce the ProgMem
struct, otherwise you have to use this function
instead.
This analog to normal Rust coercing of arrays to slices. Indeed, if you enable the crate feature “unsize”, you can use normal Rust coercing to get the same result.
§Examples
use avr_progmem::wrapper::ProgMem;
use avr_progmem::progmem;
progmem!{
static progmem ARR: [u8; 3] = [1,2,3];
}
// The array wrapper
let arr: ProgMem<[u8; 3]> = ARR;
// Coerced to a slice wrapper.
let s: ProgMem<[u8]> = arr.as_slice();
// If you enable the "unsize" crate feature, you can just coerce like that:
#[cfg(feature = "unsize")]
let s: ProgMem<[u8]> = arr;
Source§impl<T: Copy, const N: usize> ProgMem<[T; N]>
Loading elements of an array in progmem.
impl<T: Copy, const N: usize> ProgMem<[T; N]>
Loading elements of an array in progmem.
Sourcepub fn load_at(&self, idx: usize) -> T
pub fn load_at(&self, idx: usize) -> T
Load a single element from the inner array.
This method is analog to a slice indexing self.load()[idx]
, so the
same requirements apply, like the index idx
should be less then the
length N
of the array, otherwise a panic will be risen.
§Panics
This method panics, if the given index idx
is grater or equal to the
length N
of the inner type.
This method also panics, if the size of the value (i.e. size_of::<T>()
)
is beyond 255 bytes.
However, this is currently just a implementation limitation, which may
be lifted in the future.
Notice, that here T
is the type of the elements not the entire array
as it would be with load
.
Sourcepub fn load_sub_array<const M: usize>(&self, start_idx: usize) -> [T; M]
pub fn load_sub_array<const M: usize>(&self, start_idx: usize) -> [T; M]
Loads a sub array from the inner array.
This method is analog to a sub-slicing self.load()[idx..(idx+M)]
but
returning an owned array instead of a slice, simply because it has to
copy the data anyway from the progmem into the data domain (i.e. the
stack).
Also notice, that since this crate is intended for AVR
micro-controllers, static arrays are generally preferred over
dynamically allocated types such as a Vec
.
§Panics
This method panics, if the given index idx
is grater or equal to the
length N
of the inner array, or the end index idx+M
is grater than
the length N
of the inner array.
This method also panics, if the size of the value
(i.e. size_of::<[T;M]>()
) is beyond 255 bytes.
However, this is currently just a implementation limitation, which may
be lifted in the future.
Sourcepub fn iter(&self) -> PmIter<'_, T, N> ⓘ
pub fn iter(&self) -> PmIter<'_, T, N> ⓘ
Lazily iterate over all elements
Returns an iterator which lazily loads the elements one at a time
from progmem.
This means this iterator can be used to access huge arrays while
only requiring size_of::<T>()
amount of stack memory.
§Panics
The returned iterator will panic, if the size of an element (i.e. size_of::<T>()
)
is beyond 255 bytes.
However, this is currently just a implementation limitation, which may
be lifted in the future.
Notice, that here T
is the type of the elements not the entire array
as it would be with load
.
Source§impl<T> ProgMem<[T]>
Utilities to work with an slice wrapper.
impl<T> ProgMem<[T]>
Utilities to work with an slice wrapper.
You can obtain a slice wrapper by coercing an array wrapper.
Sourcepub fn at(&self, idx: usize) -> ProgMem<T>
pub fn at(&self, idx: usize) -> ProgMem<T>
Get a reference to an element from the array, without loading it.
§Panics
This method panics, if the given index idx
is grater or equal to the
length of the slice.
Sourcepub fn wrapper_iter(&self) -> PmWrapperIter<T> ⓘ
pub fn wrapper_iter(&self) -> PmWrapperIter<T> ⓘ
Iterate over all elements as wrappers.
Returns an iterator, which yields each element as a ProgMem<T>
,
which can be subsequently loaded.
Source§impl<T: Copy> ProgMem<[T]>
Loading elements of an array in progmem.
impl<T: Copy> ProgMem<[T]>
Loading elements of an array in progmem.
Sourcepub fn load_at(&self, idx: usize) -> T
pub fn load_at(&self, idx: usize) -> T
Load a single element from the slice.
This method is analog to a slice indexing, thus the same requirements
apply: the index idx
should be less then the length of the slice,
otherwise a panic will be risen.
§Panics
This method panics, if the given index idx
is grater or equal to the
length of the slice.
This method also panics, if the size of the value (i.e. size_of::<T>()
)
is beyond 255 bytes.
However, this is currently just a implementation limitation, which may
be lifted in the future.
Notice, that here T
is the type of the elements not the entire slice.
Trait Implementations§
Source§impl<'a, T: Copy, const N: usize> IntoIterator for &'a ProgMem<[T; N]>
Same as ProgMem::iter
impl<'a, T: Copy, const N: usize> IntoIterator for &'a ProgMem<[T; N]>
Same as ProgMem::iter
Source§impl<T: ?Sized> uDebug for ProgMem<T>
Available on crate feature ufmt
only.Implement uDebug
by hand, because the derive variant adds a sized constraint.
impl<T: ?Sized> uDebug for ProgMem<T>
ufmt
only.Implement uDebug
by hand, because the derive variant adds a sized constraint.
impl<T, U: ?Sized> CoerceUnsized<ProgMem<U>> for ProgMem<T>
unsize
only.Allows coercing a ProgMem<T>
to a ProgMem<U>
, where U might be unsized.
A classic example of this is coercing an array ProgMem<[T; N]>
into a
slice ProgMem<[T]>
. Thus this impl is a generalization of the
as_slice
method.
§Examples
use avr_progmem::wrapper::ProgMem;
use avr_progmem::progmem;
progmem!{
static progmem ARR: [u8; 3] = [1,2,3];
}
// The array wrapper
let arr: ProgMem<[u8; 3]> = ARR;
// Coerced to a slice wrapper, just like that.
let s: ProgMem<[u8]> = arr;