I've been learning some Rust after hearing about their
1.0 release. I'm very impressed by the compiler, the documentation, and the language itself.
The first thing I wrote in Rust was a routine to tag pointers. (If you haven't heard of pointer tagging, it's just a way of storing information within a pointer. Pointers tend to be at least 32-bit aligned, leaving the two least-significant bits of the pointer free for tags.) It works by using Rust's unsafe-cast mechanism (
std::mem::transmute) to do a little bit flipping:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| fn tag_pointer<T>(p: &T, bit: u8) -> &T {
unsafe {
let pod: usize = mem::transmute(p);
let pod = pod | (1 << bit);
mem::transmute(pod)
}
}
fn untag_pointer<T>(p: &T, bit: u8) -> &T {
unsafe {
let pod: usize = mem::transmute(p);
let pod = pod & (!(1 << bit) as usize);
mem::transmute(pod)
}
}
fn check_pointer_tag<T>(p: &T, bit: u8) -> u8 {
unsafe {
let pod: usize = mem::transmute(p);
((pod >> bit) & 1) as u8
}
}
|
To check that this works, we can do:
1
2
3
4
5
| let p = &0; // Take the address of an integer.
let pn = tag_pointer(p, 0);
assert_eq!(check_pointer_tag(p, 0), 0);
assert_eq!(check_pointer_tag(pn, 0), 1);
assert_eq!(p, untag_pointer(pn, 0));
|
N.b: it isn't safe to dereference a tagged pointer :-). Here is a
safe, alternate version which implements
Deref and
DerefMut.
This code isn't particularly tricky or interesting, but maybe it'll be useful to someone.