-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Redesign Into
derive macro
#248
Changes from all commits
518c1b1
99cb368
a062ce1
7f24761
845558e
6211b1a
e5ef86e
8c8f9ca
6e82741
7080be8
20a0cb0
8c58553
5a8cf3a
558c2f0
819454e
aa2d332
20d107e
ea8e31c
50135d4
0b6ca7b
ce2cd00
61f1a16
0d489d6
382f185
eac8e27
1ee8c09
ef8fa47
f4f874b
7df415e
87e1058
eaa3596
ff47628
9680277
e5f6540
295eb0d
60430f7
c5b1f77
14e8361
1d74fdf
249a92c
0f295f5
e93c5ed
8e5313f
cf598fa
0061e68
4994298
8116c7c
e6065db
96083d3
c27c76f
3a4a893
2db2f97
5d77999
efc860b
7a4de17
5c1823e
33767ab
6898e00
08d35f5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,166 +1,119 @@ | ||
# What `#[derive(Into)]` generates | ||
|
||
This derive creates the the exact opposite of [`#[derive(From)]`](crate::From). | ||
This derive creates the exact opposite of `#[derive(From)]`. | ||
Instead of allowing you to create a new instance of the struct from the values | ||
it should contain, it allows you to extract the values from the struct. | ||
One thing to note is that this derive doesn't actually generate an | ||
implementation for the `Into` trait. | ||
Instead it derives `From` for the values contained in the struct and thus has an | ||
indirect implementation of `Into` as recommended by the | ||
[docs](https://doc.rust-lang.org/core/convert/trait.Into.html). | ||
it should contain, it allows you to extract the values from the struct. One | ||
thing to note is that this derive doesn't actually generate an implementation | ||
for the `Into` trait. Instead, it derives `From` for the values contained in | ||
the struct and thus has an indirect implementation of `Into` as | ||
[recommended by the docs][1]. | ||
|
||
|
||
|
||
|
||
## Example usage | ||
## Structs | ||
|
||
For structs with a single field you can call `.into()` to extract the inner type. | ||
|
||
```rust | ||
# use derive_more::Into; | ||
# | ||
// Allow converting into i32 | ||
#[derive(Into, PartialEq)] | ||
struct MyInt(i32); | ||
|
||
// Additionally convert refs to the inner type refs | ||
#[derive(Into, PartialEq)] | ||
#[into(owned, ref, ref_mut)] | ||
struct MyInt64(i64); | ||
|
||
// Specify additional conversions | ||
#[derive(Into, PartialEq)] | ||
#[into(types(i16, i32))] | ||
struct MyInt8(i8); | ||
|
||
// Even for ref types | ||
#[derive(Into, PartialEq)] | ||
#[into(owned, ref(types(i64)))] | ||
struct MyInt64Wrapped(MyInt64); | ||
|
||
assert!(i32::from(MyInt(2)) == 2i32); | ||
assert!(i64::from(MyInt64(6)) == 6i64); | ||
assert!(<&i64>::from(&MyInt64(6)) == &6i64); | ||
assert!(<&mut i64>::from(&mut MyInt64(6)) == &mut 6i64); | ||
assert!(i8::from(MyInt8(7)) == 7i8); | ||
assert!(i16::from(MyInt8(7)) == 7i16); | ||
assert!(i32::from(MyInt8(7)) == 7i32); | ||
assert!(MyInt64::from(MyInt64Wrapped(MyInt64(1))) == MyInt64(1)); | ||
assert!(<&MyInt64>::from(&MyInt64Wrapped(MyInt64(1))) == &MyInt64(1)); | ||
assert!(<&i64>::from(&MyInt64Wrapped(MyInt64(1))) == &1i64); | ||
``` | ||
|
||
|
||
|
||
#[derive(Debug, Into, PartialEq)] | ||
struct Int(i32); | ||
|
||
## Tuple structs | ||
assert_eq!(2, Int(2).into()); | ||
``` | ||
|
||
When deriving `Into` for a tuple struct with a single field (i.e. a newtype) like this: | ||
For structs having multiple fields, `.into()` extracts a tuple containing the | ||
desired content for each field. | ||
|
||
```rust | ||
# use derive_more::Into; | ||
# | ||
#[derive(Into)] | ||
struct MyInt(i32); | ||
``` | ||
|
||
Code like this will be generated: | ||
#[derive(Debug, Into, PartialEq)] | ||
struct Point(i32, i32); | ||
|
||
```rust | ||
# struct MyInt(i32); | ||
impl ::core::convert::From<MyInt> for (i32) { | ||
fn from(original: MyInt) -> (i32) { | ||
(original.0) | ||
} | ||
} | ||
assert_eq!((1, 2), Point(1, 2).into()); | ||
``` | ||
|
||
The behaviour is a bit different when deriving for a struct with multiple | ||
fields, since it returns a tuple. For instance when deriving for a tuple struct | ||
with two fields like this: | ||
To specify concrete types for deriving conversions into, use `#[into(<types>)]`. | ||
|
||
```rust | ||
# use std::borrow::Cow; | ||
# | ||
# use derive_more::Into; | ||
# | ||
#[derive(Into)] | ||
struct MyInts(i32, i32); | ||
``` | ||
#[derive(Debug, Into, PartialEq)] | ||
#[into(Cow<'static, str>, String)] | ||
struct Str(Cow<'static, str>); | ||
|
||
Code like this will be generated: | ||
assert_eq!("String".to_owned(), String::from(Str("String".into()))); | ||
assert_eq!(Cow::Borrowed("Cow"), <Cow<_>>::from(Str("Cow".into()))); | ||
|
||
```rust | ||
# struct MyInts(i32, i32); | ||
impl ::core::convert::From<MyInts> for (i32, i32) { | ||
fn from(original: MyInts) -> (i32, i32) { | ||
(original.0, original.1) | ||
} | ||
#[derive(Debug, Into, PartialEq)] | ||
#[into((i64, i64), (i32, i32))] | ||
struct Point { | ||
x: i32, | ||
y: i32, | ||
} | ||
``` | ||
|
||
|
||
|
||
assert_eq!((1_i64, 2_i64), Point { x: 1_i32, y: 2_i32 }.into()); | ||
assert_eq!((3_i32, 4_i32), Point { x: 3_i32, y: 4_i32 }.into()); | ||
``` | ||
|
||
## Regular structs | ||
|
||
For regular structs almost the same code is generated as for tuple structs | ||
except in the way the field values are assigned to the new struct. | ||
When deriving for a regular struct with a single field like this: | ||
In addition to converting to owned types, this macro supports deriving into | ||
reference (mutable or not) via `#[into(ref(...))]`/`#[into(ref_mut(...))]`. | ||
|
||
```rust | ||
# use derive_more::Into; | ||
# | ||
#[derive(Into)] | ||
struct Point1D { | ||
x: i32, | ||
} | ||
``` | ||
#[derive(Debug, Into, PartialEq)] | ||
#[into(owned, ref(i32), ref_mut)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think a better example would be to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm, actually what's the difference between There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @JelteF here
|
||
struct Int(i32); | ||
|
||
Code like this will be generated: | ||
|
||
```rust | ||
# struct Point1D { | ||
# x: i32, | ||
# } | ||
impl ::core::convert::From<Point1D> for (i32) { | ||
fn from(original: Point1D) -> (i32) { | ||
(original.x) | ||
} | ||
} | ||
assert_eq!(2, Int(2).into()); | ||
assert_eq!(&2, <&i32>::from(&Int(2))); | ||
assert_eq!(&mut 2, <&mut i32>::from(&mut Int(2))); | ||
``` | ||
|
||
The behaviour is again a bit different when deriving for a struct with multiple | ||
fields, because this also returns a tuple. For instance when deriving for a | ||
tuple struct with two fields like this: | ||
In case there are fields, that shouldn't be included in the conversion, use the | ||
`#[into(skip)]` attribute. | ||
|
||
```rust | ||
# use std::marker::PhantomData; | ||
# | ||
# use derive_more::Into; | ||
# | ||
#[derive(Into)] | ||
struct Point2D { | ||
x: i32, | ||
y: i32, | ||
# struct Gram; | ||
# | ||
#[derive(Debug, Into, PartialEq)] | ||
#[into(i32, i64, i128)] | ||
struct Mass<Unit> { | ||
value: i32, | ||
#[into(skip)] | ||
_unit: PhantomData<Unit>, | ||
} | ||
|
||
``` | ||
|
||
Code like this will be generated: | ||
|
||
```rust | ||
# struct Point2D { | ||
# x: i32, | ||
# y: i32, | ||
assert_eq!(5, Mass::<Gram>::new(5).into()); | ||
assert_eq!(5_i64, Mass::<Gram>::new(5).into()); | ||
assert_eq!(5_i128, Mass::<Gram>::new(5).into()); | ||
# | ||
# impl<Unit> Mass<Unit> { | ||
# fn new(value: i32) -> Self { | ||
# Self { | ||
# value, | ||
# _unit: PhantomData, | ||
# } | ||
# } | ||
# } | ||
impl ::core::convert::From<Point2D> for (i32, i32) { | ||
fn from(original: Point2D) -> (i32, i32) { | ||
(original.x, original.y) | ||
} | ||
} | ||
``` | ||
|
||
## Enums | ||
|
||
Deriving `Into` for enums is not supported as it would not always be successful, | ||
so `TryInto` should be used instead. | ||
|
||
|
||
|
||
## Enums | ||
|
||
Deriving `Into` for enums is not supported as it would not always be successful. | ||
This is what the currently unstable | ||
[`TryInto`](https://doc.rust-lang.org/core/convert/trait.TryInto.html) should be | ||
used for, which is currently not supported by this library. | ||
[1]: https://doc.rust-lang.org/core/convert/trait.Into.html |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.