Crate borrow_with_ref_obj[][src]

The BorrowWithRefObj and BorrowMutWithRefObj traits are versions of Borrow and BorrowMut that can return a reference object (Such as std::cell::Ref or std::sync::MutexGuard) instead of just a pointer.

This allows you to accept T, &T, Rc<RefCell<T>>, Arc<Mutex<T>>, and Arc<RwLock<T>> by requiring a single trait.

Note: using these traits requires using higher-ranked trait bounds, until RFC 1598 is implemented. See the example below.

Example

use borrow_with_ref_obj::BorrowWithRefObj;
 
/// Example structure that can possibly share ownership of a u32.
/// 
/// Modeled after a work queue getting data from a central source (ex. a
/// database) that may or may not be shared with others.
/// 
/// Note: Need to use higher-ranked trait bound here (for<'refr>), to tell
/// rust that the object that `borrow` returns about its lifetime.
struct Processor<Ref: for<'refr> BorrowWithRefObj<'refr, u32>> {
    /// Potentially-shared reference to a datum.
    /// Pretend this is a database connection or something like that.
    data_source: Ref,
    /// Queue of work to process
    work_queue: Vec<u32>,
}
impl<Ref: for<'refr> BorrowWithRefObj<'refr, u32>> Processor<Ref> {
    pub fn new(source: Ref) -> Self {
        Self {
            data_source: source,
            work_queue: vec![1,2,3,4,5],
        }
    }
    
    /// Processes one element in the work queue
    pub fn process_one(&mut self) {
        let current_work = match self.work_queue.pop() {
            Some(v) => v,
            None => { return; }
        };
        let data_source = self.data_source.borrow();
        let current_result = current_work + *data_source;
        println!("{}", current_result);
    }
    
    /// Processes all elements in the work queue
    pub fn process_all(&mut self) {
        while !self.work_queue.is_empty() {
            self.process_one();
        }
    }
}
 
// Create a processor that is the sole owner of the data
let mut sole_owning_processor = Processor::new(1);
// Prints 2,3,4,5,6
sole_owning_processor.process_all();
 
// Creates a processor that borrows the data
let value = 2;
let mut borrowing_processor = Processor::new(&value);
// Prints 3,4,5,6,7
sole_owning_processor.process_all();
 
// Creates a processor that shares ownership via Rc<RefCell<u32>>
use std::rc::Rc;
use std::cell::RefCell;
 
let value = Rc::new(RefCell::new(1));
let mut rc_processor = Processor::new(Rc::clone(&value));
// Prints 2,3,4
rc_processor.process_one();
rc_processor.process_one();
rc_processor.process_one();
// Modify the value
*value.borrow_mut() = 5;
// Prints 9,10
rc_processor.process_one();
rc_processor.process_one();
 
// You can do the same as above with Arc<Mutex<T>> or Arc<RwLock<T>>, if you
// need thread-safe access.

Structs

BoxedBorrowMutWithRefObj

Dynamic BorrowMutWithRefObj whose contents can be any BorrowMutWithRefObj.

BoxedBorrowWithRefObj

Dynamic BorrowWithRefObj whose contents can be any BorrowWithRefObj.

BoxedMutReference

Wrapper for Box<dyn DerefMut<Target=T> that dereferences directly to T.

BoxedReference

Wrapper for Box<dyn Deref<Target=T> that dereferences directly to T.

Traits

BorrowMutWithRefObj

Mutable borrower whose reference is an object.

BorrowWithRefObj

Immutable borrower whose reference is an object.