owning_ref-0.4.0/.gitignore010064400017500001750000000000221264745670000140660ustar0000000000000000target Cargo.lock owning_ref-0.4.0/.travis.yml010064400017500001750000000020511264745670200142150ustar0000000000000000language: rust rust: - nightly - beta - stable before_script: - | pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH script: - | travis-cargo build && travis-cargo test && travis-cargo bench && travis-cargo --only stable doc after_success: - travis-cargo --only stable doc-upload env: global: - TRAVIS_CARGO_NIGHTLY_FEATURE="" - secure: bHizPyUOOWEDjecxCSPyZeOrnNTpLbsFRVO25fW2M5B6FOxsbJwf+ZUXI1VqoAtKBAR0JbY+xpNPTW55ANa/Xyd3/daKFxah/jriiJ+RzRf5/iCyx2ik6tp2Z4LmRZQ/XjyPsQZcPHW9vVxGxW2o8JE78VTmcZwPElLRQoCLlPddDxCmbUpiw0FywkbqFRmG+0M96ymjvl58wvPYRlA76Jd+KoTlehPd+oAmoVRlvYgUZUYUphfDlYN04wXBnSkMqZdiAolkIMAFQ3o9A/W95RUIKiARQe2L9j33/joCMZBme0tq8l6GpmaLpmiXGqKdUlHOJF3cqAPQO1Kve0whNBs4/QlH0xgav6rQcLdCLilPkTj/vFXjo9EiZrOsYFXMQ+dAejqg/+JI1LBJqEwMJZKNe6T2vlJfbCyONEHdPtkhdhT26TjO1JCTeLIFa42ejRgA21PZFFsBos7ZdZO75QW5Wrqw2BLVfZVY3kl+rAWwacj3rLnfs32Vy5KmFjG5zTBlu3HQ/LX1J9E7jwBRKTWglnAyfb8E/NXHutX0wdVrdufwGD7bufjL3uHc3fs1wYSb+wBk1HtVMe/1JWgYpiRCPk4Z+NslCgFm1h7HX2QKikHaCzz7F8TJFEzDN9Lv9JVW2RmpEQBM/lKmNMVLrLt8gAaRQbjQFA4tck9rv9g= owning_ref-0.4.0/Cargo.toml.orig010064400017500001750000000007141333561264100147660ustar0000000000000000[package] name = "owning_ref" version = "0.4.0" authors = ["Marvin Löbel "] license = "MIT" description = "A library for creating references that carry their owner with them." readme = "README.md" documentation = "http://kimundi.github.io/owning-ref-rs/owning_ref/index.html" repository = "https://github.com/Kimundi/owning-ref-rs" keywords = ["reference", "sibling", "field", "owning"] [dependencies] stable_deref_trait = "1.0.0" owning_ref-0.4.0/Cargo.toml0000644000000017350000000000000112350ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "owning_ref" version = "0.4.0" authors = ["Marvin Löbel "] description = "A library for creating references that carry their owner with them." documentation = "http://kimundi.github.io/owning-ref-rs/owning_ref/index.html" readme = "README.md" keywords = ["reference", "sibling", "field", "owning"] license = "MIT" repository = "https://github.com/Kimundi/owning-ref-rs" [dependencies.stable_deref_trait] version = "1.0.0" owning_ref-0.4.0/LICENSE010064400017500001750000000020701264745670000131100ustar0000000000000000The MIT License (MIT) Copyright (c) 2015 Marvin Löbel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. owning_ref-0.4.0/README.md010064400017500001750000000035521333560731300133610ustar0000000000000000owning-ref-rs ============== A library for creating references that carry their owner with them. This can sometimes be useful because Rust borrowing rules normally prevent moving a type that has been borrowed from. For example, this kind of code gets rejected: ```rust fn return_owned_and_referenced<'a>() -> (Vec, &'a [u8]) { let v = vec![1, 2, 3, 4]; let s = &v[1..3]; (v, s) } ``` 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 fn return_owned_and_referenced() -> OwningRef, [u8]> { let v = vec![1, 2, 3, 4]; let or = OwningRef::new(v); let or = or.map(|v| &v[1..3]); or } ``` [![Travis-CI Status](https://travis-ci.org/Kimundi/owning-ref-rs.png?branch=master)](https://travis-ci.org/Kimundi/owning-ref-rs) # Getting Started [owning-ref-rs is available on crates.io](https://crates.io/crates/owning_ref). It is recommended to look there for the newest released version, as well as links to the newest builds of the docs. At the point of the last update of this README, the latest published version could be used like this: Add the following dependency to your Cargo manifest... ```toml [dependencies] owning_ref = "0.3" ``` ...and see the [docs](http://kimundi.github.io/owning-ref-rs/owning_ref/index.html) for how to use it. # Example ```rust 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! } ``` owning_ref-0.4.0/src/lib.rs010064400017500001750000001670411333561111400140030ustar0000000000000000#![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, &'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, [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`, `Rc`, etc. Also provided are typedefs for common owner type combinations, which allow for less verbose type signatures. For example, `BoxRef` instead of `OwningRef, 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 { 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 { 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 Erased for T {} /// Helper trait for erasing the concrete type of what an owner derferences to, /// for example `Box -> Box`. 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 OwningRef { /// 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, { 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, { 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(self, f: F) -> OwningRef 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(self, f: F) -> Result, 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(self, f: F) -> OwningRef 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`. /// /// This can be used to safely erase the owner of any `OwningRef` /// to a `OwningRef, T>`. pub fn map_owner_box(self) -> OwningRef, 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, [i32; 4]> /// = OwningRef::new(Box::new([1, 2, 3, 4])); /// /// let owning_ref_b: OwningRef>, Vec<(i32, bool)>> /// = OwningRef::new(Box::new(vec![(0, false), (1, true)])); /// /// let owning_ref_a: OwningRef, i32> /// = owning_ref_a.map(|a| &a[0]); /// /// let owning_ref_b: OwningRef>, i32> /// = owning_ref_b.map(|a| &a[1].0); /// /// let owning_refs: [OwningRef, 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 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 OwningRefMut { /// 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, { 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, { 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(mut self, f: F) -> OwningRef 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(mut self, f: F) -> OwningRefMut 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(mut self, f: F) -> Result, 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(mut self, f: F) -> Result, 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(self, f: F) -> OwningRefMut 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`. /// /// This can be used to safely erase the owner of any `OwningRefMut` /// to a `OwningRefMut, T>`. pub fn map_owner_box(self) -> OwningRefMut, 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, [i32; 4]> /// = OwningRefMut::new(Box::new([1, 2, 3, 4])); /// /// let owning_ref_mut_b: OwningRefMut>, Vec<(i32, bool)>> /// = OwningRefMut::new(Box::new(vec![(0, false), (1, true)])); /// /// let owning_ref_mut_a: OwningRefMut, i32> /// = owning_ref_mut_a.map_mut(|a| &mut a[0]); /// /// let owning_ref_mut_b: OwningRefMut>, i32> /// = owning_ref_mut_b.map_mut(|a| &mut a[1].0); /// /// let owning_refs_mut: [OwningRefMut, 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 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 where O: StableAddress, H: Deref, { handle: H, _owner: O, } impl Deref for OwningHandle where O: StableAddress, H: Deref, { type Target = H::Target; fn deref(&self) -> &H::Target { self.handle.deref() } } unsafe impl StableAddress for OwningHandle where O: StableAddress, H: StableAddress, {} impl DerefMut for OwningHandle 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 OwningHandle where O: StableAddress, O::Target: ToHandle, 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 OwningHandle where O: StableAddress, O::Target: ToHandleMut, 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 OwningHandle 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(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(o: O, f: F) -> Result where F: FnOnce(*const O::Target) -> Result { 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 Deref for OwningRef { type Target = T; fn deref(&self) -> &T { unsafe { &*self.reference } } } impl Deref for OwningRefMut { type Target = T; fn deref(&self) -> &T { unsafe { &*self.reference } } } impl DerefMut for OwningRefMut { fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.reference } } } unsafe impl StableAddress for OwningRef {} unsafe impl StableAddress for OwningRefMut {} impl AsRef for OwningRef { fn as_ref(&self) -> &T { &*self } } impl AsRef for OwningRefMut { fn as_ref(&self) -> &T { &*self } } impl AsMut for OwningRefMut { fn as_mut(&mut self) -> &mut T { &mut *self } } impl Borrow for OwningRef { fn borrow(&self) -> &T { &*self } } impl From for OwningRef where O: StableAddress, O: Deref, { fn from(owner: O) -> Self { OwningRef::new(owner) } } impl From for OwningRefMut where O: StableAddress, O: DerefMut { fn from(owner: O) -> Self { OwningRefMut::new(owner) } } impl From> for OwningRef where O: StableAddress, O: DerefMut { fn from(other: OwningRefMut) -> Self { OwningRef { owner: other.owner, reference: other.reference, } } } // ^ FIXME: Is a Into impl for calling into_owner() possible as well? impl Debug for OwningRef 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 Debug for OwningRefMut 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 Clone for OwningRef where O: CloneStableAddress, { fn clone(&self) -> Self { OwningRef { owner: self.owner.clone(), reference: self.reference, } } } unsafe impl CloneStableAddress for OwningRef where O: CloneStableAddress {} unsafe impl Send for OwningRef where O: Send, for<'a> (&'a T): Send {} unsafe impl Sync for OwningRef where O: Sync, for<'a> (&'a T): Sync {} unsafe impl Send for OwningRefMut where O: Send, for<'a> (&'a mut T): Send {} unsafe impl Sync for OwningRefMut 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, "",) } } impl PartialEq for OwningRef where T: PartialEq { fn eq(&self, other: &Self) -> bool { (&*self as &T).eq(&*other as &T) } } impl Eq for OwningRef where T: Eq {} impl PartialOrd for OwningRef where T: PartialOrd { fn partial_cmp(&self, other: &Self) -> Option { (&*self as &T).partial_cmp(&*other as &T) } } impl Ord for OwningRef where T: Ord { fn cmp(&self, other: &Self) -> Ordering { (&*self as &T).cmp(&*other as &T) } } impl Hash for OwningRef where T: Hash { fn hash(&self, state: &mut H) { (&*self as &T).hash(state); } } impl PartialEq for OwningRefMut where T: PartialEq { fn eq(&self, other: &Self) -> bool { (&*self as &T).eq(&*other as &T) } } impl Eq for OwningRefMut where T: Eq {} impl PartialOrd for OwningRefMut where T: PartialOrd { fn partial_cmp(&self, other: &Self) -> Option { (&*self as &T).partial_cmp(&*other as &T) } } impl Ord for OwningRefMut where T: Ord { fn cmp(&self, other: &Self) -> Ordering { (&*self as &T).cmp(&*other as &T) } } impl Hash for OwningRefMut where T: Hash { fn hash(&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 ToHandle for RefCell { type Handle = Ref<'static, T>; unsafe fn to_handle(x: *const Self) -> Self::Handle { (*x).borrow() } } impl ToHandleMut for RefCell { 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 = OwningRef, U>; /// Typedef of a owning reference that uses a `Vec` as the owner. pub type VecRef = OwningRef, U>; /// Typedef of a owning reference that uses a `String` as the owner. pub type StringRef = OwningRef; /// Typedef of a owning reference that uses a `Rc` as the owner. pub type RcRef = OwningRef, U>; /// Typedef of a owning reference that uses a `Arc` as the owner. pub type ArcRef = OwningRef, U>; /// Typedef of a owning reference that uses a `Ref` as the owner. pub type RefRef<'a, T, U = T> = OwningRef, U>; /// Typedef of a owning reference that uses a `RefMut` as the owner. pub type RefMutRef<'a, T, U = T> = OwningRef, U>; /// Typedef of a owning reference that uses a `MutexGuard` as the owner. pub type MutexGuardRef<'a, T, U = T> = OwningRef, U>; /// Typedef of a owning reference that uses a `RwLockReadGuard` as the owner. pub type RwLockReadGuardRef<'a, T, U = T> = OwningRef, U>; /// Typedef of a owning reference that uses a `RwLockWriteGuard` as the owner. pub type RwLockWriteGuardRef<'a, T, U = T> = OwningRef, U>; /// Typedef of a mutable owning reference that uses a `Box` as the owner. pub type BoxRefMut = OwningRefMut, U>; /// Typedef of a mutable owning reference that uses a `Vec` as the owner. pub type VecRefMut = OwningRefMut, U>; /// Typedef of a mutable owning reference that uses a `String` as the owner. pub type StringRefMut = OwningRefMut; /// Typedef of a mutable owning reference that uses a `RefMut` as the owner. pub type RefMutRefMut<'a, T, U = T> = OwningRefMut, U>; /// Typedef of a mutable owning reference that uses a `MutexGuard` as the owner. pub type MutexGuardRefMut<'a, T, U = T> = OwningRefMut, U>; /// Typedef of a mutable owning reference that uses a `RwLockWriteGuard` as the owner. pub type RwLockWriteGuardRefMut<'a, T, U = T> = OwningRefMut, U>; unsafe impl<'a, T: 'a> IntoErased<'a> for Box { type Erased = Box; fn into_erased(self) -> Self::Erased { self } } unsafe impl<'a, T: 'a> IntoErased<'a> for Rc { type Erased = Rc; fn into_erased(self) -> Self::Erased { self } } unsafe impl<'a, T: 'a> IntoErased<'a> for Arc { type Erased = Arc; fn into_erased(self) -> Self::Erased { self } } /// Typedef of a owning reference that uses an erased `Box` as the owner. pub type ErasedBoxRef = OwningRef, U>; /// Typedef of a owning reference that uses an erased `Rc` as the owner. pub type ErasedRcRef = OwningRef, U>; /// Typedef of a owning reference that uses an erased `Arc` as the owner. pub type ErasedArcRef = OwningRef, U>; /// Typedef of a mutable owning reference that uses an erased `Box` as the owner. pub type ErasedBoxRefMut = OwningRefMut, 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, ()> = OwningRef::new(Box::new(())); assert_eq!(&*or, &()); } #[test] fn into() { let or: OwningRef, ()> = Box::new(()).into(); assert_eq!(&*or, &()); } #[test] fn map_offset_ref() { let or: BoxRef = Box::new(example()).into(); let or: BoxRef<_, u32> = or.map(|x| &x.0); assert_eq!(&*or, &42); let or: BoxRef = 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 = 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 = 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 = 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 = 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 = 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 = BoxRef::new(Box::new(example())) .map(|x| &x.1[..]); let o2: BoxRef = BoxRef::new(Box::new(example().1)) .map(|x| &x[..]); let os: Vec> = 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 = 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::::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, [u8]> = OwningRef::new(vec![]).map(|x| &x[..]); let b: OwningRef, [u8]> = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]); let c: OwningRef>, [u8]> = unsafe {a.map_owner(Rc::new)}; let d: OwningRef>, [u8]> = unsafe {b.map_owner(Rc::new)}; let e: OwningRef, [u8]> = c.erase_owner(); let f: OwningRef, [u8]> = d.erase_owner(); let _g = e.clone(); let _h = f.clone(); } #[test] fn total_erase_box() { let a: OwningRef, [u8]> = OwningRef::new(vec![]).map(|x| &x[..]); let b: OwningRef, [u8]> = OwningRef::new(vec![].into_boxed_slice()).map(|x| &x[..]); let c: OwningRef>, [u8]> = a.map_owner_box(); let d: OwningRef>, [u8]> = b.map_owner_box(); let _e: OwningRef, [u8]> = c.erase_owner(); let _f: OwningRef, [u8]> = d.erase_owner(); } #[test] fn try_map1() { use std::any::Any; let x = Box::new(123_i32); let y: Box = x; OwningRef::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_ok(); } #[test] fn try_map2() { use std::any::Any; let x = Box::new(123_i32); let y: Box = x; OwningRef::new(y).try_map(|x| x.downcast_ref::().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, ()> = OwningRefMut::new(Box::new(())); assert_eq!(&*or, &()); } #[test] fn new_deref_mut() { let mut or: OwningRefMut, ()> = OwningRefMut::new(Box::new(())); assert_eq!(&mut *or, &mut ()); } #[test] fn mutate() { let mut or: OwningRefMut, usize> = OwningRefMut::new(Box::new(0)); assert_eq!(&*or, &0); *or = 1; assert_eq!(&*or, &1); } #[test] fn into() { let or: OwningRefMut, ()> = Box::new(()).into(); assert_eq!(&*or, &()); } #[test] fn map_offset_ref() { let or: BoxRefMut = Box::new(example()).into(); let or: BoxRef<_, u32> = or.map(|x| &mut x.0); assert_eq!(&*or, &42); let or: BoxRefMut = 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 = 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 = Box::new(example()).into(); let or: BoxRefMut<_, u32> = or.map_mut(|x| &mut x.0); assert_eq!(&*or, &42); let or: BoxRefMut = 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 = 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 = 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 = Box::new(example().1).into(); let or: Result, ()> = or.try_map_mut(|x| Ok(&mut x[1..5])); assert_eq!(&*or.unwrap(), "ello"); let or: BoxRefMut = Box::new(example().1).into(); let or: Result, ()> = or.try_map_mut(|_| Err(())); assert!(or.is_err()); } #[test] fn as_owner() { let or: BoxRefMut = 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 = 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 = 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 = BoxRefMut::new(Box::new(example())) .map_mut(|x| &mut x.1[..]); let o2: BoxRefMut = BoxRefMut::new(Box::new(example().1)) .map_mut(|x| &mut x[..]); let os: Vec> = 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 = 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::::new(Box::new("foo".to_string())).map(|s| &s[..]); let key2 = BoxRefMut::::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, [u8]> = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]); let b: OwningRefMut, [u8]> = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]); let c: OwningRefMut>, [u8]> = unsafe {a.map_owner(Box::new)}; let d: OwningRefMut>, [u8]> = unsafe {b.map_owner(Box::new)}; let _e: OwningRefMut, [u8]> = c.erase_owner(); let _f: OwningRefMut, [u8]> = d.erase_owner(); } #[test] fn total_erase_box() { let a: OwningRefMut, [u8]> = OwningRefMut::new(vec![]).map_mut(|x| &mut x[..]); let b: OwningRefMut, [u8]> = OwningRefMut::new(vec![].into_boxed_slice()).map_mut(|x| &mut x[..]); let c: OwningRefMut>, [u8]> = a.map_owner_box(); let d: OwningRefMut>, [u8]> = b.map_owner_box(); let _e: OwningRefMut, [u8]> = c.erase_owner(); let _f: OwningRefMut, [u8]> = d.erase_owner(); } #[test] fn try_map1() { use std::any::Any; let x = Box::new(123_i32); let y: Box = x; OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).is_ok(); } #[test] fn try_map2() { use std::any::Any; let x = Box::new(123_i32); let y: Box = x; OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).is_err(); } #[test] fn try_map3() { use std::any::Any; let x = Box::new(123_i32); let y: Box = x; OwningRefMut::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_ok(); } #[test] fn try_map4() { use std::any::Any; let x = Box::new(123_i32); let y: Box = x; OwningRefMut::new(y).try_map(|x| x.downcast_ref::().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); } } }