mirror of
https://git.proxmox.com/git/proxmox
synced 2025-08-13 16:08:00 +00:00
tools: add borrow::Tied with example docs
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
025eaf5519
commit
2ecd147036
110
proxmox-tools/src/borrow.rs
Normal file
110
proxmox-tools/src/borrow.rs
Normal file
@ -0,0 +1,110 @@
|
||||
//! Helpers for borrowing and self-borrowing values.
|
||||
|
||||
/// This ties two values together, so that one value can borrow from the other, while allowing the
|
||||
/// resulting object to be stored in a struct. The life time of the borrow will not infect the
|
||||
/// surrounding type's signature.
|
||||
///
|
||||
/// A `Tied` value dereferences to its produced borrowing value, and can likely be used as a
|
||||
/// drop-in replacement for existing code which needs to get rid of lifetimes.
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// // Our owner which we want to borrow from.
|
||||
/// struct Owner(i64);
|
||||
/// struct Borrow<'a>(&'a mut i64);
|
||||
///
|
||||
/// impl Owner {
|
||||
/// pub fn borrow_mut(&mut self) -> Borrow {
|
||||
/// Borrow(&mut self.0)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Show that we can be used as a Borrow
|
||||
/// impl<'a> Borrow<'a> {
|
||||
/// pub fn i_am_a_borrow(&self) {}
|
||||
/// }
|
||||
///
|
||||
/// // The following cannot be expressed in rust:
|
||||
/// //struct Usage {
|
||||
/// // owner: Owner,
|
||||
/// // borrow: Borrow<??? lifetime of self.owner ???>
|
||||
/// //}
|
||||
///
|
||||
/// // Instead we use:
|
||||
/// use proxmox::tools::borrow::Tied;
|
||||
/// struct Usage {
|
||||
/// tied: Tied<Owner, Borrow<'static>>,
|
||||
/// }
|
||||
///
|
||||
/// let usage = Usage {
|
||||
/// tied: Tied::new(Owner(10), |owner| Box::new(unsafe { (*owner).borrow_mut() })),
|
||||
/// };
|
||||
///
|
||||
/// // tied can be used like a Borrow:
|
||||
/// usage.tied.i_am_a_borrow();
|
||||
/// ```
|
||||
pub struct Tied<T, U: ?Sized> {
|
||||
/// The contained "value" of which we want to borrow something.
|
||||
inner: Option<Box<T>>,
|
||||
/// The thing borrowing from `inner`. This is what the `Tied` value ultimately dereferences to.
|
||||
borrow: Option<Box<U>>,
|
||||
}
|
||||
|
||||
impl<T, U: ?Sized> Drop for Tied<T, U> {
|
||||
fn drop(&mut self) {
|
||||
// let's be explicit about order here!
|
||||
std::mem::drop(self.borrow.take());
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U: ?Sized> Tied<T, U> {
|
||||
/// Takes a value and a function producing the borrowing value. The owning value will be
|
||||
/// inaccessible until the tied value is resolved. The dependent value is only accessible by
|
||||
/// reference.
|
||||
pub fn new<F>(value: T, producer: F) -> Self
|
||||
where
|
||||
F: FnOnce(*mut T) -> Box<U>,
|
||||
{
|
||||
let mut value = Box::new(value);
|
||||
let borrow = producer(&mut *value);
|
||||
Self {
|
||||
inner: Some(value),
|
||||
borrow: Some(borrow),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_boxed_inner(mut self) -> Box<T> {
|
||||
self.borrow = None;
|
||||
self.inner.take().unwrap()
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> T {
|
||||
*self.into_boxed_inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U: ?Sized> AsRef<U> for Tied<T, U> {
|
||||
fn as_ref(&self) -> &U {
|
||||
self.borrow.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U: ?Sized> AsMut<U> for Tied<T, U> {
|
||||
fn as_mut(&mut self) -> &mut U {
|
||||
self.borrow.as_mut().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U: ?Sized> std::ops::Deref for Tied<T, U> {
|
||||
type Target = U;
|
||||
|
||||
fn deref(&self) -> &U {
|
||||
self.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U: ?Sized> std::ops::DerefMut for Tied<T, U> {
|
||||
fn deref_mut(&mut self) -> &mut U {
|
||||
self.as_mut()
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
use failure::*;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
pub mod borrow;
|
||||
pub mod common_regex;
|
||||
pub mod fd;
|
||||
pub mod fs;
|
||||
|
Loading…
Reference in New Issue
Block a user