Skip to content

Commit

Permalink
Put auto wrapper coercing behind a crate feature.
Browse files Browse the repository at this point in the history
  • Loading branch information
Cryptjar committed Jan 18, 2023
1 parent de35c9a commit 97c7344
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 19 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ default = ["lpm-asm-loop", "ufmt"]
lpm-asm-loop = []
# Enables some tweak to ease debugging, should not be use in production
dev = []
# Enables unsize utilities, such as wrapper coercing.
# However, this requires additional nightly Rust features, which might be unstable.
unsize = []

[dependencies]
cfg-if = "1.0"
Expand Down
34 changes: 26 additions & 8 deletions examples/uno-slices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use avr_progmem::progmem; // The macro
use avr_progmem::wrapper::ProgMem;
use cfg_if::cfg_if;
#[cfg(target_arch = "avr")]
use panic_halt as _; // halting panic implementation for AVR

Expand Down Expand Up @@ -50,14 +51,31 @@ fn main() -> ! {
//
// In order to have the benefits of slices while the data is still in
// progmem, we can also just coerce the ProgMems of arrays into ProgMems of
// slices, just like that:

let a_slice: ProgMem<[u8]> = ARRAY_A;
let b_slice: ProgMem<[u8]> = ARRAY_B;
let c_slice: ProgMem<[u8]> = ARRAY_C;

// Now they have the same type, and we can put them into a list.
let list_of_slices = [a_slice, b_slice, c_slice];
// slices:

// Once we have slice wrappers, we can store them together e.g. in a array
let list_of_slices: [ProgMem<[u8]>; 3] = {
cfg_if! {
if #[cfg(feature = "unsize")] {
// Option 1: just coerce them to a slice wrapper
// but this requires the crate feature "unsize"

[
ARRAY_A,
ARRAY_B,
ARRAY_C,
]
} else {
// Option 2: convert them explicitly via the "as_slice" method

[
ARRAY_A.as_slice(),
ARRAY_B.as_slice(),
ARRAY_C.as_slice(),
]
}
}
};

// And for instance iterate through that list.
for (i, slice) in list_of_slices.iter().enumerate() {
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
#![feature(slice_ptr_len)]
//
// Allow to implement `CoerceUnsized` on `ProgMem`
#![feature(coerce_unsized)]
#![cfg_attr(feature = "unsize", feature(coerce_unsized))]
//
// Needed for implementing `CoerceUnsized` on `ProgMem`
#![feature(unsize)]
#![cfg_attr(feature = "unsize", feature(unsize))]
//
// Allows to document required crate features on items
#![cfg_attr(doc, feature(doc_auto_cfg))]
Expand Down
59 changes: 50 additions & 9 deletions src/wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@


use core::marker::Unsize;
use core::ops::CoerceUnsized;

use derivative::Derivative;

use crate::raw::read_value;
Expand Down Expand Up @@ -58,7 +55,9 @@ use crate::raw::read_value;
/// 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).
/// object, but those will not be useful at all), either using the
/// [`as_slice`][ProgMem::as_slice] method, or by enabling the "unsize" crate
/// feature that allows normal Rust coercing.
///
///
/// # Safety
Expand Down Expand Up @@ -220,7 +219,7 @@ impl<T, const N: usize> ProgMem<[T; N]> {
/// length `N` of the array.
pub fn at(&self, idx: usize) -> ProgMem<T> {
// Just use the slice impl
let slice: ProgMem<[T]> = *self;
let slice: ProgMem<[T]> = self.as_slice();
slice.at(idx)
}

Expand All @@ -229,13 +228,49 @@ impl<T, const N: usize> ProgMem<[T; N]> {
/// Returns an iterator, which yields each element as a `ProgMem<T>`,
/// which can be subsequently loaded.
pub fn wrapper_iter(&self) -> PmWrapperIter<T> {
PmWrapperIter::new(*self)
PmWrapperIter::new(self.as_slice())
}

/// Returns the length of the array (i.e. `N`)
pub fn len(&self) -> usize {
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
///
/// ```rust
/// 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;
/// ```
///
pub fn as_slice(&self) -> ProgMem<[T]> {
ProgMem {
target: self.target,
}
}
}

/// Loading elements of an array in progmem.
Expand Down Expand Up @@ -410,7 +445,10 @@ impl<T: Copy> ProgMem<[T]> {
/// 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]>`.
/// slice `ProgMem<[T]>`. Thus this impl is a generalization of the
/// [`as_slice`][ProgMem::as_slice] method.
///
/// # Examples
///
/// ```rust
/// use avr_progmem::wrapper::ProgMem;
Expand All @@ -425,8 +463,11 @@ impl<T: Copy> ProgMem<[T]> {
/// // Coerced to a slice wrapper, just like that.
/// let s: ProgMem<[u8]> = arr;
/// ```
impl<T: ?Sized, U: ?Sized> CoerceUnsized<ProgMem<U>> for ProgMem<T> where T: Unsize<U> {}

#[cfg(feature = "unsize")]
impl<T: ?Sized, U: ?Sized> core::ops::CoerceUnsized<ProgMem<U>> for ProgMem<T> where
T: core::marker::Unsize<U>
{
}

/// An iterator over an array in progmem.
///
Expand Down

0 comments on commit 97c7344

Please sign in to comment.