#[borrowme]
Expand description
Automatically build an owned variant of a type and implement ToOwned
and
Borrow
.
Anything captured by the macro will be forwarded to the generated variant.
To have detailed control over this behavior, see the
#[borrowed_attr(<meta>)]
and #[owned_attr(<meta>)]
attributes below.
In order to work as intended, #[borrowme]
must be used before any
attributes that you want it to capture such as derives.
use serde::Serialize;
#[borrowme]
#[derive(Serialize)]
pub struct Word<'a> {
lang: &'a str,
}
implements_serialize::<Word<'_>>();
implements_serialize::<OwnedWord>();
If we use the wrong order, Serialize
won’t be seen and that derive won’t
be transferred to OwnedWord
.
use serde::Serialize;
#[derive(Serialize)]
#[borrowme]
pub struct Word<'a> {
lang: &'a str,
}
implements_serialize::<Word<'_>>();
implements_serialize::<OwnedWord>();
15 | implements_serialize::<OwnedWord>();
| ^^^^^^^^^ the trait `Serialize` is not implemented for `OwnedWord`
Implementing for asymmetric types
Some common types need special care because their ToOwned
and Borrow
implementations are asymmetric, that is that the Borrow::Target
does not
match the type that implements ToOwned
. This is easily addressed by
overriding the borrow implementation with #[borrowme(borrow_with = <path>)]
.
&[T]
The ToOwned
implementation produces a Vec<T>
, while Borrow
of
Vec<T>
produces a Vec<&T::Target>
. This can be fixed using
Vec::as_slice
.
use borrowme::borrowme;
#[borrowme]
struct VecField<'a> {
#[borrowme(borrow_with = Vec::as_slice)]
strings: &'a [String],
}
&[T]
as an owned Box<[T]>
The ToOwned
implementation produces a Vec<T>
, while borrowing that
produces a Vec<&T::Target>
. This can be fixed using Box::from
.
use borrowme::borrowme;
#[borrowme]
struct Bytes<'a> {
#[borrowme(owned = Box<[u8]>, to_owned_with = Box::from)]
bytes: &'a [u8],
}
Why isn’t this a derive?
A derive macro can’t see other attributes than the ones it declares as its own. While this is very useful to provide better encapsulation across macros it would mean that derives and other attributes that are specified on the borrowed variant can’t be forwarded to the owned one without explicitly doing it yourself. This would be tedious because most of the time it’s the behaviour you want.
This should hopefully illustrate the issue:
use borrowme::{ToOwned, Borrow};
#[derive(Debug, Clone, PartialEq, Eq, ToOwned)]
#[owned_attr(derive(Debug, Clone, PartialEq, Eq, Borrow))]
struct Word<'a> {
text: &'a str,
}
Container attributes
This section documents supported container attributes:
#[borrowme(name = <ident>)]
which is used to change the name of the generated owned variant.#[borrowed_attr(<meta>)]
and#[owned_attr(<meta>)]
which are used to add custom attributes.
Container attributes are attributes which are added to a container, such as
a struct
or an enum
. See for example #[borrowme(name = WordBuf)]
below:
#[borrowme(name = WordBuf)]
struct Word<'a> {
/* body */
}
#[borrowme(name = EnumBuf)]
enum Enum<'a> {
/* body */
}
#[borrowme(name = <ident>)]
container attribute
This allows you to pick the name to use for the generated type. By default
this is the original identifier prefixed with Owned
.
#[borrowme(name = WordBuf)]
#[derive(Debug, PartialEq)]
struct Word<'a> {
text: &'a str,
}
let word = Word {
text: "Hello World",
};
let word2 = WordBuf {
text: String::from("Hello World"),
};
assert_eq!(borrowme::to_owned(&word), word2);
#[borrowed_attr(<meta>)]
container attribute
Apply the given <meta>
as a container attribute, but only for the
borrowed variant.
#[borrowme]
#[borrowed_attr(derive(Clone))]
struct Word<'a> {
text: &'a str,
}
let word = Word {
text: "Hello World"
};
let word2 = word.clone();
assert_eq!(word.text, word2.text);
#[owned_attr(<meta>)]
container attribute
Apply the given given <meta>
as a container attribute, but only to the
owned variant.
#[borrowme]
#[owned_attr(derive(Clone))]
struct Word<'a> {
text: &'a str,
}
let word = OwnedWord {
text: String::from("Hello World")
};
let word2 = word.clone();
assert_eq!(word.text, word2.text);
Variant attributes
This section documents supported variant attributes:
#[borrowed_attr(<meta>)]
and#[owned_attr(<meta>)]
which are used to add custom attributes.
Variant attributes are attributes which apply to enum
variants.
#[borrowed_attr(<meta>)]
variant attribute
Apply the given <meta>
as a variant attribute, but only for the borrowed
variant.
#[borrowme]
#[borrowed_attr(derive(Default))]
enum Word<'a> {
Wiktionary(&'a str),
#[borrowed_attr(default)]
Unknown,
}
let word = Word::default();
assert!(matches!(word, Word::Unknown));
#[owned_attr(<meta>)]
variant attribute
Apply the given <meta>
as a variant attribute, but only for the owned
variant.
#[borrowme]
#[owned_attr(derive(Default))]
enum Word<'a> {
Wiktionary(&'a str),
#[owned_attr(default)]
Unknown,
}
let word = OwnedWord::default();
assert!(matches!(word, OwnedWord::Unknown));
Field attributes
This section documents supported field attributes:
#[owned(<type>)]
or#[borrowme(owned = <type>)]
which is a required attribute for specifying the owned type a field is being converted into.#[borrowme(mut)]
to indicate that the field needs mutable access to the container.#[borrowme(to_owned_with = <path>)]
,#[borrowme(borrow_with = <path>)]
, and#[borrowme(with = <path>)]
which are used for customizing behavior.#[copy]
and#[no_copy]
which is used to indicate if a field isCopy
and does not require conversion.#[borrowme(std)]
which indicates that the field supports std-like operations.#[borrowed_attr(<meta>)]
and#[owned_attr(<meta>)]
which are used to add custom attributes.
Field attributes are attributes which apply to fields, such as the fields in a struct.
#[owned(<type>)]
or #[borrowme(owned = <type>)]
field attributes
This specifies the owned type of the field. The latter variation is available so that it looks better when combined with other attributes.
By default we try to automatically figure out the type through
ToOwned::Owned
by converting the field type into an expression such as
<<&'static str> as ::borrowme::ToOwned>::Owned
. When this doesn’t work as
expected like when using a type which does not implement ToOwned
this can
be overriden using this attribute.
struct MyType;
struct MyOwnedType;
#[borrowme]
pub struct Word<'a> {
#[borrowme(owned = MyOwnedType, to_owned_with = to_owned_my_type, borrow_with = borrow_my_type)]
lang: &'a MyType,
}
fn to_owned_my_type(this: &MyType) -> MyOwnedType {
MyOwnedType
}
fn borrow_my_type(this: &MyOwnedType) -> &MyType {
&MyType
}
#[borrowme(mut)]
field attribute
Indicates that the field required mutable access to the parent container.
By default this uses heuristics. If a &mut T
reference is noticed in the
field type mutable access is assumed.
#[borrowme]
pub struct Text<'a> {
text: &'a mut String,
}
#[borrowme]
pub struct Word<'a> {
#[borrowme(mut)]
text: Text<'a>,
}
#[borrowme(to_owned_with = <path>)]
field attribute
Specifies a path to use when making a field owned. By default this is:
Clone
if#[borrowme(std)]
is specified.- An owned
self.<field>
expression if#[copy]
is specified. ::borrowme::ToOwned::to_owned
.
#[borrowme]
#[derive(Clone, Debug)]
pub struct Word<'a> {
#[borrowme(owned = Option<String>, to_owned_with = option_to_owned)]
lang: Option<&'a str>,
}
#[inline]
pub(crate) fn option_to_owned(option: &Option<&str>) -> Option<String> {
option.map(ToOwned::to_owned)
}
#[borrowme(borrow_with = <path>)]
field attribute
Specifies a path to use when borrowing a field. By default this is:
- A borrowed
&self.<field>
if#[borrowme(std)]
is specified and the field is not mutable. - An owned
self.<field>
expression if#[copy]
is specified. ::borrowme::Borrow::borrow
.
#[borrowme]
pub struct Word<'a> {
#[borrowme(owned = Option<String>, borrow_with = option_borrow)]
lang: Option<&'a str>,
// Note that the above works the same as `Option::as_deref`.
#[borrowme(owned = Option<String>, borrow_with = Option::as_deref)]
lang2: Option<&'a str>,
}
#[inline]
pub(crate) fn option_borrow(option: &Option<String>) -> Option<&str> {
option.as_deref()
}
#[borrowme(borrow_mut_with = <path>)]
field attribute
Using this implies #[borrowme(mut)]
.
Specifies a path to use when borrowing a mutable field. By default this is:
- A borrowed
&mut self.<field>
if#[borrowme(std)]
is specified and a mutable field is detected or specified with#[borrowme(mut)]
. - An owned
self.<field>
expression if#[copy]
is specified. ::borrowme::BorrowMut::borrow_mut
.
#[borrowme]
pub struct Word<'a> {
#[borrowme(owned = Option<String>, borrow_mut_with = option_borrow)]
lang: Option<&'a mut str>,
#[borrowme(owned = Option<String>, borrow_mut_with = Option::as_deref_mut)]
lang2: Option<&'a mut str>,
}
#[inline]
pub(crate) fn option_borrow(option: &mut Option<String>) -> Option<&mut str> {
option.as_deref_mut()
}
#[borrowme(with = <path>)]
field attribute
Specifies a path to use when calling to_owned
and borrow
on a field.
The sets to_owned
to <path>::to_owned
, and borrow
to <path>::borrow
.
Unless #[copy]
or #[borrowme(std)]
are specified, these are by
default:
::borrowme::ToOwned::to_owned
::borrowme::Borrow::borrow
.
#[borrowme]
#[derive(Clone, Debug)]
pub struct Word<'a> {
#[owned(String)]
text: &'a str,
#[borrowme(owned = Option<String>, with = self::option)]
lang: Option<&'a str>,
}
pub(crate) mod option {
use borrowme::{Borrow, ToOwned};
#[inline]
pub(crate) fn borrow<T>(this: &Option<T>) -> Option<T::Target<'_>>
where
T: Borrow,
{
match this {
Some(some) => Some(some.borrow()),
None => None,
}
}
#[inline]
pub(crate) fn to_owned<T>(option: &Option<T>) -> Option<T::Owned>
where
T: ToOwned,
{
option.as_ref().map(ToOwned::to_owned)
}
}
#[copy]
and #[no_copy]
field attribute
These can also be specified as #[borrowme(copy)]
and
#[borrowme(no_copy)]
.
Indicates that the field type is Copy
, if this is set then the value is
not cloned when the type is converted to and from its owned variant.
#[derive(Clone, Copy)]
struct OwnedBool(bool);
#[borrowme]
pub struct Word<'a> {
text: &'a str,
#[copy]
teineigo: OwnedBool,
}
By default the macro performs heuristic to determine if a field is Copy
or
not. This means that prelude types which make up common copy configurations
will be treated as copy. If this happens inadvertently the #[no_copy]
or
#[borrowme(std)]
attributes can be used.
Type which are #[copy]
by default are:
u8
,u16
,u32
,u64
,u128
, andusize
.i8
,i16
,i32
,i64
,i128
, andisize
.f32
andf64
.bool
.- Tuple types
(A, B, ..)
for which all of its elements look like they are copy. - Array types
[T; N]
for which the elementT
looks like they are copy.
This heuristic can be defeated in a handful of ways, depending on what best suits your needs.
A field can specify that the type is not Copy
using #[no_copy]
, which
makes it fall back to the default behavior:
struct bool;
impl borrowme::ToOwned for bool {
type Owned = bool;
fn to_owned(&self) -> Self::Owned {
bool
}
}
impl borrowme::Borrow for bool {
type Target<'a> = &'a bool;
fn borrow(&self) -> Self::Target<'_> {
self
}
}
#[borrowme]
pub struct Word<'a> {
#[no_copy]
teineigo: &'a bool,
}
The field can specify #[borrowme(std)]
to make use of standard methods of
cloning and getting a reference:
#[derive(Clone)]
struct bool;
#[borrowme]
pub struct NoCopy<'a> {
#[borrowme(std)]
teineigo: &'a bool,
}
Finally we can specify everything ourselves:
#[derive(Clone)]
struct bool;
impl AsRef<bool> for bool {
fn as_ref(&self) -> &bool {
self
}
}
#[borrowme]
pub struct Word<'a> {
#[borrowme(owned = bool, borrow_with = AsRef::as_ref, to_owned_with = Clone::clone)]
teineigo: &'a bool,
}
#[borrowme(std)]
field attribute
Causes conversion to happen by using the Clone
trait to convert into an
owned type and a reference expression like &self.<field>
to borrow,
mimicking the behaviour of std::borrow
.
If the field is an immediate type behind a reference, that will be used as
the target unless #[borrowme(owned = <type>)]
is specified.
#[derive(Clone)]
struct WordKind;
#[borrowme]
pub struct Word<'a> {
#[borrowme(std)]
kind: &'a WordKind,
}
#[borrowed_attr(<meta>)]
field attribute
Apply the given <meta>
as a field attribute, but only for the borrowed
variant. This allows certain attributes that are only needed for the
borrowed variant to be implemented, such as #[serde(borrow)]
.
use serde::{Serialize, Deserialize};
#[borrowme]
#[derive(Serialize, Deserialize)]
pub struct Word<'a> {
#[borrowed_attr(serde(borrow))]
lang: Option<&'a str>,
}
#[owned_attr(<meta>)]
field attribute
Apply the given <meta>
as a field attribute, but only for the owned
variant.
In the below example, only the owned variant will have a serde implementation:
use serde::{Serialize, Deserialize};
#[borrowme]
#[owned_attr(derive(Serialize, Deserialize))]
struct Word<'a> {
#[owned_attr(serde(default, skip_serializing_if = "Option::is_none"))]
lang: Option<&'a str>,
}