#![warn(missing_docs)]
pub unsafe trait StableAddress: Deref {}
pub unsafe trait CloneStableAddress: StableAddress + Clone {}
pub struct OwningRef<O, T: ?Sized> {
owner: O,
reference: *const T,
}
pub trait Erased {}
impl<T> Erased for T {}
pub unsafe trait IntoErased {
type Erased;
fn into_erased(self) -> Self::Erased;
}
impl<O, T: ?Sized> OwningRef<O, T> {
pub fn new(o: O) -> Self
where O: StableAddress,
O: Deref<Target = T>,
{
OwningRef {
reference: &*o,
owner: o,
}
}
pub fn map<F, U: ?Sized>(self, f: F) -> OwningRef<O, U>
where O: StableAddress,
F: FnOnce(&T) -> &U
{
OwningRef {
reference: f(&self),
owner: self.owner,
}
}
pub fn erase_owner(self) -> OwningRef<O::Erased, T>
where O: IntoErased,
{
OwningRef {
reference: self.reference,
owner: self.owner.into_erased(),
}
}
pub fn owner(&self) -> &O {
&self.owner
}
pub fn into_inner(self) -> O {
self.owner
}
}
use std::ops::Deref;
use std::convert::From;
use std::fmt::{self, Debug};
use std::marker::{Send, Sync};
impl<O, T: ?Sized> Deref for OwningRef<O, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe {
&*self.reference
}
}
}
impl<O, T: ?Sized> AsRef<T> for OwningRef<O, T> {
fn as_ref(&self) -> &T {
&*self
}
}
impl<O, T: ?Sized> From<O> for OwningRef<O, T>
where O: StableAddress, O: Deref<Target = T>,
{
fn from(owner: O) -> Self {
OwningRef::new(owner)
}
}
impl<O, T: ?Sized> Debug for OwningRef<O, T>
where O: Debug, T: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "OwningRef {{ owner: {:?}, reference: {:?} }}",
self.owner(), &**self)
}
}
impl<O, T: ?Sized> Clone for OwningRef<O, T>
where O: CloneStableAddress,
{
fn clone(&self) -> Self {
OwningRef {
owner: self.owner.clone(),
reference: self.reference,
}
}
}
unsafe impl<O: Send, T: ?Sized> Send for OwningRef<O, T> {}
unsafe impl<O: Sync, T: ?Sized> Sync for OwningRef<O, T> {}
impl Debug for Erased {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "<Erased>",)
}
}
use std::boxed::Box;
use std::rc::Rc;
use std::sync::Arc;
unsafe impl<T: ?Sized> StableAddress for Box<T> {}
unsafe impl<T> StableAddress for Vec<T> {}
unsafe impl StableAddress for String {}
#[cfg(feature = "nightly")]
unsafe impl<T: ?Sized> StableAddress for Rc<T> {}
#[cfg(feature = "nightly")]
unsafe impl<T: ?Sized> StableAddress for Arc<T> {}
#[cfg(feature = "nightly")]
unsafe impl<T: ?Sized> CloneStableAddress for Rc<T> {}
#[cfg(feature = "nightly")]
unsafe impl<T: ?Sized> CloneStableAddress for Arc<T> {}
#[cfg(not(feature = "nightly"))]
unsafe impl<T> CloneStableAddress for Rc<T> {}
#[cfg(not(feature = "nightly"))]
unsafe impl<T> CloneStableAddress for Arc<T> {}
#[cfg(not(feature = "nightly"))]
unsafe impl<T> StableAddress for Rc<T> {}
#[cfg(not(feature = "nightly"))]
unsafe impl<T> StableAddress for Arc<T> {}
pub type BoxRef<T, U = T> = OwningRef<Box<T>, U>;
pub type VecRef<T, U = T> = OwningRef<Vec<T>, U>;
pub type StringRef = OwningRef<String, str>;
pub type RcRef<T, U = T> = OwningRef<Rc<T>, U>;
pub type ArcRef<T, U = T> = OwningRef<Arc<T>, U>;
unsafe impl<'a, T: 'a> IntoErased for Box<T> {
type Erased = Box<Erased + 'a>;
fn into_erased(self) -> Self::Erased { self }
}
#[cfg(feature = "nightly")]
unsafe impl<'a, T: 'a> IntoErased for Rc<T> {
type Erased = Rc<Erased + 'a>;
fn into_erased(self) -> Self::Erased { self }
}
#[cfg(feature = "nightly")]
unsafe impl<'a, T: 'a> IntoErased for Arc<T> {
type Erased = Arc<Erased + 'a>;
fn into_erased(self) -> Self::Erased { self }
}
pub type ErasedBoxRef<U> = OwningRef<Box<Erased>, U>;
#[cfg(feature = "nightly")]
pub type ErasedRcRef<U> = OwningRef<Rc<Erased>, U>;
#[cfg(feature = "nightly")]
pub type ErasedArcRef<U> = OwningRef<Arc<Erased>, U>;
#[cfg(test)]
mod tests {
use super::{OwningRef, BoxRef, Erased, ErasedBoxRef};
#[derive(Debug, PartialEq)]
struct Example(u32, String, [u8; 3]);
fn example() -> Example {
Example(42, "hello world".to_string(), [1, 2, 3])
}
#[test]
fn new_deref() {
let or: OwningRef<Box<()>, ()> = OwningRef::new(Box::new(()));
assert_eq!(&*or, &());
}
#[test]
fn into() {
let or: OwningRef<Box<()>, ()> = Box::new(()).into();
assert_eq!(&*or, &());
}
#[test]
fn map_offset_ref() {
let or: BoxRef<Example> = Box::new(example()).into();
let or: BoxRef<_, u32> = or.map(|x| &x.0);
assert_eq!(&*or, &42);
let or: BoxRef<Example> = Box::new(example()).into();
let or: BoxRef<_, u8> = or.map(|x| &x.2[1]);
assert_eq!(&*or, &2);
}
#[test]
fn map_heap_ref() {
let or: BoxRef<Example> = Box::new(example()).into();
let or: BoxRef<_, str> = or.map(|x| &x.1[..5]);
assert_eq!(&*or, "hello");
}
#[test]
fn map_static_ref() {
let or: BoxRef<()> = Box::new(()).into();
let or: BoxRef<_, str> = or.map(|_| "hello");
assert_eq!(&*or, "hello");
}
#[test]
fn map_chained() {
let or: BoxRef<String> = Box::new(example().1).into();
let or: BoxRef<_, str> = or.map(|x| &x[1..5]);
let or: BoxRef<_, str> = or.map(|x| &x[..2]);
assert_eq!(&*or, "el");
}
#[test]
fn map_chained_inference() {
let or = BoxRef::new(Box::new(example().1))
.map(|x| &x[..5])
.map(|x| &x[1..3]);
assert_eq!(&*or, "el");
}
#[test]
fn owner() {
let or: BoxRef<String> = Box::new(example().1).into();
let or = or.map(|x| &x[..5]);
assert_eq!(&*or, "hello");
assert_eq!(&**or.owner(), "hello world");
}
#[test]
fn into_inner() {
let or: BoxRef<String> = Box::new(example().1).into();
let or = or.map(|x| &x[..5]);
assert_eq!(&*or, "hello");
let s = *or.into_inner();
assert_eq!(&s, "hello world");
}
#[test]
fn fmt_debug() {
let or: BoxRef<String> = Box::new(example().1).into();
let or = or.map(|x| &x[..5]);
let s = format!("{:?}", or);
assert_eq!(&s, "OwningRef { owner: \"hello world\", reference: \"hello\" }");
}
#[test]
fn erased_owner() {
let o1: BoxRef<Example, str> = BoxRef::new(Box::new(example()))
.map(|x| &x.1[..]);
let o2: BoxRef<String, str> = BoxRef::new(Box::new(example().1))
.map(|x| &x[..]);
let os: Vec<ErasedBoxRef<str>> = vec![o1.erase_owner(), o2.erase_owner()];
assert!(os.iter().all(|e| &e[..] == "hello world"));
}
#[test]
fn non_static_erased_owner() {
let foo = [413, 612];
let bar = &foo;
let o: BoxRef<&[i32; 2]> = Box::new(bar).into();
let o: BoxRef<&[i32; 2], i32> = o.map(|a: &&[i32; 2]| &a[0]);
let o: BoxRef<Erased, i32> = o.erase_owner();
assert_eq!(*o, 413);
}
}