1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
//! Simple helper for temporary object moving. //! //! It is useful if you need to pass your object somewhere and you cannot pass //! a reference to the object because you wouldn't be able to guarantee that //! the object lives long enough. For example, you don't want to use //! `Arc<Mutex<_>>` for some reason but you need to pass your object to a new //! thread and you need to use the object again in the original thread once the //! new thread does not need the object anymore. //! //! See the examples below. //! //! # Features //! * `async` - asynchronous version of the helper //! //! # Example //! ``` //! use std::{mem, thread, time::Duration}; //! use borrow_owned::BorrowOwned; //! //! struct MyStruct; //! //! let object = MyStruct; //! let (borrowed, ret) = object.borrow_owned(); //! //! thread::spawn(move || { //! println!("doing something with the object..."); //! thread::sleep(Duration::from_millis(100)); //! //! mem::drop(borrowed); //! //! println!("doing something else..."); //! thread::sleep(Duration::from_millis(100)); //! }); //! //! println!("waiting until the borrow ends..."); //! let objects = ret.wait(); //! println!("the object is back again!"); //! ``` //! //! # Asynchronous example //! ``` //! use std::{mem, time::Duration}; //! use borrow_owned::AsyncBorrowOwned; //! //! struct MyStruct; //! //! #[tokio::main] //! async fn main() { //! let object = MyStruct; //! let (borrowed, ret) = object.async_borrow_owned(); //! //! tokio::spawn(async move { //! println!("doing something with the object..."); //! tokio::time::sleep(Duration::from_millis(100)); //! //! mem::drop(borrowed); //! //! println!("doing something else..."); //! tokio::time::sleep(Duration::from_millis(100)); //! }); //! //! println!("waiting until the borrow ends..."); //! let object = ret.await; //! println!("the object is back again!"); //! } //! ``` #![cfg_attr(docsrs, feature(doc_cfg))] #[cfg(feature = "async")] mod asynchronous; use std::{ ops::{Deref, DerefMut}, sync::mpsc::{self, Receiver, Sender}, }; #[cfg(feature = "async")] pub use crate::asynchronous::{AsyncBorrowOwned, AsyncBorrowed, AsyncReturn}; /// Trait allowing objects to be temporarily moved elsewhere. pub trait BorrowOwned: Sized { /// Borrow this object. /// /// The method returns a [`Borrowed`](Borrowed) wrapper which can be easily /// moved elsewhere (e.g. a separate thread) and a [`Return`](Return) /// handle which can be used to wait until the borrow ends. fn borrow_owned(self) -> (Borrowed<Self>, Return<Self>); } impl<T> BorrowOwned for T where T: Sized, { fn borrow_owned(self) -> (Borrowed<Self>, Return<Self>) { let (tx, rx) = mpsc::channel(); let borrowed = Borrowed { tx, val: Some(self), }; let ret = Return { rx }; (borrowed, ret) } } /// Return handle. pub struct Return<T> { rx: Receiver<T>, } impl<T> Return<T> { /// Wait until the corresponding borrow ends and return the borrowed /// object. pub fn wait(self) -> T { self.rx.recv().unwrap() } } /// Borrowed object. pub struct Borrowed<T> { tx: Sender<T>, val: Option<T>, } impl<T> Drop for Borrowed<T> { fn drop(&mut self) { if let Some(val) = self.val.take() { self.tx.send(val).unwrap_or_default(); } } } impl<T> Deref for Borrowed<T> { type Target = T; fn deref(&self) -> &Self::Target { self.val.as_ref().unwrap() } } impl<T> DerefMut for Borrowed<T> { fn deref_mut(&mut self) -> &mut Self::Target { self.val.as_mut().unwrap() } }