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

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.

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.

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.

Utilities to work with an array in progmem.

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.

Iterate over all elements as wrappers.

Returns an iterator, which yields each element as a ProgMem<T>, which can be subsequently loaded.

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

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;

Loading elements of an array in progmem.

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.

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.

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.

Utilities to work with an slice wrapper.

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

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.

Iterate over all elements as wrappers.

Returns an iterator, which yields each element as a ProgMem<T>, which can be subsequently loaded.

Returns the length of the slice

Loading elements of an array in progmem.

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§

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Same as ProgMem::iter

Which kind of iterator are we turning this into?
The type of the elements being iterated over.
Creates an iterator from a value. Read more

Implement uDebug by hand, because the derive variant adds a sized constraint.

Formats the value using the given formatter

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;

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

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

The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.