I am trying to make some kind of decoder, that will be able to deserialize entries without actually copying memory, just by mapping values to some memory regions. That is what I currently managed to do (simplified for testcase):
#![allow(unstable)]
trait CastAbility: Sized { }
impl CastAbility for u64 { }
impl CastAbility for u32 { }
impl CastAbility for u16 { }
impl CastAbility for u8 { }
trait Cast {
fn cast<'a>(mem: &'a [u8]) -> Result<&'a Self, String>;
}
impl<T> Cast for T where T: CastAbility {
fn cast<'a>(mem: &'a [u8]) -> Result<&'a T, String> {
if mem.len() != std::mem::size_of::<T>() {
Err("invalid size".to_string())
} else {
Ok(unsafe { std::mem::transmute(mem.as_ptr()) })
}
}
}
impl Cast for str {
fn cast<'a>(mem: &'a [u8]) -> Result<&'a str, String> {
Ok(unsafe { std::mem::transmute(std::raw::Slice { data: mem.as_ptr(), len: mem.len() }) })
}
}
trait Read<'a> {
fn read(mem: &'a [u8]) -> Result<Self, String>;
}
#[derive(Show, PartialEq)]
struct U8AndStr<'a> {
value_u8: &'a u8,
value_str: &'a str,
}
impl<'a> Read<'a> for U8AndStr<'a> {
fn read(mem: &'a [u8]) -> Result<U8AndStr, String> {
Ok(U8AndStr {
value_u8: try!(Cast::cast(mem.slice(0, 1))),
value_str: try!(Cast::cast(mem.slice(1, mem.len()))),
})
}
}
fn main() {
let mem: &[u8] = &[0x01, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37];
let value: U8AndStr = Read::read(mem).unwrap();
println!("value: {:?}", value);
}
playpen
In fact it compiles and even works, but now I cannot understand how to use my Read trait as generic parameter. For example, suppose I want to compare a value to a decoded result of some memory area:
fn compare_to_smth<'a, T>(value: &'a T) -> bool where T: PartialEq+Read<'a> {
let mem: &[u8] = &[0x01, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37];
let smth_value: T = Read::read(mem).unwrap();
smth_value == *value
}
fn main() {
let value = U8AndStr { value_u8: &1, value_str: "01234567" };
assert!(compare_to_smth(&value));
}
It fails with "borrowed value does not live long enough", and I can guess why: because mem lifetime is the function body, not 'a, as I did specify in signature for input parameter. So I tried to use second lifetime paramater as shown:
fn compare_to_smth<'a, 'b, T>(value: &'a T) -> bool where T: PartialEq+Read<'b> {
But it also didn't work for obvious reason. So I really don't understand how to make compare_to_smth work without passing memory chunk from outside. Is there any solution, or I should refactor the code somehow?
See Question&Answers more detail:
os