#borrow #lifetime #macro

no-std borrowme

The missing compound borrowing for Rust

15 releases

0.0.15 May 18, 2024
0.0.14 May 2, 2023

#337 in Rust patterns

Download history 8/week @ 2024-06-20 6/week @ 2024-06-27 32/week @ 2024-07-04 5/week @ 2024-07-18 5/week @ 2024-07-25 4/week @ 2024-08-01 7/week @ 2024-08-08 9/week @ 2024-08-15 4/week @ 2024-08-29 3/week @ 2024-09-05 2/week @ 2024-09-12 26/week @ 2024-09-19 37/week @ 2024-09-26 5/week @ 2024-10-03

71 downloads per month
Used in 2 crates

MIT/Apache

61KB
591 lines

borrowme

github crates.io docs.rs build status

The missing compound borrowing for Rust.

Rust comes with two sibling traits which that can convert from owned to borrowed: ToOwned, Borrow and BorrowMut.

These can convert most simple types such as &str to and from String. But lets think of this in a broader perspective. How to we convert a type that has lifetimes, to one which does not? This crate defines its own ToOwned, Borrow and BorrowMut traits which serve a similar purpose to the ones in std but are implemented so that they can do this not only for simple references but also for compound types which receives lifetimes.

To help us implement these traits the #[borrowme] attribute macro is provided (see this section for why it's not a derive).

#[borrowme]
#[derive(Clone)]
#[borrowed_attr(derive(Copy))]
struct Word<'a> {
    text: &'a str,
}

From this we get the following types and implementations:

#[derive(Clone, Copy)]
struct Word<'a> {
    text: &'a str,
}

#[derive(Clone)]
struct OwnedWord {
    text: String,
}

impl borrowme::ToOwned for Word<'_> {
    type Owned = OwnedWord;

    fn to_owned(&self) -> OwnedWord {
        /* .. */
    }
}

impl borrowme::Borrow for OwnedWord {
    type Target<'a> = Word<'a>;

    fn borrow(&self) -> Word<'_> {
        /* .. */
    }
}

By itself this isn't much, but here's the big trick. Types using this crate can be composed and converted into their borrowed or owned counterparts as needed:

use std::collections::HashMap;

#[borrowme]
struct Word<'a> {
    text: &'a str,
}

#[borrowme]
struct Dictionary<'a> {
    words: HashMap<&'a str, Word<'a>>,
}

let dictionary = Dictionary {
    /* .. */
};

let owned_dictionary: OwnedDictionary = borrowme::to_owned(&dictionary);
let dictionary2: Dictionary<'_> = borrowme::borrow(&owned_dictionary);

Dependencies

~235–680KB
~16K SLoC