#![no_std]
use core::{
mem::{self, MaybeUninit},
ops::{Deref, DerefMut},
};
use stable_deref_trait::StableDeref;
pub unsafe trait ReadBuffer {
type Word;
unsafe fn read_buffer(&self) -> (*const Self::Word, usize);
}
pub unsafe trait WriteBuffer {
type Word;
unsafe fn write_buffer(&mut self) -> (*mut Self::Word, usize);
}
unsafe impl<B, T> ReadBuffer for B
where
B: Deref<Target = T> + StableDeref + 'static,
T: ReadTarget + ?Sized,
{
type Word = T::Word;
unsafe fn read_buffer(&self) -> (*const Self::Word, usize) {
self.as_read_buffer()
}
}
unsafe impl<B, T> WriteBuffer for B
where
B: DerefMut<Target = T> + StableDeref + 'static,
T: WriteTarget + ?Sized,
{
type Word = T::Word;
unsafe fn write_buffer(&mut self) -> (*mut Self::Word, usize) {
self.as_write_buffer()
}
}
pub unsafe trait Word {}
unsafe impl Word for u8 {}
unsafe impl Word for i8 {}
unsafe impl Word for u16 {}
unsafe impl Word for i16 {}
unsafe impl Word for u32 {}
unsafe impl Word for i32 {}
unsafe impl Word for u64 {}
unsafe impl Word for i64 {}
pub unsafe trait ReadTarget {
type Word: Word;
fn as_read_buffer(&self) -> (*const Self::Word, usize) {
let len = mem::size_of_val(self) / mem::size_of::<Self::Word>();
let ptr = self as *const _ as *const Self::Word;
(ptr, len)
}
}
pub unsafe trait WriteTarget {
type Word: Word;
fn as_write_buffer(&mut self) -> (*mut Self::Word, usize) {
let len = mem::size_of_val(self) / mem::size_of::<Self::Word>();
let ptr = self as *mut _ as *mut Self::Word;
(ptr, len)
}
}
unsafe impl<W: Word> ReadTarget for W {
type Word = W;
}
unsafe impl<W: Word> WriteTarget for W {
type Word = W;
}
unsafe impl<T: ReadTarget> ReadTarget for [T] {
type Word = T::Word;
}
unsafe impl<T: WriteTarget> WriteTarget for [T] {
type Word = T::Word;
}
unsafe impl<T: ReadTarget, const N: usize> ReadTarget for [T; N] {
type Word = T::Word;
}
unsafe impl<T: WriteTarget, const N: usize> WriteTarget for [T; N] {
type Word = T::Word;
}
unsafe impl<T: WriteTarget> WriteTarget for MaybeUninit<T> {
type Word = T::Word;
}
#[cfg(test)]
mod tests {
use super::*;
use core::any::Any;
fn api_read<W, B>(buffer: B) -> (*const W, usize)
where
B: ReadBuffer<Word = W>,
{
unsafe { buffer.read_buffer() }
}
fn api_write<W, B>(mut buffer: B) -> (*mut W, usize)
where
B: WriteBuffer<Word = W>,
{
unsafe { buffer.write_buffer() }
}
#[test]
fn read_api() {
const SIZE: usize = 128;
static BUF: [u8; SIZE] = [0u8; SIZE];
let (ptr, size_local) = api_read(&BUF);
assert!(unsafe { (&*ptr as &dyn Any).is::<u8>() });
assert_eq!(size_local, SIZE);
}
#[test]
fn write_api() {
const SIZE: usize = 128;
static mut BUF: [u8; SIZE] = [0u8; SIZE];
let (ptr, size_local) = api_write(unsafe { &mut BUF });
assert!(unsafe { (&*ptr as &dyn Any).is::<u8>() });
assert_eq!(size_local, SIZE);
}
}