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()
    }
}