Function read_value

Source
pub unsafe fn read_value<T>(p_addr: *const T) -> T
where T: Sized + Copy,
Expand description

Read a single T from progmem and return it by value.

This function uses either a optimized assembly with loop or just a byte-wise assembly function which is looped outside depending on whether the lpm-asm-loop crate feature is set or not.

Notice that T might be also something like [T, N] so that in fact entire arrays can be loaded using this function.

If you need to read just a single byte you might use read_byte.

§Example

use avr_progmem::raw::read_value;
use core::ptr::addr_of;

// This static must never be directly dereferenced/accessed!
// So a `let data: [u8;11] = P_ARRAY;` is Undefined Behavior!!!
// Also notice the `*` in front of the string, because we want to store the
// data, not just a reference!
/// Static bytes stored in progmem!
#[link_section = ".progmem.data"]
static P_ARRAY: [u8;11] = *b"Hello World";

// Load the bytes from progmem
// Here, it is sound, because due to the link_section it is indeed in the
// program code memory.
let data: [u8;11] = unsafe { read_value(addr_of!(P_ARRAY)) };
assert_eq!(b"Hello World", &data);

Also statically sized sub-arrays can be loaded using this function:

use std::convert::TryInto;
use avr_progmem::raw::read_value;

/// Static bytes stored in progmem!
#[link_section = ".progmem.data"]
static P_ARRAY: [u8;11] = *b"Hello World";

// Get a sub-array reference without dereferencing it

// Make sure that we convert from &[T] directly to &[T;M] without
// constructing an actual [T;M], because we MAY NOT LOAD THE DATA!
// Also notice, that this sub-slicing does ensure that the bound are
// correct.
let slice: &[u8] = &P_ARRAY[6..];
let array: &[u8;5] = slice.try_into().unwrap();

// Load the bytes from progmem
// Here, it is sound, because due to the link_section it is indeed in the
// program code memory.
let data: [u8;5] = unsafe { read_value(array) };
assert_eq!(b"World", &data);

§Panics

This function 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.

§Safety

This call is analog to core::ptr::copy thus it has the same basic requirements such as the pointer must be valid for dereferencing i.e. not dangling and the pointer must be valid to read one entire value of type T, i.e. size_of::<T>() bytes.

Additionally, p_addr must be a valid pointer into the program memory domain.

While the alignment is not strictly required for AVR, the non-AVR fallback might be actually using core::ptr::copy and therefore the pointers must be aligned.