| #![warn(missing_docs)] |
| |
| /*! |
| # An owning reference. |
| |
| This crate provides the _owning reference_ types `OwningRef` and `OwningRefMut` |
| that enables it to bundle a reference together with the owner of the data it points to. |
| This allows moving and dropping of a `OwningRef` without needing to recreate the reference. |
| |
| This can sometimes be useful because Rust borrowing rules normally prevent |
| moving a type that has been moved from. For example, this kind of code gets rejected: |
| |
| ```rust,ignore |
| fn return_owned_and_referenced<'a>() -> (Vec<u8>, &'a [u8]) { |
| let v = vec![1, 2, 3, 4]; |
| let s = &v[1..3]; |
| (v, s) |
| } |
| ``` |
| |
| Even though, from a memory-layout point of view, this can be entirely safe |
| if the new location of the vector still lives longer than the lifetime `'a` |
| of the reference because the backing allocation of the vector does not change. |
| |
| This library enables this safe usage by keeping the owner and the reference |
| bundled together in a wrapper type that ensure that lifetime constraint: |
| |
| ```rust |
| # extern crate owning_ref; |
| # use owning_ref::OwningRef; |
| # fn main() { |
| fn return_owned_and_referenced() -> OwningRef<Vec<u8>, [u8]> { |
| let v = vec![1, 2, 3, 4]; |
| let or = OwningRef::new(v); |
| let or = or.map(|v| &v[1..3]); |
| or |
| } |
| # } |
| ``` |
| |
| It works by requiring owner types to dereference to stable memory locations |
| and preventing mutable access to root containers, which in practice requires heap allocation |
| as provided by `Box<T>`, `Rc<T>`, etc. |
| |
| Also provided are typedefs for common owner type combinations, |
| which allow for less verbose type signatures. For example, `BoxRef<T>` instead of `OwningRef<Box<T>, T>`. |
| |
| The crate also provides the more advanced `OwningHandle` type, |
| which allows more freedom in bundling a dependent handle object |
| along with the data it depends on, at the cost of some unsafe needed in the API. |
| See the documentation around `OwningHandle` for more details. |
| |
| # Examples |
| |
| ## Basics |
| |
| ``` |
| extern crate owning_ref; |
| use owning_ref::BoxRef; |
| |
| fn main() { |
| // Create an array owned by a Box. |
| let arr = Box::new([1, 2, 3, 4]) as Box<[i32]>; |
| |
| // Transfer into a BoxRef. |
| let arr: BoxRef<[i32]> = BoxRef::new(arr); |
| assert_eq!(&*arr, &[1, 2, 3, 4]); |
| |
| // We can slice the array without losing ownership or changing type. |
| let arr: BoxRef<[i32]> = arr.map(|arr| &arr[1..3]); |
| assert_eq!(&*arr, &[2, 3]); |
| |
| // Also works for Arc, Rc, String and Vec! |
| } |
| ``` |
| |
| ## Caching a reference to a struct field |
| |
| ``` |
| extern crate owning_ref; |
| use owning_ref::BoxRef; |
| |
| fn main() { |
| struct Foo { |
| tag: u32, |
| x: u16, |
| y: u16, |
| z: u16, |
| } |
| let foo = Foo { tag: 1, x: 100, y: 200, z: 300 }; |
| |
| let or = BoxRef::new(Box::new(foo)).map(|foo| { |
| match foo.tag { |
| 0 => &foo.x, |
| 1 => &foo.y, |
| 2 => &foo.z, |
| _ => panic!(), |
| } |
| }); |
| |
| assert_eq!(*or, 200); |
| } |
| ``` |
| |
| ## Caching a reference to an entry in a vector |
| |
| ``` |
| extern crate owning_ref; |
| use owning_ref::VecRef; |
| |
| fn main() { |
| let v = VecRef::new(vec![1, 2, 3, 4, 5]).map(|v| &v[3]); |
| assert_eq!(*v, 4); |
| } |
| ``` |
| |
| ## Caching a subslice of a String |
| |
| ``` |
| extern crate owning_ref; |
| use owning_ref::StringRef; |
| |
| fn main() { |
| let s = StringRef::new("hello world".to_owned()) |
| .map(|s| s.split(' ').nth(1).unwrap()); |
| |
| assert_eq!(&*s, "world"); |
| } |
| ``` |
| |
| ## Reference counted slices that share ownership of the backing storage |
| |
| ``` |
| extern crate owning_ref; |
| use owning_ref::RcRef; |
| use std::rc::Rc; |
| |
| fn main() { |
| let rc: RcRef<[i32]> = RcRef::new(Rc::new([1, 2, 3, 4]) as Rc<[i32]>); |
| assert_eq!(&*rc, &[1, 2, 3, 4]); |
| |
| let rc_a: RcRef<[i32]> = rc.clone().map(|s| &s[0..2]); |
| let rc_b = rc.clone().map(|s| &s[1..3]); |
| let rc_c = rc.clone().map(|s| &s[2..4]); |
| assert_eq!(&*rc_a, &[1, 2]); |
| assert_eq!(&*rc_b, &[2, 3]); |
| assert_eq!(&*rc_c, &[3, 4]); |
| |
| let rc_c_a = rc_c.clone().map(|s| &s[1]); |
| assert_eq!(&*rc_c_a, &4); |
| } |
| ``` |
| |
| ## Atomic reference counted slices that share ownership of the backing storage |
| |
| ``` |
| extern crate owning_ref; |
| use owning_ref::ArcRef; |
| use std::sync::Arc; |
| |
| fn main() { |
| use std::thread; |
| |
| fn par_sum(rc: ArcRef<[i32]>) -> i32 { |
| if rc.len() == 0 { |
| return 0; |
| } else if rc.len() == 1 { |
| return rc[0]; |
| } |
| let mid = rc.len() / 2; |
| let left = rc.clone().map(|s| &s[..mid]); |
| let right = rc.map(|s| &s[mid..]); |
| |
| let left = thread::spawn(move || par_sum(left)); |
| let right = thread::spawn(move || par_sum(right)); |
| |
| left.join().unwrap() + right.join().unwrap() |
| } |
| |
| let rc: Arc<[i32]> = Arc::new([1, 2, 3, 4]); |
| let rc: ArcRef<[i32]> = rc.into(); |
| |
| assert_eq!(par_sum(rc), 10); |
| } |
| ``` |
| |
| ## References into RAII locks |
| |
| ``` |
| extern crate owning_ref; |
| use owning_ref::RefRef; |
| use std::cell::{RefCell, Ref}; |
| |
| fn main() { |
| let refcell = RefCell::new((1, 2, 3, 4)); |
| // Also works with Mutex and RwLock |
| |
| let refref = { |
| let refref = RefRef::new(refcell.borrow()).map(|x| &x.3); |
| assert_eq!(*refref, 4); |
| |
| // We move the RAII lock and the reference to one of |
| // the subfields in the data it guards here: |
| refref |
| }; |
| |
| assert_eq!(*refref, 4); |
| |
| drop(refref); |
| |
| assert_eq!(*refcell.borrow(), (1, 2, 3, 4)); |
| } |
| ``` |
| |
| ## Mutable reference |
| |
| When the owned container implements `DerefMut`, it is also possible to make |
| a _mutable owning reference_. (E.g. with `Box`, `RefMut`, `MutexGuard`) |
| |
| ``` |
| extern crate owning_ref; |
| use owning_ref::RefMutRefMut; |
| use std::cell::{RefCell, RefMut}; |
| |
| fn main() { |
| let refcell = RefCell::new((1, 2, 3, 4)); |
| |
| let mut refmut_refmut = { |
| let mut refmut_refmut = RefMutRefMut::new(refcell.borrow_mut()).map_mut(|x| &mut x.3); |
| assert_eq!(*refmut_refmut, 4); |
| *refmut_refmut *= 2; |
| |
| refmut_refmut |
| }; |
| |
| assert_eq!(*refmut_refmut, 8); |
| *refmut_refmut *= 2; |
| |
| drop(refmut_refmut); |
| |
| assert_eq!(*refcell.borrow(), (1, 2, 3, 16)); |
| } |
| ``` |
| */ |
| |
| extern crate stable_deref_trait; |
| pub use stable_deref_trait::{StableDeref as StableAddress, CloneStableDeref as CloneStableAddress}; |
| |
| /// An owning reference. |
| /// |
| /// This wraps an owner `O` and a reference `&T` pointing |
| /// at something reachable from `O::Target` while keeping |
| /// the ability to move `self` around. |
| /// |
| /// The owner is usually a pointer that points at some base type. |
| /// |
| /// For more details and examples, see the module and method docs. |
| pub struct OwningRef<O, T: ?Sized> { |
| owner: O, |
| reference: *const T, |
| } |
| |
| /// An mutable owning reference. |
| /// |
| /// This wraps an owner `O` and a reference `&mut T` pointing |
| /// at something reachable from `O::Target` while keeping |
| /// the ability to move `self` around. |
| /// |
| /// The owner is usually a pointer that points at some base type. |
| /// |
| /// For more details and examples, see the module and method docs. |
| pub struct OwningRefMut<O, T: ?Sized> { |
| owner: O, |
| reference: *mut T, |
| } |
| |
| /// Helper trait for an erased concrete type an owner dereferences to. |
| /// This is used in form of a trait object for keeping |
| /// something around to (virtually) call the destructor. |
| pub trait Erased {} |
| impl<T> Erased for T {} |
| |
| /// Helper trait for erasing the concrete type of what an owner derferences to, |
| /// for example `Box<T> -> Box<Erased>`. This would be unneeded with |
| /// higher kinded types support in the language. |
| pub unsafe trait IntoErased<'a> { |
| /// Owner with the dereference type substituted to `Erased`. |
| type Erased; |
| /// Perform the type erasure. |
| fn into_erased(self) -> Self::Erased; |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // OwningRef |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| impl<O, T: ?Sized> OwningRef<O, T> { |
| /// Creates a new owning reference from a owner |
| /// initialized to the direct dereference of it. |
| /// |
| /// # Example |
| /// ``` |
| /// extern crate owning_ref; |
| /// use owning_ref::OwningRef; |
| /// |
| /// fn main() { |
| /// let owning_ref = OwningRef::new(Box::new(42)); |
| /// assert_eq!(*owning_ref, 42); |
| /// } |
| /// ``` |
| pub fn new(o: O) -> Self |
| where O: StableAddress, |
| O: Deref<Target = T>, |
| { |
| OwningRef { |
| reference: &*o, |
| owner: o, |
| } |
| } |
| |
| /// Like `new`, but doesn’t require `O` to implement the `StableAddress` trait. |
| /// Instead, the caller is responsible to make the same promises as implementing the trait. |
| /// |
| /// This is useful for cases where coherence rules prevents implementing the trait |
| /// without adding a dependency to this crate in a third-party library. |
| pub unsafe fn new_assert_stable_address(o: O) -> Self |
| where O: Deref<Target = T>, |
| { |
| OwningRef { |
| reference: &*o, |
| owner: o, |
| } |
| } |
| |
| /// Converts `self` into a new owning reference that points at something reachable |
| /// from the previous one. |
| /// |
| /// This can be a reference to a field of `U`, something reachable from a field of |
| /// `U`, or even something unrelated with a `'static` lifetime. |
| /// |
| /// # Example |
| /// ``` |
| /// extern crate owning_ref; |
| /// use owning_ref::OwningRef; |
| /// |
| /// fn main() { |
| /// let owning_ref = OwningRef::new(Box::new([1, 2, 3, 4])); |
| /// |
| /// // create a owning reference that points at the |
| /// // third element of the array. |
| /// let owning_ref = owning_ref.map(|array| &array[2]); |
| /// assert_eq!(*owning_ref, 3); |
| /// } |
| /// ``` |
| 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, |
| } |
| } |
| |
| /// Tries to convert `self` into a new owning reference that points |
| /// at something reachable from the previous one. |
| /// |
| /// This can be a reference to a field of `U`, something reachable from a field of |
| /// `U`, or even something unrelated with a `'static` lifetime. |
| /// |
| /// # Example |
| /// ``` |
| /// extern crate owning_ref; |
| /// use owning_ref::OwningRef; |
| /// |
| /// fn main() { |
| /// let owning_ref = OwningRef::new(Box::new([1, 2, 3, 4])); |
| /// |
| /// // create a owning reference that points at the |
| /// // third element of the array. |
| /// let owning_ref = owning_ref.try_map(|array| { |
| /// if array[2] == 3 { Ok(&array[2]) } else { Err(()) } |
| /// }); |
| /// assert_eq!(*owning_ref.unwrap(), 3); |
| /// } |
| /// ``` |
| pub fn try_map<F, U: ?Sized, E>(self, f: F) -> Result<OwningRef<O, U>, E> |
| where O: StableAddress, |
| F: FnOnce(&T) -> Result<&U, E> |
| { |
| Ok(OwningRef { |
| reference: f(&self)?, |
| owner: self.owner, |
| }) |
| } |
| |
| /// Converts `self` into a new owning reference with a different owner type. |
| /// |
| /// The new owner type needs to still contain the original owner in some way |
| /// so that the reference into it remains valid. This function is marked unsafe |
| /// because the user needs to manually uphold this guarantee. |
| pub unsafe fn map_owner<F, P>(self, f: F) -> OwningRef<P, T> |
| where O: StableAddress, |
| P: StableAddress, |
| F: FnOnce(O) -> P |
| { |
| OwningRef { |
| reference: self.reference, |
| owner: f(self.owner), |
| } |
| } |
| |
| /// Converts `self` into a new owning reference where the owner is wrapped |
| /// in an additional `Box<O>`. |
| /// |
| /// This can be used to safely erase the owner of any `OwningRef<O, T>` |
| /// to a `OwningRef<Box<Erased>, T>`. |
| pub fn map_owner_box(self) -> OwningRef<Box<O>, T> { |
| OwningRef { |
| reference: self.reference, |
| owner: Box::new(self.owner), |
| } |
| } |
| |
| /// Erases the concrete base type of the owner with a trait object. |
| /// |
| /// This allows mixing of owned references with different owner base types. |
| /// |
| /// # Example |
| /// ``` |
| /// extern crate owning_ref; |
| /// use owning_ref::{OwningRef, Erased}; |
| /// |
| /// fn main() { |
| /// // NB: Using the concrete types here for explicitnes. |
| /// // For less verbose code type aliases like `BoxRef` are provided. |
| /// |
| /// let owning_ref_a: OwningRef<Box<[i32; 4]>, [i32; 4]> |
| /// = OwningRef::new(Box::new([1, 2, 3, 4])); |
| /// |
| /// let owning_ref_b: OwningRef<Box<Vec<(i32, bool)>>, Vec<(i32, bool)>> |
| /// = OwningRef::new(Box::new(vec![(0, false), (1, true)])); |
| /// |
| /// let owning_ref_a: OwningRef<Box<[i32; 4]>, i32> |
| /// = owning_ref_a.map(|a| &a[0]); |
| /// |
| /// let owning_ref_b: OwningRef<Box<Vec<(i32, bool)>>, i32> |
| /// = owning_ref_b.map(|a| &a[1].0); |
| /// |
| /// let owning_refs: [OwningRef<Box<Erased>, i32>; 2] |
| /// = [owning_ref_a.erase_owner(), owning_ref_b.erase_owner()]; |
| /// |
| /// assert_eq!(*owning_refs[0], 1); |
| /// assert_eq!(*owning_refs[1], 1); |
| /// } |
| /// ``` |
| pub fn erase_owner<'a>(self) -> OwningRef<O::Erased, T> |
| where O: IntoErased<'a>, |
| { |
| OwningRef { |
| reference: self.reference, |
| owner: self.owner.into_erased(), |
| } |
| } |
| |
| // TODO: wrap_owner |
| |
| /// A reference to the underlying owner. |
| pub fn as_owner(&self) -> &O { |
| &self.owner |
| } |
| |
| /// Discards the reference and retrieves the owner. |
| pub fn into_owner(self) -> O { |
| self.owner |
| } |
| } |
| |
| impl<O, T: ?Sized> OwningRefMut<O, T> { |
| /// Creates a new owning reference from a owner |
| /// initialized to the direct dereference of it. |
| /// |
| /// # Example |
| /// ``` |
| /// extern crate owning_ref; |
| /// use owning_ref::OwningRefMut; |
| /// |
| /// fn main() { |
| /// let owning_ref_mut = OwningRefMut::new(Box::new(42)); |
| /// assert_eq!(*owning_ref_mut, 42); |
| /// } |
| /// ``` |
| pub fn new(mut o: O) -> Self |
| where O: StableAddress, |
| O: DerefMut<Target = T>, |
| { |
| OwningRefMut { |
| reference: &mut *o, |
| owner: o, |
| } |
| } |
| |
| /// Like `new`, but doesn’t require `O` to implement the `StableAddress` trait. |
| /// Instead, the caller is responsible to make the same promises as implementing the trait. |
| /// |
| /// This is useful for cases where coherence rules prevents implementing the trait |
| /// without adding a dependency to this crate in a third-party library. |
| pub unsafe fn new_assert_stable_address(mut o: O) -> Self |
| where O: DerefMut<Target = T>, |
| { |
| OwningRefMut { |
| reference: &mut *o, |
| owner: o, |
| } |
| } |
| |
| /// Converts `self` into a new _shared_ owning reference that points at |
| /// something reachable from the previous one. |
| /// |
| /// This can be a reference to a field of `U`, something reachable from a field of |
| /// `U`, or even something unrelated with a `'static` lifetime. |
| /// |
| /// # Example |
| /// ``` |
| /// extern crate owning_ref; |
| /// use owning_ref::OwningRefMut; |
| /// |
| /// fn main() { |
| /// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4])); |
| /// |
| /// // create a owning reference that points at the |
| /// // third element of the array. |
| /// let owning_ref = owning_ref_mut.map(|array| &array[2]); |
| /// assert_eq!(*owning_ref, 3); |
| /// } |
| /// ``` |
| pub fn map<F, U: ?Sized>(mut self, f: F) -> OwningRef<O, U> |
| where O: StableAddress, |
| F: FnOnce(&mut T) -> &U |
| { |
| OwningRef { |
| reference: f(&mut self), |
| owner: self.owner, |
| } |
| } |
| |
| /// Converts `self` into a new _mutable_ owning reference that points at |
| /// something reachable from the previous one. |
| /// |
| /// This can be a reference to a field of `U`, something reachable from a field of |
| /// `U`, or even something unrelated with a `'static` lifetime. |
| /// |
| /// # Example |
| /// ``` |
| /// extern crate owning_ref; |
| /// use owning_ref::OwningRefMut; |
| /// |
| /// fn main() { |
| /// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4])); |
| /// |
| /// // create a owning reference that points at the |
| /// // third element of the array. |
| /// let owning_ref_mut = owning_ref_mut.map_mut(|array| &mut array[2]); |
| /// assert_eq!(*owning_ref_mut, 3); |
| /// } |
| /// ``` |
| pub fn map_mut<F, U: ?Sized>(mut self, f: F) -> OwningRefMut<O, U> |
| where O: StableAddress, |
| F: FnOnce(&mut T) -> &mut U |
| { |
| OwningRefMut { |
| reference: f(&mut self), |
| owner: self.owner, |
| } |
| } |
| |
| /// Tries to convert `self` into a new _shared_ owning reference that points |
| /// at something reachable from the previous one. |
| /// |
| /// This can be a reference to a field of `U`, something reachable from a field of |
| /// `U`, or even something unrelated with a `'static` lifetime. |
| /// |
| /// # Example |
| /// ``` |
| /// extern crate owning_ref; |
| /// use owning_ref::OwningRefMut; |
| /// |
| /// fn main() { |
| /// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4])); |
| /// |
| /// // create a owning reference that points at the |
| /// // third element of the array. |
| /// let owning_ref = owning_ref_mut.try_map(|array| { |
| /// if array[2] == 3 { Ok(&array[2]) } else { Err(()) } |
| /// }); |
| /// assert_eq!(*owning_ref.unwrap(), 3); |
| /// } |
| /// ``` |
| pub fn try_map<F, U: ?Sized, E>(mut self, f: F) -> Result<OwningRef<O, U>, E> |
| where O: StableAddress, |
| F: FnOnce(&mut T) -> Result<&U, E> |
| { |
| Ok(OwningRef { |
| reference: f(&mut self)?, |
| owner: self.owner, |
| }) |
| } |
| |
| /// Tries to convert `self` into a new _mutable_ owning reference that points |
| /// at something reachable from the previous one. |
| /// |
| /// This can be a reference to a field of `U`, something reachable from a field of |
| /// `U`, or even something unrelated with a `'static` lifetime. |
| /// |
| /// # Example |
| /// ``` |
| /// extern crate owning_ref; |
| /// use owning_ref::OwningRefMut; |
| /// |
| /// fn main() { |
| /// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4])); |
| /// |
| /// // create a owning reference that points at the |
| /// // third element of the array. |
| /// let owning_ref_mut = owning_ref_mut.try_map_mut(|array| { |
| /// if array[2] == 3 { Ok(&mut array[2]) } else { Err(()) } |
| /// }); |
| /// assert_eq!(*owning_ref_mut.unwrap(), 3); |
| /// } |
| /// ``` |
| pub fn try_map_mut<F, U: ?Sized, E>(mut self, f: F) -> Result<OwningRefMut<O, U>, E> |
| where O: StableAddress, |
| F: FnOnce(&mut T) -> Result<&mut U, E> |
| { |
| Ok(OwningRefMut { |
| reference: f(&mut self)?, |
| owner: self.owner, |
| }) |
| } |
| |
| /// Converts `self` into a new owning reference with a different owner type. |
| /// |
| /// The new owner type needs to still contain the original owner in some way |
| /// so that the reference into it remains valid. This function is marked unsafe |
| /// because the user needs to manually uphold this guarantee. |
| pub unsafe fn map_owner<F, P>(self, f: F) -> OwningRefMut<P, T> |
| where O: StableAddress, |
| P: StableAddress, |
| F: FnOnce(O) -> P |
| { |
| OwningRefMut { |
| reference: self.reference, |
| owner: f(self.owner), |
| } |
| } |
| |
| /// Converts `self` into a new owning reference where the owner is wrapped |
| /// in an additional `Box<O>`. |
| /// |
| /// This can be used to safely erase the owner of any `OwningRefMut<O, T>` |
| /// to a `OwningRefMut<Box<Erased>, T>`. |
| pub fn map_owner_box(self) -> OwningRefMut<Box<O>, T> { |
| OwningRefMut { |
| reference: self.reference, |
| owner: Box::new(self.owner), |
| } |
| } |
| |
| /// Erases the concrete base type of the owner with a trait object. |
| /// |
| /// This allows mixing of owned references with different owner base types. |
| /// |
| /// # Example |
| /// ``` |
| /// extern crate owning_ref; |
| /// use owning_ref::{OwningRefMut, Erased}; |
| /// |
| /// fn main() { |
| /// // NB: Using the concrete types here for explicitnes. |
| /// // For less verbose code type aliases like `BoxRef` are provided. |
| /// |
| /// let owning_ref_mut_a: OwningRefMut<Box<[i32; 4]>, [i32; 4]> |
| /// = OwningRefMut::new(Box::new([1, 2, 3, 4])); |
| /// |
| /// let owning_ref_mut_b: OwningRefMut<Box<Vec<(i32, bool)>>, Vec<(i32, bool)>> |
| /// = OwningRefMut::new(Box::new(vec![(0, false), (1, true)])); |
| /// |
| /// let owning_ref_mut_a: OwningRefMut<Box<[i32; 4]>, i32> |
| /// = owning_ref_mut_a.map_mut(|a| &mut a[0]); |
| /// |
| /// let owning_ref_mut_b: OwningRefMut<Box<Vec<(i32, bool)>>, i32> |
| /// = owning_ref_mut_b.map_mut(|a| &mut a[1].0); |
| /// |
| /// let owning_refs_mut: [OwningRefMut<Box<Erased>, i32>; 2] |
| /// = [owning_ref_mut_a.erase_owner(), owning_ref_mut_b.erase_owner()]; |
| /// |
| /// assert_eq!(*owning_refs_mut[0], 1); |
| /// assert_eq!(*owning_refs_mut[1], 1); |
| /// } |
| /// ``` |
| pub fn erase_owner<'a>(self) -> OwningRefMut<O::Erased, T> |
| where O: IntoErased<'a>, |
| { |
| OwningRefMut { |
| reference: self.reference, |
| owner: self.owner.into_erased(), |
| } |
| } |
| |
| // TODO: wrap_owner |
| |
| /// A reference to the underlying owner. |
| pub fn as_owner(&self) -> &O { |
| &self.owner |
| } |
| |
| /// A mutable reference to the underlying owner. |
| pub fn as_owner_mut(&mut self) -> &mut O { |
| &mut self.owner |
| } |
| |
| /// Discards the reference and retrieves the owner. |
| pub fn into_owner(self) -> O { |
| self.owner |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // OwningHandle |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| use std::ops::{Deref, DerefMut}; |
| |
| /// `OwningHandle` is a complement to `OwningRef`. Where `OwningRef` allows |
| /// consumers to pass around an owned object and a dependent reference, |
| /// `OwningHandle` contains an owned object and a dependent _object_. |
| /// |
| /// `OwningHandle` can encapsulate a `RefMut` along with its associated |
| /// `RefCell`, or an `RwLockReadGuard` along with its associated `RwLock`. |
| /// However, the API is completely generic and there are no restrictions on |
| /// what types of owning and dependent objects may be used. |
| /// |
| /// `OwningHandle` is created by passing an owner object (which dereferences |
| /// to a stable address) along with a callback which receives a pointer to |
| /// that stable location. The callback may then dereference the pointer and |
| /// mint a dependent object, with the guarantee that the returned object will |
| /// not outlive the referent of the pointer. |
| /// |
| /// Since the callback needs to dereference a raw pointer, it requires `unsafe` |
| /// code. To avoid forcing this unsafety on most callers, the `ToHandle` trait is |
| /// implemented for common data structures. Types that implement `ToHandle` can |
| /// be wrapped into an `OwningHandle` without passing a callback. |
| pub struct OwningHandle<O, H> |
| where O: StableAddress, H: Deref, |
| { |
| handle: H, |
| _owner: O, |
| } |
| |
| impl<O, H> Deref for OwningHandle<O, H> |
| where O: StableAddress, H: Deref, |
| { |
| type Target = H::Target; |
| fn deref(&self) -> &H::Target { |
| self.handle.deref() |
| } |
| } |
| |
| unsafe impl<O, H> StableAddress for OwningHandle<O, H> |
| where O: StableAddress, H: StableAddress, |
| {} |
| |
| impl<O, H> DerefMut for OwningHandle<O, H> |
| where O: StableAddress, H: DerefMut, |
| { |
| fn deref_mut(&mut self) -> &mut H::Target { |
| self.handle.deref_mut() |
| } |
| } |
| |
| /// Trait to implement the conversion of owner to handle for common types. |
| pub trait ToHandle { |
| /// The type of handle to be encapsulated by the OwningHandle. |
| type Handle: Deref; |
| |
| /// Given an appropriately-long-lived pointer to ourselves, create a |
| /// handle to be encapsulated by the `OwningHandle`. |
| unsafe fn to_handle(x: *const Self) -> Self::Handle; |
| } |
| |
| /// Trait to implement the conversion of owner to mutable handle for common types. |
| pub trait ToHandleMut { |
| /// The type of handle to be encapsulated by the OwningHandle. |
| type HandleMut: DerefMut; |
| |
| /// Given an appropriately-long-lived pointer to ourselves, create a |
| /// mutable handle to be encapsulated by the `OwningHandle`. |
| unsafe fn to_handle_mut(x: *const Self) -> Self::HandleMut; |
| } |
| |
| impl<O, H> OwningHandle<O, H> |
| where O: StableAddress, O::Target: ToHandle<Handle = H>, H: Deref, |
| { |
| /// Create a new `OwningHandle` for a type that implements `ToHandle`. For types |
| /// that don't implement `ToHandle`, callers may invoke `new_with_fn`, which accepts |
| /// a callback to perform the conversion. |
| pub fn new(o: O) -> Self { |
| OwningHandle::new_with_fn(o, |x| unsafe { O::Target::to_handle(x) }) |
| } |
| } |
| |
| impl<O, H> OwningHandle<O, H> |
| where O: StableAddress, O::Target: ToHandleMut<HandleMut = H>, H: DerefMut, |
| { |
| /// Create a new mutable `OwningHandle` for a type that implements `ToHandleMut`. |
| pub fn new_mut(o: O) -> Self { |
| OwningHandle::new_with_fn(o, |x| unsafe { O::Target::to_handle_mut(x) }) |
| } |
| } |
| |
| impl<O, H> OwningHandle<O, H> |
| where O: StableAddress, H: Deref, |
| { |
| /// Create a new OwningHandle. The provided callback will be invoked with |
| /// a pointer to the object owned by `o`, and the returned value is stored |
| /// as the object to which this `OwningHandle` will forward `Deref` and |
| /// `DerefMut`. |
| pub fn new_with_fn<F>(o: O, f: F) -> Self |
| where F: FnOnce(*const O::Target) -> H |
| { |
| let h: H; |
| { |
| h = f(o.deref() as *const O::Target); |
| } |
| |
| OwningHandle { |
| handle: h, |
| _owner: o, |
| } |
| } |
| |
| /// Create a new OwningHandle. The provided callback will be invoked with |
| /// a pointer to the object owned by `o`, and the returned value is stored |
| /// as the object to which this `OwningHandle` will forward `Deref` and |
| /// `DerefMut`. |
| pub fn try_new<F, E>(o: O, f: F) -> Result<Self, E> |
| where F: FnOnce(*const O::Target) -> Result<H, E> |
| { |
| let h: H; |
| { |
| h = f(o.deref() as *const O::Target)?; |
| } |
| |
| Ok(OwningHandle { |
| handle: h, |
| _owner: o, |
| }) |
| } |
| |
| /// A getter for the underlying owner. |
| pub fn as_owner(&self) -> &O { |
| &self._owner |
| } |
| |
| /// Discards the dependent object and returns the owner. |
| pub fn into_owner(self) -> O { |
| self._owner |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // std traits |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| use std::convert::From; |
| use std::fmt::{self, Debug}; |
| use std::marker::{Send, Sync}; |
| use std::cmp::{Eq, PartialEq, Ord, PartialOrd, Ordering}; |
| use std::hash::{Hash, Hasher}; |
| use std::borrow::Borrow; |
| |
| impl<O, T: ?Sized> Deref for OwningRef<O, T> { |
| type Target = T; |
| |
| fn deref(&self) -> &T { |
| unsafe { |
| &*self.reference |
| } |
| } |
| } |
| |
| impl<O, T: ?Sized> Deref for OwningRefMut<O, T> { |
| type Target = T; |
| |
| fn deref(&self) -> &T { |
| unsafe { |
| &*self.reference |
| } |
| } |
| } |
| |
| impl<O, T: ?Sized> DerefMut for OwningRefMut<O, T> { |
| fn deref_mut(&mut self) -> &mut T { |
| unsafe { |
| &mut *self.reference |
| } |
| } |
| } |
| |
| unsafe impl<O, T: ?Sized> StableAddress for OwningRef<O, T> {} |
| |
| unsafe impl<O, T: ?Sized> StableAddress for OwningRefMut<O, T> {} |
| |
| impl<O, T: ?Sized> AsRef<T> for OwningRef<O, T> { |
| fn as_ref(&self) -> &T { |
| &*self |
| } |
| } |
| |
| impl<O, T: ?Sized> AsRef<T> for OwningRefMut<O, T> { |
| fn as_ref(&self) -> &T { |
| &*self |
| } |
| } |
| |
| impl<O, T: ?Sized> AsMut<T> for OwningRefMut<O, T> { |
| fn as_mut(&mut self) -> &mut T { |
| &mut *self |
| } |
| } |
| |
| impl<O, T: ?Sized> Borrow<T> for OwningRef<O, T> { |
| fn borrow(&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> From<O> for OwningRefMut<O, T> |
| where O: StableAddress, |
| O: DerefMut<Target = T> |
| { |
| fn from(owner: O) -> Self { |
| OwningRefMut::new(owner) |
| } |
| } |
| |
| impl<O, T: ?Sized> From<OwningRefMut<O, T>> for OwningRef<O, T> |
| where O: StableAddress, |
| O: DerefMut<Target = T> |
| { |
| fn from(other: OwningRefMut<O, T>) -> Self { |
| OwningRef { |
| owner: other.owner, |
| reference: other.reference, |
| } |
| } |
| } |
| |
| // ^ FIXME: Is a Into impl for calling into_owner() possible as well? |
| |
| 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.as_owner(), |
| &**self) |
| } |
| } |
| |
| impl<O, T: ?Sized> Debug for OwningRefMut<O, T> |
| where O: Debug, |
| T: Debug, |
| { |
| fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
| write!(f, |
| "OwningRefMut {{ owner: {:?}, reference: {:?} }}", |
| self.as_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, T: ?Sized> CloneStableAddress for OwningRef<O, T> |
| where O: CloneStableAddress {} |
| |
| unsafe impl<O, T: ?Sized> Send for OwningRef<O, T> |
| where O: Send, for<'a> (&'a T): Send {} |
| unsafe impl<O, T: ?Sized> Sync for OwningRef<O, T> |
| where O: Sync, for<'a> (&'a T): Sync {} |
| |
| unsafe impl<O, T: ?Sized> Send for OwningRefMut<O, T> |
| where O: Send, for<'a> (&'a mut T): Send {} |
| unsafe impl<O, T: ?Sized> Sync for OwningRefMut<O, T> |
| where O: Sync, for<'a> (&'a mut T): Sync {} |
| |
| impl Debug for Erased { |
| fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
| write!(f, "<Erased>",) |
| } |
| } |
| |
| impl<O, T: ?Sized> PartialEq for OwningRef<O, T> where T: PartialEq { |
| fn eq(&self, other: &Self) -> bool { |
| (&*self as &T).eq(&*other as &T) |
| } |
| } |
| |
| impl<O, T: ?Sized> Eq for OwningRef<O, T> where T: Eq {} |
| |
| impl<O, T: ?Sized> PartialOrd for OwningRef<O, T> where T: PartialOrd { |
| fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
| (&*self as &T).partial_cmp(&*other as &T) |
| } |
| } |
| |
| impl<O, T: ?Sized> Ord for OwningRef<O, T> where T: Ord { |
| fn cmp(&self, other: &Self) -> Ordering { |
| (&*self as &T).cmp(&*other as &T) |
| } |
| } |
| |
| impl<O, T: ?Sized> Hash for OwningRef<O, T> where T: Hash { |
| fn hash<H: Hasher>(&self, state: &mut H) { |
| (&*self as &T).hash(state); |
| } |
| } |
| |
| impl<O, T: ?Sized> PartialEq for OwningRefMut<O, T> where T: PartialEq { |
| fn eq(&self, other: &Self) -> bool { |
| (&*self as &T).eq(&*other as &T) |
| } |
| } |
| |
| impl<O, T: ?Sized> Eq for OwningRefMut<O, T> where T: Eq {} |
| |
| impl<O, T: ?Sized> PartialOrd for OwningRefMut<O, T> where T: PartialOrd { |
| fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
| (&*self as &T).partial_cmp(&*other as &T) |
| } |
| } |
| |
| impl<O, T: ?Sized> Ord for OwningRefMut<O, T> where T: Ord { |
| fn cmp(&self, other: &Self) -> Ordering { |
| (&*self as &T).cmp(&*other as &T) |
| } |
| } |
| |
| impl<O, T: ?Sized> Hash for OwningRefMut<O, T> where T: Hash { |
| fn hash<H: Hasher>(&self, state: &mut H) { |
| (&*self as &T).hash(state); |
| } |
| } |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // std types integration and convenience type defs |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| use std::boxed::Box; |
| use std::rc::Rc; |
| use std::sync::Arc; |
| use std::sync::{MutexGuard, RwLockReadGuard, RwLockWriteGuard}; |
| use std::cell::{Ref, RefCell, RefMut}; |
| |
| impl<T: 'static> ToHandle for RefCell<T> { |
| type Handle = Ref<'static, T>; |
| unsafe fn to_handle(x: *const Self) -> Self::Handle { (*x).borrow() } |
| } |
| |
| impl<T: 'static> ToHandleMut for RefCell<T> { |
| type HandleMut = RefMut<'static, T>; |
| unsafe fn to_handle_mut(x: *const Self) -> Self::HandleMut { (*x).borrow_mut() } |
| } |
| |
| // NB: Implementing ToHandle{,Mut} for Mutex and RwLock requires a decision |
| // about which handle creation to use (i.e. read() vs try_read()) as well as |
| // what to do with error results. |
| |
| /// Typedef of a owning reference that uses a `Box` as the owner. |
| pub type BoxRef<T, U = T> = OwningRef<Box<T>, U>; |
| /// Typedef of a owning reference that uses a `Vec` as the owner. |
| pub type VecRef<T, U = T> = OwningRef<Vec<T>, U>; |
| /// Typedef of a owning reference that uses a `String` as the owner. |
| pub type StringRef = OwningRef<String, str>; |
| |
| /// Typedef of a owning reference that uses a `Rc` as the owner. |
| pub type RcRef<T, U = T> = OwningRef<Rc<T>, U>; |
| /// Typedef of a owning reference that uses a `Arc` as the owner. |
| pub type ArcRef<T, U = T> = OwningRef<Arc<T>, U>; |
| |
| /// Typedef of a owning reference that uses a `Ref` as the owner. |
| pub type RefRef<'a, T, U = T> = OwningRef<Ref<'a, T>, U>; |
| /// Typedef of a owning reference that uses a `RefMut` as the owner. |
| pub type RefMutRef<'a, T, U = T> = OwningRef<RefMut<'a, T>, U>; |
| /// Typedef of a owning reference that uses a `MutexGuard` as the owner. |
| pub type MutexGuardRef<'a, T, U = T> = OwningRef<MutexGuard<'a, T>, U>; |
| /// Typedef of a owning reference that uses a `RwLockReadGuard` as the owner. |
| pub type RwLockReadGuardRef<'a, T, U = T> = OwningRef<RwLockReadGuard<'a, T>, U>; |
| /// Typedef of a owning reference that uses a `RwLockWriteGuard` as the owner. |
| pub type RwLockWriteGuardRef<'a, T, U = T> = OwningRef<RwLockWriteGuard<'a, T>, U>; |
| |
| /// Typedef of a mutable owning reference that uses a `Box` as the owner. |
| pub type BoxRefMut<T, U = T> = OwningRefMut<Box<T>, U>; |
| /// Typedef of a mutable owning reference that uses a `Vec` as the owner. |
| pub type VecRefMut<T, U = T> = OwningRefMut<Vec<T>, U>; |
| /// Typedef of a mutable owning reference that uses a `String` as the owner. |
| pub type StringRefMut = OwningRefMut<String, str>; |
| |
| /// Typedef of a mutable owning reference that uses a `RefMut` as the owner. |
| pub type RefMutRefMut<'a, T, U = T> = OwningRefMut<RefMut<'a, T>, U>; |
| /// Typedef of a mutable owning reference that uses a `MutexGuard` as the owner. |
| pub type MutexGuardRefMut<'a, T, U = T> = OwningRefMut<MutexGuard<'a, T>, U>; |
| /// Typedef of a mutable owning reference that uses a `RwLockWriteGuard` as the owner. |
| pub type RwLockWriteGuardRefMut<'a, T, U = T> = OwningRefMut<RwLockWriteGuard<'a, T>, U>; |
| |
| unsafe impl<'a, T: 'a> IntoErased<'a> for Box<T> { |
| type Erased = Box<Erased + 'a>; |
| fn into_erased(self) -> Self::Erased { |
| self |
| } |
| } |
| unsafe impl<'a, T: 'a> IntoErased<'a> for Rc<T> { |
| type Erased = Rc<Erased + 'a>; |
| fn into_erased(self) -> Self::Erased { |
| self |
| } |
| } |
| unsafe impl<'a, T: 'a> IntoErased<'a> for Arc<T> { |
| type Erased = Arc<Erased + 'a>; |
| fn into_erased(self) -> Self::Erased { |
| self |
| } |
| } |
| |
| /// Typedef of a owning reference that uses an erased `Box` as the owner. |
| pub type ErasedBoxRef<U> = OwningRef<Box<Erased>, U>; |
| /// Typedef of a owning reference that uses an erased `Rc` as the owner. |
| pub type ErasedRcRef<U> = OwningRef<Rc<Erased>, U>; |
| /// Typedef of a owning reference that uses an erased `Arc` as the owner. |
| pub type ErasedArcRef<U> = OwningRef<Arc<Erased>, U>; |
| |
| /// Typedef of a mutable owning reference that uses an erased `Box` as the owner. |
| pub type ErasedBoxRefMut<U> = OwningRefMut<Box<Erased>, U>; |
| |
| #[cfg(test)] |
| mod tests { |
| mod owning_ref { |
| use super::super::OwningRef; |
| use super::super::{RcRef, BoxRef, Erased, ErasedBoxRef}; |
| use std::cmp::{PartialEq, Ord, PartialOrd, Ordering}; |
| use std::hash::{Hash, Hasher}; |
| use std::collections::hash_map::DefaultHasher; |
| use std::collections::HashMap; |
| use std::rc::Rc; |
| |
| #[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 as_owner() { |
| let or: BoxRef<String> = Box::new(example().1).into(); |
| let or = or.map(|x| &x[..5]); |
| assert_eq!(&*or, "hello"); |
| assert_eq!(&**or.as_owner(), "hello world"); |
| } |
| |
| #[test] |
| fn into_owner() { |
| let or: BoxRef<String> = Box::new(example().1).into(); |
| let or = or.map(|x| &x[..5]); |
| assert_eq!(&*or, "hello"); |
| let s = *or.into_owner(); |
| 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; |
| |
| // FIXME: lifetime inference fails us, and we can't easily define a lifetime for a closure |
| // (see https://github.com/rust-lang/rust/issues/22340) |
| // So we use a function to identify the lifetimes instead. |
| fn borrow<'a>(a: &'a &[i32; 2]) -> &'a i32 { |
| &a[0] |
| } |
| |
| let o: BoxRef<&[i32; 2]> = Box::new(bar).into(); |
| let o: BoxRef<&[i32; 2], i32> = o.map(borrow); |
| let o: BoxRef<Erased, i32> = o.erase_owner(); |
| |
| assert_eq!(*o, 413); |
| } |
| |
| #[test] |
| fn raii_locks() { |
| use super::super::{RefRef, RefMutRef}; |
| use std::cell::RefCell; |
| use super::super::{MutexGuardRef, RwLockReadGuardRef, RwLockWriteGuardRef}; |
| use std::sync::{Mutex, RwLock}; |
| |
| { |
| let a = RefCell::new(1); |
| let a = { |
| let a = RefRef::new(a.borrow()); |
| assert_eq!(*a, 1); |
| a |
| }; |
| assert_eq!(*a, 1); |
| drop(a); |
| } |
| { |
| let a = RefCell::new(1); |
| let a = { |
| let a = RefMutRef::new(a.borrow_mut()); |
| assert_eq!(*a, 1); |
| a |
| }; |
| assert_eq!(*a, 1); |
| drop(a); |
| } |
| { |
| let a = Mutex::new(1); |
| let a = { |
| let a = MutexGuardRef::new(a.lock().unwrap()); |
| assert_eq!(*a, 1); |
| a |
| }; |
| assert_eq!(*a, 1); |
| drop(a); |
| } |
| { |
| let a = RwLock::new(1); |
| let a = { |
| let a = RwLockReadGuardRef::new(a.read().unwrap()); |
| assert_eq!(*a, 1); |
| a |
| }; |
| assert_eq!(*a, 1); |
| drop(a); |
| } |
| { |
| let a = RwLock::new(1); |
| let a = { |
| let a = RwLockWriteGuardRef::new(a.write().unwrap()); |
| assert_eq!(*a, 1); |
| a |
| }; |
| assert_eq!(*a, 1); |
| drop(a); |
| } |
| } |
| |
| #[test] |
| fn eq() { |
| let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); |
| let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); |
| assert_eq!(or1.eq(&or2), true); |
| } |
| |
| #[test] |
| fn cmp() { |
| let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); |
| let or2: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice()); |
| assert_eq!(or1.cmp(&or2), Ordering::Less); |
| } |
| |
| #[test] |
| fn partial_cmp() { |
| let or1: BoxRef<[u8]> = BoxRef::new(vec![4, 5, 6].into_boxed_slice()); |
| let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); |
| assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater)); |
| } |
| |
| #[test] |
| fn hash() { |
| let mut h1 = DefaultHasher::new(); |
| let mut h2 = DefaultHasher::new(); |
| |
| let or1: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); |
| let or2: BoxRef<[u8]> = BoxRef::new(vec![1, 2, 3].into_boxed_slice()); |
| |
| or1.hash(&mut h1); |
| or2.hash(&mut h2); |
| |
| assert_eq!(h1.finish(), h2.finish()); |
| } |
| |
| #[test] |
| fn borrow() { |
| let mut hash = HashMap::new(); |
| let key = RcRef::<String>::new(Rc::new("foo-bar".to_string())).map(|s| &s[..]); |
| |
| hash.insert(key.clone().map(|s| &s[..3]), 42); |
| hash.insert(key.clone().map(|s| &s[4..]), 23); |
| |
| assert_eq!(hash.get("foo"), Some(&42)); |
| assert_eq!(hash.get("bar"), Some(&23)); |
| } |
| |
| #[test] |
| fn total_erase() { |
| let a: OwningRef<Vec<u8>, [u8]> |
| = OwningRef::new(vec![]).map(|x| &x[..]); |
| let b: OwningRef<Box<[u8]>, [u8]> |
| = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]); |
| |
| let c: OwningRef<Rc<Vec<u8>>, [u8]> = unsafe {a.map_owner(Rc::new)}; |
| let d: OwningRef<Rc<Box<[u8]>>, [u8]> = unsafe {b.map_owner(Rc::new)}; |
| |
| let e: OwningRef<Rc<Erased>, [u8]> = c.erase_owner(); |
| let f: OwningRef<Rc<Erased>, [u8]> = d.erase_owner(); |
| |
| let _g = e.clone(); |
| let _h = f.clone(); |
| } |
| |
| #[test] |
| fn total_erase_box() { |
| let a: OwningRef<Vec<u8>, [u8]> |
| = OwningRef::new(vec![]).map(|x| &x[..]); |
| let b: OwningRef<Box<[u8]>, [u8]> |
| = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]); |
| |
| let c: OwningRef<Box<Vec<u8>>, [u8]> = a.map_owner_box(); |
| let d: OwningRef<Box<Box<[u8]>>, [u8]> = b.map_owner_box(); |
| |
| let _e: OwningRef<Box<Erased>, [u8]> = c.erase_owner(); |
| let _f: OwningRef<Box<Erased>, [u8]> = d.erase_owner(); |
| } |
| |
| #[test] |
| fn try_map1() { |
| use std::any::Any; |
| |
| let x = Box::new(123_i32); |
| let y: Box<Any> = x; |
| |
| OwningRef::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_ok(); |
| } |
| |
| #[test] |
| fn try_map2() { |
| use std::any::Any; |
| |
| let x = Box::new(123_i32); |
| let y: Box<Any> = x; |
| |
| OwningRef::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_err(); |
| } |
| } |
| |
| mod owning_handle { |
| use super::super::OwningHandle; |
| use super::super::RcRef; |
| use std::rc::Rc; |
| use std::cell::RefCell; |
| use std::sync::Arc; |
| use std::sync::RwLock; |
| |
| #[test] |
| fn owning_handle() { |
| use std::cell::RefCell; |
| let cell = Rc::new(RefCell::new(2)); |
| let cell_ref = RcRef::new(cell); |
| let mut handle = OwningHandle::new_with_fn(cell_ref, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); |
| assert_eq!(*handle, 2); |
| *handle = 3; |
| assert_eq!(*handle, 3); |
| } |
| |
| #[test] |
| fn try_owning_handle_ok() { |
| use std::cell::RefCell; |
| let cell = Rc::new(RefCell::new(2)); |
| let cell_ref = RcRef::new(cell); |
| let mut handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| { |
| Ok(unsafe { |
| x.as_ref() |
| }.unwrap().borrow_mut()) |
| }).unwrap(); |
| assert_eq!(*handle, 2); |
| *handle = 3; |
| assert_eq!(*handle, 3); |
| } |
| |
| #[test] |
| fn try_owning_handle_err() { |
| use std::cell::RefCell; |
| let cell = Rc::new(RefCell::new(2)); |
| let cell_ref = RcRef::new(cell); |
| let handle = OwningHandle::try_new::<_, ()>(cell_ref, |x| { |
| if false { |
| return Ok(unsafe { |
| x.as_ref() |
| }.unwrap().borrow_mut()) |
| } |
| Err(()) |
| }); |
| assert!(handle.is_err()); |
| } |
| |
| #[test] |
| fn nested() { |
| use std::cell::RefCell; |
| use std::sync::{Arc, RwLock}; |
| |
| let result = { |
| let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString")))); |
| let curr = RcRef::new(complex); |
| let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); |
| let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap()); |
| assert_eq!(*curr, "someString"); |
| *curr = "someOtherString"; |
| curr |
| }; |
| assert_eq!(*result, "someOtherString"); |
| } |
| |
| #[test] |
| fn owning_handle_safe() { |
| use std::cell::RefCell; |
| let cell = Rc::new(RefCell::new(2)); |
| let cell_ref = RcRef::new(cell); |
| let handle = OwningHandle::new(cell_ref); |
| assert_eq!(*handle, 2); |
| } |
| |
| #[test] |
| fn owning_handle_mut_safe() { |
| use std::cell::RefCell; |
| let cell = Rc::new(RefCell::new(2)); |
| let cell_ref = RcRef::new(cell); |
| let mut handle = OwningHandle::new_mut(cell_ref); |
| assert_eq!(*handle, 2); |
| *handle = 3; |
| assert_eq!(*handle, 3); |
| } |
| |
| #[test] |
| fn owning_handle_safe_2() { |
| let result = { |
| let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString")))); |
| let curr = RcRef::new(complex); |
| let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut()); |
| let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap()); |
| assert_eq!(*curr, "someString"); |
| *curr = "someOtherString"; |
| curr |
| }; |
| assert_eq!(*result, "someOtherString"); |
| } |
| } |
| |
| mod owning_ref_mut { |
| use super::super::{OwningRefMut, BoxRefMut, Erased, ErasedBoxRefMut}; |
| use super::super::BoxRef; |
| use std::cmp::{PartialEq, Ord, PartialOrd, Ordering}; |
| use std::hash::{Hash, Hasher}; |
| use std::collections::hash_map::DefaultHasher; |
| use std::collections::HashMap; |
| |
| #[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: OwningRefMut<Box<()>, ()> = OwningRefMut::new(Box::new(())); |
| assert_eq!(&*or, &()); |
| } |
| |
| #[test] |
| fn new_deref_mut() { |
| let mut or: OwningRefMut<Box<()>, ()> = OwningRefMut::new(Box::new(())); |
| assert_eq!(&mut *or, &mut ()); |
| } |
| |
| #[test] |
| fn mutate() { |
| let mut or: OwningRefMut<Box<usize>, usize> = OwningRefMut::new(Box::new(0)); |
| assert_eq!(&*or, &0); |
| *or = 1; |
| assert_eq!(&*or, &1); |
| } |
| |
| #[test] |
| fn into() { |
| let or: OwningRefMut<Box<()>, ()> = Box::new(()).into(); |
| assert_eq!(&*or, &()); |
| } |
| |
| #[test] |
| fn map_offset_ref() { |
| let or: BoxRefMut<Example> = Box::new(example()).into(); |
| let or: BoxRef<_, u32> = or.map(|x| &mut x.0); |
| assert_eq!(&*or, &42); |
| |
| let or: BoxRefMut<Example> = Box::new(example()).into(); |
| let or: BoxRef<_, u8> = or.map(|x| &mut x.2[1]); |
| assert_eq!(&*or, &2); |
| } |
| |
| #[test] |
| fn map_heap_ref() { |
| let or: BoxRefMut<Example> = Box::new(example()).into(); |
| let or: BoxRef<_, str> = or.map(|x| &mut x.1[..5]); |
| assert_eq!(&*or, "hello"); |
| } |
| |
| #[test] |
| fn map_static_ref() { |
| let or: BoxRefMut<()> = Box::new(()).into(); |
| let or: BoxRef<_, str> = or.map(|_| "hello"); |
| assert_eq!(&*or, "hello"); |
| } |
| |
| #[test] |
| fn map_mut_offset_ref() { |
| let or: BoxRefMut<Example> = Box::new(example()).into(); |
| let or: BoxRefMut<_, u32> = or.map_mut(|x| &mut x.0); |
| assert_eq!(&*or, &42); |
| |
| let or: BoxRefMut<Example> = Box::new(example()).into(); |
| let or: BoxRefMut<_, u8> = or.map_mut(|x| &mut x.2[1]); |
| assert_eq!(&*or, &2); |
| } |
| |
| #[test] |
| fn map_mut_heap_ref() { |
| let or: BoxRefMut<Example> = Box::new(example()).into(); |
| let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x.1[..5]); |
| assert_eq!(&*or, "hello"); |
| } |
| |
| #[test] |
| fn map_mut_static_ref() { |
| static mut MUT_S: [u8; 5] = *b"hello"; |
| |
| let mut_s: &'static mut [u8] = unsafe { &mut MUT_S }; |
| |
| let or: BoxRefMut<()> = Box::new(()).into(); |
| let or: BoxRefMut<_, [u8]> = or.map_mut(move |_| mut_s); |
| assert_eq!(&*or, b"hello"); |
| } |
| |
| #[test] |
| fn map_mut_chained() { |
| let or: BoxRefMut<String> = Box::new(example().1).into(); |
| let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[1..5]); |
| let or: BoxRefMut<_, str> = or.map_mut(|x| &mut x[..2]); |
| assert_eq!(&*or, "el"); |
| } |
| |
| #[test] |
| fn map_chained_inference() { |
| let or = BoxRefMut::new(Box::new(example().1)) |
| .map_mut(|x| &mut x[..5]) |
| .map_mut(|x| &mut x[1..3]); |
| assert_eq!(&*or, "el"); |
| } |
| |
| #[test] |
| fn try_map_mut() { |
| let or: BoxRefMut<String> = Box::new(example().1).into(); |
| let or: Result<BoxRefMut<_, str>, ()> = or.try_map_mut(|x| Ok(&mut x[1..5])); |
| assert_eq!(&*or.unwrap(), "ello"); |
| |
| let or: BoxRefMut<String> = Box::new(example().1).into(); |
| let or: Result<BoxRefMut<_, str>, ()> = or.try_map_mut(|_| Err(())); |
| assert!(or.is_err()); |
| } |
| |
| #[test] |
| fn as_owner() { |
| let or: BoxRefMut<String> = Box::new(example().1).into(); |
| let or = or.map_mut(|x| &mut x[..5]); |
| assert_eq!(&*or, "hello"); |
| assert_eq!(&**or.as_owner(), "hello world"); |
| } |
| |
| #[test] |
| fn into_owner() { |
| let or: BoxRefMut<String> = Box::new(example().1).into(); |
| let or = or.map_mut(|x| &mut x[..5]); |
| assert_eq!(&*or, "hello"); |
| let s = *or.into_owner(); |
| assert_eq!(&s, "hello world"); |
| } |
| |
| #[test] |
| fn fmt_debug() { |
| let or: BoxRefMut<String> = Box::new(example().1).into(); |
| let or = or.map_mut(|x| &mut x[..5]); |
| let s = format!("{:?}", or); |
| assert_eq!(&s, |
| "OwningRefMut { owner: \"hello world\", reference: \"hello\" }"); |
| } |
| |
| #[test] |
| fn erased_owner() { |
| let o1: BoxRefMut<Example, str> = BoxRefMut::new(Box::new(example())) |
| .map_mut(|x| &mut x.1[..]); |
| |
| let o2: BoxRefMut<String, str> = BoxRefMut::new(Box::new(example().1)) |
| .map_mut(|x| &mut x[..]); |
| |
| let os: Vec<ErasedBoxRefMut<str>> = vec![o1.erase_owner(), o2.erase_owner()]; |
| assert!(os.iter().all(|e| &e[..] == "hello world")); |
| } |
| |
| #[test] |
| fn non_static_erased_owner() { |
| let mut foo = [413, 612]; |
| let bar = &mut foo; |
| |
| // FIXME: lifetime inference fails us, and we can't easily define a lifetime for a closure |
| // (see https://github.com/rust-lang/rust/issues/22340) |
| // So we use a function to identify the lifetimes instead. |
| fn borrow<'a>(a: &'a mut &mut [i32; 2]) -> &'a mut i32 { |
| &mut a[0] |
| } |
| |
| let o: BoxRefMut<&mut [i32; 2]> = Box::new(bar).into(); |
| let o: BoxRefMut<&mut [i32; 2], i32> = o.map_mut(borrow); |
| let o: BoxRefMut<Erased, i32> = o.erase_owner(); |
| |
| assert_eq!(*o, 413); |
| } |
| |
| #[test] |
| fn raii_locks() { |
| use super::super::RefMutRefMut; |
| use std::cell::RefCell; |
| use super::super::{MutexGuardRefMut, RwLockWriteGuardRefMut}; |
| use std::sync::{Mutex, RwLock}; |
| |
| { |
| let a = RefCell::new(1); |
| let a = { |
| let a = RefMutRefMut::new(a.borrow_mut()); |
| assert_eq!(*a, 1); |
| a |
| }; |
| assert_eq!(*a, 1); |
| drop(a); |
| } |
| { |
| let a = Mutex::new(1); |
| let a = { |
| let a = MutexGuardRefMut::new(a.lock().unwrap()); |
| assert_eq!(*a, 1); |
| a |
| }; |
| assert_eq!(*a, 1); |
| drop(a); |
| } |
| { |
| let a = RwLock::new(1); |
| let a = { |
| let a = RwLockWriteGuardRefMut::new(a.write().unwrap()); |
| assert_eq!(*a, 1); |
| a |
| }; |
| assert_eq!(*a, 1); |
| drop(a); |
| } |
| } |
| |
| #[test] |
| fn eq() { |
| let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); |
| let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); |
| assert_eq!(or1.eq(&or2), true); |
| } |
| |
| #[test] |
| fn cmp() { |
| let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); |
| let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice()); |
| assert_eq!(or1.cmp(&or2), Ordering::Less); |
| } |
| |
| #[test] |
| fn partial_cmp() { |
| let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![4, 5, 6].into_boxed_slice()); |
| let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); |
| assert_eq!(or1.partial_cmp(&or2), Some(Ordering::Greater)); |
| } |
| |
| #[test] |
| fn hash() { |
| let mut h1 = DefaultHasher::new(); |
| let mut h2 = DefaultHasher::new(); |
| |
| let or1: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); |
| let or2: BoxRefMut<[u8]> = BoxRefMut::new(vec![1, 2, 3].into_boxed_slice()); |
| |
| or1.hash(&mut h1); |
| or2.hash(&mut h2); |
| |
| assert_eq!(h1.finish(), h2.finish()); |
| } |
| |
| #[test] |
| fn borrow() { |
| let mut hash = HashMap::new(); |
| let key1 = BoxRefMut::<String>::new(Box::new("foo".to_string())).map(|s| &s[..]); |
| let key2 = BoxRefMut::<String>::new(Box::new("bar".to_string())).map(|s| &s[..]); |
| |
| hash.insert(key1, 42); |
| hash.insert(key2, 23); |
| |
| assert_eq!(hash.get("foo"), Some(&42)); |
| assert_eq!(hash.get("bar"), Some(&23)); |
| } |
| |
| #[test] |
| fn total_erase() { |
| let a: OwningRefMut<Vec<u8>, [u8]> |
| = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]); |
| let b: OwningRefMut<Box<[u8]>, [u8]> |
| = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]); |
| |
| let c: OwningRefMut<Box<Vec<u8>>, [u8]> = unsafe {a.map_owner(Box::new)}; |
| let d: OwningRefMut<Box<Box<[u8]>>, [u8]> = unsafe {b.map_owner(Box::new)}; |
| |
| let _e: OwningRefMut<Box<Erased>, [u8]> = c.erase_owner(); |
| let _f: OwningRefMut<Box<Erased>, [u8]> = d.erase_owner(); |
| } |
| |
| #[test] |
| fn total_erase_box() { |
| let a: OwningRefMut<Vec<u8>, [u8]> |
| = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]); |
| let b: OwningRefMut<Box<[u8]>, [u8]> |
| = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]); |
| |
| let c: OwningRefMut<Box<Vec<u8>>, [u8]> = a.map_owner_box(); |
| let d: OwningRefMut<Box<Box<[u8]>>, [u8]> = b.map_owner_box(); |
| |
| let _e: OwningRefMut<Box<Erased>, [u8]> = c.erase_owner(); |
| let _f: OwningRefMut<Box<Erased>, [u8]> = d.erase_owner(); |
| } |
| |
| #[test] |
| fn try_map1() { |
| use std::any::Any; |
| |
| let x = Box::new(123_i32); |
| let y: Box<Any> = x; |
| |
| OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::<i32>().ok_or(())).is_ok(); |
| } |
| |
| #[test] |
| fn try_map2() { |
| use std::any::Any; |
| |
| let x = Box::new(123_i32); |
| let y: Box<Any> = x; |
| |
| OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::<i32>().ok_or(())).is_err(); |
| } |
| |
| #[test] |
| fn try_map3() { |
| use std::any::Any; |
| |
| let x = Box::new(123_i32); |
| let y: Box<Any> = x; |
| |
| OwningRefMut::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_ok(); |
| } |
| |
| #[test] |
| fn try_map4() { |
| use std::any::Any; |
| |
| let x = Box::new(123_i32); |
| let y: Box<Any> = x; |
| |
| OwningRefMut::new(y).try_map(|x| x.downcast_ref::<i32>().ok_or(())).is_err(); |
| } |
| |
| #[test] |
| fn into_owning_ref() { |
| use super::super::BoxRef; |
| |
| let or: BoxRefMut<()> = Box::new(()).into(); |
| let or: BoxRef<()> = or.into(); |
| assert_eq!(&*or, &()); |
| } |
| |
| struct Foo { |
| u: u32, |
| } |
| struct Bar { |
| f: Foo, |
| } |
| |
| #[test] |
| fn ref_mut() { |
| use std::cell::RefCell; |
| |
| let a = RefCell::new(Bar { f: Foo { u: 42 } }); |
| let mut b = OwningRefMut::new(a.borrow_mut()); |
| assert_eq!(b.f.u, 42); |
| b.f.u = 43; |
| let mut c = b.map_mut(|x| &mut x.f); |
| assert_eq!(c.u, 43); |
| c.u = 44; |
| let mut d = c.map_mut(|x| &mut x.u); |
| assert_eq!(*d, 44); |
| *d = 45; |
| assert_eq!(*d, 45); |
| } |
| } |
| } |