use core::convert::TryInto;
use rkyv::{ser::Serializer, Fallible};
use xous::{
map_memory, send_message, unmap_memory, Error, MemoryAddress, MemoryFlags, MemoryMessage,
MemoryRange, MemorySize, Message, Result, CID,
};
#[derive(Debug)]
pub struct Buffer<'a> {
range: MemoryRange,
valid: MemoryRange,
offset: Option<MemoryAddress>,
slice: &'a mut [u8],
should_drop: bool,
memory_message: Option<&'a mut MemoryMessage>,
}
pub struct XousDeserializer;
#[derive(Debug)]
pub enum XousUnreachable {}
impl rkyv::Fallible for XousDeserializer {
type Error = XousUnreachable;
}
impl<'a> Buffer<'a> {
#[allow(dead_code)]
pub fn new(len: usize) -> Self {
let remainder = if ((len & 0xFFF) == 0) && (len > 0) {
0
} else {
0x1000 - (len & 0xFFF)
};
let flags = MemoryFlags::R | MemoryFlags::W;
let new_mem = map_memory(
None,
None,
len + remainder,
flags,
)
.expect("Buffer: error in new()/map_memory");
let valid =
unsafe { MemoryRange::new(new_mem.as_mut_ptr() as usize, len + remainder).unwrap() };
Buffer {
range: new_mem,
slice: unsafe {
core::slice::from_raw_parts_mut(new_mem.as_mut_ptr(), len + remainder)
},
valid,
offset: None,
should_drop: true,
memory_message: None,
}
}
pub fn volatile_clear(&mut self) {
let b = self.slice.as_mut_ptr();
for i in 0..self.slice.len() {
unsafe {
b.add(i).write_volatile(core::mem::zeroed());
}
}
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
#[allow(dead_code)]
pub unsafe fn to_raw_parts(&self) -> (usize, usize, usize) {
if let Some(offset) = self.offset {
(
self.valid.as_ptr() as usize,
self.valid.len(),
usize::from(offset),
)
} else {
(self.valid.as_ptr() as usize, self.valid.len(), 0)
}
}
#[allow(dead_code)]
pub unsafe fn from_raw_parts(address: usize, len: usize, offset: usize) -> Self {
let mem = MemoryRange::new(address, len).expect("invalid memory range args");
let off = if offset != 0 {
Some(offset.try_into().unwrap())
} else {
None
};
Buffer {
range: mem,
slice: core::slice::from_raw_parts_mut(mem.as_mut_ptr(), mem.len()),
valid: mem,
offset: off,
should_drop: false,
memory_message: None,
}
}
#[allow(dead_code)]
pub unsafe fn from_memory_message(mem: &'a MemoryMessage) -> Self {
Buffer {
range: mem.buf,
slice: core::slice::from_raw_parts_mut(mem.buf.as_mut_ptr(), mem.buf.len()),
valid: mem.buf,
offset: mem.offset,
should_drop: false,
memory_message: None,
}
}
#[allow(dead_code)]
pub unsafe fn from_memory_message_mut(mem: &'a mut MemoryMessage) -> Self {
Buffer {
range: mem.buf,
slice: core::slice::from_raw_parts_mut(mem.buf.as_mut_ptr(), mem.buf.len()),
valid: mem.buf,
offset: mem.offset,
should_drop: false,
memory_message: Some(mem),
}
}
#[allow(dead_code)]
pub fn lend_mut(&mut self, connection: CID, id: u32) -> core::result::Result<Result, Error> {
let msg = MemoryMessage {
id: id as usize,
buf: self.valid,
offset: self.offset,
valid: MemorySize::new(self.slice.len()),
};
let result = send_message(connection, Message::MutableBorrow(msg));
if let Ok(Result::MemoryReturned(offset, _valid)) = result {
self.offset = offset;
}
result
}
#[allow(dead_code)]
pub fn lend(&self, connection: CID, id: u32) -> core::result::Result<Result, Error> {
let msg = MemoryMessage {
id: id as usize,
buf: self.valid,
offset: self.offset,
valid: MemorySize::new(self.slice.len()),
};
send_message(connection, Message::Borrow(msg))
}
#[allow(dead_code)]
pub fn send(mut self, connection: CID, id: u32) -> core::result::Result<Result, Error> {
let msg = MemoryMessage {
id: id as usize,
buf: self.valid,
offset: self.offset,
valid: MemorySize::new(self.slice.len()),
};
let result = send_message(connection, Message::Move(msg))?;
self.should_drop = false;
Ok(result)
}
#[allow(dead_code)]
pub fn into_buf<S>(src: S) -> core::result::Result<Self, ()>
where
S: rkyv::Serialize<rkyv::ser::serializers::BufferSerializer<Buffer<'a>>>,
{
let buf = Self::new(core::mem::size_of::<S>());
let mut ser = rkyv::ser::serializers::BufferSerializer::new(buf);
let pos = ser.serialize_value(&src).or(Err(()))?;
let mut buf = ser.into_inner();
buf.offset = MemoryAddress::new(pos);
Ok(buf)
}
#[allow(dead_code)]
pub fn rewrite<S>(&mut self, src: S) -> core::result::Result<(), xous::Error>
where
S: rkyv::Serialize<rkyv::ser::serializers::BufferSerializer<&'a mut [u8]>>,
{
let copied_slice =
unsafe { core::slice::from_raw_parts_mut(self.slice.as_mut_ptr(), self.slice.len()) };
let mut ser = rkyv::ser::serializers::BufferSerializer::new(copied_slice);
let pos = ser.serialize_value(&src).or(Err(())).unwrap();
self.slice = ser.into_inner();
self.offset = MemoryAddress::new(pos);
Ok(())
}
#[allow(dead_code)]
pub fn replace<S>(&mut self, src: S) -> core::result::Result<(), &'static str>
where
S: rkyv::Serialize<rkyv::ser::serializers::BufferSerializer<&'a mut [u8]>>,
{
if self.memory_message.is_none() {
Err("couldn't serialize because buffer wasn't mutable")?;
}
let copied_slice =
unsafe { core::slice::from_raw_parts_mut(self.slice.as_mut_ptr(), self.slice.len()) };
let mut ser = rkyv::ser::serializers::BufferSerializer::new(copied_slice);
let pos = ser.serialize_value(&src).map_err(|err| err).unwrap();
self.offset = MemoryAddress::new(pos);
if let Some(ref mut msg) = self.memory_message.as_mut() {
msg.offset = MemoryAddress::new(pos);
}
Ok(())
}
#[allow(dead_code)]
pub fn as_flat<T, U>(&self) -> core::result::Result<&U, ()>
where
T: rkyv::Archive<Archived = U>,
{
let pos = self.offset.map(|o| o.get()).unwrap_or_default();
let r = unsafe { rkyv::archived_value::<T>(self.slice, pos) };
Ok(r)
}
#[allow(dead_code)]
pub fn to_original<T, U>(&self) -> core::result::Result<T, ()>
where
T: rkyv::Archive<Archived = U>,
U: rkyv::Deserialize<T, dyn Fallible<Error = XousUnreachable>>,
{
let pos = self.offset.map(|o| o.get()).unwrap_or_default();
let r = unsafe { rkyv::archived_value::<T>(self.slice, pos) };
Ok(r.deserialize(&mut XousDeserializer {}).unwrap())
}
}
impl<'a> core::convert::AsRef<[u8]> for Buffer<'a> {
fn as_ref(&self) -> &[u8] {
self.slice
}
}
impl<'a> core::convert::AsMut<[u8]> for Buffer<'a> {
fn as_mut(&mut self) -> &mut [u8] {
self.slice
}
}
impl<'a> core::ops::Deref for Buffer<'a> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&*self.slice
}
}
impl<'a> core::ops::DerefMut for Buffer<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.slice
}
}
impl<'a> Drop for Buffer<'a> {
fn drop(&mut self) {
if self.should_drop {
unmap_memory(self.range).expect("Buffer: failed to drop memory");
}
}
}