diff --git a/Cargo.toml b/Cargo.toml index c9b1a84..57389ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/examples/uno-slices.rs b/examples/uno-slices.rs index da14b06..c8176d1 100644 --- a/examples/uno-slices.rs +++ b/examples/uno-slices.rs @@ -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 @@ -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() { diff --git a/src/lib.rs b/src/lib.rs index 48c2b9d..c677f67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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))] diff --git a/src/wrapper.rs b/src/wrapper.rs index d4dc600..bb92f5a 100644 --- a/src/wrapper.rs +++ b/src/wrapper.rs @@ -20,9 +20,6 @@ -use core::marker::Unsize; -use core::ops::CoerceUnsized; - use derivative::Derivative; use crate::raw::read_value; @@ -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 @@ -220,7 +219,7 @@ impl ProgMem<[T; N]> { /// length `N` of the array. pub fn at(&self, idx: usize) -> ProgMem { // Just use the slice impl - let slice: ProgMem<[T]> = *self; + let slice: ProgMem<[T]> = self.as_slice(); slice.at(idx) } @@ -229,13 +228,49 @@ impl ProgMem<[T; N]> { /// Returns an iterator, which yields each element as a `ProgMem`, /// which can be subsequently loaded. pub fn wrapper_iter(&self) -> PmWrapperIter { - 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. @@ -410,7 +445,10 @@ impl ProgMem<[T]> { /// Allows coercing a `ProgMem` to a `ProgMem`, 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; @@ -425,8 +463,11 @@ impl ProgMem<[T]> { /// // Coerced to a slice wrapper, just like that. /// let s: ProgMem<[u8]> = arr; /// ``` -impl CoerceUnsized> for ProgMem where T: Unsize {} - +#[cfg(feature = "unsize")] +impl core::ops::CoerceUnsized> for ProgMem where + T: core::marker::Unsize +{ +} /// An iterator over an array in progmem. ///