#![cfg_attr(not(test), no_std)]
#![warn(missing_docs)]
#![allow(async_fn_in_trait)]
use aligned::Aligned;
pub trait BlockDevice<const SIZE: usize> {
type Error: core::fmt::Debug;
type Align: aligned::Alignment;
async fn read(
&mut self,
block_address: u32,
data: &mut [Aligned<Self::Align, [u8; SIZE]>],
) -> Result<(), Self::Error>;
async fn write(
&mut self,
block_address: u32,
data: &[Aligned<Self::Align, [u8; SIZE]>],
) -> Result<(), Self::Error>;
async fn size(&mut self) -> Result<u64, Self::Error>;
}
impl<T: BlockDevice<SIZE>, const SIZE: usize> BlockDevice<SIZE> for &mut T {
type Error = T::Error;
type Align = T::Align;
async fn read(
&mut self,
block_address: u32,
data: &mut [Aligned<Self::Align, [u8; SIZE]>],
) -> Result<(), Self::Error> {
(*self).read(block_address, data).await
}
async fn write(
&mut self,
block_address: u32,
data: &[Aligned<Self::Align, [u8; SIZE]>],
) -> Result<(), Self::Error> {
(*self).write(block_address, data).await
}
async fn size(&mut self) -> Result<u64, Self::Error> {
(*self).size().await
}
}
pub fn slice_to_blocks<ALIGN, const SIZE: usize>(slice: &[u8]) -> &[Aligned<ALIGN, [u8; SIZE]>]
where
ALIGN: aligned::Alignment,
{
let align: usize = core::mem::align_of::<Aligned<ALIGN, ()>>();
assert!(slice.len() % SIZE == 0);
assert!(slice.len() % align == 0);
assert!(slice.as_ptr().cast::<u8>() as usize % align == 0);
unsafe {
core::slice::from_raw_parts(
slice.as_ptr() as *const Aligned<ALIGN, [u8; SIZE]>,
slice.len() / SIZE,
)
}
}
pub fn slice_to_blocks_mut<ALIGN, const SIZE: usize>(
slice: &mut [u8],
) -> &mut [Aligned<ALIGN, [u8; SIZE]>]
where
ALIGN: aligned::Alignment,
{
let align: usize = core::mem::align_of::<Aligned<ALIGN, [u8; SIZE]>>();
assert!(slice.len() % SIZE == 0);
assert!(slice.len() % align == 0);
assert!(slice.as_ptr().cast::<u8>() as usize % align == 0);
unsafe {
core::slice::from_raw_parts_mut(
slice.as_mut_ptr() as *mut Aligned<ALIGN, [u8; SIZE]>,
slice.len() / SIZE,
)
}
}
pub fn blocks_to_slice<ALIGN, const SIZE: usize>(buf: &[Aligned<ALIGN, [u8; SIZE]>]) -> &[u8]
where
ALIGN: aligned::Alignment,
{
let align: usize = core::mem::align_of::<Aligned<ALIGN, ()>>();
assert!(SIZE % align == 0);
unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len() * SIZE) }
}
pub fn blocks_to_slice_mut<ALIGN, const SIZE: usize>(
buf: &mut [Aligned<ALIGN, [u8; SIZE]>],
) -> &mut [u8]
where
ALIGN: aligned::Alignment,
{
let align: usize = core::mem::align_of::<Aligned<ALIGN, ()>>();
assert!(SIZE % align == 0);
unsafe { core::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * SIZE) }
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_conversion_round_trip() {
let blocks = &mut [
Aligned::<aligned::A4, _>([0; 512]),
Aligned::<aligned::A4, _>([0; 512]),
];
let slice = blocks_to_slice_mut(blocks);
assert!(slice.len() == 1024);
let blocks: &mut [Aligned<aligned::A4, [u8; 512]>] = slice_to_blocks_mut(slice);
assert!(blocks.len() == 2);
}
}