Crates.io | memory_slice |
lib.rs | memory_slice |
version | 0.1.0-preview3 |
source | src |
created_at | 2020-09-25 17:34:44.009773 |
updated_at | 2020-09-26 19:03:31.056674 |
description | A memory slice over potentialy uninitialized memory that allowes safe and borrow-checked, reads, writes and reinterpretation of data of any kind. |
homepage | |
repository | https://gitlab.com/okannen/memory_slice |
max_upload_size | |
id | 292902 |
size | 35,220 |
memory_slice
that can alias any kind of data, and provides an API that allow user to read, write and borrow
data of any type.
Any kind of data can be viewed as constant memory slice:
use memory_slice::AsMemory;
let v: [u8;4] = [1,1,1,1];
//as_memory return a &memory_slice
assert_eq!(unsafe{v.as_memory().read::<i32>()},1 + (1<<8) + (1<<16) + (1<<24));
But only types that do not preserve any invariants are accessible as mutable memory slice:
This will compile:
use memory_slice::AsMutMemory;
let mut v: [u8;4] = [1,1,1,1];
//as_memory return a &memory_slice
v.as_mut_memory().write(16 as u16);
This will not compile:
use memory_slice::AsMutMemory;
use std::string::String;
let mut v = String::new();
//as_memory return a &memory_slice
v.as_mut_memory().write(16 as u16); //compilation failure
Mutable memory slices can be used to write information of any type while preserving borrow rules. The API provide also a smart pointer that will drop value created on the memory slice:
use memory_slice::{align,AsMutMemory,AsMemory};
// creates an array of 64 u8 aligned as 8:
let mut buff = align!(8,[0 as u8;64]);
//the create an int inside the buffer and get a reference to it
let (padding, v1, remaining_buffer) = buff.as_mut_memory().write(42 as i32);
assert!(padding.is_empty());
//unsafe{buff[0]}; //error => cannot borrow buff as immutable
//use the remaining unitialized buffer to write an u64 in it:
let (padding, v2, remaining_buffer2) = remaining_buffer.write(42 as u64);
assert_eq!(padding.len(), 4);
//unsafe{remaing_buffer.read::<u8>()}; //error => cannot borrow remaining_buffer
//v1 and v2 are reference to the i32 and u64 created inside buff
assert_eq!(*v1 as u64, *v2);
{
extern crate alloc;
use alloc::borrow::ToOwned;
//In what remains of the buffer, let's create a value that needs to be dropped:
let (_padding, v3, _remaining) = remaining_buffer2.emplace("42".to_owned());
//v3 is a smart pointer to the String created in the buffer that will drop
//this string when it goes out of scope
assert_eq!(*v1, v3.parse::<i32>().unwrap());
} //string refered by v3 is dropped
//buff is not anymore borrowed, so it is accessible:
assert_eq!(unsafe { buff.as_memory().read::<i32>() }, 42);
//memory slice can be indexed (!!less inoffensive than it looks)
unsafe{*buff.as_mut_memory()[2..4].as_mut_unchecked()=16 as u16};
assert_ne!(unsafe { buff.as_memory().read::<i32>() }, 42);
A macro named buffer
is provided to create uninitialized
buffer:
use memory_slice::buffer;
// create an uninitialized buffer of 64 bytes aligned as 8.
let mut buff = buffer!(64,8);
// buffer are dereferencable as memory_slice
//the create an int inside the buffer and get a reference to it
buff.write(42 as i32);