Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
A safe version of tagged pointers in rust
use std::mem;
use std::ops::{Deref, DerefMut};
#[derive(Copy, Clone, Debug)]
struct Tagged<'a, T: 'a> {
pointer: &'a T
}
impl<'a, T> Tagged<'a, T> {
fn tag(&'a mut self) -> &'a mut Tagged<'a, T> {
unsafe {
let pod: usize = mem::transmute(self.pointer);
let pod = pod | 1;
self.pointer = mem::transmute(pod);
}
self
}
fn untag(&'a mut self) -> &'a mut Tagged<'a, T> {
unsafe {
let pod: usize = mem::transmute(self.pointer);
let pod = pod & (!1 as usize);
self.pointer = mem::transmute(pod);
}
self
}
fn is_tagged(&'a mut self) -> bool {
unsafe {
let pod: usize = mem::transmute(self.pointer);
(pod & 1) == 1
}
}
}
impl<'a, T> Deref for Tagged<'a, T> {
type Target = T;
fn deref<'b>(&'b self) -> &'b T {
unsafe {
let pod: usize = mem::transmute(self.pointer);
let pod = pod & (!1 as usize);
mem::transmute(pod)
}
}
}
impl<'a, T> DerefMut for Tagged<'a, T> {
fn deref_mut<'b>(&'b mut self) -> &'b mut T {
unsafe {
let pod: usize = mem::transmute(self.pointer);
let pod = pod & (!1 as usize);
mem::transmute(pod)
}
}
}
fn check_tagged0() {
let mut p = Tagged { pointer: &42 };
assert_eq!(p.is_tagged(), false);
}
fn check_tagged1() {
let mut p = Tagged { pointer: &42 };
let mut p = p.tag();
assert_eq!(p.is_tagged(), true);
}
fn check_deref0() {
let p = Tagged { pointer: &42 };
assert_eq!(*p, 42);
}
fn check_deref1() {
let mut p = Tagged { pointer: &42 };
let p = *p.tag();
assert_eq!(*p, 42);
}
fn check_deref2() {
let n = 42;
let mut p = Tagged { pointer: &n };
*p = 0;
assert_eq!(*p, 0);
}
fn check_deref3() {
let n = 42;
let mut p = Tagged { pointer: &n };
let mut p = *p.tag();
*p = 0;
assert_eq!(*p, 0);
}
fn check_untag() {
let n = 42;
let mut p: Tagged<i32> = Tagged { pointer: &n };
let mut p: &mut Tagged<i32> = p.tag();
assert_eq!(p.clone().is_tagged(), true);
let p: &mut Tagged<i32> = p.untag();
assert_eq!(p.clone().is_tagged(), false);
}
fn main() {
check_tagged0();
check_tagged1();
check_deref0();
check_deref1();
check_deref2();
check_deref3();
check_untag();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment