Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Add `Hash` derive similar to `std`'s one, but considering generics correctly,
and supporting custom hash functions per field or skipping fields.
([#532](https://github.com/JelteF/derive_more/pull/532))
- Add `Borrow` derive for single-field structs.
- Add `BorrowMut` derive for single-field structs.

### Fixed

Expand Down
31 changes: 30 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ default = ["std"]
add = ["derive_more-impl/add"]
add_assign = ["derive_more-impl/add_assign"]
as_ref = ["derive_more-impl/as_ref"]
borrow = ["derive_more-impl/borrow"]
constructor = ["derive_more-impl/constructor"]
debug = ["derive_more-impl/debug"]
deref = ["derive_more-impl/deref"]
Expand Down Expand Up @@ -85,6 +86,7 @@ full = [
"add",
"add_assign",
"as_ref",
"borrow",
"constructor",
"debug",
"deref",
Expand Down Expand Up @@ -132,6 +134,16 @@ name = "as_ref"
path = "tests/as_ref.rs"
required-features = ["as_ref"]

[[test]]
name = "borrow"
path = "tests/borrow.rs"
required-features = ["borrow"]

[[test]]
name = "borrow_mut"
path = "tests/borrow_mut.rs"
required-features = ["borrow"]

[[test]]
name = "boats_display_derive"
path = "tests/boats_display_derive.rs"
Expand Down Expand Up @@ -260,7 +272,24 @@ required-features = ["unwrap"]
[[test]]
name = "compile_fail"
path = "tests/compile_fail/mod.rs"
required-features = ["as_ref", "debug", "display", "from", "into", "is_variant", "try_from", "try_into"]
required-features = [
"add",
"add_assign",
"as_ref",
"borrow",
"debug",
"display",
"eq",
"from",
"from_str",
"hash",
"into",
"is_variant",
"mul",
"mul_assign",
"try_from",
"try_into",
]

[[test]]
name = "no_std"
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ These are traits that are used to convert automatically between types.
5. [`TryInto`]
6. [`IntoIterator`]
7. [`AsRef`], [`AsMut`]
8. [`Borrow`], [`BorrowMut`]


### Formatting traits
Expand Down Expand Up @@ -250,6 +251,8 @@ Changing [MSRV] (minimum supported Rust version) of this crate is treated as a *
[`IntoIterator`]: https://docs.rs/derive_more/latest/derive_more/derive.IntoIterator.html
[`AsRef`]: https://docs.rs/derive_more/latest/derive_more/derive.AsRef.html
[`AsMut`]: https://docs.rs/derive_more/latest/derive_more/derive.AsMut.html
[`Borrow`]: https://docs.rs/derive_more/latest/derive_more/derive.Borrow.html
[`BorrowMut`]: https://docs.rs/derive_more/latest/derive_more/derive.BorrowMut.html

[`Debug`]: https://docs.rs/derive_more/latest/derive_more/derive.Debug.html
[`Display`-like]: https://docs.rs/derive_more/latest/derive_more/derive.Display.html
Expand Down
2 changes: 2 additions & 0 deletions impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ default = []
add = ["syn/extra-traits", "syn/visit"]
add_assign = ["syn/extra-traits", "syn/visit"]
as_ref = ["syn/extra-traits", "syn/visit"]
borrow = ["syn/visit"]
constructor = []
debug = ["syn/extra-traits", "dep:unicode-ident"]
deref = []
Expand Down Expand Up @@ -80,6 +81,7 @@ full = [
"add",
"add_assign",
"as_ref",
"borrow",
"constructor",
"debug",
"deref",
Expand Down
7 changes: 3 additions & 4 deletions impl/doc/as_mut.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,12 @@ of the field itself, and types for which the field type implements `AsMut`.
# use derive_more::AsMut;
#
#[derive(AsMut)]
#[as_mut(str, [u8], String)]
#[as_mut(str, String)]
struct Types(String);

let mut item = Types("test".to_owned());
let _: &mut str = item.as_mut();
let _: &mut [u8] = item.as_mut();
let _: &mut String = item.as_mut();_
let _: &mut String = item.as_mut();
```

> **WARNING**: When either the field type, or the specified conversion type,
Expand Down Expand Up @@ -148,7 +147,7 @@ Generates:
# valid: bool,
# }
impl AsMut<str> for MyWrapper {
fn as_mut(&mut self) -> &mut String {
fn as_mut(&mut self) -> &mut str {
self.name.as_mut()
}
}
Expand Down
90 changes: 90 additions & 0 deletions impl/doc/borrow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# What `#[derive(Borrow)]` generates

Deriving `Borrow` generates an implementation of `core::borrow::Borrow` that
borrows a single-field struct as its field.

`Borrow` has stronger semantic requirements than `AsRef`: equality, ordering and
hashing of the borrowed value are expected to match those of the owning value.
For that reason, this derive only supports structs with exactly one field.




## Newtypes and Structs with One Field

When `Borrow` is derived for a newtype or a struct with one field, a single
implementation is generated for the field type.

```rust
# use derive_more::Borrow;
#
#[derive(Borrow)]
struct MyWrapper(String);
```

Generates code equivalent to:

```rust
# struct MyWrapper(String);
impl core::borrow::Borrow<String> for MyWrapper {
fn borrow(&self) -> &String {
&self.0
}
}
```

It's also possible to use the `#[borrow(forward)]` attribute to forward to the
field's `Borrow` implementation.

```rust
# use derive_more::Borrow;
# use derive_more::core::borrow::Borrow as _;
#
#[derive(Borrow)]
#[borrow(forward)]
struct MyWrapper(String);

let item = MyWrapper("test".to_owned());
let _: &str = item.borrow();
```

This generates code equivalent to:

```rust
# struct MyWrapper(String);
impl<T: ?Sized> core::borrow::Borrow<T> for MyWrapper
where
String: core::borrow::Borrow<T>,
{
#[inline]
fn borrow(&self) -> &T {
self.0.borrow()
}
}
```

Forwarding cannot be derived through a generic parameter, an associated type of
a generic parameter, or a forwarding pointer to either. Directly borrowing an
associated type of a generic parameter is not supported either. These shapes can
overlap with `core`'s blanket `impl<T> Borrow<T> for T`.




## Structs with Multiple Fields

Deriving `Borrow` for structs with more than one field is not supported.

```rust,compile_fail
# use derive_more::Borrow;
#
#[derive(Borrow)]
struct User(String, bool);
```




## Enums

Deriving `Borrow` for enums is not supported.
108 changes: 108 additions & 0 deletions impl/doc/borrow_mut.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# What `#[derive(BorrowMut)]` generates

Deriving `BorrowMut` generates an implementation of
`core::borrow::BorrowMut` that mutably borrows a single-field struct as its
field.

`BorrowMut<T>` requires `Borrow<T>`, so the type must also implement the
matching `Borrow` implementation. Usually this means deriving both `Borrow` and
`BorrowMut`.




## Newtypes and Structs with One Field

When `BorrowMut` is derived for a newtype or a struct with one field, a single
implementation is generated for the field type.

```rust
# use derive_more::{Borrow, BorrowMut};
#
#[derive(Borrow, BorrowMut)]
struct MyWrapper(String);
```

Generates code equivalent to:

```rust
# struct MyWrapper(String);
# impl core::borrow::Borrow<String> for MyWrapper {
# fn borrow(&self) -> &String {
# &self.0
# }
# }
impl core::borrow::BorrowMut<String> for MyWrapper {
fn borrow_mut(&mut self) -> &mut String {
&mut self.0
}
}
```

It's also possible to use the `#[borrow_mut(forward)]` attribute to forward to
the field's `BorrowMut` implementation. The matching `Borrow` implementation
must borrow the same type, so forwarded `BorrowMut` usually goes together with
`#[borrow(forward)]`.

```rust
# use derive_more::{Borrow, BorrowMut};
# use derive_more::core::borrow::BorrowMut as _;
#
#[derive(Borrow, BorrowMut)]
#[borrow(forward)]
#[borrow_mut(forward)]
struct MyWrapper(String);

let mut item = MyWrapper("test".to_owned());
let _: &mut str = item.borrow_mut();
```

This generates code equivalent to:

```rust
# struct MyWrapper(String);
# impl<T: ?Sized> core::borrow::Borrow<T> for MyWrapper
# where
# String: core::borrow::Borrow<T>,
# {
# #[inline]
# fn borrow(&self) -> &T {
# self.0.borrow()
# }
# }
impl<T: ?Sized> core::borrow::BorrowMut<T> for MyWrapper
where
String: core::borrow::BorrowMut<T>,
{
#[inline]
fn borrow_mut(&mut self) -> &mut T {
self.0.borrow_mut()
}
}
```

Forwarding cannot be derived through a generic parameter, an associated type of
a generic parameter, or a forwarding pointer to either. Directly borrowing an
associated type of a generic parameter is not supported either. These shapes can
overlap with `core`'s blanket `impl<T> BorrowMut<T> for T`.




## Structs with Multiple Fields

Deriving `BorrowMut` for structs with more than one field is not supported.

```rust,compile_fail
# use derive_more::{Borrow, BorrowMut};
#
#[derive(Borrow, BorrowMut)]
struct User(String, bool);
```




## Enums

Deriving `BorrowMut` for enums is not supported.
Loading
Loading