#[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>

source

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>

source

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>

source

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.

source

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.

source

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

pub fn len(&self) -> usize

Returns the length of the array (i.e. N)

source

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.

source

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.

source

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.

source

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.

You can obtain a slice wrapper by coercing an array wrapper.

source

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.

source

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

pub fn len(&self) -> usize

Returns the length of the slice

source§

impl<T: Copy> ProgMem<[T]>

Loading elements of an array in progmem.

source

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<T: ?Sized> Clone for ProgMem<T>

source§

fn clone(&self) -> Self

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<T: ?Sized> Debug for ProgMem<T>

source§

fn fmt(&self, __f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'a, T: Copy, const N: usize> IntoIterator for &'a ProgMem<[T; N]>

Same as ProgMem::iter

§

type IntoIter = PmIter<'a, T, N>

Which kind of iterator are we turning this into?
§

type Item = T

The type of the elements being iterated over.
source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
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.

source§

fn fmt<W>(&self, fmt: &mut Formatter<'_, W>) -> Result<(), W::Error>where
    W: uWrite + ?Sized,

Formats the value using the given formatter
source§

impl<T, U: ?Sized> CoerceUnsized<ProgMem<U>> for ProgMem<T>where
    T: Unsize<U> + ?Sized,

Available on crate feature 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;
source§

impl<T: ?Sized> Copy for ProgMem<T>

source§

impl<T: ?Sized> Send for ProgMem<T>

source§

impl<T: ?Sized> Sync for ProgMem<T>

Auto Trait Implementations§

§

impl<T: ?Sized> RefUnwindSafe for ProgMem<T>where
    T: RefUnwindSafe,

§

impl<T: ?Sized> Unpin for ProgMem<T>

§

impl<T: ?Sized> UnwindSafe for ProgMem<T>where
    T: RefUnwindSafe,

Blanket Implementations§

source§

impl<T> Any for Twhere
    T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere
    T: ?Sized,

const: unstable · source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere
    T: ?Sized,

const: unstable · source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

const: unstable · source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere
    U: From<T>,

const: unstable · source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for Twhere
    U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
const: unstable · source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere
    U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
const: unstable · source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.