4 releases (2 breaking)

0.5.2 Feb 14, 2023
0.5.0 Aug 19, 2022
0.4.0 Aug 17, 2022
0.3.0 Jul 27, 2022

#16 in #emulate

Download history 26/week @ 2024-04-01 38/week @ 2024-04-08 32/week @ 2024-05-20 24/week @ 2024-05-27 180/week @ 2024-06-03 4/week @ 2024-06-17

187 downloads per month
Used in reborrow

MIT license

15KB
266 lines

Emulate reborrowing for user types.

A generalized reference is a type that has reference semantics, without actually being a native Rust reference (like &T and &mut T). e.g.:

struct MyRefMut<'borrow> {
    a: &'borrow mut i32,
    b: &'borrow mut i32,
}

Given a &'a [mut] reference of a &'b view over some owned object, reborrowing it means getting an active &'a view over the owned object, which renders the original reference inactive until it's dropped, at which point the original reference becomes active again.

This crate defines traits to make generalized references more ergonomic to use by giving the ability to borrow and reborrow them.

Features

derive: This imports a derive macro helper for implementing reborrow for user types. It can be used with a Ref/RefMut pair of structs/tuple structs with the same member names, one containing shared references and the other mutable references. The shared variant must be Copy, and the macro is used on the mutable variant and generates the relevant traits for both types.

Examples

This fails to compile since we can't use a non-Copy value after it's moved.

fn takes_mut_option(o: Option<&mut i32>) {}

let mut x = 0;
let o = Some(&mut x);
takes_mut_option(o); // `o` is moved here,
takes_mut_option(o); // so it can't be used here.

This can be worked around by unwrapping the option, reborrowing it, and then wrapping it again.

fn takes_mut_option(o: Option<&mut i32>) {}

let mut x = 0;
let mut o = Some(&mut x);
takes_mut_option(o.as_mut().map(|r| &mut **r)); // "Reborrowing" the `Option`
takes_mut_option(o.as_mut().map(|r| &mut **r)); // allows us to use it later on.
drop(o); // can still be used here

Using this crate, this can be shortened to

use reborrow::ReborrowMut;

fn takes_mut_option(o: Option<&mut i32>) {}

let mut x = 0;
let mut o = Some(&mut x);
takes_mut_option(o.rb_mut()); // "Reborrowing" the `Option`
takes_mut_option(o.rb_mut()); // allows us to use it later on.
drop(o); // can still be used here

The derive macro can be used with structs or tuple structs, and generates the trait definitions for Reborrow and ReborrowMut.

use reborrow::{ReborrowCopyTraits, ReborrowTraits};

#[derive(ReborrowCopyTraits)]
pub struct I32Ref<'a, 'b> {
    pub i: i32,
    pub j: &'a i32,
    pub k: &'b i32,
}

#[derive(ReborrowCopyTraits)]
pub struct I32TupleRef<'a, 'b>(pub i32, pub &'a i32, pub &'b i32);

#[derive(ReborrowTraits)]
#[Const(I32Ref)]
struct I32RefMut<'a, 'b> {
    i: i32,
    #[reborrow]
    j: &'a mut i32,
    #[reborrow]
    k: &'b mut i32,
}

#[derive(ReborrowTraits)]
#[Const(I32TupleRef)]
pub struct I32TupleRefMut<'a, 'b>(
    i32,
    #[reborrow] &'a mut i32,
    #[reborrow] &'b mut i32,
);

Dependencies

~1.5MB
~35K SLoC