Merge pull request #50 from NikVolf/mem-up

Memory extensions (copy + little refactoring)
This commit is contained in:
Nikolay Volf 2017-06-14 18:31:07 +03:00 committed by GitHub
commit 73669922c9

View File

@ -18,6 +18,22 @@ pub struct MemoryInstance {
maximum_size: u32, maximum_size: u32,
} }
struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref<Target=Vec<u8>> {
buffer: &'a B,
offset: usize,
size: usize,
}
impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref<Target=Vec<u8>> {
fn range(&self) -> ::std::ops::Range<usize> {
self.offset..self.offset+self.size
}
fn slice(&self) -> &[u8] {
&self.buffer[self.range()]
}
}
impl MemoryInstance { impl MemoryInstance {
/// Create new linear memory instance. /// Create new linear memory instance.
pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error> { pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error> {
@ -48,36 +64,18 @@ impl MemoryInstance {
/// Get data at given offset. /// Get data at given offset.
pub fn get(&self, offset: u32, size: usize) -> Result<Vec<u8>, Error> { pub fn get(&self, offset: u32, size: usize) -> Result<Vec<u8>, Error> {
let begin = offset as usize;
let end = match begin.checked_add(size) {
Some(end) => end,
None => return Err(Error::Memory(format!("trying to read memory block of size {} from offset {}", size, offset))),
};
let buffer = self.buffer.read(); let buffer = self.buffer.read();
if buffer.len() < end { let region = self.checked_region(&buffer, offset as usize, size)?;
return Err(Error::Memory(format!("trying to read region [{}..{}] in memory [0..{}]", begin, end, buffer.len())));
}
Ok(buffer[begin..end].to_vec()) Ok(region.slice().to_vec())
} }
/// Set data at given offset. /// Set data at given offset.
pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> { pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> {
let size = value.len();
let begin = offset as usize;
let end = match begin.checked_add(size) {
Some(end) => end,
None => return Err(Error::Memory(format!("trying to update memory block of size {} from offset {}", size, offset))),
};
let mut buffer = self.buffer.write(); let mut buffer = self.buffer.write();
if buffer.len() < end { let range = self.checked_region(&buffer, offset as usize, value.len())?.range();
return Err(Error::Memory(format!("trying to update region [{}..{}] in memory [0..{}]", begin, end, buffer.len())));
}
let mut mut_buffer = buffer.as_mut_slice(); buffer[range].copy_from_slice(value);
mut_buffer[begin..end].copy_from_slice(value);
Ok(()) Ok(())
} }
@ -96,4 +94,37 @@ impl MemoryInstance {
}, },
} }
} }
fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result<CheckedRegion<'a, B>, Error>
where B: ::std::ops::Deref<Target=Vec<u8>>
{
let end = offset.checked_add(size)
.ok_or(Error::Memory(format!("trying to access memory block of size {} from offset {}", size, offset)))?;
if end > buffer.len() {
return Err(Error::Memory(format!("trying to access region [{}..{}] in memory [0..{}]", offset, end, buffer.len())));
}
Ok(CheckedRegion {
buffer: buffer,
offset: offset,
size: size,
})
}
/// Copy memory region
pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> {
let buffer = self.buffer.write();
let read_region = self.checked_region(&buffer, src_offset, len)?;
let write_region = self.checked_region(&buffer, dst_offset, len)?;
unsafe { ::std::ptr::copy(
buffer[read_region.range()].as_ptr(),
buffer[write_region.range()].as_ptr() as *mut _,
len,
)}
Ok(())
}
} }