It works. Thanks.
Before that, I tried just use raw pointer as in C. Like:
use std::{collections::HashMap, hash::Hash, io::Write};
struct Key(* const [u8]);
impl Hash for Key {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
unsafe {
(*self.0).hash(state);
}
}
}
impl PartialEq for Key {
fn eq(&self, other: &Self) -> bool {
unsafe {
*self.0 == *other.0
}
}
}
impl Eq for Key {}
struct Val(* mut [u8; 4]);
fn parse(data: &mut [u8]) -> Result<HashMap<Key, Val>, &'static str> {
let mut map = HashMap::<Key, Val>::new();
let mut cursor = 0;
while !data.is_empty() {
let mut key_len = 0;
while data[cursor + key_len] != 0 && cursor + key_len < data.len() {
key_len += 1;
}
if cursor + key_len + 5 > data.len() {
return Err("Not enough data for value");
}
let key = Key(&data[cursor..cursor + key_len]);
let val = Val(&mut (&mut data[cursor + key_len + 1..cursor + key_len + 5]).try_into().unwrap());
map.insert(key, val);
cursor += key_len + 5;
}
Ok(map)
}
fn main() {
let mut data = vec![];
data.write(b"key1").unwrap();
data.write(&[0]).unwrap();
data.write(&24_u32.to_be_bytes()).unwrap();
data.write(b"key2").unwrap();
data.write(&[0]).unwrap();
data.write(&42_u32.to_be_bytes()).unwrap();
let _ = parse(&mut data).unwrap();
// println!("Value1: {}", u32::from_be_bytes(*parsed["key1".as_bytes()]));
// println!("Value2: {}", u32::from_be_bytes(*parsed["key2".as_bytes()]));
}
And miri compains when I dereference the raw pointer.
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `/home/billy/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/cargo-miri runner target/miri/x86_64-unknown-linux-gnu/debug/play`
warning: field `0` is never read
--> src/main.rs:20:12
|
20 | struct Val(* mut [u8; 4]);
| --- ^^^^^^^^^^^^^
| |
| field in this struct
|
= note: `#[warn(dead_code)]` on by default
help: consider changing the field to be of unit type to suppress this warning while preserving the field numbering, or remove the field
|
20 | struct Val(());
| ~~
error: Undefined Behavior: trying to retag from <3017> for SharedReadOnly permission at alloc1089[0x0], but that tag does not exist in the borrow stack for this location
--> src/main.rs:7:13
|
7 | (*self.0).hash(state);
| ^^^^^^^^^
| |
| trying to retag from <3017> for SharedReadOnly permission at alloc1089[0x0], but that tag does not exist in the borrow stack for this location
| this error occurs as part of retag at alloc1089[0x0..0x4]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <3017> was created by a SharedReadOnly retag at offsets [0x0..0x4]
--> src/main.rs:34:23
|
34 | let key = Key(&data[cursor..cursor + key_len]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: <3017> was later invalidated at offsets [0x0..0x12] by a Unique retag
--> src/main.rs:35:34
|
35 | let val = Val(&mut (&mut data[cursor + key_len + 1..cursor + key_len + 5]).try_into().unwrap());
| ^^^^
= note: BACKTRACE (of the first span):
= note: inside `<Key as std::hash::Hash>::hash::<std::hash::DefaultHasher>` at src/main.rs:7:13: 7:22
= note: inside `core::hash::impls::<impl std::hash::Hash for &Key>::hash::<std::hash::DefaultHasher>` at /home/billy/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/hash/mod.rs:941:13: 941:33
= note: inside `<std::hash::RandomState as std::hash::BuildHasher>::hash_one::<&Key>` at /home/billy/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/hash/mod.rs:701:9: 701:28
= note: inside `hashbrown::map::make_hash::<Key, std::hash::RandomState>` at /home/billy/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-2eab394af869c8a2/hashbrown-0.14.3/src/map.rs:262:5: 262:31
= note: inside `hashbrown::map::HashMap::<Key, Val, std::hash::RandomState>::insert` at /home/billy/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-2eab394af869c8a2/hashbrown-0.14.3/src/map.rs:1752:20: 1752:61
= note: inside `std::collections::HashMap::<Key, Val>::insert` at /home/billy/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/collections/hash/map.rs:1105:9: 1105:31
note: inside `parse`
--> src/main.rs:36:9
|
36 | map.insert(key, val);
| ^^^^^^^^^^^^^^^^^^^^
note: inside `main`
--> src/main.rs:50:13
|
50 | let _ = parse(&mut data).unwrap();
| ^^^^^^^^^^^^^^^^
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error; 1 warning emitted
I wonder what is the root cause of this error. Isn't it true that raw pointers has no no-aliasing
optimization?