use crate::{
map_memory, send_message, unmap_memory, Error, MemoryMessage, MemoryRange, MemorySize, Message,
Result, CID,
};
pub struct StringBuffer<'a> {
bytes: Option<&'a mut [u8]>,
length: u32,
should_free: bool,
memory_message: Option<&'a mut MemoryMessage>,
}
impl<'a> StringBuffer<'a> {
pub fn new() -> Self {
StringBuffer {
bytes: None,
length: 0,
should_free: true,
memory_message: None,
}
}
pub fn with_capacity(capacity: usize) -> Self {
let remainder = if ((capacity & 0xFFF) == 0) && (capacity > 0) {
0
} else {
0x1000 - (capacity & 0xFFF)
};
let flags = crate::MemoryFlags::R | crate::MemoryFlags::W;
let new_mem = map_memory(
None,
None,
capacity + remainder,
flags,
)
.expect("Buffer: error in new()/map_memory");
StringBuffer {
bytes: Some(unsafe {
core::slice::from_raw_parts_mut(new_mem.as_mut_ptr(), capacity + remainder)
}),
length: 0,
should_free: true,
memory_message: None,
}
}
fn resize(&mut self, new_capacity: usize) {
if self.memory_message.is_some() {
return;
}
let remainder = if ((new_capacity & 0xFFF) == 0) && (new_capacity > 0) {
0
} else {
0x1000 - (new_capacity & 0xFFF)
};
let rounded_new_capacity = new_capacity + remainder;
if rounded_new_capacity == self.bytes.as_ref().map(|b| b.len()).unwrap_or(0) {
return;
}
let flags = crate::MemoryFlags::R | crate::MemoryFlags::W;
let new_slice = if rounded_new_capacity > 0 {
let new_mem = map_memory(None, None, rounded_new_capacity, flags)
.expect("Buffer: error in new()/map_memory");
let new_slice = unsafe {
core::slice::from_raw_parts_mut(new_mem.as_mut_ptr(), rounded_new_capacity)
};
for (dest_byte, src_byte) in new_slice
.iter_mut()
.zip(self.as_bytes()[0..self.len()].iter())
{
*dest_byte = *src_byte;
}
Some(new_slice)
} else {
None
};
if let Some(old_slice) = self.bytes.take() {
let old_addr = old_slice.as_ptr();
let old_length = old_slice.len();
unmap_memory(unsafe { MemoryRange::new(old_addr as usize, old_length).unwrap() })
.unwrap();
}
self.bytes = new_slice;
if new_capacity < self.len() {
self.length = new_capacity as u32;
}
}
pub fn as_bytes(&self) -> &[u8] {
if let Some(bytes) = &self.bytes {
bytes
} else {
&[]
}
}
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
if let Some(bytes) = self.bytes.as_mut() {
bytes
} else {
&mut []
}
}
pub fn as_str(&self) -> core::result::Result<&str, core::str::Utf8Error> {
if let Some(bytes) = &self.bytes {
core::str::from_utf8(&bytes[0..self.len()])
} else {
Ok("")
}
}
pub fn len(&self) -> usize {
self.length as usize
}
pub fn is_empty(&self) -> bool {
self.length == 0
}
pub fn clear(&mut self) {
self.length = 0;
if let Some(mm) = self.memory_message.as_mut() {
mm.valid = None;
}
}
pub fn to_str(&self) -> &str {
if let Some(bytes) = &self.bytes {
unsafe { core::str::from_utf8_unchecked(&bytes[0..self.len()]) }
} else {
""
}
}
fn create_memory_message(&self, id: u32) -> MemoryMessage {
if let Some(bytes) = &self.bytes {
let backing_store =
unsafe { MemoryRange::new(bytes.as_ptr() as _, bytes.len()).unwrap() };
MemoryMessage {
id: id as usize,
buf: backing_store,
offset: None,
valid: MemorySize::new(self.len()),
}
} else {
panic!("Tried to create a memory message with no string!");
}
}
pub unsafe fn from_memory_message(mem: &'a MemoryMessage) -> Self {
StringBuffer {
bytes: Some(core::slice::from_raw_parts_mut(
mem.buf.as_mut_ptr(),
mem.buf.len(),
)),
length: mem.valid.map(|v| v.get()).unwrap_or(0) as u32,
should_free: false,
memory_message: None,
}
}
pub unsafe fn from_memory_message_mut(mem: &'a mut MemoryMessage) -> Self {
StringBuffer {
bytes: Some(core::slice::from_raw_parts_mut(
mem.buf.as_mut_ptr(),
mem.buf.len(),
)),
length: mem.valid.map(|v| v.get()).unwrap_or(0) as u32,
should_free: false,
memory_message: Some(mem),
}
}
pub fn lend_mut(&mut self, connection: CID, id: u32) -> core::result::Result<Result, Error> {
let msg = self.create_memory_message(id);
let result = send_message(connection, Message::MutableBorrow(msg));
if let Ok(Result::MemoryReturned(_offset, valid)) = result {
self.length = valid.map(|v| v.get()).unwrap_or(0) as u32;
}
result
}
pub fn lend(&self, connection: CID, id: u32) -> core::result::Result<Result, Error> {
let msg = self.create_memory_message(id);
send_message(connection, Message::Borrow(msg))
}
pub fn send(mut self, connection: CID, id: u32) -> core::result::Result<Result, Error> {
let msg = self.create_memory_message(id);
let result = send_message(connection, Message::Move(msg))?;
self.should_free = false;
Ok(result)
}
}
impl<'a> core::str::FromStr for StringBuffer<'a> {
type Err = &'static str;
fn from_str(src: &str) -> core::result::Result<StringBuffer<'a>, &'static str> {
let mut s = Self::with_capacity(src.len());
for (dest_byte, src_byte) in s.bytes.as_mut().unwrap().iter_mut().zip(src.as_bytes()) {
*dest_byte = *src_byte;
}
s.length = s.as_bytes().len().min(src.as_bytes().len()) as u32;
if s.as_str().is_err() {
s.length = 0;
}
Ok(s)
}
}
impl<'a> Default for StringBuffer<'a> {
fn default() -> Self {
Self::new()
}
}
impl<'a> core::fmt::Display for StringBuffer<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.to_str())
}
}
impl<'a> core::fmt::Write for StringBuffer<'a> {
fn write_str(&mut self, s: &str) -> core::result::Result<(), core::fmt::Error> {
self.resize(self.len() + s.len());
let length = self.len();
for (dest, src) in self.as_bytes_mut()[length..].iter_mut().zip(s.as_bytes()) {
*dest = *src;
}
self.length += s.len() as u32;
if let Some(mm) = self.memory_message.as_mut() {
mm.valid = MemorySize::new(self.length as _).or(None);
}
Ok(())
}
}
impl<'a> core::fmt::Debug for StringBuffer<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.to_str())
}
}
impl<'a> core::convert::AsRef<str> for StringBuffer<'a> {
fn as_ref(&self) -> &str {
self.to_str()
}
}
impl<'a> PartialEq for StringBuffer<'a> {
fn eq(&self, other: &Self) -> bool {
self.length == other.length
&& self.as_bytes()[..self.len()] == other.as_bytes()[..other.len()]
}
}
impl<'a> Eq for StringBuffer<'a> {}
impl<'a> Drop for StringBuffer<'a> {
fn drop(&mut self) {
if self.should_free && !self.as_bytes().is_empty() {
let range = unsafe {
MemoryRange::new(self.as_bytes().as_ptr() as _, self.as_bytes().len()).unwrap()
};
unmap_memory(range).expect("Buffer: failed to drop memory");
}
}
}