зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1716518 - Upgrade derive_more to v0.99.11. r=emilio
Latest version is v0.99.14 but it adds new dependencies. Differential Revision: https://phabricator.services.mozilla.com/D117780
This commit is contained in:
Родитель
fe32d4f0f5
Коммит
7b2c7f4f51
|
@ -1136,9 +1136,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.2"
|
||||
version = "0.99.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2159be042979966de68315bce7034bb000c775f22e3e834e1c52ff78f041cae8"
|
||||
checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -5,12 +5,70 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
|
||||
## 0.99.10 - 2020-??-??
|
||||
|
||||
### Improvements
|
||||
|
||||
- `From` supports additional types for conversion: `#[from(types(u8, u16))]`.
|
||||
|
||||
|
||||
## 0.99.7 - 2020-05-16
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fix generic derives for `MulAssign`
|
||||
|
||||
### Improvements
|
||||
|
||||
- When specifying specific features of the crate to only enable specific
|
||||
derives, the `extra-traits` feature of `syn` is not always enabled
|
||||
when those the specified features do not require it. This should speed up
|
||||
compile time of `syn` when this feature is not needed.
|
||||
|
||||
|
||||
## 0.99.6 - 2020-05-13
|
||||
|
||||
### Improvements
|
||||
|
||||
- Make sure output of derives is deterministic, for better support in
|
||||
rust-analyzer
|
||||
|
||||
|
||||
## 0.99.5 - 2020-03-28
|
||||
|
||||
### New features
|
||||
|
||||
- Support for deriving `Error`!!! (many thanks to @ffuugoo and @tyranron)
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fix generic bounds for `Deref` and `DerefMut` with `forward`, i.e. put `Deref`
|
||||
bound on whole type, so on `where Box<T>: Deref` instead of on `T: Deref`.
|
||||
([#107](https://github.com/JelteF/derive_more/issues/114))
|
||||
|
||||
- The `tests` directory is now correctly included in the crate (requested by
|
||||
Debian package maintainers)
|
||||
|
||||
## 0.99.4 - 2020-03-28
|
||||
|
||||
Note: This version is yanked, because quickly after release it was found out
|
||||
tests did not run in CI.
|
||||
|
||||
## 0.99.3 - 2020-02-19
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fix generic bounds for `Deref` and `DerefMut` with no `forward`, i.e. no bounds
|
||||
are necessary. ([#107](https://github.com/JelteF/derive_more/issues/114))
|
||||
|
||||
|
||||
## 0.99.2 - 2019-11-17
|
||||
|
||||
### Fixes
|
||||
|
||||
- Hotfix for a regression in allowed `Display` derives using `#` flag, such as
|
||||
`{:#b}` ([#107](https://github.com/JelteF/derive_more/issues/105))
|
||||
`{:#b}` ([#107](https://github.com/JelteF/derive_more/issues/107))
|
||||
|
||||
## 0.99.1 - 2019-11-12
|
||||
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.2"
|
||||
version = "0.99.11"
|
||||
dependencies = [
|
||||
"peg 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -39,6 +40,27 @@ dependencies = [
|
|||
"proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.3"
|
||||
|
@ -59,5 +81,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802"
|
||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
"checksum quote 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49d77c41ca8767f2f41394c11a4eebccab83da25e7cc035387a3125f02be90a3"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum syn 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "158521e6f544e7e3dcfc370ac180794aa38cb34a1b1e07609376d4adcf429b93"
|
||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "derive_more"
|
||||
version = "0.99.2"
|
||||
version = "0.99.11"
|
||||
authors = ["Jelte Fennema <github-tech@jeltef.nl>"]
|
||||
include = ["src/**/*.rs", "Cargo.toml", "LICENSE", "README.md", "CHANGELOG.md", "test/**/*.rs"]
|
||||
include = ["src/**/*.rs", "Cargo.toml", "LICENSE", "README.md", "CHANGELOG.md", "tests/**/*.rs"]
|
||||
autotests = true
|
||||
description = "Adds #[derive(x)] macros for more traits"
|
||||
documentation = "https://jeltef.github.io/derive_more/derive_more/"
|
||||
|
@ -79,6 +79,11 @@ name = "display"
|
|||
path = "tests/display.rs"
|
||||
required-features = ["display"]
|
||||
|
||||
[[test]]
|
||||
name = "error"
|
||||
path = "tests/error_tests.rs"
|
||||
required-features = ["error"]
|
||||
|
||||
[[test]]
|
||||
name = "from"
|
||||
path = "tests/from.rs"
|
||||
|
@ -156,35 +161,40 @@ version = "1"
|
|||
|
||||
[dependencies.syn]
|
||||
version = "1"
|
||||
features = ["extra-traits"]
|
||||
[build-dependencies.peg]
|
||||
version = "0.5"
|
||||
optional = true
|
||||
|
||||
[build-dependencies.rustc_version]
|
||||
version = "0.2"
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
add = []
|
||||
add_assign = []
|
||||
as_mut = []
|
||||
as_ref = []
|
||||
constructor = []
|
||||
default = ["add_assign", "add", "as_mut", "as_ref", "constructor", "deref", "deref_mut", "display", "from", "from_str", "index", "index_mut", "into", "into_iterator", "iterator", "mul_assign", "mul", "not", "sum", "try_into"]
|
||||
default = ["add_assign", "add", "as_mut", "as_ref", "constructor", "deref", "deref_mut", "display", "error", "from", "from_str", "index", "index_mut", "into", "into_iterator", "iterator", "mul_assign", "mul", "not", "sum", "try_into"]
|
||||
deref = []
|
||||
deref_mut = []
|
||||
display = []
|
||||
from = []
|
||||
display = ["syn/extra-traits"]
|
||||
error = ["syn/extra-traits"]
|
||||
from = ["syn/extra-traits"]
|
||||
from_str = []
|
||||
generate-parsing-rs = ["peg"]
|
||||
index = []
|
||||
index_mut = []
|
||||
into = []
|
||||
into = ["syn/extra-traits"]
|
||||
into_iterator = []
|
||||
iterator = []
|
||||
mul = []
|
||||
mul_assign = []
|
||||
mul = ["syn/extra-traits"]
|
||||
mul_assign = ["syn/extra-traits"]
|
||||
nightly = []
|
||||
not = []
|
||||
not = ["syn/extra-traits"]
|
||||
sum = []
|
||||
try_into = []
|
||||
testing-helpers = ["rustc_version"]
|
||||
try_into = ["syn/extra-traits"]
|
||||
[badges.github]
|
||||
repository = "JelteF/derive_more"
|
||||
workflow = "CI"
|
||||
|
|
|
@ -90,6 +90,11 @@ These traits are used for converting a struct to a string in different ways.
|
|||
1. [`Display`-like], contains `Display`, `Binary`, `Octal`, `LowerHex`,
|
||||
`UpperHex`, `LowerExp`, `UpperExp`, `Pointer`
|
||||
|
||||
### Error-handling traits
|
||||
These traits are used to define error-types.
|
||||
|
||||
1. [`Error`]
|
||||
|
||||
### Operators
|
||||
|
||||
These are traits that can be used for operator overloading.
|
||||
|
@ -159,6 +164,8 @@ extern crate derive_more;
|
|||
|
||||
[`Display`-like]: https://jeltef.github.io/derive_more/derive_more/display.html
|
||||
|
||||
[`Error`]: https://jeltef.github.io/derive_more/derive_more/error.html
|
||||
|
||||
[`Index`]: https://jeltef.github.io/derive_more/derive_more/index_op.html
|
||||
[`Deref`]: https://jeltef.github.io/derive_more/derive_more/deref.html
|
||||
[`Not`-like]: https://jeltef.github.io/derive_more/derive_more/not.html
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
use crate::utils::{add_where_clauses_for_new_ident, MultiFieldData, State};
|
||||
use crate::utils::{
|
||||
add_where_clauses_for_new_ident, AttrParams, MultiFieldData, State,
|
||||
};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{parse::Result, DeriveInput, Ident};
|
||||
|
||||
pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> {
|
||||
let as_mut_type = &Ident::new("__AsMutT", Span::call_site());
|
||||
let state = State::with_field_ignore_and_forward(
|
||||
let state = State::with_type_bound(
|
||||
input,
|
||||
trait_name,
|
||||
quote!(::core::convert),
|
||||
String::from("as_mut"),
|
||||
AttrParams::ignore_and_forward(),
|
||||
false,
|
||||
)?;
|
||||
let MultiFieldData {
|
||||
fields,
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
use crate::utils::{add_where_clauses_for_new_ident, MultiFieldData, State};
|
||||
use crate::utils::{
|
||||
add_where_clauses_for_new_ident, AttrParams, MultiFieldData, State,
|
||||
};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{parse::Result, DeriveInput, Ident};
|
||||
|
||||
pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> {
|
||||
let as_ref_type = &Ident::new("__AsRefT", Span::call_site());
|
||||
let state = State::with_field_ignore_and_forward(
|
||||
let state = State::with_type_bound(
|
||||
input,
|
||||
trait_name,
|
||||
quote!(::core::convert),
|
||||
String::from("as_ref"),
|
||||
AttrParams::ignore_and_forward(),
|
||||
false,
|
||||
)?;
|
||||
let MultiFieldData {
|
||||
fields,
|
||||
|
@ -61,13 +65,13 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStre
|
|||
})
|
||||
.collect();
|
||||
let bodies = sub_items.iter().map(|i| &i.0);
|
||||
let impl_genericses = sub_items.iter().map(|i| &i.1);
|
||||
let impl_generics = sub_items.iter().map(|i| &i.1);
|
||||
let where_clauses = sub_items.iter().map(|i| &i.2);
|
||||
let trait_paths = sub_items.iter().map(|i| &i.3);
|
||||
let return_types = sub_items.iter().map(|i| &i.4);
|
||||
|
||||
Ok(quote! {#(
|
||||
impl#impl_genericses #trait_paths for #input_type#ty_generics
|
||||
impl#impl_generics #trait_paths for #input_type#ty_generics
|
||||
#where_clauses
|
||||
{
|
||||
#[inline]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::utils::{SingleFieldData, State};
|
||||
use crate::utils::{add_extra_where_clauses, SingleFieldData, State};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse::Result, DeriveInput};
|
||||
|
@ -16,22 +16,31 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStre
|
|||
field_type,
|
||||
trait_path,
|
||||
casted_trait,
|
||||
impl_generics,
|
||||
ty_generics,
|
||||
where_clause,
|
||||
member,
|
||||
info,
|
||||
..
|
||||
} = state.assert_single_enabled_field();
|
||||
|
||||
let (target, body) = if info.forward {
|
||||
let (target, body, generics) = if info.forward {
|
||||
(
|
||||
quote!(#casted_trait::Target),
|
||||
quote!(#casted_trait::deref(&#member)),
|
||||
add_extra_where_clauses(
|
||||
&input.generics,
|
||||
quote! {
|
||||
where #field_type: #trait_path
|
||||
},
|
||||
),
|
||||
)
|
||||
} else {
|
||||
(quote!(#field_type), quote!(&#member))
|
||||
(
|
||||
quote!(#field_type),
|
||||
quote!(&#member),
|
||||
input.generics.clone(),
|
||||
)
|
||||
};
|
||||
let (impl_generics, _, where_clause) = generics.split_for_impl();
|
||||
|
||||
Ok(quote! {
|
||||
impl#impl_generics #trait_path for #input_type#ty_generics #where_clause
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::utils::{SingleFieldData, State};
|
||||
use crate::utils::{add_extra_where_clauses, SingleFieldData, State};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse::Result, DeriveInput};
|
||||
|
@ -15,18 +15,26 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStre
|
|||
input_type,
|
||||
trait_path,
|
||||
casted_trait,
|
||||
impl_generics,
|
||||
ty_generics,
|
||||
where_clause,
|
||||
field_type,
|
||||
member,
|
||||
info,
|
||||
..
|
||||
} = state.assert_single_enabled_field();
|
||||
let body = if info.forward {
|
||||
quote!(#casted_trait::deref_mut(&mut #member))
|
||||
let (body, generics) = if info.forward {
|
||||
(
|
||||
quote!(#casted_trait::deref_mut(&mut #member)),
|
||||
add_extra_where_clauses(
|
||||
&input.generics,
|
||||
quote! {
|
||||
where #field_type: #trait_path
|
||||
},
|
||||
),
|
||||
)
|
||||
} else {
|
||||
quote!(&mut #member)
|
||||
(quote!(&mut #member), input.generics.clone())
|
||||
};
|
||||
let (impl_generics, _, where_clause) = generics.split_for_impl();
|
||||
|
||||
Ok(quote! {
|
||||
impl#impl_generics #trait_path for #input_type#ty_generics #where_clause
|
||||
|
|
|
@ -1,21 +1,15 @@
|
|||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fmt::Display,
|
||||
iter::FromIterator as _,
|
||||
ops::Deref as _,
|
||||
str::FromStr as _,
|
||||
};
|
||||
use std::{fmt::Display, iter::FromIterator as _, str::FromStr as _};
|
||||
|
||||
use crate::utils::add_extra_where_clauses;
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::{
|
||||
parse::{Error, Parser as _, Result},
|
||||
punctuated::Punctuated,
|
||||
spanned::Spanned as _,
|
||||
parse::Parser as _, punctuated::Punctuated, spanned::Spanned as _, Error, Result,
|
||||
};
|
||||
|
||||
/// Provides the hook to expand `#[derive(Display)]` into an implementation of `Display`
|
||||
use crate::utils;
|
||||
use utils::{HashMap, HashSet};
|
||||
|
||||
/// Provides the hook to expand `#[derive(Display)]` into an implementation of `From`
|
||||
pub fn expand(input: &syn::DeriveInput, trait_name: &str) -> Result<TokenStream> {
|
||||
let trait_name = trait_name.trim_end_matches("Custom");
|
||||
let trait_ident = syn::Ident::new(trait_name, Span::call_site());
|
||||
|
@ -51,7 +45,7 @@ pub fn expand(input: &syn::DeriveInput, trait_name: &str) -> Result<TokenStream>
|
|||
})
|
||||
.collect();
|
||||
let where_clause = quote_spanned!(input.span()=> where #(#bounds),*);
|
||||
add_extra_where_clauses(&input.generics, where_clause)
|
||||
utils::add_extra_where_clauses(&input.generics, where_clause)
|
||||
} else {
|
||||
input.generics.clone()
|
||||
};
|
||||
|
@ -278,7 +272,7 @@ impl<'a, 'b> State<'a, 'b> {
|
|||
return Err(Error::new(span, "No bounds specified"));
|
||||
}
|
||||
|
||||
let mut bounds = HashMap::new();
|
||||
let mut bounds = HashMap::default();
|
||||
|
||||
for generic_param in generic_params {
|
||||
let type_param = match generic_param {
|
||||
|
@ -303,7 +297,7 @@ impl<'a, 'b> State<'a, 'b> {
|
|||
qself: None,
|
||||
path: type_param.ident.into(),
|
||||
});
|
||||
let bounds = bounds.entry(ty).or_insert_with(HashSet::new);
|
||||
let bounds = bounds.entry(ty).or_insert_with(HashSet::default);
|
||||
|
||||
for bound in type_param.bounds {
|
||||
let bound = match bound {
|
||||
|
@ -352,11 +346,12 @@ impl<'a, 'b> State<'a, 'b> {
|
|||
op if op.segments.first().expect("path shouldn't be empty").ident
|
||||
== "fmt" =>
|
||||
{
|
||||
let expected_affix_usage = "outer `enum` `fmt` is an affix spec that expects no args and at most 1 placeholder for inner variant display";
|
||||
if outer_enum {
|
||||
if list.nested.iter().skip(1).count() != 0 {
|
||||
return Err(Error::new(
|
||||
list.nested[1].span(),
|
||||
"`fmt` formatting requires a single `fmt` argument",
|
||||
expected_affix_usage,
|
||||
));
|
||||
}
|
||||
// TODO: Check for a single `Display` group?
|
||||
|
@ -385,7 +380,7 @@ impl<'a, 'b> State<'a, 'b> {
|
|||
if num_placeholders > 1 {
|
||||
return Err(Error::new(
|
||||
list.nested[1].span(),
|
||||
"fmt string for enum should have at at most 1 placeholder",
|
||||
expected_affix_usage,
|
||||
));
|
||||
}
|
||||
if num_placeholders == 1 {
|
||||
|
@ -447,7 +442,7 @@ impl<'a, 'b> State<'a, 'b> {
|
|||
} else if fields.len() > 1 {
|
||||
return Err(Error::new(
|
||||
fields.span(),
|
||||
"Can not automatically infer format for types with more than 1 field",
|
||||
"Cannot automatically infer format for types with more than 1 field",
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -480,7 +475,7 @@ impl<'a, 'b> State<'a, 'b> {
|
|||
|
||||
Ok(ParseResult {
|
||||
arms: quote_spanned!(self.input.span()=> _ => #fmt,),
|
||||
bounds: HashMap::new(),
|
||||
bounds: HashMap::default(),
|
||||
requires_helper: false,
|
||||
})
|
||||
}
|
||||
|
@ -504,7 +499,7 @@ impl<'a, 'b> State<'a, 'b> {
|
|||
let fmt = fmt?;
|
||||
Ok(ParseResult {
|
||||
arms: quote_spanned!(self.input.span()=> #fmt),
|
||||
bounds: HashMap::new(),
|
||||
bounds: HashMap::default(),
|
||||
requires_helper: true,
|
||||
})
|
||||
}
|
||||
|
@ -558,14 +553,14 @@ impl<'a, 'b> State<'a, 'b> {
|
|||
self.find_meta(&self.input.attrs, "fmt")?.ok_or_else(|| {
|
||||
Error::new(
|
||||
self.input.span(),
|
||||
"Can not automatically infer format for unions",
|
||||
"Cannot automatically infer format for unions",
|
||||
)
|
||||
})?;
|
||||
let fmt = self.parse_meta_fmt(&meta, false)?.0;
|
||||
|
||||
Ok(ParseResult {
|
||||
arms: quote_spanned!(self.input.span()=> _ => #fmt,),
|
||||
bounds: HashMap::new(),
|
||||
bounds: HashMap::default(),
|
||||
requires_helper: false,
|
||||
})
|
||||
}
|
||||
|
@ -613,29 +608,30 @@ impl<'a, 'b> State<'a, 'b> {
|
|||
meta: &syn::Meta,
|
||||
) -> HashMap<syn::Type, HashSet<syn::TraitBound>> {
|
||||
if self.type_params.is_empty() {
|
||||
return HashMap::new();
|
||||
return HashMap::default();
|
||||
}
|
||||
|
||||
let fields_type_params: HashMap<syn::Path, _> = fields
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, field)| {
|
||||
self.get_type_param(&field.ty).map(|ty| {
|
||||
(
|
||||
field
|
||||
.ident
|
||||
.clone()
|
||||
.unwrap_or_else(|| {
|
||||
Ident::new(&format!("_{}", i), Span::call_site())
|
||||
})
|
||||
.into(),
|
||||
ty,
|
||||
)
|
||||
})
|
||||
utils::get_if_type_parameter_used_in_type(&self.type_params, &field.ty)
|
||||
.map(|ty| {
|
||||
(
|
||||
field
|
||||
.ident
|
||||
.clone()
|
||||
.unwrap_or_else(|| {
|
||||
Ident::new(&format!("_{}", i), Span::call_site())
|
||||
})
|
||||
.into(),
|
||||
ty,
|
||||
)
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
if fields_type_params.is_empty() {
|
||||
return HashMap::new();
|
||||
return HashMap::default();
|
||||
}
|
||||
|
||||
let list = match meta {
|
||||
|
@ -658,7 +654,7 @@ impl<'a, 'b> State<'a, 'b> {
|
|||
})
|
||||
.collect();
|
||||
if fmt_args.is_empty() {
|
||||
return HashMap::new();
|
||||
return HashMap::default();
|
||||
}
|
||||
let fmt_string = match &list.nested[0] {
|
||||
syn::NestedMeta::Meta(syn::Meta::NameValue(syn::MetaNameValue {
|
||||
|
@ -679,13 +675,13 @@ impl<'a, 'b> State<'a, 'b> {
|
|||
};
|
||||
|
||||
Placeholder::parse_fmt_string(&fmt_string).into_iter().fold(
|
||||
HashMap::new(),
|
||||
HashMap::default(),
|
||||
|mut bounds, pl| {
|
||||
if let Some(arg) = fmt_args.get(&pl.position) {
|
||||
if fields_type_params.contains_key(arg) {
|
||||
bounds
|
||||
.entry(fields_type_params[arg].clone())
|
||||
.or_insert_with(HashSet::new)
|
||||
.or_insert_with(HashSet::default)
|
||||
.insert(trait_name_to_trait_bound(pl.trait_name));
|
||||
}
|
||||
}
|
||||
|
@ -698,81 +694,31 @@ impl<'a, 'b> State<'a, 'b> {
|
|||
fields: &syn::Fields,
|
||||
) -> HashMap<syn::Type, HashSet<syn::TraitBound>> {
|
||||
if self.type_params.is_empty() {
|
||||
return HashMap::new();
|
||||
return HashMap::default();
|
||||
}
|
||||
if let syn::Fields::Unit = fields {
|
||||
return HashMap::new();
|
||||
return HashMap::default();
|
||||
}
|
||||
// infer_fmt() uses only first field.
|
||||
fields
|
||||
.iter()
|
||||
.take(1)
|
||||
.filter_map(|field| {
|
||||
self.get_type_param(&field.ty).map(|ty| {
|
||||
(
|
||||
ty,
|
||||
[trait_name_to_trait_bound(attribute_name_to_trait_name(
|
||||
self.trait_attr,
|
||||
))]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
utils::get_if_type_parameter_used_in_type(&self.type_params, &field.ty)
|
||||
.map(|ty| {
|
||||
(
|
||||
ty,
|
||||
[trait_name_to_trait_bound(attribute_name_to_trait_name(
|
||||
self.trait_attr,
|
||||
))]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
fn get_type_param(&self, ty: &syn::Type) -> Option<syn::Type> {
|
||||
if self.has_type_param_in(ty) {
|
||||
match ty {
|
||||
syn::Type::Reference(syn::TypeReference { elem: ty, .. }) => {
|
||||
Some(ty.deref().clone())
|
||||
}
|
||||
ty => Some(ty.clone()),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
fn has_type_param_in(&self, ty: &syn::Type) -> bool {
|
||||
match ty {
|
||||
syn::Type::Path(ty) => {
|
||||
if let Some(qself) = &ty.qself {
|
||||
if self.has_type_param_in(&qself.ty) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(segment) = ty.path.segments.first() {
|
||||
if self.type_params.contains(&segment.ident) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ty.path.segments.iter().any(|segment| {
|
||||
if let syn::PathArguments::AngleBracketed(arguments) =
|
||||
&segment.arguments
|
||||
{
|
||||
arguments.args.iter().any(|argument| match argument {
|
||||
syn::GenericArgument::Type(ty) => {
|
||||
self.has_type_param_in(ty)
|
||||
}
|
||||
syn::GenericArgument::Constraint(constraint) => {
|
||||
self.type_params.contains(&constraint.ident)
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
syn::Type::Reference(ty) => self.has_type_param_in(&ty.elem),
|
||||
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Representation of formatting placeholder.
|
||||
|
|
|
@ -0,0 +1,437 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{spanned::Spanned as _, Error, Result};
|
||||
|
||||
use crate::utils::{
|
||||
self, AttrParams, DeriveType, FullMetaInfo, HashSet, MetaInfo, MultiFieldData,
|
||||
State,
|
||||
};
|
||||
|
||||
pub fn expand(
|
||||
input: &syn::DeriveInput,
|
||||
trait_name: &'static str,
|
||||
) -> Result<TokenStream> {
|
||||
let syn::DeriveInput {
|
||||
ident, generics, ..
|
||||
} = input;
|
||||
|
||||
let state = State::with_attr_params(
|
||||
input,
|
||||
trait_name,
|
||||
quote!(::std::error),
|
||||
trait_name.to_lowercase(),
|
||||
allowed_attr_params(),
|
||||
)?;
|
||||
|
||||
let type_params: HashSet<_> = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter_map(|generic| match generic {
|
||||
syn::GenericParam::Type(ty) => Some(ty.ident.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let (bounds, source, backtrace) = match state.derive_type {
|
||||
DeriveType::Named | DeriveType::Unnamed => render_struct(&type_params, &state)?,
|
||||
DeriveType::Enum => render_enum(&type_params, &state)?,
|
||||
};
|
||||
|
||||
let source = source.map(|source| {
|
||||
quote! {
|
||||
fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
|
||||
#source
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let backtrace = backtrace.map(|backtrace| {
|
||||
quote! {
|
||||
fn backtrace(&self) -> Option<&::std::backtrace::Backtrace> {
|
||||
#backtrace
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let mut generics = generics.clone();
|
||||
|
||||
if !type_params.is_empty() {
|
||||
let generic_parameters = generics.params.iter();
|
||||
generics = utils::add_extra_where_clauses(
|
||||
&generics,
|
||||
quote! {
|
||||
where
|
||||
#ident<#(#generic_parameters),*>: ::std::fmt::Debug + ::std::fmt::Display
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if !bounds.is_empty() {
|
||||
let bounds = bounds.iter();
|
||||
generics = utils::add_extra_where_clauses(
|
||||
&generics,
|
||||
quote! {
|
||||
where
|
||||
#(#bounds: ::std::fmt::Debug + ::std::fmt::Display + ::std::error::Error + 'static),*
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||
|
||||
let render = quote! {
|
||||
impl#impl_generics ::std::error::Error for #ident#ty_generics #where_clause {
|
||||
#source
|
||||
#backtrace
|
||||
}
|
||||
};
|
||||
|
||||
Ok(render)
|
||||
}
|
||||
|
||||
fn render_struct(
|
||||
type_params: &HashSet<syn::Ident>,
|
||||
state: &State,
|
||||
) -> Result<(HashSet<syn::Type>, Option<TokenStream>, Option<TokenStream>)> {
|
||||
let parsed_fields = parse_fields(&type_params, &state)?;
|
||||
|
||||
let source = parsed_fields.render_source_as_struct();
|
||||
let backtrace = parsed_fields.render_backtrace_as_struct();
|
||||
|
||||
Ok((parsed_fields.bounds, source, backtrace))
|
||||
}
|
||||
|
||||
fn render_enum(
|
||||
type_params: &HashSet<syn::Ident>,
|
||||
state: &State,
|
||||
) -> Result<(HashSet<syn::Type>, Option<TokenStream>, Option<TokenStream>)> {
|
||||
let mut bounds = HashSet::default();
|
||||
let mut source_match_arms = Vec::new();
|
||||
let mut backtrace_match_arms = Vec::new();
|
||||
|
||||
for variant in state.enabled_variant_data().variants {
|
||||
let mut default_info = FullMetaInfo::default();
|
||||
default_info.enabled = true;
|
||||
|
||||
let state = State::from_variant(
|
||||
state.input,
|
||||
state.trait_name,
|
||||
state.trait_module.clone(),
|
||||
state.trait_attr.clone(),
|
||||
allowed_attr_params(),
|
||||
variant,
|
||||
default_info,
|
||||
)?;
|
||||
|
||||
let parsed_fields = parse_fields(&type_params, &state)?;
|
||||
|
||||
if let Some(expr) = parsed_fields.render_source_as_enum_variant_match_arm() {
|
||||
source_match_arms.push(expr);
|
||||
}
|
||||
|
||||
if let Some(expr) = parsed_fields.render_backtrace_as_enum_variant_match_arm() {
|
||||
backtrace_match_arms.push(expr);
|
||||
}
|
||||
|
||||
bounds.extend(parsed_fields.bounds.into_iter());
|
||||
}
|
||||
|
||||
let render = |match_arms: &mut Vec<TokenStream>| {
|
||||
if !match_arms.is_empty() && match_arms.len() < state.variants.len() {
|
||||
match_arms.push(quote!(_ => None));
|
||||
}
|
||||
|
||||
if !match_arms.is_empty() {
|
||||
let expr = quote! {
|
||||
match self {
|
||||
#(#match_arms),*
|
||||
}
|
||||
};
|
||||
|
||||
Some(expr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let source = render(&mut source_match_arms);
|
||||
let backtrace = render(&mut backtrace_match_arms);
|
||||
|
||||
Ok((bounds, source, backtrace))
|
||||
}
|
||||
|
||||
fn allowed_attr_params() -> AttrParams {
|
||||
AttrParams {
|
||||
enum_: vec!["ignore"],
|
||||
struct_: vec!["ignore"],
|
||||
variant: vec!["ignore"],
|
||||
field: vec!["ignore", "source", "backtrace"],
|
||||
}
|
||||
}
|
||||
|
||||
struct ParsedFields<'input, 'state> {
|
||||
data: MultiFieldData<'input, 'state>,
|
||||
source: Option<usize>,
|
||||
backtrace: Option<usize>,
|
||||
bounds: HashSet<syn::Type>,
|
||||
}
|
||||
|
||||
impl<'input, 'state> ParsedFields<'input, 'state> {
|
||||
fn new(data: MultiFieldData<'input, 'state>) -> Self {
|
||||
Self {
|
||||
data,
|
||||
source: None,
|
||||
backtrace: None,
|
||||
bounds: HashSet::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'input, 'state> ParsedFields<'input, 'state> {
|
||||
fn render_source_as_struct(&self) -> Option<TokenStream> {
|
||||
let source = self.source?;
|
||||
let ident = &self.data.members[source];
|
||||
Some(render_some(quote!(&#ident)))
|
||||
}
|
||||
|
||||
fn render_source_as_enum_variant_match_arm(&self) -> Option<TokenStream> {
|
||||
let source = self.source?;
|
||||
let pattern = self.data.matcher(&[source], &[quote!(source)]);
|
||||
let expr = render_some(quote!(source));
|
||||
Some(quote!(#pattern => #expr))
|
||||
}
|
||||
|
||||
fn render_backtrace_as_struct(&self) -> Option<TokenStream> {
|
||||
let backtrace = self.backtrace?;
|
||||
let backtrace_expr = &self.data.members[backtrace];
|
||||
Some(quote!(Some(&#backtrace_expr)))
|
||||
}
|
||||
|
||||
fn render_backtrace_as_enum_variant_match_arm(&self) -> Option<TokenStream> {
|
||||
let backtrace = self.backtrace?;
|
||||
let pattern = self.data.matcher(&[backtrace], &[quote!(backtrace)]);
|
||||
Some(quote!(#pattern => Some(backtrace)))
|
||||
}
|
||||
}
|
||||
|
||||
fn render_some<T>(expr: T) -> TokenStream
|
||||
where
|
||||
T: quote::ToTokens,
|
||||
{
|
||||
quote!(Some(#expr as &(dyn ::std::error::Error + 'static)))
|
||||
}
|
||||
|
||||
fn parse_fields<'input, 'state>(
|
||||
type_params: &HashSet<syn::Ident>,
|
||||
state: &'state State<'input>,
|
||||
) -> Result<ParsedFields<'input, 'state>> {
|
||||
let mut parsed_fields = match state.derive_type {
|
||||
DeriveType::Named => {
|
||||
parse_fields_impl(state, |attr, field, _| {
|
||||
// Unwrapping is safe, cause fields in named struct
|
||||
// always have an ident
|
||||
let ident = field.ident.as_ref().unwrap();
|
||||
|
||||
match attr {
|
||||
"source" => ident == "source",
|
||||
"backtrace" => {
|
||||
ident == "backtrace"
|
||||
|| is_type_path_ends_with_segment(&field.ty, "Backtrace")
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
DeriveType::Unnamed => {
|
||||
let mut parsed_fields =
|
||||
parse_fields_impl(state, |attr, field, len| match attr {
|
||||
"source" => {
|
||||
len == 1
|
||||
&& !is_type_path_ends_with_segment(&field.ty, "Backtrace")
|
||||
}
|
||||
"backtrace" => {
|
||||
is_type_path_ends_with_segment(&field.ty, "Backtrace")
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})?;
|
||||
|
||||
parsed_fields.source = parsed_fields
|
||||
.source
|
||||
.or_else(|| infer_source_field(&state.fields, &parsed_fields));
|
||||
|
||||
Ok(parsed_fields)
|
||||
}
|
||||
|
||||
_ => unreachable!(),
|
||||
}?;
|
||||
|
||||
if let Some(source) = parsed_fields.source {
|
||||
add_bound_if_type_parameter_used_in_type(
|
||||
&mut parsed_fields.bounds,
|
||||
type_params,
|
||||
&state.fields[source].ty,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(parsed_fields)
|
||||
}
|
||||
|
||||
/// Checks if `ty` is [`syn::Type::Path`] and ends with segment matching `tail`
|
||||
/// and doesn't contain any generic parameters.
|
||||
fn is_type_path_ends_with_segment(ty: &syn::Type, tail: &str) -> bool {
|
||||
let ty = match ty {
|
||||
syn::Type::Path(ty) => ty,
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
// Unwrapping is safe, cause 'syn::TypePath.path.segments'
|
||||
// have to have at least one segment
|
||||
let segment = ty.path.segments.last().unwrap();
|
||||
|
||||
match segment.arguments {
|
||||
syn::PathArguments::None => (),
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
segment.ident == tail
|
||||
}
|
||||
|
||||
fn infer_source_field(
|
||||
fields: &[&syn::Field],
|
||||
parsed_fields: &ParsedFields,
|
||||
) -> Option<usize> {
|
||||
// if we have exactly two fields
|
||||
if fields.len() != 2 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// no source field was specified/inferred
|
||||
if parsed_fields.source.is_some() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// but one of the fields was specified/inferred as backtrace field
|
||||
if let Some(backtrace) = parsed_fields.backtrace {
|
||||
// then infer *other field* as source field
|
||||
let source = (backtrace + 1) % 2;
|
||||
// unless it was explicitly marked as non-source
|
||||
if parsed_fields.data.infos[source].info.source != Some(false) {
|
||||
return Some(source);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn parse_fields_impl<'input, 'state, P>(
|
||||
state: &'state State<'input>,
|
||||
is_valid_default_field_for_attr: P,
|
||||
) -> Result<ParsedFields<'input, 'state>>
|
||||
where
|
||||
P: Fn(&str, &syn::Field, usize) -> bool,
|
||||
{
|
||||
let MultiFieldData { fields, infos, .. } = state.enabled_fields_data();
|
||||
|
||||
let iter = fields
|
||||
.iter()
|
||||
.zip(infos.iter().map(|info| &info.info))
|
||||
.enumerate()
|
||||
.map(|(index, (field, info))| (index, *field, info));
|
||||
|
||||
let source = parse_field_impl(
|
||||
&is_valid_default_field_for_attr,
|
||||
state.fields.len(),
|
||||
iter.clone(),
|
||||
"source",
|
||||
|info| info.source,
|
||||
)?;
|
||||
|
||||
let backtrace = parse_field_impl(
|
||||
&is_valid_default_field_for_attr,
|
||||
state.fields.len(),
|
||||
iter.clone(),
|
||||
"backtrace",
|
||||
|info| info.backtrace,
|
||||
)?;
|
||||
|
||||
let mut parsed_fields = ParsedFields::new(state.enabled_fields_data());
|
||||
|
||||
if let Some((index, _, _)) = source {
|
||||
parsed_fields.source = Some(index);
|
||||
}
|
||||
|
||||
if let Some((index, _, _)) = backtrace {
|
||||
parsed_fields.backtrace = Some(index);
|
||||
}
|
||||
|
||||
Ok(parsed_fields)
|
||||
}
|
||||
|
||||
fn parse_field_impl<'a, P, V>(
|
||||
is_valid_default_field_for_attr: &P,
|
||||
len: usize,
|
||||
iter: impl Iterator<Item = (usize, &'a syn::Field, &'a MetaInfo)> + Clone,
|
||||
attr: &str,
|
||||
value: V,
|
||||
) -> Result<Option<(usize, &'a syn::Field, &'a MetaInfo)>>
|
||||
where
|
||||
P: Fn(&str, &syn::Field, usize) -> bool,
|
||||
V: Fn(&MetaInfo) -> Option<bool>,
|
||||
{
|
||||
let explicit_fields = iter.clone().filter(|(_, _, info)| match value(info) {
|
||||
Some(true) => true,
|
||||
_ => false,
|
||||
});
|
||||
|
||||
let inferred_fields = iter.filter(|(_, field, info)| match value(info) {
|
||||
None => is_valid_default_field_for_attr(attr, field, len),
|
||||
_ => false,
|
||||
});
|
||||
|
||||
let field = assert_iter_contains_zero_or_one_item(
|
||||
explicit_fields,
|
||||
&format!(
|
||||
"Multiple `{}` attributes specified. \
|
||||
Single attribute per struct/enum variant allowed.",
|
||||
attr
|
||||
),
|
||||
)?;
|
||||
|
||||
let field = match field {
|
||||
field @ Some(_) => field,
|
||||
None => assert_iter_contains_zero_or_one_item(
|
||||
inferred_fields,
|
||||
"Conflicting fields found. Consider specifying some \
|
||||
`#[error(...)]` attributes to resolve conflict.",
|
||||
)?,
|
||||
};
|
||||
|
||||
Ok(field)
|
||||
}
|
||||
|
||||
fn assert_iter_contains_zero_or_one_item<'a>(
|
||||
mut iter: impl Iterator<Item = (usize, &'a syn::Field, &'a MetaInfo)>,
|
||||
error_msg: &str,
|
||||
) -> Result<Option<(usize, &'a syn::Field, &'a MetaInfo)>> {
|
||||
let item = match iter.next() {
|
||||
Some(item) => item,
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
if let Some((_, field, _)) = iter.next() {
|
||||
return Err(Error::new(field.span(), error_msg));
|
||||
}
|
||||
|
||||
Ok(Some(item))
|
||||
}
|
||||
|
||||
fn add_bound_if_type_parameter_used_in_type(
|
||||
bounds: &mut HashSet<syn::Type>,
|
||||
type_params: &HashSet<syn::Ident>,
|
||||
ty: &syn::Type,
|
||||
) {
|
||||
if let Some(ty) = utils::get_if_type_parameter_used_in_type(type_params, ty) {
|
||||
bounds.insert(ty);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,14 @@
|
|||
use crate::utils::{
|
||||
add_where_clauses_for_new_ident, AttrParams, DeriveType, MultiFieldData, State,
|
||||
};
|
||||
use std::iter;
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
use std::collections::HashMap;
|
||||
use syn::{parse::Result, DeriveInput, Ident, Index};
|
||||
|
||||
use crate::utils::{
|
||||
add_where_clauses_for_new_ident, AttrParams, DeriveType, HashMap, MultiFieldData,
|
||||
RefType, State,
|
||||
};
|
||||
|
||||
/// Provides the hook to expand `#[derive(From)]` into an implementation of `From`
|
||||
pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> {
|
||||
let state = State::with_attr_params(
|
||||
|
@ -15,8 +18,8 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStre
|
|||
trait_name.to_lowercase(),
|
||||
AttrParams {
|
||||
enum_: vec!["forward", "ignore"],
|
||||
variant: vec!["forward", "ignore"],
|
||||
struct_: vec!["forward"],
|
||||
variant: vec!["forward", "ignore", "types"],
|
||||
struct_: vec!["forward", "types"],
|
||||
field: vec!["forward"],
|
||||
},
|
||||
)?;
|
||||
|
@ -31,70 +34,80 @@ pub fn struct_from(input: &DeriveInput, state: &State) -> TokenStream {
|
|||
let multi_field_data = state.enabled_fields_data();
|
||||
let MultiFieldData {
|
||||
fields,
|
||||
variant_info,
|
||||
infos,
|
||||
input_type,
|
||||
trait_path,
|
||||
..
|
||||
} = multi_field_data.clone();
|
||||
|
||||
let mut new_generics = input.generics.clone();
|
||||
let sub_items: Vec<_> = infos
|
||||
.iter()
|
||||
.zip(fields.iter())
|
||||
.enumerate()
|
||||
.map(|(i, (info, field))| {
|
||||
let additional_types = variant_info.additional_types(RefType::No);
|
||||
let mut impls = Vec::with_capacity(additional_types.len() + 1);
|
||||
for explicit_type in iter::once(None).chain(additional_types.iter().map(Some)) {
|
||||
let mut new_generics = input.generics.clone();
|
||||
|
||||
let mut initializers = Vec::with_capacity(infos.len());
|
||||
let mut from_types = Vec::with_capacity(infos.len());
|
||||
for (i, (info, field)) in infos.iter().zip(fields.iter()).enumerate() {
|
||||
let field_type = &field.ty;
|
||||
let variable = if fields.len() == 1 {
|
||||
quote!(original)
|
||||
quote! { original }
|
||||
} else {
|
||||
let tuple_index = Index::from(i);
|
||||
quote!(original.#tuple_index)
|
||||
quote! { original.#tuple_index }
|
||||
};
|
||||
if info.forward {
|
||||
if let Some(type_) = explicit_type {
|
||||
initializers.push(quote! {
|
||||
<#field_type as #trait_path<#type_>>::from(#variable)
|
||||
});
|
||||
from_types.push(quote! { #type_ });
|
||||
} else if info.forward {
|
||||
let type_param =
|
||||
&Ident::new(&format!("__FromT{}", i), Span::call_site());
|
||||
let sub_trait_path = quote!(#trait_path<#type_param>);
|
||||
let sub_trait_path = quote! { #trait_path<#type_param> };
|
||||
let type_where_clauses = quote! {
|
||||
where #field_type: #sub_trait_path
|
||||
};
|
||||
new_generics = add_where_clauses_for_new_ident(
|
||||
&input.generics,
|
||||
&new_generics,
|
||||
&[field],
|
||||
type_param,
|
||||
type_where_clauses,
|
||||
true,
|
||||
);
|
||||
let casted_trait = quote!(<#field_type as #sub_trait_path>);
|
||||
(quote!(#casted_trait::from(#variable)), quote!(#type_param))
|
||||
let casted_trait = quote! { <#field_type as #sub_trait_path> };
|
||||
initializers.push(quote! { #casted_trait::from(#variable) });
|
||||
from_types.push(quote! { #type_param });
|
||||
} else {
|
||||
(variable, quote!(#field_type))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let initializers: Vec<_> = sub_items.iter().map(|i| &i.0).collect();
|
||||
let from_types: Vec<_> = sub_items.iter().map(|i| &i.1).collect();
|
||||
|
||||
let body = multi_field_data.initializer(&initializers);
|
||||
let (impl_generics, _, where_clause) = new_generics.split_for_impl();
|
||||
let (_, ty_generics, _) = input.generics.split_for_impl();
|
||||
|
||||
quote! {
|
||||
impl#impl_generics #trait_path<(#(#from_types),*)> for
|
||||
#input_type#ty_generics #where_clause {
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline]
|
||||
fn from(original: (#(#from_types),*)) -> #input_type#ty_generics {
|
||||
#body
|
||||
initializers.push(variable);
|
||||
from_types.push(quote! { #field_type });
|
||||
}
|
||||
}
|
||||
|
||||
let body = multi_field_data.initializer(&initializers);
|
||||
let (impl_generics, _, where_clause) = new_generics.split_for_impl();
|
||||
let (_, ty_generics, _) = input.generics.split_for_impl();
|
||||
|
||||
impls.push(quote! {
|
||||
#[automatically_derived]
|
||||
impl#impl_generics #trait_path<(#(#from_types),*)> for
|
||||
#input_type#ty_generics #where_clause {
|
||||
|
||||
#[inline]
|
||||
fn from(original: (#(#from_types),*)) -> #input_type#ty_generics {
|
||||
#body
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
quote! { #( #impls )* }
|
||||
}
|
||||
|
||||
fn enum_from(input: &DeriveInput, state: State) -> TokenStream {
|
||||
let mut tokens = TokenStream::new();
|
||||
|
||||
let mut variants_per_types = HashMap::new();
|
||||
let mut variants_per_types = HashMap::default();
|
||||
for variant_state in state.enabled_variant_data().variant_states {
|
||||
let multi_field_data = variant_state.enabled_fields_data();
|
||||
let MultiFieldData { field_types, .. } = multi_field_data.clone();
|
||||
|
@ -112,7 +125,7 @@ fn enum_from(input: &DeriveInput, state: State) -> TokenStream {
|
|||
..
|
||||
} = multi_field_data.clone();
|
||||
// If there would be a conflict on a empty tuple derive, ignore the
|
||||
// variants that are not explicitely enabled or have explicitely enabled
|
||||
// variants that are not explicitly enabled or have explicitly enabled
|
||||
// or disabled fields
|
||||
if field_types.is_empty()
|
||||
&& variant_states.len() > 1
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
use crate::utils::{add_extra_generic_param, AttrParams, MultiFieldData, State};
|
||||
use std::iter;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{parse::Result, DeriveInput};
|
||||
|
||||
use crate::utils::{add_extra_generic_param, AttrParams, MultiFieldData, State};
|
||||
|
||||
/// Provides the hook to expand `#[derive(Into)]` into an implementation of `Into`
|
||||
pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> {
|
||||
let state = State::with_attr_params(
|
||||
|
@ -13,7 +16,7 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStre
|
|||
AttrParams {
|
||||
enum_: vec!["ignore", "owned", "ref", "ref_mut"],
|
||||
variant: vec!["ignore", "owned", "ref", "ref_mut"],
|
||||
struct_: vec!["ignore", "owned", "ref", "ref_mut"],
|
||||
struct_: vec!["ignore", "owned", "ref", "ref_mut", "types"],
|
||||
field: vec!["ignore"],
|
||||
},
|
||||
)?;
|
||||
|
@ -41,18 +44,40 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStre
|
|||
input.generics.split_for_impl()
|
||||
};
|
||||
|
||||
let into = quote! {
|
||||
impl#impl_generics ::core::convert::From<#reference_with_lifetime #input_type#ty_generics> for
|
||||
(#(#reference_with_lifetime #field_types),*) #where_clause {
|
||||
let additional_types = variant_info.additional_types(ref_type);
|
||||
for explicit_type in iter::once(None).chain(additional_types.iter().map(Some)) {
|
||||
let into_types: Vec<_> = field_types
|
||||
.iter()
|
||||
.map(|field_type| {
|
||||
// No, `.unwrap_or()` won't work here, because we use different types.
|
||||
if let Some(type_) = explicit_type {
|
||||
quote! { #reference_with_lifetime #type_ }
|
||||
} else {
|
||||
quote! { #reference_with_lifetime #field_type }
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline]
|
||||
fn from(original: #reference_with_lifetime #input_type#ty_generics) -> (#(#reference_with_lifetime #field_types),*) {
|
||||
(#(#reference original.#field_idents),*)
|
||||
let initializers = field_idents.iter().map(|field_ident| {
|
||||
if let Some(type_) = explicit_type {
|
||||
quote! { <#reference #type_>::from(#reference original.#field_ident) }
|
||||
} else {
|
||||
quote! { #reference original.#field_ident }
|
||||
}
|
||||
}
|
||||
};
|
||||
into.to_tokens(&mut tokens);
|
||||
});
|
||||
|
||||
(quote! {
|
||||
#[automatically_derived]
|
||||
impl#impl_generics ::core::convert::From<#reference_with_lifetime #input_type#ty_generics> for
|
||||
(#(#into_types),*) #where_clause {
|
||||
|
||||
#[inline]
|
||||
fn from(original: #reference_with_lifetime #input_type#ty_generics) -> (#(#into_types),*) {
|
||||
(#(#initializers),*)
|
||||
}
|
||||
}
|
||||
}).to_tokens(&mut tokens);
|
||||
}
|
||||
}
|
||||
Ok(tokens)
|
||||
}
|
||||
|
|
|
@ -90,6 +90,11 @@
|
|||
//! 1. [`Display`-like], contains `Display`, `Binary`, `Octal`, `LowerHex`,
|
||||
//! `UpperHex`, `LowerExp`, `UpperExp`, `Pointer`
|
||||
//!
|
||||
//! ### Error-handling traits
|
||||
//! These traits are used to define error-types.
|
||||
//!
|
||||
//! 1. [`Error`]
|
||||
//!
|
||||
//! ### Operators
|
||||
//!
|
||||
//! These are traits that can be used for operator overloading.
|
||||
|
@ -160,6 +165,8 @@
|
|||
//!
|
||||
//! [`Display`-like]: https://jeltef.github.io/derive_more/derive_more/display.html
|
||||
//!
|
||||
//! [`Error`]: https://jeltef.github.io/derive_more/derive_more/error.html
|
||||
//!
|
||||
//! [`Index`]: https://jeltef.github.io/derive_more/derive_more/index_op.html
|
||||
//! [`Deref`]: https://jeltef.github.io/derive_more/derive_more/deref.html
|
||||
//! [`Not`-like]: https://jeltef.github.io/derive_more/derive_more/not.html
|
||||
|
@ -173,11 +180,12 @@
|
|||
//!
|
||||
//! [`Constructor`]: https://jeltef.github.io/derive_more/derive_more/constructor.html
|
||||
|
||||
// Suppress Clippy tips to use `matches!` macro, because minimal supported Rust version is 1.36.0.
|
||||
// Remove this suppression once minimal supported Rust version is bumped up to 1.42.0 or above.
|
||||
#![cfg_attr(nightly, allow(clippy::match_like_matches_macro))]
|
||||
#![recursion_limit = "128"]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro2;
|
||||
use syn;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use syn::parse::Error as ParseError;
|
||||
|
@ -207,6 +215,8 @@ mod deref;
|
|||
mod deref_mut;
|
||||
#[cfg(feature = "display")]
|
||||
mod display;
|
||||
#[cfg(feature = "error")]
|
||||
mod error;
|
||||
#[cfg(feature = "from")]
|
||||
mod from;
|
||||
#[cfg(feature = "from_str")]
|
||||
|
@ -352,6 +362,8 @@ create_derive!(
|
|||
create_derive!("sum", sum_like, Sum, sum_derive);
|
||||
create_derive!("sum", sum_like, Product, product_derive);
|
||||
|
||||
create_derive!("error", error, Error, error_derive, error);
|
||||
|
||||
create_derive!("from_str", from_str, FromStr, from_str_derive);
|
||||
|
||||
create_derive!("display", display, Display, display_derive, display);
|
||||
|
|
|
@ -56,7 +56,7 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStre
|
|||
Ok(quote!(
|
||||
impl#impl_generics #trait_path<#scalar_ident> for #input_type#ty_generics #where_clause{
|
||||
#[inline]
|
||||
fn #method_ident(&mut self, rhs: #scalar_ident#ty_generics) {
|
||||
fn #method_ident(&mut self, rhs: #scalar_ident) {
|
||||
#(#exprs;
|
||||
)*
|
||||
}
|
||||
|
|
|
@ -654,9 +654,11 @@ fn __parse_format_spec<'input>(
|
|||
Matched(__pos, _) => {
|
||||
let __choice_res = {
|
||||
let __seq_res = {
|
||||
let mut __repeat_pos =
|
||||
let mut
|
||||
__repeat_pos =
|
||||
__pos;
|
||||
let mut __repeat_value =
|
||||
let mut
|
||||
__repeat_value =
|
||||
vec![];
|
||||
loop {
|
||||
let __pos =
|
||||
|
@ -717,7 +719,8 @@ fn __parse_format_spec<'input>(
|
|||
let __choice_res = {
|
||||
let mut __repeat_pos =
|
||||
__pos;
|
||||
let mut __repeat_value = vec![];
|
||||
let mut
|
||||
__repeat_value = vec![];
|
||||
loop {
|
||||
let __pos = __repeat_pos ;
|
||||
let __step_res =
|
||||
|
|
|
@ -4,9 +4,10 @@ use crate::utils::{
|
|||
};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{quote, ToTokens};
|
||||
use std::collections::HashMap;
|
||||
use syn::{DeriveInput, Result};
|
||||
|
||||
use crate::utils::HashMap;
|
||||
|
||||
/// Provides the hook to expand `#[derive(TryInto)]` into an implementation of `TryInto`
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> {
|
||||
|
@ -26,7 +27,7 @@ pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStre
|
|||
panic!("Only enums can derive TryInto");
|
||||
}
|
||||
|
||||
let mut variants_per_types = HashMap::new();
|
||||
let mut variants_per_types = HashMap::default();
|
||||
|
||||
for variant_state in state.enabled_variant_data().variant_states {
|
||||
let multi_field_data = variant_state.enabled_fields_data();
|
||||
|
|
|
@ -1,16 +1,29 @@
|
|||
#![cfg_attr(not(feature = "default"), allow(dead_code))]
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{
|
||||
parse::{Error, Result},
|
||||
parse_str,
|
||||
spanned::Spanned,
|
||||
Attribute, Data, DeriveInput, Field, Fields, FieldsNamed, FieldsUnnamed,
|
||||
GenericParam, Generics, Ident, ImplGenerics, Index, Meta, NestedMeta, Type,
|
||||
parse_quote, punctuated::Punctuated, spanned::Spanned, Attribute, Data,
|
||||
DeriveInput, Error, Field, Fields, FieldsNamed, FieldsUnnamed, GenericParam,
|
||||
Generics, Ident, ImplGenerics, Index, Meta, NestedMeta, Result, Token, Type,
|
||||
TypeGenerics, TypeParamBound, Variant, WhereClause,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub struct DeterministicState;
|
||||
|
||||
impl std::hash::BuildHasher for DeterministicState {
|
||||
type Hasher = std::collections::hash_map::DefaultHasher;
|
||||
|
||||
fn build_hasher(&self) -> Self::Hasher {
|
||||
Self::Hasher::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub type HashMap<K, V> = std::collections::HashMap<K, V, DeterministicState>;
|
||||
pub type HashSet<K> = std::collections::HashSet<K, DeterministicState>;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||
pub enum RefType {
|
||||
No,
|
||||
Ref,
|
||||
|
@ -63,6 +76,15 @@ impl RefType {
|
|||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_attr_name(name: &str) -> Self {
|
||||
match name {
|
||||
"owned" => RefType::No,
|
||||
"ref" => RefType::Ref,
|
||||
"ref_mut" => RefType::Mut,
|
||||
_ => panic!("'{}' is not a RefType", name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn numbered_vars(count: usize, prefix: &str) -> Vec<Ident> {
|
||||
|
@ -99,10 +121,9 @@ pub fn add_extra_type_param_bound_op_output<'a>(
|
|||
let mut generics = generics.clone();
|
||||
for type_param in &mut generics.type_params_mut() {
|
||||
let type_ident = &type_param.ident;
|
||||
let bound: TypeParamBound = parse_str(
|
||||
"e!(::core::ops::#trait_ident<Output=#type_ident>).to_string(),
|
||||
)
|
||||
.unwrap();
|
||||
let bound: TypeParamBound = parse_quote! {
|
||||
::core::ops::#trait_ident<Output=#type_ident>
|
||||
};
|
||||
type_param.bounds.push(bound)
|
||||
}
|
||||
|
||||
|
@ -121,7 +142,7 @@ pub fn add_extra_ty_param_bound<'a>(
|
|||
bound: &'a TokenStream,
|
||||
) -> Generics {
|
||||
let mut generics = generics.clone();
|
||||
let bound: TypeParamBound = parse_str(&bound.to_string()).unwrap();
|
||||
let bound: TypeParamBound = parse_quote! { #bound };
|
||||
for type_param in &mut generics.type_params_mut() {
|
||||
type_param.bounds.push(bound.clone())
|
||||
}
|
||||
|
@ -154,7 +175,7 @@ pub fn add_extra_generic_param(
|
|||
generics: &Generics,
|
||||
generic_param: TokenStream,
|
||||
) -> Generics {
|
||||
let generic_param: GenericParam = parse_str(&generic_param.to_string()).unwrap();
|
||||
let generic_param: GenericParam = parse_quote! { #generic_param };
|
||||
let mut generics = generics.clone();
|
||||
generics.params.push(generic_param);
|
||||
|
||||
|
@ -165,8 +186,7 @@ pub fn add_extra_where_clauses(
|
|||
generics: &Generics,
|
||||
type_where_clauses: TokenStream,
|
||||
) -> Generics {
|
||||
let mut type_where_clauses: WhereClause =
|
||||
parse_str(&type_where_clauses.to_string()).unwrap();
|
||||
let mut type_where_clauses: WhereClause = parse_quote! { #type_where_clauses };
|
||||
let mut new_generics = generics.clone();
|
||||
if let Some(old_where) = new_generics.where_clause {
|
||||
type_where_clauses.predicates.extend(old_where.predicates)
|
||||
|
@ -210,7 +230,7 @@ fn panic_one_field(trait_name: &str, trait_attr: &str) -> ! {
|
|||
))
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum DeriveType {
|
||||
Unnamed,
|
||||
Named,
|
||||
|
@ -261,6 +281,10 @@ impl AttrParams {
|
|||
field: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ignore_and_forward() -> AttrParams {
|
||||
AttrParams::new(vec!["ignore", "forward"])
|
||||
}
|
||||
}
|
||||
|
||||
impl<'input> State<'input> {
|
||||
|
@ -270,12 +294,13 @@ impl<'input> State<'input> {
|
|||
trait_module: TokenStream,
|
||||
trait_attr: String,
|
||||
) -> Result<State<'arg_input>> {
|
||||
State::with_attr_params(
|
||||
State::new_impl(
|
||||
input,
|
||||
trait_name,
|
||||
trait_module,
|
||||
trait_attr,
|
||||
AttrParams::default(),
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -285,12 +310,13 @@ impl<'input> State<'input> {
|
|||
trait_module: TokenStream,
|
||||
trait_attr: String,
|
||||
) -> Result<State<'arg_input>> {
|
||||
State::with_attr_params(
|
||||
State::new_impl(
|
||||
input,
|
||||
trait_name,
|
||||
trait_module,
|
||||
trait_attr,
|
||||
AttrParams::new(vec!["ignore"]),
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -300,12 +326,13 @@ impl<'input> State<'input> {
|
|||
trait_module: TokenStream,
|
||||
trait_attr: String,
|
||||
) -> Result<State<'arg_input>> {
|
||||
State::with_attr_params(
|
||||
State::new_impl(
|
||||
input,
|
||||
trait_name,
|
||||
trait_module,
|
||||
trait_attr,
|
||||
AttrParams::new(vec!["ignore", "forward"]),
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -315,12 +342,13 @@ impl<'input> State<'input> {
|
|||
trait_module: TokenStream,
|
||||
trait_attr: String,
|
||||
) -> Result<State<'arg_input>> {
|
||||
State::with_attr_params(
|
||||
State::new_impl(
|
||||
input,
|
||||
trait_name,
|
||||
trait_module,
|
||||
trait_attr,
|
||||
AttrParams::new(vec!["ignore", "owned", "ref", "ref_mut"]),
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -330,6 +358,42 @@ impl<'input> State<'input> {
|
|||
trait_module: TokenStream,
|
||||
trait_attr: String,
|
||||
allowed_attr_params: AttrParams,
|
||||
) -> Result<State<'arg_input>> {
|
||||
State::new_impl(
|
||||
input,
|
||||
trait_name,
|
||||
trait_module,
|
||||
trait_attr,
|
||||
allowed_attr_params,
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn with_type_bound<'arg_input>(
|
||||
input: &'arg_input DeriveInput,
|
||||
trait_name: &'static str,
|
||||
trait_module: TokenStream,
|
||||
trait_attr: String,
|
||||
allowed_attr_params: AttrParams,
|
||||
add_type_bound: bool,
|
||||
) -> Result<State<'arg_input>> {
|
||||
Self::new_impl(
|
||||
input,
|
||||
trait_name,
|
||||
trait_module,
|
||||
trait_attr,
|
||||
allowed_attr_params,
|
||||
add_type_bound,
|
||||
)
|
||||
}
|
||||
|
||||
fn new_impl<'arg_input>(
|
||||
input: &'arg_input DeriveInput,
|
||||
trait_name: &'static str,
|
||||
trait_module: TokenStream,
|
||||
trait_attr: String,
|
||||
allowed_attr_params: AttrParams,
|
||||
add_type_bound: bool,
|
||||
) -> Result<State<'arg_input>> {
|
||||
let trait_name = trait_name.trim_end_matches("ToInner");
|
||||
let trait_ident = Ident::new(trait_name, Span::call_site());
|
||||
|
@ -352,7 +416,7 @@ impl<'input> State<'input> {
|
|||
data_enum.variants.iter().collect(),
|
||||
),
|
||||
Data::Union(_) => {
|
||||
panic!(format!("can not derive({}) for union", trait_name))
|
||||
panic!(format!("cannot derive({}) for union", trait_name))
|
||||
}
|
||||
};
|
||||
let attrs: Vec<_> = if derive_type == DeriveType::Enum {
|
||||
|
@ -380,14 +444,32 @@ impl<'input> State<'input> {
|
|||
.filter_map(|info| info.enabled.map(|_| info))
|
||||
.next();
|
||||
|
||||
let defaults = struct_meta_info.to_full(FullMetaInfo {
|
||||
// Default to enabled true, except when first attribute has explicit
|
||||
// enabling
|
||||
enabled: first_match.map_or(true, |info| !info.enabled.unwrap()),
|
||||
// Default to enabled true, except when first attribute has explicit
|
||||
// enabling.
|
||||
//
|
||||
// Except for derive Error.
|
||||
//
|
||||
// The way `else` case works is that if any field have any valid
|
||||
// attribute specified, then all fields without any attributes
|
||||
// specified are filtered out from `State::enabled_fields`.
|
||||
//
|
||||
// However, derive Error *infers* fields and there are cases when
|
||||
// one of the fields may have an attribute specified, but another field
|
||||
// would be inferred. So, for derive Error macro we default enabled
|
||||
// to true unconditionally (i.e., even if some fields have attributes
|
||||
// specified).
|
||||
let default_enabled = if trait_name == "Error" {
|
||||
true
|
||||
} else {
|
||||
first_match.map_or(true, |info| !info.enabled.unwrap())
|
||||
};
|
||||
|
||||
let defaults = struct_meta_info.into_full(FullMetaInfo {
|
||||
enabled: default_enabled,
|
||||
forward: false,
|
||||
// Default to owned true, except when first attribute has one of owned,
|
||||
// ref or ref_mut
|
||||
// - not a single attibute means default true
|
||||
// - not a single attribute means default true
|
||||
// - an attribute, but non of owned, ref or ref_mut means default true
|
||||
// - an attribute, and owned, ref or ref_mut means default false
|
||||
owned: first_match.map_or(true, |info| {
|
||||
|
@ -399,14 +481,14 @@ impl<'input> State<'input> {
|
|||
});
|
||||
|
||||
let full_meta_infos: Vec<_> = meta_infos
|
||||
.iter()
|
||||
.map(|info| info.to_full(defaults))
|
||||
.into_iter()
|
||||
.map(|info| info.into_full(defaults.clone()))
|
||||
.collect();
|
||||
|
||||
let variant_states: Result<Vec<_>> = if derive_type == DeriveType::Enum {
|
||||
variants
|
||||
.iter()
|
||||
.zip(full_meta_infos.iter().copied())
|
||||
.zip(full_meta_infos.iter().cloned())
|
||||
.map(|(variant, info)| {
|
||||
State::from_variant(
|
||||
input,
|
||||
|
@ -422,7 +504,12 @@ impl<'input> State<'input> {
|
|||
} else {
|
||||
Ok(vec![])
|
||||
};
|
||||
let generics = add_extra_ty_param_bound(&input.generics, &trait_path);
|
||||
|
||||
let generics = if add_type_bound {
|
||||
add_extra_ty_param_bound(&input.generics, &trait_path)
|
||||
} else {
|
||||
input.generics.clone()
|
||||
};
|
||||
|
||||
Ok(State {
|
||||
input,
|
||||
|
@ -474,8 +561,8 @@ impl<'input> State<'input> {
|
|||
.collect();
|
||||
let meta_infos = meta_infos?;
|
||||
let full_meta_infos: Vec<_> = meta_infos
|
||||
.iter()
|
||||
.map(|info| info.to_full(default_info))
|
||||
.into_iter()
|
||||
.map(|info| info.into_full(default_info.clone()))
|
||||
.collect();
|
||||
|
||||
let generics = add_extra_ty_param_bound(&input.generics, &trait_path);
|
||||
|
@ -519,7 +606,7 @@ impl<'input> State<'input> {
|
|||
field: data.fields[0],
|
||||
field_type: data.field_types[0],
|
||||
member: data.members[0].clone(),
|
||||
info: data.infos[0],
|
||||
info: data.infos[0].clone(),
|
||||
field_ident: data.field_idents[0].clone(),
|
||||
trait_path: data.trait_path,
|
||||
trait_path_with_params: data.trait_path_with_params.clone(),
|
||||
|
@ -533,7 +620,7 @@ impl<'input> State<'input> {
|
|||
|
||||
pub fn enabled_fields_data<'state>(&'state self) -> MultiFieldData<'input, 'state> {
|
||||
if self.derive_type == DeriveType::Enum {
|
||||
panic!(format!("can not derive({}) for enum", self.trait_name))
|
||||
panic!(format!("cannot derive({}) for enum", self.trait_name))
|
||||
}
|
||||
let fields = self.enabled_fields();
|
||||
let field_idents = self.enabled_fields_idents();
|
||||
|
@ -568,7 +655,7 @@ impl<'input> State<'input> {
|
|||
input_type,
|
||||
variant_type,
|
||||
variant_name,
|
||||
variant_info: self.default_info,
|
||||
variant_info: self.default_info.clone(),
|
||||
fields,
|
||||
field_types,
|
||||
field_indexes,
|
||||
|
@ -675,7 +762,7 @@ impl<'input> State<'input> {
|
|||
self.full_meta_infos
|
||||
.iter()
|
||||
.filter(|info| info.enabled)
|
||||
.copied()
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
@ -773,25 +860,20 @@ impl<'input, 'state> SingleFieldData<'input, 'state> {
|
|||
fn get_meta_info(
|
||||
trait_attr: &str,
|
||||
attrs: &[Attribute],
|
||||
allowed_attr_params: &[&'static str],
|
||||
allowed_attr_params: &[&str],
|
||||
) -> Result<MetaInfo> {
|
||||
let mut it = attrs
|
||||
.iter()
|
||||
.filter_map(|m| m.parse_meta().ok())
|
||||
.filter(|m| {
|
||||
if let Some(ident) = m.path().segments.first().map(|p| &p.ident) {
|
||||
ident == trait_attr
|
||||
} else {
|
||||
false
|
||||
}
|
||||
m.path()
|
||||
.segments
|
||||
.first()
|
||||
.map(|p| p.ident == trait_attr)
|
||||
.unwrap_or_default()
|
||||
});
|
||||
let mut info = MetaInfo {
|
||||
enabled: None,
|
||||
forward: None,
|
||||
owned: None,
|
||||
ref_: None,
|
||||
ref_mut: None,
|
||||
};
|
||||
|
||||
let mut info = MetaInfo::default();
|
||||
|
||||
let meta = if let Some(meta) = it.next() {
|
||||
meta
|
||||
|
@ -805,81 +887,222 @@ fn get_meta_info(
|
|||
|
||||
info.enabled = Some(true);
|
||||
|
||||
if let Some(meta2) = it.next() {
|
||||
if let Some(another_meta) = it.next() {
|
||||
return Err(Error::new(
|
||||
meta2.span(),
|
||||
another_meta.span(),
|
||||
"Only a single attribute is allowed",
|
||||
));
|
||||
}
|
||||
|
||||
let list = match meta.clone() {
|
||||
Meta::Path(_) => {
|
||||
if allowed_attr_params.contains(&"ignore") {
|
||||
return Ok(info);
|
||||
} else {
|
||||
return Err(Error::new(meta.span(), format!("Empty attribute is not allowed, add one of the following parameters: {}",
|
||||
allowed_attr_params.join(", ")
|
||||
)));
|
||||
return Err(Error::new(
|
||||
meta.span(),
|
||||
format!(
|
||||
"Empty attribute is not allowed, add one of the following parameters: {}",
|
||||
allowed_attr_params.join(", "),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
Meta::List(list) => list,
|
||||
_ => {
|
||||
return Err(Error::new(meta.span(), "Attribute format not supported1"));
|
||||
}
|
||||
};
|
||||
for element in list.nested.into_iter() {
|
||||
let nested_meta = if let NestedMeta::Meta(meta) = element {
|
||||
meta
|
||||
} else {
|
||||
return Err(Error::new(meta.span(), "Attribute format not supported3"));
|
||||
};
|
||||
if let Meta::Path(_) = nested_meta {
|
||||
} else {
|
||||
return Err(Error::new(meta.span(), "Attribute format not supported4"));
|
||||
}
|
||||
let ident = if let Some(ident) =
|
||||
nested_meta.path().segments.first().map(|p| &p.ident)
|
||||
{
|
||||
ident
|
||||
} else {
|
||||
return Err(Error::new(meta.span(), "Attribute format not supported5"));
|
||||
};
|
||||
|
||||
let str_ident: &str = &ident.to_string();
|
||||
if !allowed_attr_params.contains(&str_ident) {
|
||||
Meta::NameValue(val) => {
|
||||
return Err(Error::new(
|
||||
ident.span(),
|
||||
format!(
|
||||
"Attribute parameter not supported. Supported attribute parameters are: {}",
|
||||
allowed_attr_params.join(", ")
|
||||
),
|
||||
val.span(),
|
||||
"Attribute doesn't support name-value format here",
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
parse_punctuated_nested_meta(&mut info, &list.nested, allowed_attr_params, None)?;
|
||||
|
||||
match str_ident {
|
||||
"ignore" => {
|
||||
info.enabled = Some(false);
|
||||
}
|
||||
"forward" => {
|
||||
info.forward = Some(true);
|
||||
}
|
||||
"owned" => {
|
||||
info.owned = Some(true);
|
||||
}
|
||||
"ref" => {
|
||||
info.ref_ = Some(true);
|
||||
}
|
||||
"ref_mut" => {
|
||||
info.ref_mut = Some(true);
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::new(meta.span(), "Attribute format not supported7"));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(info)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
fn parse_punctuated_nested_meta(
|
||||
info: &mut MetaInfo,
|
||||
meta: &Punctuated<NestedMeta, Token![,]>,
|
||||
allowed_attr_params: &[&str],
|
||||
wrapper_name: Option<&str>,
|
||||
) -> Result<()> {
|
||||
for meta in meta.iter() {
|
||||
let meta = match meta {
|
||||
NestedMeta::Meta(meta) => meta,
|
||||
NestedMeta::Lit(lit) => {
|
||||
return Err(Error::new(
|
||||
lit.span(),
|
||||
"Attribute doesn't support literals here",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
match meta {
|
||||
Meta::List(list) if list.path.is_ident("not") => {
|
||||
if wrapper_name.is_some() {
|
||||
// Only single top-level `not` attribute is allowed.
|
||||
return Err(Error::new(
|
||||
list.span(),
|
||||
"Attribute doesn't support multiple multiple or nested `not` parameters",
|
||||
));
|
||||
}
|
||||
parse_punctuated_nested_meta(
|
||||
info,
|
||||
&list.nested,
|
||||
allowed_attr_params,
|
||||
Some("not"),
|
||||
)?;
|
||||
}
|
||||
|
||||
Meta::List(list) => {
|
||||
let path = &list.path;
|
||||
if !allowed_attr_params.iter().any(|param| path.is_ident(param)) {
|
||||
return Err(Error::new(
|
||||
meta.span(),
|
||||
format!(
|
||||
"Attribute nested parameter not supported. \
|
||||
Supported attribute parameters are: {}",
|
||||
allowed_attr_params.join(", "),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
let mut parse_nested = true;
|
||||
|
||||
let attr_name = path.get_ident().unwrap().to_string();
|
||||
match (wrapper_name, attr_name.as_str()) {
|
||||
(None, "owned") => info.owned = Some(true),
|
||||
(None, "ref") => info.ref_ = Some(true),
|
||||
(None, "ref_mut") => info.ref_mut = Some(true),
|
||||
|
||||
#[cfg(any(feature = "from", feature = "into"))]
|
||||
(None, "types")
|
||||
| (Some("owned"), "types")
|
||||
| (Some("ref"), "types")
|
||||
| (Some("ref_mut"), "types") => {
|
||||
parse_nested = false;
|
||||
for meta in &list.nested {
|
||||
match meta {
|
||||
NestedMeta::Meta(meta) => {
|
||||
let path = if let Meta::Path(p) = meta {
|
||||
p
|
||||
} else {
|
||||
return Err(Error::new(
|
||||
meta.span(),
|
||||
format!(
|
||||
"Attribute doesn't support type {}",
|
||||
quote! { #meta },
|
||||
),
|
||||
));
|
||||
};
|
||||
|
||||
for ref_type in wrapper_name
|
||||
.map(|n| vec![RefType::from_attr_name(n)])
|
||||
.unwrap_or_else(|| {
|
||||
vec![
|
||||
RefType::No,
|
||||
RefType::Ref,
|
||||
RefType::Mut,
|
||||
]
|
||||
})
|
||||
{
|
||||
if info
|
||||
.types
|
||||
.entry(ref_type)
|
||||
.or_default()
|
||||
.replace(path.clone())
|
||||
.is_some()
|
||||
{
|
||||
return Err(Error::new(
|
||||
path.span(),
|
||||
format!(
|
||||
"Duplicate type `{}` specified",
|
||||
quote! { #path },
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
NestedMeta::Lit(lit) => return Err(Error::new(
|
||||
lit.span(),
|
||||
"Attribute doesn't support nested literals here",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
return Err(Error::new(
|
||||
list.span(),
|
||||
format!(
|
||||
"Attribute doesn't support nested parameter `{}` here",
|
||||
quote! { #path },
|
||||
),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
if parse_nested {
|
||||
parse_punctuated_nested_meta(
|
||||
info,
|
||||
&list.nested,
|
||||
allowed_attr_params,
|
||||
Some(&attr_name),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
Meta::Path(path) => {
|
||||
if !allowed_attr_params.iter().any(|param| path.is_ident(param)) {
|
||||
return Err(Error::new(
|
||||
meta.span(),
|
||||
format!(
|
||||
"Attribute parameter not supported. \
|
||||
Supported attribute parameters are: {}",
|
||||
allowed_attr_params.join(", "),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
let attr_name = path.get_ident().unwrap().to_string();
|
||||
match (wrapper_name, attr_name.as_str()) {
|
||||
(None, "ignore") => info.enabled = Some(false),
|
||||
(None, "forward") => info.forward = Some(true),
|
||||
(Some("not"), "forward") => info.forward = Some(false),
|
||||
(None, "owned") => info.owned = Some(true),
|
||||
(None, "ref") => info.ref_ = Some(true),
|
||||
(None, "ref_mut") => info.ref_mut = Some(true),
|
||||
(None, "source") => info.source = Some(true),
|
||||
(Some("not"), "source") => info.source = Some(false),
|
||||
(None, "backtrace") => info.backtrace = Some(true),
|
||||
(Some("not"), "backtrace") => info.backtrace = Some(false),
|
||||
_ => {
|
||||
return Err(Error::new(
|
||||
path.span(),
|
||||
format!(
|
||||
"Attribute doesn't support parameter `{}` here",
|
||||
quote! { #path }
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Meta::NameValue(val) => {
|
||||
return Err(Error::new(
|
||||
val.span(),
|
||||
"Attribute doesn't support name-value parameters here",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct FullMetaInfo {
|
||||
pub enabled: bool,
|
||||
pub forward: bool,
|
||||
|
@ -889,31 +1112,34 @@ pub struct FullMetaInfo {
|
|||
pub info: MetaInfo,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct MetaInfo {
|
||||
pub enabled: Option<bool>,
|
||||
pub forward: Option<bool>,
|
||||
pub owned: Option<bool>,
|
||||
pub ref_: Option<bool>,
|
||||
pub ref_mut: Option<bool>,
|
||||
pub source: Option<bool>,
|
||||
pub backtrace: Option<bool>,
|
||||
#[cfg(any(feature = "from", feature = "into"))]
|
||||
pub types: HashMap<RefType, HashSet<syn::Path>>,
|
||||
}
|
||||
|
||||
impl MetaInfo {
|
||||
fn to_full(self, defaults: FullMetaInfo) -> FullMetaInfo {
|
||||
let info = self;
|
||||
fn into_full(self, defaults: FullMetaInfo) -> FullMetaInfo {
|
||||
FullMetaInfo {
|
||||
enabled: self.enabled.unwrap_or(defaults.enabled),
|
||||
forward: self.forward.unwrap_or(defaults.forward),
|
||||
owned: self.owned.unwrap_or(defaults.owned),
|
||||
ref_: self.ref_.unwrap_or(defaults.ref_),
|
||||
ref_mut: self.ref_mut.unwrap_or(defaults.ref_mut),
|
||||
info,
|
||||
info: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FullMetaInfo {
|
||||
pub fn ref_types(self) -> Vec<RefType> {
|
||||
pub fn ref_types(&self) -> Vec<RefType> {
|
||||
let mut ref_types = vec![];
|
||||
if self.owned {
|
||||
ref_types.push(RefType::No);
|
||||
|
@ -926,4 +1152,70 @@ impl FullMetaInfo {
|
|||
}
|
||||
ref_types
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "from", feature = "into"))]
|
||||
pub fn additional_types(&self, ref_type: RefType) -> HashSet<syn::Path> {
|
||||
self.info.types.get(&ref_type).cloned().unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_if_type_parameter_used_in_type(
|
||||
type_parameters: &HashSet<syn::Ident>,
|
||||
ty: &syn::Type,
|
||||
) -> Option<syn::Type> {
|
||||
if is_type_parameter_used_in_type(type_parameters, ty) {
|
||||
match ty {
|
||||
syn::Type::Reference(syn::TypeReference { elem: ty, .. }) => {
|
||||
Some((&**ty).clone())
|
||||
}
|
||||
ty => Some(ty.clone()),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_type_parameter_used_in_type(
|
||||
type_parameters: &HashSet<syn::Ident>,
|
||||
ty: &syn::Type,
|
||||
) -> bool {
|
||||
match ty {
|
||||
syn::Type::Path(ty) => {
|
||||
if let Some(qself) = &ty.qself {
|
||||
if is_type_parameter_used_in_type(type_parameters, &qself.ty) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(segment) = ty.path.segments.first() {
|
||||
if type_parameters.contains(&segment.ident) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ty.path.segments.iter().any(|segment| {
|
||||
if let syn::PathArguments::AngleBracketed(arguments) =
|
||||
&segment.arguments
|
||||
{
|
||||
arguments.args.iter().any(|argument| match argument {
|
||||
syn::GenericArgument::Type(ty) => {
|
||||
is_type_parameter_used_in_type(type_parameters, ty)
|
||||
}
|
||||
syn::GenericArgument::Constraint(constraint) => {
|
||||
type_parameters.contains(&constraint.ident)
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
syn::Type::Reference(ty) => {
|
||||
is_type_parameter_used_in_type(type_parameters, &ty.elem)
|
||||
}
|
||||
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#![allow(dead_code)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(Add)]
|
||||
struct MyInts(i32, i32);
|
||||
|
||||
#[derive(Add)]
|
||||
struct Point2D {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
#[derive(Add)]
|
||||
enum MixedInts {
|
||||
SmallInt(i32),
|
||||
BigInt(i64),
|
||||
TwoSmallInts(i32, i32),
|
||||
NamedSmallInts { x: i32, y: i32 },
|
||||
UnsignedOne(u32),
|
||||
UnsignedTwo(u32),
|
||||
Unit,
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#![allow(dead_code)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(AddAssign)]
|
||||
struct MyInts(i32, i32);
|
||||
|
||||
#[derive(AddAssign)]
|
||||
struct Point2D {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::ptr;
|
||||
|
||||
#[derive(AsMut)]
|
||||
struct SingleFieldTuple(String);
|
||||
|
||||
#[test]
|
||||
fn single_field_tuple() {
|
||||
let mut item = SingleFieldTuple(String::from("test"));
|
||||
|
||||
assert!(ptr::eq(&mut item.0, item.as_mut()));
|
||||
}
|
||||
|
||||
#[derive(AsMut)]
|
||||
#[as_mut(forward)]
|
||||
struct SingleFieldForward(Vec<i32>);
|
||||
|
||||
#[test]
|
||||
fn single_field_forward() {
|
||||
let mut item = SingleFieldForward(vec![]);
|
||||
let _: &mut [i32] = (&mut item).as_mut();
|
||||
}
|
||||
|
||||
#[derive(AsMut)]
|
||||
struct SingleFieldStruct {
|
||||
first: String,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_field_struct() {
|
||||
let mut item = SingleFieldStruct {
|
||||
first: String::from("test"),
|
||||
};
|
||||
|
||||
assert!(ptr::eq(&mut item.first, item.as_mut()));
|
||||
}
|
||||
|
||||
#[derive(AsMut)]
|
||||
struct MultiFieldTuple(#[as_mut] String, #[as_mut] PathBuf, Vec<usize>);
|
||||
|
||||
#[test]
|
||||
fn multi_field_tuple() {
|
||||
let mut item = MultiFieldTuple(String::from("test"), PathBuf::new(), vec![]);
|
||||
|
||||
assert!(ptr::eq(&mut item.0, item.as_mut()));
|
||||
assert!(ptr::eq(&mut item.1, item.as_mut()));
|
||||
}
|
||||
|
||||
#[derive(AsMut)]
|
||||
struct MultiFieldStruct {
|
||||
#[as_mut]
|
||||
first: String,
|
||||
#[as_mut]
|
||||
second: PathBuf,
|
||||
third: Vec<usize>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_field_struct() {
|
||||
let mut item = MultiFieldStruct {
|
||||
first: String::from("test"),
|
||||
second: PathBuf::new(),
|
||||
third: vec![],
|
||||
};
|
||||
|
||||
assert!(ptr::eq(&mut item.first, item.as_mut()));
|
||||
assert!(ptr::eq(&mut item.second, item.as_mut()));
|
||||
}
|
||||
|
||||
#[derive(AsMut)]
|
||||
struct SingleFieldGenericStruct<T> {
|
||||
first: T,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_field_generic_struct() {
|
||||
let mut item = SingleFieldGenericStruct {
|
||||
first: String::from("test"),
|
||||
};
|
||||
|
||||
assert!(ptr::eq(&mut item.first, item.as_mut()));
|
||||
}
|
||||
|
||||
#[derive(AsMut)]
|
||||
struct MultiFieldGenericStruct<T> {
|
||||
#[as_mut]
|
||||
first: Vec<T>,
|
||||
#[as_mut]
|
||||
second: PathBuf,
|
||||
third: Vec<usize>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_field_generic_struct() {
|
||||
let mut item = MultiFieldGenericStruct {
|
||||
first: b"test".to_vec(),
|
||||
second: PathBuf::new(),
|
||||
third: vec![],
|
||||
};
|
||||
|
||||
assert!(ptr::eq(&mut item.first, item.as_mut()));
|
||||
assert!(ptr::eq(&mut item.second, item.as_mut()));
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::ptr;
|
||||
|
||||
#[derive(AsRef)]
|
||||
struct SingleFieldTuple(String);
|
||||
|
||||
#[test]
|
||||
fn single_field_tuple() {
|
||||
let item = SingleFieldTuple(String::from("test"));
|
||||
|
||||
assert!(ptr::eq(&item.0, item.as_ref()));
|
||||
}
|
||||
|
||||
#[derive(AsRef)]
|
||||
#[as_ref(forward)]
|
||||
struct SingleFieldForward(Vec<i32>);
|
||||
|
||||
#[test]
|
||||
fn single_field_forward() {
|
||||
let item = SingleFieldForward(vec![]);
|
||||
let _: &[i32] = (&item).as_ref();
|
||||
}
|
||||
|
||||
#[derive(AsRef)]
|
||||
struct SingleFieldStruct {
|
||||
first: String,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_field_struct() {
|
||||
let item = SingleFieldStruct {
|
||||
first: String::from("test"),
|
||||
};
|
||||
|
||||
assert!(ptr::eq(&item.first, item.as_ref()));
|
||||
}
|
||||
|
||||
#[derive(AsRef)]
|
||||
struct MultiFieldTuple(#[as_ref] String, #[as_ref] PathBuf, Vec<usize>);
|
||||
|
||||
#[test]
|
||||
fn multi_field_tuple() {
|
||||
let item = MultiFieldTuple(String::from("test"), PathBuf::new(), vec![]);
|
||||
|
||||
assert!(ptr::eq(&item.0, item.as_ref()));
|
||||
assert!(ptr::eq(&item.1, item.as_ref()));
|
||||
}
|
||||
|
||||
#[derive(AsRef)]
|
||||
struct MultiFieldStruct {
|
||||
#[as_ref]
|
||||
first: String,
|
||||
#[as_ref]
|
||||
second: PathBuf,
|
||||
third: Vec<usize>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_field_struct() {
|
||||
let item = MultiFieldStruct {
|
||||
first: String::from("test"),
|
||||
second: PathBuf::new(),
|
||||
third: vec![],
|
||||
};
|
||||
|
||||
assert!(ptr::eq(&item.first, item.as_ref()));
|
||||
assert!(ptr::eq(&item.second, item.as_ref()));
|
||||
}
|
||||
|
||||
#[derive(AsRef)]
|
||||
struct SingleFieldGenericStruct<T> {
|
||||
first: T,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_field_generic_struct() {
|
||||
let item = SingleFieldGenericStruct {
|
||||
first: String::from("test"),
|
||||
};
|
||||
|
||||
assert!(ptr::eq(&item.first, item.as_ref()));
|
||||
}
|
||||
|
||||
#[derive(AsRef)]
|
||||
struct MultiFieldGenericStruct<T, U> {
|
||||
#[as_ref]
|
||||
first: Vec<T>,
|
||||
#[as_ref]
|
||||
second: [U; 2],
|
||||
third: Vec<usize>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_field_generic_struct() {
|
||||
let item = MultiFieldGenericStruct {
|
||||
first: b"test".to_vec(),
|
||||
second: [0i32, 1i32],
|
||||
third: vec![],
|
||||
};
|
||||
|
||||
assert!(ptr::eq(&item.first, item.as_ref()));
|
||||
assert!(ptr::eq(&item.second, item.as_ref()));
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
// The following code is from https://github.com/withoutboats/display_derive/blob/232a32ee19e262aacbd2c93be5b4ce9e89a5fc30/tests/tests.rs
|
||||
// Written by without boats originally
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "An error has occurred.")]
|
||||
struct UnitError;
|
||||
|
||||
#[test]
|
||||
fn unit_struct() {
|
||||
let s = format!("{}", UnitError);
|
||||
assert_eq!(&s[..], "An error has occurred.");
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "Error code: {}", code)]
|
||||
struct RecordError {
|
||||
code: u32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn record_struct() {
|
||||
let s = format!("{}", RecordError { code: 0 });
|
||||
assert_eq!(&s[..], "Error code: 0");
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "Error code: {}", _0)]
|
||||
struct TupleError(i32);
|
||||
|
||||
#[test]
|
||||
fn tuple_struct() {
|
||||
let s = format!("{}", TupleError(2));
|
||||
assert_eq!(&s[..], "Error code: 2");
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
enum EnumError {
|
||||
#[display(fmt = "Error code: {}", code)]
|
||||
StructVariant { code: i32 },
|
||||
#[display(fmt = "Error: {}", _0)]
|
||||
TupleVariant(&'static str),
|
||||
#[display(fmt = "An error has occurred.")]
|
||||
UnitVariant,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_error() {
|
||||
let s = format!("{}", EnumError::StructVariant { code: 2 });
|
||||
assert_eq!(&s[..], "Error code: 2");
|
||||
let s = format!("{}", EnumError::TupleVariant("foobar"));
|
||||
assert_eq!(&s[..], "Error: foobar");
|
||||
let s = format!("{}", EnumError::UnitVariant);
|
||||
assert_eq!(&s[..], "An error has occurred.");
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#![allow(dead_code)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(Constructor)]
|
||||
struct EmptyTuple();
|
||||
|
||||
#[derive(Constructor)]
|
||||
struct EmptyStruct {}
|
||||
|
||||
#[derive(Constructor)]
|
||||
struct EmptyUnit;
|
||||
|
||||
#[derive(Constructor)]
|
||||
struct MyInts(i32, i32);
|
||||
|
||||
#[derive(Constructor)]
|
||||
struct Point2D {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
#![allow(dead_code, unused_imports)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(Deref)]
|
||||
#[deref(forward)]
|
||||
struct MyBoxedInt(Box<i32>);
|
||||
|
||||
#[derive(Deref)]
|
||||
#[deref(forward)]
|
||||
struct NumRef<'a> {
|
||||
num: &'a i32,
|
||||
}
|
||||
|
||||
#[derive(Deref)]
|
||||
struct NumRef2<'a> {
|
||||
#[deref(forward)]
|
||||
num: &'a i32,
|
||||
useless: bool,
|
||||
}
|
||||
|
||||
#[derive(Deref)]
|
||||
#[deref(forward)]
|
||||
struct NumRef3<'a> {
|
||||
num: &'a i32,
|
||||
#[deref(ignore)]
|
||||
useless: bool,
|
||||
}
|
||||
|
||||
#[derive(Deref)]
|
||||
struct MyInt(i32);
|
||||
|
||||
#[derive(Deref)]
|
||||
struct Point1D {
|
||||
x: i32,
|
||||
}
|
||||
|
||||
#[derive(Deref)]
|
||||
struct Point1D2 {
|
||||
x: i32,
|
||||
#[deref(ignore)]
|
||||
useless: bool,
|
||||
}
|
||||
|
||||
#[derive(Deref)]
|
||||
struct CoolVec {
|
||||
cool: bool,
|
||||
#[deref]
|
||||
vec: Vec<i32>,
|
||||
}
|
||||
|
||||
#[derive(Deref)]
|
||||
struct GenericVec<T>(Vec<T>);
|
||||
|
||||
#[test]
|
||||
fn deref_generic() {
|
||||
let gv = GenericVec(Vec::<i32>::new());
|
||||
assert!(gv.is_empty())
|
||||
}
|
||||
|
||||
#[derive(Deref)]
|
||||
struct GenericBox<T>(#[deref(forward)] Box<T>);
|
||||
|
||||
#[test]
|
||||
fn deref_generic_forward() {
|
||||
let boxed = GenericBox(Box::new(1i32));
|
||||
assert_eq!(*boxed, 1i32);
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
#![allow(dead_code, unused_imports)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(DerefMut)]
|
||||
#[deref_mut(forward)]
|
||||
struct MyBoxedInt(Box<i32>);
|
||||
// Deref implementation is needed for DerefMut
|
||||
impl ::core::ops::Deref for MyBoxedInt {
|
||||
type Target = <Box<i32> as ::core::ops::Deref>::Target;
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
<Box<i32> as ::core::ops::Deref>::deref(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DerefMut)]
|
||||
struct NumRef<'a> {
|
||||
#[deref_mut(forward)]
|
||||
num: &'a mut i32,
|
||||
}
|
||||
// Deref implementation is needed for DerefMut
|
||||
impl<'a> ::core::ops::Deref for NumRef<'a> {
|
||||
type Target = <&'a mut i32 as ::core::ops::Deref>::Target;
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
<&'a mut i32 as ::core::ops::Deref>::deref(&self.num)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DerefMut)]
|
||||
#[deref_mut(forward)]
|
||||
struct NumRef2<'a> {
|
||||
num: &'a mut i32,
|
||||
#[deref_mut(ignore)]
|
||||
useless: bool,
|
||||
}
|
||||
|
||||
// Deref implementation is needed for DerefMut
|
||||
impl<'a> ::core::ops::Deref for NumRef2<'a> {
|
||||
type Target = <&'a mut i32 as ::core::ops::Deref>::Target;
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
<&'a mut i32 as ::core::ops::Deref>::deref(&self.num)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DerefMut)]
|
||||
struct MyInt(i32);
|
||||
|
||||
// Deref implementation is needed for DerefMutToInner
|
||||
impl ::core::ops::Deref for MyInt {
|
||||
type Target = i32;
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DerefMut)]
|
||||
struct Point1D {
|
||||
x: i32,
|
||||
}
|
||||
|
||||
// Deref implementation is needed for DerefMutToInner
|
||||
impl ::core::ops::Deref for Point1D {
|
||||
type Target = i32;
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.x
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DerefMut)]
|
||||
struct CoolVec {
|
||||
cool: bool,
|
||||
#[deref_mut]
|
||||
vec: Vec<i32>,
|
||||
}
|
||||
impl ::core::ops::Deref for CoolVec {
|
||||
type Target = Vec<i32>;
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.vec
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(DerefMut)]
|
||||
struct GenericVec<T>(Vec<T>);
|
||||
|
||||
impl<T> ::core::ops::Deref for GenericVec<T> {
|
||||
type Target = Vec<T>;
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deref_mut_generic() {
|
||||
let mut gv = GenericVec::<i32>(vec![42]);
|
||||
assert!(gv.get_mut(0).is_some());
|
||||
}
|
||||
|
||||
#[derive(DerefMut)]
|
||||
struct GenericBox<T>(#[deref_mut(forward)] Box<T>);
|
||||
|
||||
impl<T> ::core::ops::Deref for GenericBox<T>
|
||||
where
|
||||
Box<T>: ::core::ops::Deref,
|
||||
{
|
||||
type Target = <Box<T> as ::core::ops::Deref>::Target;
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
<Box<T> as ::core::ops::Deref>::deref(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deref_mut_generic_forward() {
|
||||
let mut boxed = GenericBox(Box::new(1i32));
|
||||
*boxed = 3;
|
||||
assert_eq!(*boxed, 3i32);
|
||||
}
|
|
@ -0,0 +1,405 @@
|
|||
#![allow(dead_code, unused_imports)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
// Here just to make sure that this doesn't conflict with
|
||||
// the derives in some way
|
||||
use std::fmt::Binary;
|
||||
|
||||
#[derive(Display, Octal, Binary)]
|
||||
struct MyInt(i32);
|
||||
|
||||
#[derive(UpperHex)]
|
||||
enum IntEnum {
|
||||
U8(u8),
|
||||
I8(i8),
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "({}, {})", x, y)]
|
||||
struct Point2D {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "{}", message)]
|
||||
struct Error {
|
||||
message: &'static str,
|
||||
backtrace: (),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
fn new(message: &'static str) -> Self {
|
||||
Self {
|
||||
message,
|
||||
backtrace: (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
enum E {
|
||||
Uint(u32),
|
||||
#[display(fmt = "I am B {:b}", i)]
|
||||
Binary {
|
||||
i: i8,
|
||||
},
|
||||
#[display(fmt = "I am C {}", "_0.display()")]
|
||||
Path(PathBuf),
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "Java EE")]
|
||||
enum EE {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "Hello there!")]
|
||||
union U {
|
||||
i: u32,
|
||||
}
|
||||
|
||||
#[derive(Octal)]
|
||||
#[octal(fmt = "7")]
|
||||
struct S;
|
||||
|
||||
#[derive(UpperHex)]
|
||||
#[upper_hex(fmt = "UpperHex")]
|
||||
struct UH;
|
||||
|
||||
#[derive(DebugCustom)]
|
||||
#[debug(fmt = "MyDebug")]
|
||||
struct D;
|
||||
|
||||
#[derive(Display)]
|
||||
struct Unit;
|
||||
|
||||
#[derive(Display)]
|
||||
struct UnitStruct {}
|
||||
|
||||
#[derive(Display)]
|
||||
enum EmptyEnum {}
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "Generic")]
|
||||
struct Generic<T>(T);
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "Here's a prefix for {} and a suffix")]
|
||||
enum Affix {
|
||||
A(u32),
|
||||
#[display(fmt = "{} -- {}", wat, stuff)]
|
||||
B {
|
||||
wat: String,
|
||||
stuff: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_display() {
|
||||
assert_eq!(MyInt(-2).to_string(), "-2");
|
||||
assert_eq!(format!("{:b}", MyInt(9)), "1001");
|
||||
assert_eq!(format!("{:#b}", MyInt(9)), "0b1001");
|
||||
assert_eq!(format!("{:o}", MyInt(9)), "11");
|
||||
assert_eq!(format!("{:X}", IntEnum::I8(-1)), "FF");
|
||||
assert_eq!(format!("{:#X}", IntEnum::U8(255)), "0xFF");
|
||||
assert_eq!(Point2D { x: 3, y: 4 }.to_string(), "(3, 4)");
|
||||
assert_eq!(Error::new("Error").to_string(), "Error");
|
||||
assert_eq!(E::Uint(2).to_string(), "2");
|
||||
assert_eq!(E::Binary { i: -2 }.to_string(), "I am B 11111110");
|
||||
assert_eq!(E::Path("abc".into()).to_string(), "I am C abc");
|
||||
assert_eq!(EE::A.to_string(), "Java EE");
|
||||
assert_eq!(EE::B.to_string(), "Java EE");
|
||||
assert_eq!(U { i: 2 }.to_string(), "Hello there!");
|
||||
assert_eq!(format!("{:o}", S), "7");
|
||||
assert_eq!(format!("{:X}", UH), "UpperHex");
|
||||
assert_eq!(format!("{:?}", D), "MyDebug");
|
||||
assert_eq!(Unit.to_string(), "Unit");
|
||||
assert_eq!(UnitStruct {}.to_string(), "UnitStruct");
|
||||
assert_eq!(Generic(()).to_string(), "Generic");
|
||||
assert_eq!(
|
||||
Affix::A(2).to_string(),
|
||||
"Here's a prefix for 2 and a suffix"
|
||||
);
|
||||
assert_eq!(
|
||||
Affix::B {
|
||||
wat: "things".to_owned(),
|
||||
stuff: false,
|
||||
}
|
||||
.to_string(),
|
||||
"Here's a prefix for things -- false and a suffix"
|
||||
);
|
||||
}
|
||||
|
||||
mod generic {
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "Generic {}", field)]
|
||||
struct NamedGenericStruct<T> {
|
||||
field: T,
|
||||
}
|
||||
#[test]
|
||||
fn named_generic_struct() {
|
||||
assert_eq!(NamedGenericStruct { field: 1 }.to_string(), "Generic 1");
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
struct AutoNamedGenericStruct<T> {
|
||||
field: T,
|
||||
}
|
||||
#[test]
|
||||
fn auto_named_generic_struct() {
|
||||
assert_eq!(AutoNamedGenericStruct { field: 1 }.to_string(), "1");
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "Generic {}", "_0")]
|
||||
struct UnnamedGenericStruct<T>(T);
|
||||
#[test]
|
||||
fn unnamed_generic_struct() {
|
||||
assert_eq!(UnnamedGenericStruct(2).to_string(), "Generic 2");
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
struct AutoUnnamedGenericStruct<T>(T);
|
||||
#[test]
|
||||
fn auto_unnamed_generic_struct() {
|
||||
assert_eq!(AutoUnnamedGenericStruct(2).to_string(), "2");
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
enum GenericEnum<A, B> {
|
||||
#[display(fmt = "Gen::A {}", field)]
|
||||
A { field: A },
|
||||
#[display(fmt = "Gen::B {}", "_0")]
|
||||
B(B),
|
||||
}
|
||||
#[test]
|
||||
fn generic_enum() {
|
||||
assert_eq!(GenericEnum::A::<_, u8> { field: 1 }.to_string(), "Gen::A 1");
|
||||
assert_eq!(GenericEnum::B::<u8, _>(2).to_string(), "Gen::B 2");
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
enum AutoGenericEnum<A, B> {
|
||||
A { field: A },
|
||||
B(B),
|
||||
}
|
||||
#[test]
|
||||
fn auto_generic_enum() {
|
||||
assert_eq!(AutoGenericEnum::A::<_, u8> { field: 1 }.to_string(), "1");
|
||||
assert_eq!(AutoGenericEnum::B::<u8, _>(2).to_string(), "2");
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "{} {} <-> {0:o} {1:#x} <-> {0:?} {1:X?}", a, b)]
|
||||
struct MultiTraitNamedGenericStruct<A, B> {
|
||||
a: A,
|
||||
b: B,
|
||||
}
|
||||
#[test]
|
||||
fn multi_trait_named_generic_struct() {
|
||||
let s = MultiTraitNamedGenericStruct { a: 8u8, b: 255 };
|
||||
assert_eq!(s.to_string(), "8 255 <-> 10 0xff <-> 8 FF");
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "{} {} {{}} {0:o} {1:#x} - {0:>4?} {1:^4X?}", "_0", "_1")]
|
||||
struct MultiTraitUnnamedGenericStruct<A, B>(A, B);
|
||||
#[test]
|
||||
fn multi_trait_unnamed_generic_struct() {
|
||||
let s = MultiTraitUnnamedGenericStruct(8u8, 255);
|
||||
assert_eq!(s.to_string(), "8 255 {} 10 0xff - 8 FF ");
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "{}", "3 * 4")]
|
||||
struct UnusedGenericStruct<T>(T);
|
||||
#[test]
|
||||
fn unused_generic_struct() {
|
||||
let s = UnusedGenericStruct(());
|
||||
assert_eq!(s.to_string(), "12");
|
||||
}
|
||||
|
||||
mod associated_type_field_enumerator {
|
||||
use super::*;
|
||||
|
||||
trait Trait {
|
||||
type Type;
|
||||
}
|
||||
|
||||
struct Struct;
|
||||
|
||||
impl Trait for Struct {
|
||||
type Type = i32;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_generic_named_struct_associated() {
|
||||
#[derive(Display)]
|
||||
struct AutoGenericNamedStructAssociated<T: Trait> {
|
||||
field: <T as Trait>::Type,
|
||||
}
|
||||
|
||||
let s = AutoGenericNamedStructAssociated::<Struct> { field: 10 };
|
||||
assert_eq!(s.to_string(), "10");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_generic_unnamed_struct_associated() {
|
||||
#[derive(Display)]
|
||||
struct AutoGenericUnnamedStructAssociated<T: Trait>(<T as Trait>::Type);
|
||||
|
||||
let s = AutoGenericUnnamedStructAssociated::<Struct>(10);
|
||||
assert_eq!(s.to_string(), "10");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_generic_enum_associated() {
|
||||
#[derive(Display)]
|
||||
enum AutoGenericEnumAssociated<T: Trait> {
|
||||
Enumerator(<T as Trait>::Type),
|
||||
}
|
||||
|
||||
let e = AutoGenericEnumAssociated::<Struct>::Enumerator(10);
|
||||
assert_eq!(e.to_string(), "10");
|
||||
}
|
||||
}
|
||||
|
||||
mod complex_type_field_enumerator {
|
||||
use super::*;
|
||||
|
||||
#[derive(Display)]
|
||||
struct Struct<T>(T);
|
||||
|
||||
#[test]
|
||||
fn auto_generic_named_struct_complex() {
|
||||
#[derive(Display)]
|
||||
struct AutoGenericNamedStructComplex<T> {
|
||||
field: Struct<T>,
|
||||
}
|
||||
|
||||
let s = AutoGenericNamedStructComplex { field: Struct(10) };
|
||||
assert_eq!(s.to_string(), "10");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_generic_unnamed_struct_complex() {
|
||||
#[derive(Display)]
|
||||
struct AutoGenericUnnamedStructComplex<T>(Struct<T>);
|
||||
|
||||
let s = AutoGenericUnnamedStructComplex(Struct(10));
|
||||
assert_eq!(s.to_string(), "10");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_generic_enum_complex() {
|
||||
#[derive(Display)]
|
||||
enum AutoGenericEnumComplex<T> {
|
||||
Enumerator(Struct<T>),
|
||||
}
|
||||
|
||||
let e = AutoGenericEnumComplex::Enumerator(Struct(10));
|
||||
assert_eq!(e.to_string(), "10")
|
||||
}
|
||||
}
|
||||
|
||||
mod reference {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn auto_generic_reference() {
|
||||
#[derive(Display)]
|
||||
struct AutoGenericReference<'a, T>(&'a T);
|
||||
|
||||
let s = AutoGenericReference(&10);
|
||||
assert_eq!(s.to_string(), "10");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_generic_static_reference() {
|
||||
#[derive(Display)]
|
||||
struct AutoGenericStaticReference<T: 'static>(&'static T);
|
||||
|
||||
let s = AutoGenericStaticReference(&10);
|
||||
assert_eq!(s.to_string(), "10");
|
||||
}
|
||||
}
|
||||
|
||||
mod indirect {
|
||||
use super::*;
|
||||
|
||||
#[derive(Display)]
|
||||
struct Struct<T>(T);
|
||||
|
||||
#[test]
|
||||
fn auto_generic_indirect() {
|
||||
#[derive(Display)]
|
||||
struct AutoGenericIndirect<T: 'static>(Struct<&'static T>);
|
||||
|
||||
const V: i32 = 10;
|
||||
let s = AutoGenericIndirect(Struct(&V));
|
||||
assert_eq!(s.to_string(), "10");
|
||||
}
|
||||
}
|
||||
|
||||
mod bound {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn simple() {
|
||||
#[derive(Display)]
|
||||
#[display(fmt = "{} {}", _0, _1)]
|
||||
struct Struct<T1, T2>(T1, T2);
|
||||
|
||||
let s = Struct(10, 20);
|
||||
assert_eq!(s.to_string(), "10 20");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn redundant() {
|
||||
#[derive(Display)]
|
||||
#[display(bound = "T1: ::core::fmt::Display, T2: ::core::fmt::Display")]
|
||||
#[display(fmt = "{} {}", _0, _1)]
|
||||
struct Struct<T1, T2>(T1, T2);
|
||||
|
||||
let s = Struct(10, 20);
|
||||
assert_eq!(s.to_string(), "10 20");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complex() {
|
||||
trait Trait1 {
|
||||
fn function1(&self) -> &'static str;
|
||||
}
|
||||
|
||||
trait Trait2 {
|
||||
fn function2(&self) -> &'static str;
|
||||
}
|
||||
|
||||
impl Trait1 for i32 {
|
||||
fn function1(&self) -> &'static str {
|
||||
"WHAT"
|
||||
}
|
||||
}
|
||||
|
||||
impl Trait2 for i32 {
|
||||
fn function2(&self) -> &'static str {
|
||||
"EVER"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Display)]
|
||||
#[display(bound = "T1: Trait1 + Trait2, T2: Trait1 + Trait2")]
|
||||
#[display(fmt = "{} {} {} {}", "_0.function1()", _0, "_1.function2()", _1)]
|
||||
struct Struct<T1, T2>(T1, T2);
|
||||
|
||||
let s = Struct(10, 20);
|
||||
assert_eq!(s.to_string(), "WHAT 10 EVER 20");
|
||||
}
|
||||
}
|
||||
}
|
249
third_party/rust/derive_more/tests/error/derives_for_enums_with_source.rs
поставляемый
Normal file
249
third_party/rust/derive_more/tests/error/derives_for_enums_with_source.rs
поставляемый
Normal file
|
@ -0,0 +1,249 @@
|
|||
use super::*;
|
||||
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
enum TestErr {
|
||||
Unit,
|
||||
NamedImplicitNoSource {
|
||||
field: i32,
|
||||
},
|
||||
NamedImplicitSource {
|
||||
source: SimpleErr,
|
||||
field: i32,
|
||||
},
|
||||
NamedExplicitNoSource {
|
||||
#[error(not(source))]
|
||||
source: SimpleErr,
|
||||
field: i32,
|
||||
},
|
||||
NamedExplicitSource {
|
||||
#[error(source)]
|
||||
explicit_source: SimpleErr,
|
||||
field: i32,
|
||||
},
|
||||
NamedExplicitNoSourceRedundant {
|
||||
#[error(not(source))]
|
||||
field: i32,
|
||||
},
|
||||
NamedExplicitSourceRedundant {
|
||||
#[error(source)]
|
||||
source: SimpleErr,
|
||||
field: i32,
|
||||
},
|
||||
NamedExplicitSuppressesImplicit {
|
||||
source: i32,
|
||||
#[error(source)]
|
||||
field: SimpleErr,
|
||||
},
|
||||
UnnamedImplicitNoSource(i32, i32),
|
||||
UnnamedImplicitSource(SimpleErr),
|
||||
UnnamedExplicitNoSource(#[error(not(source))] SimpleErr),
|
||||
UnnamedExplicitSource(#[error(source)] SimpleErr, i32),
|
||||
UnnamedExplicitNoSourceRedundant(
|
||||
#[error(not(source))] i32,
|
||||
#[error(not(source))] i32,
|
||||
),
|
||||
UnnamedExplicitSourceRedundant(#[error(source)] SimpleErr),
|
||||
NamedIgnore {
|
||||
#[error(ignore)]
|
||||
source: SimpleErr,
|
||||
field: i32,
|
||||
},
|
||||
UnnamedIgnore(#[error(ignore)] SimpleErr),
|
||||
NamedIgnoreRedundant {
|
||||
#[error(ignore)]
|
||||
field: i32,
|
||||
},
|
||||
UnnamedIgnoreRedundant(#[error(ignore)] i32, #[error(ignore)] i32),
|
||||
#[error(ignore)]
|
||||
NamedVariantIgnore {
|
||||
source: SimpleErr,
|
||||
field: i32,
|
||||
},
|
||||
#[error(ignore)]
|
||||
UnnamedVariantIgnore(SimpleErr),
|
||||
#[error(ignore)]
|
||||
NamedVariantIgnoreRedundant {
|
||||
field: i32,
|
||||
},
|
||||
#[error(ignore)]
|
||||
UnnamedVariantIgnoreRedundant(i32, i32),
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit() {
|
||||
assert!(TestErr::Unit.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_no_source() {
|
||||
let err = TestErr::NamedImplicitNoSource { field: 0 };
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_source() {
|
||||
let err = TestErr::NamedImplicitSource {
|
||||
source: SimpleErr,
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_source() {
|
||||
let err = TestErr::NamedExplicitNoSource {
|
||||
source: SimpleErr,
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_source() {
|
||||
let err = TestErr::NamedExplicitSource {
|
||||
explicit_source: SimpleErr,
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_source_redundant() {
|
||||
let err = TestErr::NamedExplicitNoSourceRedundant { field: 0 };
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_source_redundant() {
|
||||
let err = TestErr::NamedExplicitSourceRedundant {
|
||||
source: SimpleErr,
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_suppresses_implicit() {
|
||||
let err = TestErr::NamedExplicitSuppressesImplicit {
|
||||
source: 0,
|
||||
field: SimpleErr,
|
||||
};
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_no_source() {
|
||||
assert!(TestErr::UnnamedImplicitNoSource(0, 0).source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_source() {
|
||||
let err = TestErr::UnnamedImplicitSource(SimpleErr);
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_source() {
|
||||
let err = TestErr::UnnamedExplicitNoSource(SimpleErr);
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_source() {
|
||||
let err = TestErr::UnnamedExplicitSource(SimpleErr, 0);
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_source_redundant() {
|
||||
let err = TestErr::UnnamedExplicitNoSourceRedundant(0, 0);
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_source_redundant() {
|
||||
let err = TestErr::UnnamedExplicitSourceRedundant(SimpleErr);
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_ignore() {
|
||||
let err = TestErr::NamedIgnore {
|
||||
source: SimpleErr,
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_ignore() {
|
||||
let err = TestErr::UnnamedIgnore(SimpleErr);
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_ignore_redundant() {
|
||||
let err = TestErr::NamedIgnoreRedundant { field: 0 };
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_ignore_redundant() {
|
||||
let err = TestErr::UnnamedIgnoreRedundant(0, 0);
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_variant_ignore() {
|
||||
let err = TestErr::NamedVariantIgnore {
|
||||
source: SimpleErr,
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_variant_ignore() {
|
||||
let err = TestErr::UnnamedVariantIgnore(SimpleErr);
|
||||
|
||||
assert!(err.source().is_none())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_variant_ignore_redundant() {
|
||||
let err = TestErr::NamedVariantIgnoreRedundant { field: 0 };
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_variant_ignore_redundant() {
|
||||
let err = TestErr::UnnamedVariantIgnoreRedundant(0, 0);
|
||||
|
||||
assert!(err.source().is_none())
|
||||
}
|
248
third_party/rust/derive_more/tests/error/derives_for_generic_enums_with_source.rs
поставляемый
Normal file
248
third_party/rust/derive_more/tests/error/derives_for_generic_enums_with_source.rs
поставляемый
Normal file
|
@ -0,0 +1,248 @@
|
|||
use super::*;
|
||||
|
||||
derive_display!(TestErr, T, E);
|
||||
#[derive(Debug, Error)]
|
||||
enum TestErr<E, T> {
|
||||
Unit,
|
||||
NamedImplicitNoSource {
|
||||
field: T,
|
||||
},
|
||||
NamedImplicitSource {
|
||||
source: E,
|
||||
field: T,
|
||||
},
|
||||
NamedExplicitNoSource {
|
||||
#[error(not(source))]
|
||||
source: E,
|
||||
field: T,
|
||||
},
|
||||
NamedExplicitSource {
|
||||
#[error(source)]
|
||||
explicit_source: E,
|
||||
field: T,
|
||||
},
|
||||
NamedExplicitNoSourceRedundant {
|
||||
#[error(not(source))]
|
||||
field: T,
|
||||
},
|
||||
NamedExplicitSourceRedundant {
|
||||
#[error(source)]
|
||||
source: E,
|
||||
field: T,
|
||||
},
|
||||
NamedExplicitSuppressesImplicit {
|
||||
source: T,
|
||||
#[error(source)]
|
||||
field: E,
|
||||
},
|
||||
UnnamedImplicitNoSource(T, T),
|
||||
UnnamedImplicitSource(E),
|
||||
UnnamedExplicitNoSource(#[error(not(source))] E),
|
||||
UnnamedExplicitSource(#[error(source)] E, T),
|
||||
UnnamedExplicitNoSourceRedundant(#[error(not(source))] T, #[error(not(source))] T),
|
||||
UnnamedExplicitSourceRedundant(#[error(source)] E),
|
||||
NamedIgnore {
|
||||
#[error(ignore)]
|
||||
source: E,
|
||||
field: T,
|
||||
},
|
||||
UnnamedIgnore(#[error(ignore)] E),
|
||||
NamedIgnoreRedundant {
|
||||
#[error(ignore)]
|
||||
field: T,
|
||||
},
|
||||
UnnamedIgnoreRedundant(#[error(ignore)] T, #[error(ignore)] T),
|
||||
#[error(ignore)]
|
||||
NamedVariantIgnore {
|
||||
source: E,
|
||||
field: T,
|
||||
},
|
||||
#[error(ignore)]
|
||||
UnnamedVariantIgnore(E),
|
||||
#[error(ignore)]
|
||||
NamedVariantIgnoreRedundant {
|
||||
field: T,
|
||||
},
|
||||
#[error(ignore)]
|
||||
UnnamedVariantIgnoreRedundant(T, T),
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit() {
|
||||
assert!(TestErr::<SimpleErr, i32>::Unit.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_no_source() {
|
||||
let err = TestErr::<SimpleErr, _>::NamedImplicitNoSource { field: 0 };
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_source() {
|
||||
let err = TestErr::NamedImplicitSource {
|
||||
source: SimpleErr,
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_source() {
|
||||
let err = TestErr::NamedExplicitNoSource {
|
||||
source: SimpleErr,
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_source() {
|
||||
let err = TestErr::NamedExplicitSource {
|
||||
explicit_source: SimpleErr,
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_source_redundant() {
|
||||
let err = TestErr::<SimpleErr, _>::NamedExplicitNoSourceRedundant { field: 0 };
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_source_redundant() {
|
||||
let err = TestErr::NamedExplicitSourceRedundant {
|
||||
source: SimpleErr,
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_suppresses_implicit() {
|
||||
let err = TestErr::NamedExplicitSuppressesImplicit {
|
||||
source: 0,
|
||||
field: SimpleErr,
|
||||
};
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_no_source() {
|
||||
let err = TestErr::<SimpleErr, _>::UnnamedImplicitNoSource(0, 0);
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_source() {
|
||||
let err = TestErr::<_, i32>::UnnamedImplicitSource(SimpleErr);
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_source() {
|
||||
let err = TestErr::<_, i32>::UnnamedExplicitNoSource(SimpleErr);
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_source() {
|
||||
let err = TestErr::UnnamedExplicitSource(SimpleErr, 0);
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_source_redundant() {
|
||||
let err = TestErr::<SimpleErr, _>::UnnamedExplicitNoSourceRedundant(0, 0);
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_source_redundant() {
|
||||
let err = TestErr::<_, i32>::UnnamedExplicitSourceRedundant(SimpleErr);
|
||||
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_ignore() {
|
||||
let err = TestErr::NamedIgnore {
|
||||
source: SimpleErr,
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_ignore() {
|
||||
let err = TestErr::<_, i32>::UnnamedIgnore(SimpleErr);
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_ignore_redundant() {
|
||||
let err = TestErr::<SimpleErr, _>::NamedIgnoreRedundant { field: 0 };
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_ignore_redundant() {
|
||||
let err = TestErr::<SimpleErr, _>::UnnamedIgnoreRedundant(0, 0);
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_variant_ignore() {
|
||||
let err = TestErr::NamedVariantIgnore {
|
||||
source: SimpleErr,
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_variant_ignore() {
|
||||
let err = TestErr::<_, i32>::UnnamedVariantIgnore(SimpleErr);
|
||||
|
||||
assert!(err.source().is_none())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_variant_ignore_redundant() {
|
||||
let err = TestErr::<SimpleErr, _>::NamedVariantIgnoreRedundant { field: 0 };
|
||||
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_variant_ignore_redundant() {
|
||||
let err = TestErr::<SimpleErr, _>::UnnamedVariantIgnoreRedundant(0, 0);
|
||||
|
||||
assert!(err.source().is_none())
|
||||
}
|
245
third_party/rust/derive_more/tests/error/derives_for_generic_structs_with_source.rs
поставляемый
Normal file
245
third_party/rust/derive_more/tests/error/derives_for_generic_structs_with_source.rs
поставляемый
Normal file
|
@ -0,0 +1,245 @@
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn named_implicit_no_source() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<T> {
|
||||
field: T,
|
||||
}
|
||||
|
||||
assert!(TestErr::<i32>::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_source() {
|
||||
derive_display!(TestErr, E, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<E, T> {
|
||||
source: E,
|
||||
field: T,
|
||||
}
|
||||
|
||||
let err = TestErr::<SimpleErr, i32>::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_source() {
|
||||
derive_display!(TestErr, E, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<E, T> {
|
||||
#[error(not(source))]
|
||||
source: E,
|
||||
field: T,
|
||||
}
|
||||
|
||||
let err = TestErr::<SimpleErr, i32>::default();
|
||||
assert!(err.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_source() {
|
||||
derive_display!(TestErr, E, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<E, T> {
|
||||
#[error(source)]
|
||||
explicit_source: E,
|
||||
field: T,
|
||||
}
|
||||
|
||||
let err = TestErr::<SimpleErr, i32>::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_source_redundant() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<T> {
|
||||
#[error(not(source))]
|
||||
field: T,
|
||||
}
|
||||
|
||||
assert!(TestErr::<i32>::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_source_redundant() {
|
||||
derive_display!(TestErr, E, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<E, T> {
|
||||
#[error(source)]
|
||||
source: E,
|
||||
field: T,
|
||||
}
|
||||
|
||||
let err = TestErr::<SimpleErr, i32>::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_suppresses_implicit() {
|
||||
derive_display!(TestErr, E, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<E, T> {
|
||||
source: E,
|
||||
#[error(source)]
|
||||
field: T,
|
||||
}
|
||||
|
||||
let err = TestErr::<i32, SimpleErr>::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_no_source() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<T>(T, T);
|
||||
|
||||
assert!(TestErr::<i32>::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_source() {
|
||||
derive_display!(TestErr, E);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<E>(E);
|
||||
|
||||
let err = TestErr::<SimpleErr>::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_source() {
|
||||
derive_display!(TestErr, E);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<E>(#[error(not(source))] E);
|
||||
|
||||
assert!(TestErr::<SimpleErr>::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_source() {
|
||||
derive_display!(TestErr, E, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<E, T>(#[error(source)] E, T);
|
||||
|
||||
let err = TestErr::<SimpleErr, i32>::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_source_redundant() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<T>(#[error(not(source))] T, #[error(not(source))] T);
|
||||
|
||||
assert!(TestErr::<i32>::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_source_redundant() {
|
||||
derive_display!(TestErr, E);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<E>(#[error(source)] E);
|
||||
|
||||
let err = TestErr::<SimpleErr>::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_ignore() {
|
||||
derive_display!(TestErr, E, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<E, T> {
|
||||
#[error(ignore)]
|
||||
source: E,
|
||||
field: T,
|
||||
}
|
||||
|
||||
assert!(TestErr::<SimpleErr, i32>::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_ignore() {
|
||||
derive_display!(TestErr, E);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<E>(#[error(ignore)] E);
|
||||
|
||||
assert!(TestErr::<SimpleErr>::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_ignore_redundant() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<T> {
|
||||
#[error(ignore)]
|
||||
field: T,
|
||||
}
|
||||
|
||||
assert!(TestErr::<i32>::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_ignore_redundant() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<T>(#[error(ignore)] T, #[error(ignore)] T);
|
||||
|
||||
assert!(TestErr::<i32>::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_struct_ignore() {
|
||||
derive_display!(TestErr, E, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
#[error(ignore)]
|
||||
struct TestErr<E, T> {
|
||||
source: E,
|
||||
field: T,
|
||||
}
|
||||
|
||||
assert!(TestErr::<SimpleErr, i32>::default().source().is_none())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_struct_ignore() {
|
||||
derive_display!(TestErr, E);
|
||||
#[derive(Default, Debug, Error)]
|
||||
#[error(ignore)]
|
||||
struct TestErr<E>(E);
|
||||
|
||||
assert!(TestErr::<SimpleErr>::default().source().is_none())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_struct_ignore_redundant() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
#[error(ignore)]
|
||||
struct TestErr<T> {
|
||||
field: T,
|
||||
}
|
||||
|
||||
assert!(TestErr::<i32>::default().source().is_none())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_struct_ignore_redundant() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
#[error(ignore)]
|
||||
struct TestErr<T>(T, T);
|
||||
|
||||
assert!(TestErr::<i32>::default().source().is_none())
|
||||
}
|
249
third_party/rust/derive_more/tests/error/derives_for_structs_with_source.rs
поставляемый
Normal file
249
third_party/rust/derive_more/tests/error/derives_for_structs_with_source.rs
поставляемый
Normal file
|
@ -0,0 +1,249 @@
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn unit() {
|
||||
assert!(SimpleErr.source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_no_source() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
assert!(TestErr::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_source() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr {
|
||||
source: SimpleErr,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
let err = TestErr::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_source() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr {
|
||||
#[error(not(source))]
|
||||
source: SimpleErr,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
assert!(TestErr::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_source() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr {
|
||||
#[error(source)]
|
||||
explicit_source: SimpleErr,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
let err = TestErr::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_source_redundant() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr {
|
||||
#[error(not(source))]
|
||||
field: i32,
|
||||
}
|
||||
|
||||
assert!(TestErr::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_source_redundant() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr {
|
||||
#[error(source)]
|
||||
source: SimpleErr,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
let err = TestErr::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_suppresses_implicit() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr {
|
||||
source: i32,
|
||||
#[error(source)]
|
||||
field: SimpleErr,
|
||||
}
|
||||
|
||||
let err = TestErr::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_no_source() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr(i32, i32);
|
||||
|
||||
assert!(TestErr::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_source() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr(SimpleErr);
|
||||
|
||||
let err = TestErr::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_source() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr(#[error(not(source))] SimpleErr);
|
||||
|
||||
assert!(TestErr::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_source() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr(#[error(source)] SimpleErr, i32);
|
||||
|
||||
let err = TestErr::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_source_redundant() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr(#[error(not(source))] i32, #[error(not(source))] i32);
|
||||
|
||||
assert!(TestErr::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_source_redundant() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr(#[error(source)] SimpleErr);
|
||||
|
||||
let err = TestErr::default();
|
||||
assert!(err.source().is_some());
|
||||
assert!(err.source().unwrap().is::<SimpleErr>());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_ignore() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr {
|
||||
#[error(ignore)]
|
||||
source: SimpleErr,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
assert!(TestErr::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_ignore() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr(#[error(ignore)] SimpleErr);
|
||||
|
||||
assert!(TestErr::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_ignore_redundant() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr {
|
||||
#[error(ignore)]
|
||||
field: i32,
|
||||
}
|
||||
|
||||
assert!(TestErr::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_ignore_redundant() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr(#[error(ignore)] i32, #[error(ignore)] i32);
|
||||
|
||||
assert!(TestErr::default().source().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_struct_ignore() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
#[error(ignore)]
|
||||
struct TestErr {
|
||||
source: SimpleErr,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
assert!(TestErr::default().source().is_none())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_struct_ignore() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
#[error(ignore)]
|
||||
struct TestErr(SimpleErr);
|
||||
|
||||
assert!(TestErr::default().source().is_none())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_struct_ignore_redundant() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
#[error(ignore)]
|
||||
struct TestErr {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
assert!(TestErr::default().source().is_none())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_struct_ignore_redundant() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
#[error(ignore)]
|
||||
struct TestErr(i32, i32);
|
||||
|
||||
assert!(TestErr::default().source().is_none())
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
use std::error::Error;
|
||||
|
||||
/// Derives `std::fmt::Display` for structs/enums.
|
||||
/// Derived implementation outputs empty string.
|
||||
/// Useful, as a way to formally satisfy `Display` trait bound.
|
||||
///
|
||||
/// ## Syntax:
|
||||
///
|
||||
/// For regular structs/enums:
|
||||
///
|
||||
/// ```
|
||||
/// enum MyEnum {
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
/// derive_display!(MyEnum);
|
||||
/// ```
|
||||
///
|
||||
/// For generic structs/enums:
|
||||
///
|
||||
/// ```
|
||||
/// struct MyGenericStruct<T, U> {
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
/// derive_display!(MyGenericStruct, T, U);
|
||||
/// ```
|
||||
macro_rules! derive_display {
|
||||
(@fmt) => {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
write!(f, "")
|
||||
}
|
||||
};
|
||||
($type:ident) => {
|
||||
impl ::std::fmt::Display for $type {
|
||||
derive_display!(@fmt);
|
||||
}
|
||||
};
|
||||
($type:ident, $($type_parameters:ident),*) => {
|
||||
impl<$($type_parameters),*> ::std::fmt::Display for $type<$($type_parameters),*> {
|
||||
derive_display!(@fmt);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mod derives_for_enums_with_source;
|
||||
mod derives_for_generic_enums_with_source;
|
||||
mod derives_for_generic_structs_with_source;
|
||||
mod derives_for_structs_with_source;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
mod nightly;
|
||||
|
||||
derive_display!(SimpleErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct SimpleErr;
|
272
third_party/rust/derive_more/tests/error/nightly/derives_for_enums_with_backtrace.rs
поставляемый
Normal file
272
third_party/rust/derive_more/tests/error/nightly/derives_for_enums_with_backtrace.rs
поставляемый
Normal file
|
@ -0,0 +1,272 @@
|
|||
use super::*;
|
||||
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
enum TestErr {
|
||||
Unit,
|
||||
NamedImplicitNoBacktrace {
|
||||
field: i32,
|
||||
},
|
||||
NamedImplicitBacktraceByFieldName {
|
||||
backtrace: MyBacktrace,
|
||||
field: i32,
|
||||
},
|
||||
NamedImplicitBacktraceByFieldType {
|
||||
implicit_backtrace: Backtrace,
|
||||
field: i32,
|
||||
},
|
||||
NamedExplicitNoBacktraceByFieldName {
|
||||
#[error(not(backtrace))]
|
||||
backtrace: MyBacktrace,
|
||||
field: i32,
|
||||
},
|
||||
NamedExplicitNoBacktraceByFieldType {
|
||||
#[error(not(backtrace))]
|
||||
implicit_backtrace: Backtrace,
|
||||
field: i32,
|
||||
},
|
||||
NamedExplicitBacktrace {
|
||||
#[error(backtrace)]
|
||||
explicit_backtrace: MyBacktrace,
|
||||
field: i32,
|
||||
},
|
||||
NamedExplicitNoBacktraceRedundant {
|
||||
#[error(not(backtrace))]
|
||||
not_backtrace: MyBacktrace,
|
||||
#[error(not(backtrace))]
|
||||
field: i32,
|
||||
},
|
||||
NamedExplicitBacktraceByFieldNameRedundant {
|
||||
#[error(backtrace)]
|
||||
backtrace: MyBacktrace,
|
||||
field: i32,
|
||||
},
|
||||
NamedExplicitBacktraceByFieldTypeRedundant {
|
||||
#[error(backtrace)]
|
||||
implicit_backtrace: Backtrace,
|
||||
field: i32,
|
||||
},
|
||||
NamedExplicitSupressesImplicit {
|
||||
#[error(backtrace)]
|
||||
not_backtrace: MyBacktrace,
|
||||
backtrace: Backtrace,
|
||||
field: i32,
|
||||
},
|
||||
UnnamedImplicitNoBacktrace(i32, i32),
|
||||
UnnamedImplicitBacktrace(Backtrace, i32, i32),
|
||||
UnnamedExplicitNoBacktrace(#[error(not(backtrace))] Backtrace, i32),
|
||||
UnnamedExplicitBacktrace(#[error(backtrace)] MyBacktrace, i32, i32),
|
||||
UnnamedExplicitNoBacktraceRedundant(
|
||||
#[error(not(backtrace))] MyBacktrace,
|
||||
#[error(not(backtrace))] i32,
|
||||
),
|
||||
UnnamedExplicitBacktraceRedundant(#[error(backtrace)] Backtrace, i32, i32),
|
||||
UnnamedExplicitSupressesImplicit(#[error(backtrace)] MyBacktrace, Backtrace, i32),
|
||||
}
|
||||
|
||||
impl TestErr {
|
||||
fn get_stored_backtrace(&self) -> &Backtrace {
|
||||
match self {
|
||||
Self::NamedImplicitBacktraceByFieldName { backtrace, .. } => backtrace,
|
||||
Self::NamedImplicitBacktraceByFieldType {
|
||||
implicit_backtrace, ..
|
||||
} => implicit_backtrace,
|
||||
Self::NamedExplicitBacktrace {
|
||||
explicit_backtrace, ..
|
||||
} => explicit_backtrace,
|
||||
Self::NamedExplicitBacktraceByFieldNameRedundant { backtrace, .. } => {
|
||||
backtrace
|
||||
}
|
||||
Self::NamedExplicitBacktraceByFieldTypeRedundant {
|
||||
implicit_backtrace,
|
||||
..
|
||||
} => implicit_backtrace,
|
||||
Self::NamedExplicitSupressesImplicit { not_backtrace, .. } => not_backtrace,
|
||||
Self::UnnamedImplicitBacktrace(backtrace, _, _) => backtrace,
|
||||
Self::UnnamedExplicitBacktrace(backtrace, _, _) => backtrace,
|
||||
Self::UnnamedExplicitBacktraceRedundant(backtrace, _, _) => backtrace,
|
||||
Self::UnnamedExplicitSupressesImplicit(backtrace, _, _) => backtrace,
|
||||
_ => panic!("ERROR IN TEST IMPLEMENTATION"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_unused_backtrace(&self) -> &Backtrace {
|
||||
match self {
|
||||
Self::NamedExplicitSupressesImplicit { backtrace, .. } => backtrace,
|
||||
Self::UnnamedExplicitSupressesImplicit(_, backtrace, _) => backtrace,
|
||||
_ => panic!("ERROR IN TEST IMPLEMENTATION"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
#[test]
|
||||
fn unit() {
|
||||
assert!(TestErr::Unit.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_no_backtrace() {
|
||||
let err = TestErr::NamedImplicitNoBacktrace { field: 0 };
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_backtrace_by_field_name() {
|
||||
let err = TestErr::NamedImplicitBacktraceByFieldName {
|
||||
backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_backtrace_by_field_type() {
|
||||
let err = TestErr::NamedImplicitBacktraceByFieldType {
|
||||
implicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_backtrace_by_field_name() {
|
||||
let err = TestErr::NamedExplicitNoBacktraceByFieldName {
|
||||
backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_backtrace_by_field_type() {
|
||||
let err = TestErr::NamedExplicitNoBacktraceByFieldType {
|
||||
implicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_backtrace() {
|
||||
let err = TestErr::NamedExplicitBacktrace {
|
||||
explicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_backtrace_redundant() {
|
||||
let err = TestErr::NamedExplicitNoBacktraceRedundant {
|
||||
not_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_backtrace_by_field_name_redundant() {
|
||||
let err = TestErr::NamedExplicitBacktraceByFieldNameRedundant {
|
||||
backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_backtrace_by_field_type_redundant() {
|
||||
let err = TestErr::NamedExplicitBacktraceByFieldTypeRedundant {
|
||||
implicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_supresses_implicit() {
|
||||
let err = TestErr::NamedExplicitSupressesImplicit {
|
||||
not_backtrace: Backtrace::force_capture(),
|
||||
backtrace: (|| Backtrace::force_capture())(), // ensure backtraces are different
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
assert_bt!(!=, err, .get_unused_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_no_backtrace() {
|
||||
let err = TestErr::UnnamedImplicitNoBacktrace(0, 0);
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_backtrace() {
|
||||
let err = TestErr::UnnamedImplicitBacktrace(Backtrace::force_capture(), 0, 0);
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_backtrace() {
|
||||
let err = TestErr::UnnamedExplicitNoBacktrace(Backtrace::force_capture(), 0);
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_backtrace() {
|
||||
let err = TestErr::UnnamedExplicitBacktrace(Backtrace::force_capture(), 0, 0);
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_backtrace_redundant() {
|
||||
let err =
|
||||
TestErr::UnnamedExplicitNoBacktraceRedundant(Backtrace::force_capture(), 0);
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_backtrace_redundant() {
|
||||
let err =
|
||||
TestErr::UnnamedExplicitBacktraceRedundant(Backtrace::force_capture(), 0, 0);
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_supresses_implicit() {
|
||||
let err = TestErr::UnnamedExplicitSupressesImplicit(
|
||||
Backtrace::force_capture(),
|
||||
(|| Backtrace::force_capture())(), // ensure backtraces are different
|
||||
0,
|
||||
);
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
assert_bt!(!=, err, .get_unused_backtrace);
|
||||
}
|
272
third_party/rust/derive_more/tests/error/nightly/derives_for_generic_enums_with_backtrace.rs
поставляемый
Normal file
272
third_party/rust/derive_more/tests/error/nightly/derives_for_generic_enums_with_backtrace.rs
поставляемый
Normal file
|
@ -0,0 +1,272 @@
|
|||
use super::*;
|
||||
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
enum TestErr<T> {
|
||||
Unit,
|
||||
NamedImplicitNoBacktrace {
|
||||
field: T,
|
||||
},
|
||||
NamedImplicitBacktraceByFieldName {
|
||||
backtrace: MyBacktrace,
|
||||
field: T,
|
||||
},
|
||||
NamedImplicitBacktraceByFieldType {
|
||||
implicit_backtrace: Backtrace,
|
||||
field: T,
|
||||
},
|
||||
NamedExplicitNoBacktraceByFieldName {
|
||||
#[error(not(backtrace))]
|
||||
backtrace: MyBacktrace,
|
||||
field: T,
|
||||
},
|
||||
NamedExplicitNoBacktraceByFieldType {
|
||||
#[error(not(backtrace))]
|
||||
implicit_backtrace: Backtrace,
|
||||
field: T,
|
||||
},
|
||||
NamedExplicitBacktrace {
|
||||
#[error(backtrace)]
|
||||
explicit_backtrace: MyBacktrace,
|
||||
field: T,
|
||||
},
|
||||
NamedExplicitNoBacktraceRedundant {
|
||||
#[error(not(backtrace))]
|
||||
not_backtrace: MyBacktrace,
|
||||
#[error(not(backtrace))]
|
||||
field: T,
|
||||
},
|
||||
NamedExplicitBacktraceByFieldNameRedundant {
|
||||
#[error(backtrace)]
|
||||
backtrace: MyBacktrace,
|
||||
field: T,
|
||||
},
|
||||
NamedExplicitBacktraceByFieldTypeRedundant {
|
||||
#[error(backtrace)]
|
||||
implicit_backtrace: Backtrace,
|
||||
field: T,
|
||||
},
|
||||
NamedExplicitSupressesImplicit {
|
||||
#[error(backtrace)]
|
||||
not_backtrace: MyBacktrace,
|
||||
backtrace: Backtrace,
|
||||
field: T,
|
||||
},
|
||||
UnnamedImplicitNoBacktrace(T, T),
|
||||
UnnamedImplicitBacktrace(Backtrace, T, T),
|
||||
UnnamedExplicitNoBacktrace(#[error(not(backtrace))] Backtrace, T),
|
||||
UnnamedExplicitBacktrace(#[error(backtrace)] MyBacktrace, T, T),
|
||||
UnnamedExplicitNoBacktraceRedundant(
|
||||
#[error(not(backtrace))] MyBacktrace,
|
||||
#[error(not(backtrace))] T,
|
||||
),
|
||||
UnnamedExplicitBacktraceRedundant(#[error(backtrace)] Backtrace, T, T),
|
||||
UnnamedExplicitSupressesImplicit(#[error(backtrace)] MyBacktrace, Backtrace, T),
|
||||
}
|
||||
|
||||
impl<T> TestErr<T> {
|
||||
fn get_stored_backtrace(&self) -> &Backtrace {
|
||||
match self {
|
||||
Self::NamedImplicitBacktraceByFieldName { backtrace, .. } => backtrace,
|
||||
Self::NamedImplicitBacktraceByFieldType {
|
||||
implicit_backtrace, ..
|
||||
} => implicit_backtrace,
|
||||
Self::NamedExplicitBacktrace {
|
||||
explicit_backtrace, ..
|
||||
} => explicit_backtrace,
|
||||
Self::NamedExplicitBacktraceByFieldNameRedundant { backtrace, .. } => {
|
||||
backtrace
|
||||
}
|
||||
Self::NamedExplicitBacktraceByFieldTypeRedundant {
|
||||
implicit_backtrace,
|
||||
..
|
||||
} => implicit_backtrace,
|
||||
Self::NamedExplicitSupressesImplicit { not_backtrace, .. } => not_backtrace,
|
||||
Self::UnnamedImplicitBacktrace(backtrace, _, _) => backtrace,
|
||||
Self::UnnamedExplicitBacktrace(backtrace, _, _) => backtrace,
|
||||
Self::UnnamedExplicitBacktraceRedundant(backtrace, _, _) => backtrace,
|
||||
Self::UnnamedExplicitSupressesImplicit(backtrace, _, _) => backtrace,
|
||||
_ => panic!("ERROR IN TEST IMPLEMENTATION"),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_unused_backtrace(&self) -> &Backtrace {
|
||||
match self {
|
||||
Self::NamedExplicitSupressesImplicit { backtrace, .. } => backtrace,
|
||||
Self::UnnamedExplicitSupressesImplicit(_, backtrace, _) => backtrace,
|
||||
_ => panic!("ERROR IN TEST IMPLEMENTATION"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
#[test]
|
||||
fn unit() {
|
||||
assert!(TestErr::<i32>::Unit.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_no_backtrace() {
|
||||
let err = TestErr::NamedImplicitNoBacktrace { field: 0 };
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_backtrace_by_field_name() {
|
||||
let err = TestErr::NamedImplicitBacktraceByFieldName {
|
||||
backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_backtrace_by_field_type() {
|
||||
let err = TestErr::NamedImplicitBacktraceByFieldType {
|
||||
implicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_backtrace_by_field_name() {
|
||||
let err = TestErr::NamedExplicitNoBacktraceByFieldName {
|
||||
backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_backtrace_by_field_type() {
|
||||
let err = TestErr::NamedExplicitNoBacktraceByFieldType {
|
||||
implicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_backtrace() {
|
||||
let err = TestErr::NamedExplicitBacktrace {
|
||||
explicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_backtrace_redundant() {
|
||||
let err = TestErr::NamedExplicitNoBacktraceRedundant {
|
||||
not_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_backtrace_by_field_name_redundant() {
|
||||
let err = TestErr::NamedExplicitBacktraceByFieldNameRedundant {
|
||||
backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_backtrace_by_field_type_redundant() {
|
||||
let err = TestErr::NamedExplicitBacktraceByFieldTypeRedundant {
|
||||
implicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_supresses_implicit() {
|
||||
let err = TestErr::NamedExplicitSupressesImplicit {
|
||||
not_backtrace: Backtrace::force_capture(),
|
||||
backtrace: (|| Backtrace::force_capture())(), // ensure backtraces are different
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
assert_bt!(!=, err, .get_unused_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_no_backtrace() {
|
||||
let err = TestErr::UnnamedImplicitNoBacktrace(0, 0);
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_backtrace() {
|
||||
let err = TestErr::UnnamedImplicitBacktrace(Backtrace::force_capture(), 0, 0);
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_backtrace() {
|
||||
let err = TestErr::UnnamedExplicitNoBacktrace(Backtrace::force_capture(), 0);
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_backtrace() {
|
||||
let err = TestErr::UnnamedExplicitBacktrace(Backtrace::force_capture(), 0, 0);
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_backtrace_redundant() {
|
||||
let err =
|
||||
TestErr::UnnamedExplicitNoBacktraceRedundant(Backtrace::force_capture(), 0);
|
||||
|
||||
assert!(err.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_backtrace_redundant() {
|
||||
let err =
|
||||
TestErr::UnnamedExplicitBacktraceRedundant(Backtrace::force_capture(), 0, 0);
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_supresses_implicit() {
|
||||
let err = TestErr::UnnamedExplicitSupressesImplicit(
|
||||
Backtrace::force_capture(),
|
||||
(|| Backtrace::force_capture())(), // ensure backtraces are different
|
||||
0,
|
||||
);
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, .get_stored_backtrace);
|
||||
assert_bt!(!=, err, .get_unused_backtrace);
|
||||
}
|
275
third_party/rust/derive_more/tests/error/nightly/derives_for_generic_structs_with_backtrace.rs
поставляемый
Normal file
275
third_party/rust/derive_more/tests/error/nightly/derives_for_generic_structs_with_backtrace.rs
поставляемый
Normal file
|
@ -0,0 +1,275 @@
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn named_implicit_no_backtrace() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<T> {
|
||||
field: T,
|
||||
}
|
||||
|
||||
assert!(TestErr::<i32>::default().backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_backtrace_by_field_name() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T> {
|
||||
backtrace: MyBacktrace,
|
||||
field: T,
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
let err = TestErr {
|
||||
backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_backtrace_by_field_type() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T> {
|
||||
implicit_backtrace: Backtrace,
|
||||
field: T,
|
||||
}
|
||||
|
||||
let err = TestErr {
|
||||
implicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, implicit_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_backtrace_by_field_name() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T> {
|
||||
#[error(not(backtrace))]
|
||||
backtrace: MyBacktrace,
|
||||
field: T,
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
assert!(TestErr {
|
||||
backtrace: Backtrace::force_capture(),
|
||||
field: 0
|
||||
}
|
||||
.backtrace()
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_backtrace_by_field_type() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T> {
|
||||
#[error(not(backtrace))]
|
||||
implicit_backtrace: Backtrace,
|
||||
field: T,
|
||||
}
|
||||
|
||||
assert!(TestErr {
|
||||
implicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0
|
||||
}
|
||||
.backtrace()
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_backtrace() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T> {
|
||||
#[error(backtrace)]
|
||||
explicit_backtrace: MyBacktrace,
|
||||
field: T,
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
let err = TestErr {
|
||||
explicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, explicit_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_backtrace_redundant() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T> {
|
||||
#[error(not(backtrace))]
|
||||
not_backtrace: MyBacktrace,
|
||||
#[error(not(backtrace))]
|
||||
field: T,
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
assert!(TestErr {
|
||||
not_backtrace: Backtrace::force_capture(),
|
||||
field: 0
|
||||
}
|
||||
.backtrace()
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_backtrace_by_field_name_redundant() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T> {
|
||||
#[error(backtrace)]
|
||||
backtrace: MyBacktrace,
|
||||
field: T,
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
let err = TestErr {
|
||||
backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_backtrace_by_field_type_redundant() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T> {
|
||||
#[error(backtrace)]
|
||||
implicit_backtrace: Backtrace,
|
||||
field: T,
|
||||
}
|
||||
|
||||
let err = TestErr {
|
||||
implicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, implicit_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_supresses_implicit() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T> {
|
||||
#[error(backtrace)]
|
||||
not_backtrace: MyBacktrace,
|
||||
backtrace: Backtrace,
|
||||
field: T,
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
let err = TestErr {
|
||||
not_backtrace: Backtrace::force_capture(),
|
||||
backtrace: (|| Backtrace::force_capture())(), // ensure backtraces are different
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, not_backtrace);
|
||||
assert_bt!(!=, err);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_no_backtrace() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr<T>(T, T);
|
||||
|
||||
assert!(TestErr::<i32>::default().backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_backtrace() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T>(Backtrace, T, T);
|
||||
|
||||
let err = TestErr(Backtrace::force_capture(), 0, 0);
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_backtrace() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T>(#[error(not(backtrace))] Backtrace, T);
|
||||
|
||||
assert!(TestErr(Backtrace::force_capture(), 0).backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_backtrace() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T>(#[error(backtrace)] MyBacktrace, T, T);
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
let err = TestErr(Backtrace::force_capture(), 0, 0);
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_backtrace_redundant() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T>(
|
||||
#[error(not(backtrace))] MyBacktrace,
|
||||
#[error(not(backtrace))] T,
|
||||
);
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
assert!(TestErr(Backtrace::force_capture(), 0).backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_backtrace_redundant() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T>(#[error(backtrace)] Backtrace, T, T);
|
||||
|
||||
let err = TestErr(Backtrace::force_capture(), 0, 0);
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_supresses_implicit() {
|
||||
derive_display!(TestErr, T);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr<T>(#[error(backtrace)] MyBacktrace, Backtrace, T);
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
let err = TestErr(
|
||||
Backtrace::force_capture(),
|
||||
(|| Backtrace::force_capture())(), // ensure backtraces are different
|
||||
0,
|
||||
);
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, 0);
|
||||
assert_bt!(!=, err, 1);
|
||||
}
|
280
third_party/rust/derive_more/tests/error/nightly/derives_for_structs_with_backtrace.rs
поставляемый
Normal file
280
third_party/rust/derive_more/tests/error/nightly/derives_for_structs_with_backtrace.rs
поставляемый
Normal file
|
@ -0,0 +1,280 @@
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn unit() {
|
||||
assert!(SimpleErr.backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_no_backtrace() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
assert!(TestErr::default().backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_backtrace_by_field_name() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr {
|
||||
backtrace: MyBacktrace,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
let err = TestErr {
|
||||
backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_implicit_backtrace_by_field_type() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr {
|
||||
implicit_backtrace: Backtrace,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
let err = TestErr {
|
||||
implicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, implicit_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_backtrace_by_field_name() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr {
|
||||
#[error(not(backtrace))]
|
||||
backtrace: MyBacktrace,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
assert!(TestErr {
|
||||
backtrace: Backtrace::force_capture(),
|
||||
field: 0
|
||||
}
|
||||
.backtrace()
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_backtrace_by_field_type() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr {
|
||||
#[error(not(backtrace))]
|
||||
implicit_backtrace: Backtrace,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
assert!(TestErr {
|
||||
implicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0
|
||||
}
|
||||
.backtrace()
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_backtrace() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr {
|
||||
#[error(backtrace)]
|
||||
explicit_backtrace: MyBacktrace,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
let err = TestErr {
|
||||
explicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, explicit_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_no_backtrace_redundant() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr {
|
||||
#[error(not(backtrace))]
|
||||
not_backtrace: MyBacktrace,
|
||||
#[error(not(backtrace))]
|
||||
field: i32,
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
assert!(TestErr {
|
||||
not_backtrace: Backtrace::force_capture(),
|
||||
field: 0
|
||||
}
|
||||
.backtrace()
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_backtrace_by_field_name_redundant() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr {
|
||||
#[error(backtrace)]
|
||||
backtrace: MyBacktrace,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
let err = TestErr {
|
||||
backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_backtrace_by_field_type_redundant() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr {
|
||||
#[error(backtrace)]
|
||||
implicit_backtrace: Backtrace,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
let err = TestErr {
|
||||
implicit_backtrace: Backtrace::force_capture(),
|
||||
field: 0,
|
||||
};
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, implicit_backtrace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_explicit_supresses_implicit() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr {
|
||||
#[error(backtrace)]
|
||||
not_backtrace: MyBacktrace,
|
||||
backtrace: Backtrace,
|
||||
field: i32,
|
||||
}
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
let err = TestErr {
|
||||
not_backtrace: Backtrace::force_capture(),
|
||||
backtrace: (|| Backtrace::force_capture())(), // ensure backtraces are different
|
||||
field: 0,
|
||||
};
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, not_backtrace);
|
||||
assert_bt!(!=, err);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_no_backtrace() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Default, Debug, Error)]
|
||||
struct TestErr(i32, i32);
|
||||
|
||||
assert!(TestErr::default().backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_implicit_backtrace() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr(Backtrace, i32, i32);
|
||||
|
||||
let err = TestErr(Backtrace::force_capture(), 0, 0);
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_backtrace() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr(#[error(not(backtrace))] Backtrace, i32);
|
||||
|
||||
assert!(TestErr(Backtrace::force_capture(), 0).backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_backtrace() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr(#[error(backtrace)] MyBacktrace, i32, i32);
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
let err = TestErr(Backtrace::force_capture(), 0, 0);
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_no_backtrace_redundant() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr(
|
||||
#[error(not(backtrace))] MyBacktrace,
|
||||
#[error(not(backtrace))] i32,
|
||||
);
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
assert!(TestErr(Backtrace::force_capture(), 0).backtrace().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_backtrace_redundant() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr(#[error(backtrace)] Backtrace, i32, i32);
|
||||
|
||||
let err = TestErr(Backtrace::force_capture(), 0, 0);
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_explicit_supresses_implicit() {
|
||||
derive_display!(TestErr);
|
||||
#[derive(Debug, Error)]
|
||||
struct TestErr(#[error(backtrace)] MyBacktrace, Backtrace, i32);
|
||||
|
||||
type MyBacktrace = Backtrace;
|
||||
|
||||
let err = TestErr(
|
||||
Backtrace::force_capture(),
|
||||
(|| Backtrace::force_capture())(), // ensure backtraces are different
|
||||
0,
|
||||
);
|
||||
|
||||
assert!(err.backtrace().is_some());
|
||||
assert_bt!(==, err, 0);
|
||||
assert_bt!(!=, err, 1);
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
use std::backtrace::Backtrace;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Asserts that backtrace returned by `Error::backtrace` method equals/not-equals
|
||||
/// backtrace stored in object itself.
|
||||
///
|
||||
/// Comparison is done by converting backtraces to strings
|
||||
/// and then comparing these strings.
|
||||
///
|
||||
/// ## Syntax
|
||||
///
|
||||
/// * Equals: `assert_bt!(==, ...)`
|
||||
/// * Not-equals: `assert_bt!(!=, ...)`
|
||||
///
|
||||
/// ### Backtrace Access
|
||||
///
|
||||
/// Shortcut for named-structs with `backtrace` field.
|
||||
/// Access backtrace as `error.backtrace`.
|
||||
///
|
||||
/// ```
|
||||
/// assert_bt!(==, error);
|
||||
/// ```
|
||||
///
|
||||
/// Full form for named- and tuple-structs.
|
||||
/// Access backtrace as `error.some_other_field` and `error.1` respectively.
|
||||
///
|
||||
/// ```
|
||||
/// assert_bt!(!=, error, some_other_field);
|
||||
/// assert_bt!(==, error, 1);
|
||||
/// ```
|
||||
///
|
||||
/// Access as a method call.
|
||||
/// Useful for enums (i.e., you can define a method that will match on enum variants
|
||||
/// and return backtrace for each variant).
|
||||
/// Access backtrace as `error.get_stored_backtrace_method()`.
|
||||
///
|
||||
/// ```
|
||||
/// assert_bt!(!=, error, .get_stored_backtrace_method);
|
||||
/// ```
|
||||
macro_rules! assert_bt {
|
||||
(@impl $macro:ident, $error:expr, $backtrace:expr) => {
|
||||
$macro!($error.backtrace().unwrap().to_string(), $backtrace.to_string());
|
||||
};
|
||||
(@expand $macro:ident, $error:expr, .$backtrace:ident) => {
|
||||
assert_bt!(@impl $macro, $error, $error.$backtrace())
|
||||
};
|
||||
(@expand $macro:ident, $error:expr, $backtrace:tt) => {
|
||||
assert_bt!(@impl $macro, $error, $error.$backtrace)
|
||||
};
|
||||
(@expand $macro:ident, $error:expr) => {
|
||||
assert_bt!(@expand $macro, $error, backtrace)
|
||||
};
|
||||
(==, $($args:tt)*) => {
|
||||
assert_bt!(@expand assert_eq, $($args)*)
|
||||
};
|
||||
(!=, $($args:tt)*) => {
|
||||
assert_bt!(@expand assert_ne, $($args)*)
|
||||
};
|
||||
}
|
||||
|
||||
mod derives_for_enums_with_backtrace;
|
||||
mod derives_for_generic_enums_with_backtrace;
|
||||
mod derives_for_generic_structs_with_backtrace;
|
||||
mod derives_for_structs_with_backtrace;
|
||||
|
||||
derive_display!(BacktraceErr);
|
||||
#[derive(Debug)]
|
||||
struct BacktraceErr {
|
||||
backtrace: Backtrace,
|
||||
}
|
||||
|
||||
impl Default for BacktraceErr {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
backtrace: Backtrace::force_capture(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for BacktraceErr {
|
||||
fn backtrace(&self) -> Option<&Backtrace> {
|
||||
Some(&self.backtrace)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#![cfg_attr(feature = "nightly", feature(backtrace))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
mod error;
|
|
@ -0,0 +1,171 @@
|
|||
#![allow(dead_code)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(From)]
|
||||
struct EmptyTuple();
|
||||
|
||||
#[derive(From)]
|
||||
struct EmptyStruct {}
|
||||
|
||||
#[derive(From)]
|
||||
struct EmptyUnit;
|
||||
|
||||
#[derive(From)]
|
||||
struct MyInt(i32);
|
||||
|
||||
#[derive(From)]
|
||||
struct MyInts(i32, i32);
|
||||
|
||||
#[derive(From)]
|
||||
struct Point1D {
|
||||
x: i32,
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
struct Point2D {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
enum MixedInts {
|
||||
SmallInt(i32),
|
||||
NamedBigInt {
|
||||
int: i64,
|
||||
},
|
||||
TwoSmallInts(i32, i32),
|
||||
NamedBigInts {
|
||||
x: i64,
|
||||
y: i64,
|
||||
},
|
||||
#[from(ignore)]
|
||||
Unsigned(u32),
|
||||
NamedUnsigned {
|
||||
x: u32,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
#[derive(From)]
|
||||
#[from(forward)]
|
||||
struct MyIntForward(u64);
|
||||
|
||||
#[test]
|
||||
fn forward_struct() {
|
||||
assert_eq!(MyIntForward(42), 42u32.into());
|
||||
assert_eq!(MyIntForward(42), 42u16.into());
|
||||
assert_eq!(MyIntForward(42), 42u64.into());
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
#[derive(From)]
|
||||
enum MixedIntsForward {
|
||||
#[from(forward)]
|
||||
SmallInt(i32),
|
||||
NamedBigInt {
|
||||
int: i64,
|
||||
},
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn forward_enum() {
|
||||
assert_eq!(MixedIntsForward::SmallInt(42), 42i32.into());
|
||||
assert_eq!(MixedIntsForward::SmallInt(42), 42i16.into());
|
||||
}
|
||||
|
||||
#[derive(From, PartialEq)]
|
||||
enum AutoIgnore {
|
||||
SmallInt(i32),
|
||||
Uninteresting,
|
||||
Uninteresting2,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_ignore_variants() {
|
||||
assert!(AutoIgnore::SmallInt(42) == 42i32.into());
|
||||
}
|
||||
|
||||
#[derive(From, PartialEq)]
|
||||
enum AutoIgnoreWithDefaultTrue {
|
||||
#[from(ignore)]
|
||||
SmallInt(i32),
|
||||
Uninteresting,
|
||||
Uninteresting2,
|
||||
}
|
||||
|
||||
#[derive(From, PartialEq)]
|
||||
enum AutoIgnoreWithForwardFields2 {
|
||||
#[from(forward)]
|
||||
SmallInt(i32),
|
||||
SmallIntIgnore(i32),
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_ignore_with_forward_field2() {
|
||||
assert!(AutoIgnoreWithForwardFields2::SmallInt(42) == 42i32.into());
|
||||
assert!(AutoIgnoreWithForwardFields2::SmallInt(42) == 42i16.into());
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(From)]
|
||||
#[from(types(u8, u16, u32))]
|
||||
struct MyIntExplicit(u64);
|
||||
|
||||
#[test]
|
||||
fn explicit_types_struct() {
|
||||
assert_eq!(MyIntExplicit(42), 42u8.into());
|
||||
assert_eq!(MyIntExplicit(42), 42u16.into());
|
||||
assert_eq!(MyIntExplicit(42), 42u32.into());
|
||||
assert_eq!(MyIntExplicit(42), 42u64.into());
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(From)]
|
||||
#[from(types(i8, i16))]
|
||||
struct MyIntsExplicit(i32, i32);
|
||||
|
||||
#[test]
|
||||
fn explicit_types_struct_tupled() {
|
||||
assert_eq!(MyIntsExplicit(42, 42), (42i32, 42i32).into());
|
||||
assert_eq!(MyIntsExplicit(42, 42), (42i8, 42i8).into());
|
||||
assert_eq!(MyIntsExplicit(42, 42), (42i16, 42i16).into());
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(From)]
|
||||
enum MixedIntsExplicit {
|
||||
#[from(types(i8))]
|
||||
SmallInt(i32),
|
||||
#[from(types(i16, i64))]
|
||||
AnotherInt(i128),
|
||||
NamedBigInt {
|
||||
int: i64,
|
||||
},
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicit_types_enum() {
|
||||
assert_eq!(MixedIntsExplicit::SmallInt(42), 42i32.into());
|
||||
assert_eq!(MixedIntsExplicit::SmallInt(42), 42i8.into());
|
||||
|
||||
assert_eq!(MixedIntsExplicit::AnotherInt(42), 42i128.into());
|
||||
assert_eq!(MixedIntsExplicit::AnotherInt(42), 42i64.into());
|
||||
assert_eq!(MixedIntsExplicit::AnotherInt(42), 42i16.into());
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(From)]
|
||||
#[from(types(i8, i16))]
|
||||
struct Point2DExplicit {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicit_types_point_2d() {
|
||||
let expected = Point2DExplicit { x: 42, y: 42 };
|
||||
assert_eq!(expected, (42i32, 42i32).into());
|
||||
assert_eq!(expected, (42i8, 42i8).into());
|
||||
assert_eq!(expected, (42i16, 42i16).into());
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#![allow(dead_code)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(FromStr)]
|
||||
struct MyInt(i32);
|
||||
|
||||
#[derive(FromStr)]
|
||||
struct Point1D {
|
||||
x: i32,
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
#![allow(dead_code, non_camel_case_types)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(
|
||||
From,
|
||||
FromStr,
|
||||
Display,
|
||||
Index,
|
||||
Not,
|
||||
Add,
|
||||
Mul,
|
||||
Sum,
|
||||
IndexMut,
|
||||
AddAssign,
|
||||
MulAssign,
|
||||
Deref,
|
||||
DerefMut,
|
||||
IntoIterator,
|
||||
Constructor
|
||||
)]
|
||||
#[deref(forward)]
|
||||
#[deref_mut(forward)]
|
||||
#[into_iterator(owned, ref, ref_mut)]
|
||||
struct Wrapped<T: Clone>(T);
|
||||
|
||||
#[derive(Deref, DerefMut)]
|
||||
struct Wrapped2<T: Clone>(T);
|
||||
|
||||
#[derive(From, Not, Add, Mul, AddAssign, MulAssign, Constructor, Sum)]
|
||||
struct WrappedDouble<T: Clone, U: Clone>(T, U);
|
||||
|
||||
#[derive(From)]
|
||||
#[from(forward)]
|
||||
struct WrappedDouble2<T: Clone, U: Clone>(T, U);
|
||||
|
||||
#[derive(
|
||||
From,
|
||||
FromStr,
|
||||
Display,
|
||||
Index,
|
||||
Not,
|
||||
Add,
|
||||
Mul,
|
||||
IndexMut,
|
||||
AddAssign,
|
||||
MulAssign,
|
||||
Deref,
|
||||
DerefMut,
|
||||
IntoIterator,
|
||||
Constructor,
|
||||
Sum
|
||||
)]
|
||||
#[deref(forward)]
|
||||
#[deref_mut(forward)]
|
||||
#[into_iterator(owned, ref, ref_mut)]
|
||||
struct Struct<T: Clone> {
|
||||
t: T,
|
||||
}
|
||||
|
||||
#[derive(Deref, DerefMut)]
|
||||
struct Struct2<T: Clone> {
|
||||
t: T,
|
||||
}
|
||||
|
||||
#[derive(From, Not, Add, Mul, AddAssign, MulAssign, Constructor, Sum)]
|
||||
struct DoubleStruct<T: Clone, U: Clone> {
|
||||
t: T,
|
||||
u: U,
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
#[from(forward)]
|
||||
struct DoubleStruct2<T: Clone, U: Clone> {
|
||||
t: T,
|
||||
u: U,
|
||||
}
|
||||
|
||||
#[derive(From, Not, Add)]
|
||||
enum TupleEnum<T: Clone, U: Clone> {
|
||||
Tuple(T),
|
||||
DoubleTuple(T, U),
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
#[from(forward)]
|
||||
enum TupleEnum2<T: Clone, U: Clone, X: Clone> {
|
||||
DoubleTuple(T, U),
|
||||
TripleTuple(T, U, X),
|
||||
}
|
||||
|
||||
#[derive(From, Not, Add)]
|
||||
enum StructEnum<T: Clone, U: Clone> {
|
||||
Struct { t: T },
|
||||
DoubleStruct { t: T, u: U },
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
#[from(forward)]
|
||||
enum StructEnum2<T: Clone, U: Clone, X: Clone> {
|
||||
DoubleStruct { t: T, u: U },
|
||||
TripleStruct { t: T, u: U, x: X },
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#![allow(dead_code, unused_imports)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(Index)]
|
||||
struct MyVec(Vec<i32>);
|
||||
|
||||
#[derive(Index)]
|
||||
struct Numbers {
|
||||
#[index]
|
||||
numbers: Vec<i32>,
|
||||
useless: bool,
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#![allow(dead_code, unused_imports)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(IndexMut)]
|
||||
struct MyVec(Vec<i32>);
|
||||
//Index implementation is required for IndexMut
|
||||
impl<__IdxT> ::core::ops::Index<__IdxT> for MyVec
|
||||
where
|
||||
Vec<i32>: ::core::ops::Index<__IdxT>,
|
||||
{
|
||||
type Output = <Vec<i32> as ::core::ops::Index<__IdxT>>::Output;
|
||||
#[inline]
|
||||
fn index(&self, idx: __IdxT) -> &Self::Output {
|
||||
<Vec<i32> as ::core::ops::Index<__IdxT>>::index(&self.0, idx)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(IndexMut)]
|
||||
struct Numbers {
|
||||
#[index_mut]
|
||||
numbers: Vec<i32>,
|
||||
useless: bool,
|
||||
}
|
||||
|
||||
//Index implementation is required for IndexMut
|
||||
impl<__IdxT> ::core::ops::Index<__IdxT> for Numbers
|
||||
where
|
||||
Vec<i32>: ::core::ops::Index<__IdxT>,
|
||||
{
|
||||
type Output = <Vec<i32> as ::core::ops::Index<__IdxT>>::Output;
|
||||
#[inline]
|
||||
fn index(&self, idx: __IdxT) -> &Self::Output {
|
||||
<Vec<i32> as ::core::ops::Index<__IdxT>>::index(&self.numbers, idx)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
#![allow(dead_code)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(Into)]
|
||||
#[into(owned, ref, ref_mut)]
|
||||
struct EmptyTuple();
|
||||
|
||||
#[derive(Into)]
|
||||
#[into(owned, ref, ref_mut)]
|
||||
struct EmptyStruct {}
|
||||
|
||||
#[derive(Into)]
|
||||
#[into(owned, ref, ref_mut)]
|
||||
struct EmptyUnit;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[derive(Into)]
|
||||
#[into(owned(types(i64, i128)), ref, ref_mut)]
|
||||
struct MyInt(i32);
|
||||
|
||||
#[test]
|
||||
fn explicit_types_struct_owned_only() {
|
||||
assert_eq!(i32::from(MyInt(42)), 42i32);
|
||||
assert_eq!(<&i32>::from(&MyInt(42)), &42i32);
|
||||
assert_eq!(<&mut i32>::from(&mut MyInt(42)), &mut 42i32);
|
||||
assert_eq!(i64::from(MyInt(42)), 42i64);
|
||||
assert_eq!(i128::from(MyInt(42)), 42i128);
|
||||
}
|
||||
|
||||
#[derive(Into)]
|
||||
#[into(owned, ref, ref_mut)]
|
||||
struct MyInts(i32, i32);
|
||||
|
||||
#[derive(Into)]
|
||||
#[into(owned, ref, ref_mut)]
|
||||
struct Point1D {
|
||||
x: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Into)]
|
||||
#[into(owned, ref, ref_mut)]
|
||||
struct Point2D {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
#[derive(Into)]
|
||||
#[into(owned, ref, ref_mut)]
|
||||
struct Point2DWithIgnored {
|
||||
x: i32,
|
||||
y: i32,
|
||||
#[into(ignore)]
|
||||
useless: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[derive(Into)]
|
||||
#[into(owned(types(i64, i128)), ref, ref_mut, types(i32))]
|
||||
struct MyIntExplicit(MyInt);
|
||||
|
||||
#[test]
|
||||
fn explicit_types_struct_all() {
|
||||
let mut input = MyIntExplicit(MyInt(42));
|
||||
assert_eq!(MyInt::from(input), MyInt(42));
|
||||
assert_eq!(<&MyInt>::from(&input), &MyInt(42));
|
||||
assert_eq!(<&mut MyInt>::from(&mut input), &mut MyInt(42));
|
||||
assert_eq!(i32::from(input), 42i32);
|
||||
assert_eq!(<&i32>::from(&input), &42i32);
|
||||
assert_eq!(<&mut i32>::from(&mut input), &mut 42i32);
|
||||
assert_eq!(i64::from(input), 42i64);
|
||||
assert_eq!(i128::from(input), 42i128);
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[derive(Into)]
|
||||
#[into(owned(types(i32, i64, i128)), ref(types(i32)), ref_mut(types(i32)))]
|
||||
struct MyIntsExplicit(i32, MyInt, MyIntExplicit);
|
||||
|
||||
#[test]
|
||||
fn explicit_types_struct_tupled() {
|
||||
let mut input = MyIntsExplicit(42i32, MyInt(42), MyIntExplicit(MyInt(42)));
|
||||
assert_eq!(
|
||||
<(i32, MyInt, MyIntExplicit)>::from(input),
|
||||
(42i32, MyInt(42), MyIntExplicit(MyInt(42))),
|
||||
);
|
||||
assert_eq!(
|
||||
<(&i32, &MyInt, &MyIntExplicit)>::from(&input),
|
||||
(&42i32, &MyInt(42), &MyIntExplicit(MyInt(42))),
|
||||
);
|
||||
assert_eq!(
|
||||
<(&mut i32, &mut MyInt, &mut MyIntExplicit)>::from(&mut input),
|
||||
(&mut 42i32, &mut MyInt(42), &mut MyIntExplicit(MyInt(42))),
|
||||
);
|
||||
assert_eq!(<(i32, i32, i32)>::from(input), (42i32, 42i32, 42i32));
|
||||
assert_eq!(<(&i32, &i32, &i32)>::from(&input), (&42i32, &42i32, &42i32));
|
||||
assert_eq!(
|
||||
<(&mut i32, &mut i32, &mut i32)>::from(&mut input),
|
||||
(&mut 42i32, &mut 42i32, &mut 42i32),
|
||||
);
|
||||
assert_eq!(<(i64, i64, i64)>::from(input), (42i64, 42i64, 42i64));
|
||||
assert_eq!(<(i128, i128, i128)>::from(input), (42i128, 42i128, 42i128));
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[derive(Into)]
|
||||
#[into(owned, ref, ref_mut, types(i32))]
|
||||
struct Point2DExplicit {
|
||||
x: MyInt,
|
||||
y: MyInt,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicit_types_point_2d() {
|
||||
let mut input = Point2DExplicit {
|
||||
x: MyInt(42),
|
||||
y: MyInt(42),
|
||||
};
|
||||
assert_eq!(<(i32, i32)>::from(input), (42i32, 42i32));
|
||||
assert_eq!(<(&i32, &i32)>::from(&input), (&42i32, &42i32));
|
||||
assert_eq!(
|
||||
<(&mut i32, &mut i32)>::from(&mut input),
|
||||
(&mut 42i32, &mut 42i32)
|
||||
);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
#![allow(dead_code, unused_imports)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(IntoIterator)]
|
||||
#[into_iterator(owned, ref, ref_mut)]
|
||||
struct MyVec(Vec<i32>);
|
||||
|
||||
#[derive(IntoIterator)]
|
||||
#[into_iterator(owned, ref, ref_mut)]
|
||||
struct Numbers {
|
||||
numbers: Vec<i32>,
|
||||
}
|
||||
|
||||
#[derive(IntoIterator)]
|
||||
struct Numbers2 {
|
||||
#[into_iterator(owned, ref, ref_mut)]
|
||||
numbers: Vec<i32>,
|
||||
useless: bool,
|
||||
useless2: bool,
|
||||
}
|
||||
|
||||
#[derive(IntoIterator)]
|
||||
struct Numbers3 {
|
||||
#[into_iterator(ref, ref_mut)]
|
||||
numbers: Vec<i32>,
|
||||
useless: bool,
|
||||
useless2: bool,
|
||||
}
|
||||
|
||||
// Test that owned is not enabled when ref/ref_mut are enabled without owned
|
||||
impl ::core::iter::IntoIterator for Numbers3 {
|
||||
type Item = <Vec<i32> as ::core::iter::IntoIterator>::Item;
|
||||
type IntoIter = <Vec<i32> as ::core::iter::IntoIterator>::IntoIter;
|
||||
#[inline]
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
<Vec<i32> as ::core::iter::IntoIterator>::into_iter(self.numbers)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(From)]
|
||||
#[derive(Into)]
|
||||
#[derive(Constructor)]
|
||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
||||
#[derive(Add)]
|
||||
#[derive(Mul)]
|
||||
#[derive(Neg)]
|
||||
#[derive(AddAssign)]
|
||||
#[derive(MulAssign)]
|
||||
#[derive(FromStr)]
|
||||
#[derive(Display)]
|
||||
#[derive(Octal)]
|
||||
#[derive(Binary)]
|
||||
#[derive(Deref, DerefMut)]
|
||||
#[into(owned, ref, ref_mut)]
|
||||
struct MyInt(i32);
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Add)]
|
||||
#[derive(Sum)]
|
||||
#[derive(Mul)]
|
||||
#[derive(MulAssign)]
|
||||
#[derive(Product)]
|
||||
#[mul(forward)]
|
||||
#[mul_assign(forward)]
|
||||
struct MyInt2(i32);
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(Index, IndexMut)]
|
||||
#[derive(Deref, DerefMut)]
|
||||
#[derive(IntoIterator)]
|
||||
#[deref(forward)]
|
||||
#[deref_mut(forward)]
|
||||
#[into_iterator(owned, ref, ref_mut)]
|
||||
struct MyVec(Vec<i32>);
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(Deref, DerefMut)]
|
||||
#[deref(forward)]
|
||||
#[deref_mut(forward)]
|
||||
struct MyBoxedInt(Box<i32>);
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(Not)]
|
||||
#[derive(From)]
|
||||
struct MyBool(bool);
|
||||
|
||||
#[derive(From)]
|
||||
#[derive(Into)]
|
||||
#[derive(Constructor)]
|
||||
#[derive(Add)]
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(Mul)]
|
||||
#[derive(AddAssign)]
|
||||
struct MyUInt(u64, u64);
|
||||
|
||||
#[derive(From)]
|
||||
#[derive(Into)]
|
||||
#[derive(Constructor)]
|
||||
#[derive(FromStr)]
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(Display)]
|
||||
struct SimpleStruct {
|
||||
int1: u64,
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
#[derive(Constructor)]
|
||||
#[derive(Add, Sub, Mul, Div, Rem, BitAnd, BitOr, BitXor, Shr, Shl)]
|
||||
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
|
||||
#[derive(Into)]
|
||||
#[derive(AddAssign)]
|
||||
#[into(owned, ref, ref_mut)]
|
||||
struct NormalStruct {
|
||||
int1: u64,
|
||||
int2: u64,
|
||||
}
|
||||
|
||||
#[derive(From)]
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
struct NestedInt(MyInt);
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(From)]
|
||||
#[derive(Add, Sub)]
|
||||
enum SimpleMyIntEnum {
|
||||
Int(i32),
|
||||
#[from(ignore)]
|
||||
_UnsignedOne(u32),
|
||||
_UnsignedTwo(u32),
|
||||
}
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(From)]
|
||||
#[derive(Neg)]
|
||||
enum SimpleSignedIntEnum {
|
||||
Int(i32),
|
||||
Int2(i16),
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(From)]
|
||||
#[derive(Add, Sub)]
|
||||
#[derive(Neg)]
|
||||
enum SimpleEnum {
|
||||
Int(i32),
|
||||
#[from(ignore)]
|
||||
_Ints(i32, i32),
|
||||
LabeledInts {
|
||||
a: i32,
|
||||
b: i32,
|
||||
},
|
||||
_SomeUnit,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(From)]
|
||||
#[derive(Add, Sub)]
|
||||
enum MyIntEnum {
|
||||
SmallInt(i32),
|
||||
BigInt(i64),
|
||||
TwoInts(i32, i32),
|
||||
Point2D {
|
||||
x: i64,
|
||||
y: i64,
|
||||
},
|
||||
#[from(ignore)]
|
||||
_UnsignedOne(u32),
|
||||
_UnsignedTwo(u32),
|
||||
#[from(ignore)]
|
||||
_Uints1(u64, u64),
|
||||
_Uints2 {
|
||||
x: u64,
|
||||
y: u64,
|
||||
},
|
||||
Nothing,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(Add, Mul)]
|
||||
struct DoubleUInt(u32, u32);
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(Add, Mul)]
|
||||
struct DoubleUIntStruct {
|
||||
x: u32,
|
||||
y: u32,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
#[derive(From, Into, Constructor)]
|
||||
struct Unit;
|
||||
|
||||
// Tests that we can forward to a path
|
||||
// containing `$crate`
|
||||
macro_rules! use_dollar_crate {
|
||||
() => {
|
||||
struct Foo;
|
||||
#[derive(From)]
|
||||
enum Bar {
|
||||
First(#[from(forward)] $crate::Foo),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
use_dollar_crate!();
|
||||
|
||||
#[test]
|
||||
fn main() {
|
||||
let mut myint: MyInt = 5.into();
|
||||
let _: SimpleMyIntEnum = 5i32.into();
|
||||
let _: MyIntEnum = 5i32.into();
|
||||
let _: MyIntEnum = 6i64.into();
|
||||
let _: MyIntEnum = (5i32, 8i32).into();
|
||||
let _: MyIntEnum = (5i64, 8i64).into();
|
||||
let _: MyIntEnum = ().into();
|
||||
|
||||
let int_ref: &i32 = (&myint).into();
|
||||
assert_eq!(int_ref, &5);
|
||||
|
||||
let int_ref_mut: &mut i32 = (&mut myint).into();
|
||||
assert_eq!(int_ref_mut, &mut 5);
|
||||
|
||||
let mut myint: MyInt = 5.into();
|
||||
let _: Unit = ().into();
|
||||
assert_eq!((), Unit.into());
|
||||
assert_eq!(Unit, Unit::new());
|
||||
assert_eq!(MyInt(5), 5.into());
|
||||
assert_eq!(Ok(MyInt(5)), "5".parse());
|
||||
assert_eq!(5, MyInt(5).into());
|
||||
assert_eq!(MyInt(5), MyInt::new(5));
|
||||
assert_eq!(-MyInt(5), (-5).into());
|
||||
assert_eq!("30", format!("{}", MyInt(30)));
|
||||
assert_eq!("36", format!("{:o}", MyInt(30)));
|
||||
assert_eq!("100", format!("{:b}", MyInt(4)));
|
||||
assert_eq!(!MyBool(true), false.into());
|
||||
assert_eq!(MyIntEnum::SmallInt(5), 5.into());
|
||||
|
||||
assert_eq!(SimpleStruct { int1: 5 }, 5.into());
|
||||
assert_eq!(5u64, SimpleStruct { int1: 5 }.into());
|
||||
assert_eq!(Ok(SimpleStruct { int1: 5 }), "5".parse());
|
||||
assert_eq!("5", format!("{}", SimpleStruct { int1: 5 }));
|
||||
assert_eq!(NormalStruct { int1: 5, int2: 6 }, (5, 6).into());
|
||||
assert_eq!(SimpleStruct { int1: 5 }, SimpleStruct::new(5));
|
||||
assert_eq!(NormalStruct { int1: 5, int2: 6 }, NormalStruct::new(5, 6));
|
||||
assert_eq!((5, 6), NormalStruct::new(5, 6).into());
|
||||
let mut norm_struct = NormalStruct::new(5, 6);
|
||||
let uints_ref: (&u64, &u64) = (&norm_struct).into();
|
||||
assert_eq!((&5, &6), uints_ref);
|
||||
let uints_ref_mut: (&mut u64, &mut u64) = (&mut norm_struct).into();
|
||||
assert_eq!((&mut 5, &mut 6), uints_ref_mut);
|
||||
|
||||
assert_eq!(MyInt(4) + MyInt(1), 5.into());
|
||||
myint += MyInt(3);
|
||||
assert_eq!(myint, 8.into());
|
||||
myint *= 5;
|
||||
assert_eq!(myint, 40.into());
|
||||
assert_eq!(MyInt(4) + MyInt(1), 5.into());
|
||||
assert_eq!(MyUInt(4, 5) + MyUInt(1, 2), MyUInt(5, 7));
|
||||
assert_eq!(MyUInt(4, 5), MyUInt::new(4, 5));
|
||||
assert_eq!((4, 5), MyUInt(4, 5).into());
|
||||
let mut s1 = NormalStruct { int1: 1, int2: 2 };
|
||||
let s2 = NormalStruct { int1: 2, int2: 3 };
|
||||
let s3 = NormalStruct { int1: 3, int2: 5 };
|
||||
assert_eq!(s1 + s2, s3);
|
||||
assert_eq!(s3 - s2, s1);
|
||||
s1 += s2;
|
||||
assert_eq!(s1, s3);
|
||||
|
||||
assert_eq!((SimpleMyIntEnum::Int(6) + 5.into()).unwrap(), 11.into());
|
||||
assert_eq!((SimpleMyIntEnum::Int(6) - 5.into()).unwrap(), 1.into());
|
||||
assert_eq!((SimpleMyIntEnum::Int(6) - 5.into()).unwrap(), 1.into());
|
||||
assert_eq!(-SimpleSignedIntEnum::Int(6), (-6i32).into());
|
||||
assert_eq!(
|
||||
(SimpleEnum::LabeledInts { a: 6, b: 5 }
|
||||
+ SimpleEnum::LabeledInts { a: 1, b: 4 })
|
||||
.unwrap(),
|
||||
SimpleEnum::LabeledInts { a: 7, b: 9 }
|
||||
);
|
||||
|
||||
let _ = (MyIntEnum::SmallInt(5) + 6.into()).unwrap();
|
||||
assert_eq!((-SimpleEnum::Int(5)).unwrap(), (-5).into());
|
||||
|
||||
assert_eq!(MyInt(50), MyInt(5) * 10);
|
||||
assert_eq!(DoubleUInt(5, 6) * 10, DoubleUInt(50, 60));
|
||||
// assert_eq!(DoubleUIntStruct{x:5, y:6} * 10, DoubleUIntStruct{x:50, y:60});
|
||||
|
||||
let mut myint = MyInt(5);
|
||||
assert_eq!(5, *myint);
|
||||
*myint = 7;
|
||||
assert_eq!(MyInt(7), myint);
|
||||
|
||||
let mut my_vec = MyVec(vec![5, 8]);
|
||||
assert_eq!(5, my_vec[0]);
|
||||
assert_eq!(8, my_vec[1]);
|
||||
my_vec[0] = 20;
|
||||
assert_eq!(20, my_vec[0]);
|
||||
assert_eq!((&my_vec).into_iter().next(), Some(&20));
|
||||
assert_eq!((&mut my_vec).into_iter().next(), Some(&mut 20));
|
||||
assert_eq!(my_vec.into_iter().next(), Some(20));
|
||||
|
||||
let int_vec = vec![MyInt2(2), MyInt2(3)];
|
||||
assert_eq!(MyInt2(5), int_vec.clone().into_iter().sum());
|
||||
assert_eq!(MyInt2(6), int_vec.clone().into_iter().product());
|
||||
let mut myint2 = MyInt2(8);
|
||||
myint2 *= MyInt2(4);
|
||||
assert_eq!(MyInt2(32), myint2);
|
||||
|
||||
let mut boxed = MyBoxedInt(Box::new(5));
|
||||
assert_eq!(5, *boxed);
|
||||
*boxed = 7;
|
||||
assert_eq!(MyBoxedInt(Box::new(7)), boxed)
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#![allow(dead_code)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(Mul)]
|
||||
struct MyInt(i32);
|
||||
|
||||
#[derive(Mul)]
|
||||
struct MyInts(i32, i32);
|
||||
|
||||
#[derive(Mul)]
|
||||
struct Point1D {
|
||||
x: i32,
|
||||
}
|
||||
|
||||
#[derive(Mul)]
|
||||
struct Point2D {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#![allow(dead_code)]
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(MulAssign)]
|
||||
struct MyInt(i32);
|
||||
|
||||
#[derive(MulAssign)]
|
||||
struct MyInts(i32, i32);
|
||||
|
||||
#[derive(MulAssign)]
|
||||
#[mul_assign(forward)]
|
||||
struct MyIntForward(i32);
|
||||
|
||||
#[derive(MulAssign)]
|
||||
struct Point1D {
|
||||
x: i32,
|
||||
}
|
||||
|
||||
#[derive(MulAssign)]
|
||||
struct Point2D {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
#[derive(MulAssign)]
|
||||
struct MyInt2<T> {
|
||||
x: i32,
|
||||
ph: PhantomData<T>,
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
#![no_std]
|
||||
#![allow(dead_code)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(
|
||||
AddAssign,
|
||||
MulAssign,
|
||||
Add,
|
||||
Mul,
|
||||
Not,
|
||||
Index,
|
||||
Display,
|
||||
FromStr,
|
||||
Into,
|
||||
From,
|
||||
IndexMut,
|
||||
Sum,
|
||||
Deref,
|
||||
DerefMut,
|
||||
Constructor
|
||||
)]
|
||||
#[into(owned, ref, ref_mut)]
|
||||
struct MyInts(u64);
|
||||
|
||||
#[derive(Deref, DerefMut)]
|
||||
#[deref(forward)]
|
||||
#[deref_mut(forward)]
|
||||
struct MyBoxedInt<'a>(&'a mut u64);
|
||||
|
||||
#[derive(
|
||||
From,
|
||||
FromStr,
|
||||
Display,
|
||||
Index,
|
||||
Not,
|
||||
Add,
|
||||
Mul,
|
||||
Sum,
|
||||
IndexMut,
|
||||
AddAssign,
|
||||
Deref,
|
||||
DerefMut,
|
||||
IntoIterator,
|
||||
Constructor
|
||||
)]
|
||||
#[deref(forward)]
|
||||
#[deref_mut(forward)]
|
||||
#[into_iterator(owned, ref, ref_mut)]
|
||||
struct Wrapped<T: Clone>(T);
|
||||
|
||||
#[derive(Deref, DerefMut)]
|
||||
struct Wrapped2<T: Clone>(T);
|
||||
|
||||
#[derive(From, Not, Add, Mul, AddAssign, Constructor, Sum)]
|
||||
struct WrappedDouble<T: Clone, U: Clone>(T, U);
|
||||
|
||||
#[derive(Add, Not, TryInto)]
|
||||
#[try_into(owned, ref, ref_mut)]
|
||||
enum MixedInts {
|
||||
SmallInt(i32),
|
||||
BigInt(i64),
|
||||
TwoSmallInts(i32, i32),
|
||||
NamedSmallInts { x: i32, y: i32 },
|
||||
UnsignedOne(u32),
|
||||
UnsignedTwo(u32),
|
||||
}
|
||||
|
||||
#[derive(Not, Add)]
|
||||
enum EnumWithUnit {
|
||||
SmallInt(i32),
|
||||
Unit,
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#![allow(dead_code)]
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(Not)]
|
||||
struct MyInts(i32, i32);
|
||||
|
||||
#[derive(Not)]
|
||||
struct Point2D {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
#[derive(Not)]
|
||||
enum MixedInts {
|
||||
SmallInt(i32),
|
||||
BigInt(i64),
|
||||
TwoSmallInts(i32, i32),
|
||||
NamedSmallInts { x: i32, y: i32 },
|
||||
UnsignedOne(u32),
|
||||
UnsignedTwo(u32),
|
||||
}
|
||||
|
||||
#[derive(Not)]
|
||||
enum EnumWithUnit {
|
||||
SmallInt(i32),
|
||||
Unit,
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
#[derive(Sum)]
|
||||
struct MyInts(i32, i64);
|
||||
|
||||
// Add implementation is needed for Sum
|
||||
impl ::core::ops::Add for MyInts {
|
||||
type Output = MyInts;
|
||||
#[inline]
|
||||
fn add(self, rhs: MyInts) -> MyInts {
|
||||
MyInts(self.0.add(rhs.0), self.1.add(rhs.1))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Sum)]
|
||||
struct Point2D {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
impl ::core::ops::Add for Point2D {
|
||||
type Output = Point2D;
|
||||
#[inline]
|
||||
fn add(self, rhs: Point2D) -> Point2D {
|
||||
Point2D {
|
||||
x: self.x.add(rhs.x),
|
||||
y: self.y.add(rhs.y),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate derive_more;
|
||||
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
// Ensure that the TryFrom macro is hygenic and doesn't break when `Result` has
|
||||
// been redefined.
|
||||
type Result = ();
|
||||
|
||||
#[derive(Clone, Copy, TryInto)]
|
||||
#[try_into(owned, ref, ref_mut)]
|
||||
enum MixedInts {
|
||||
SmallInt(i32),
|
||||
NamedBigInt {
|
||||
int: i64,
|
||||
},
|
||||
UnsignedWithIgnoredField(#[try_into(ignore)] bool, i64),
|
||||
NamedUnsignedWithIgnnoredField {
|
||||
#[try_into(ignore)]
|
||||
useless: bool,
|
||||
x: i64,
|
||||
},
|
||||
TwoSmallInts(i32, i32),
|
||||
NamedBigInts {
|
||||
x: i64,
|
||||
y: i64,
|
||||
},
|
||||
Unsigned(u32),
|
||||
NamedUnsigned {
|
||||
x: u32,
|
||||
},
|
||||
Unit,
|
||||
#[try_into(ignore)]
|
||||
Unit2,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_into() {
|
||||
let mut i = MixedInts::SmallInt(42);
|
||||
assert_eq!(Ok(42i32), i.try_into());
|
||||
assert_eq!(Ok(&42i32), (&i).try_into());
|
||||
assert_eq!(Ok(&mut 42i32), (&mut i).try_into());
|
||||
assert_eq!(
|
||||
i64::try_from(i),
|
||||
Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64")
|
||||
);
|
||||
assert_eq!(
|
||||
<(i32, i32)>::try_from(i),
|
||||
Err("Only TwoSmallInts can be converted to (i32, i32)")
|
||||
);
|
||||
assert_eq!(
|
||||
<(i64, i64)>::try_from(i),
|
||||
Err("Only NamedBigInts can be converted to (i64, i64)")
|
||||
);
|
||||
assert_eq!(
|
||||
u32::try_from(i),
|
||||
Err("Only Unsigned, NamedUnsigned can be converted to u32")
|
||||
);
|
||||
assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()"));
|
||||
|
||||
let mut i = MixedInts::NamedBigInt { int: 42 };
|
||||
assert_eq!(
|
||||
i32::try_from(i),
|
||||
Err("Only SmallInt can be converted to i32")
|
||||
);
|
||||
assert_eq!(Ok(42i64), i.try_into());
|
||||
assert_eq!(Ok(&42i64), (&i).try_into());
|
||||
assert_eq!(Ok(&mut 42i64), (&mut i).try_into());
|
||||
assert_eq!(
|
||||
<(i32, i32)>::try_from(i),
|
||||
Err("Only TwoSmallInts can be converted to (i32, i32)")
|
||||
);
|
||||
assert_eq!(
|
||||
<(i64, i64)>::try_from(i),
|
||||
Err("Only NamedBigInts can be converted to (i64, i64)")
|
||||
);
|
||||
assert_eq!(
|
||||
u32::try_from(i),
|
||||
Err("Only Unsigned, NamedUnsigned can be converted to u32")
|
||||
);
|
||||
assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()"));
|
||||
|
||||
let mut i = MixedInts::TwoSmallInts(42, 64);
|
||||
assert_eq!(
|
||||
i32::try_from(i),
|
||||
Err("Only SmallInt can be converted to i32")
|
||||
);
|
||||
assert_eq!(
|
||||
i64::try_from(i),
|
||||
Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64")
|
||||
);
|
||||
assert_eq!(Ok((42i32, 64i32)), i.try_into());
|
||||
assert_eq!(Ok((&42i32, &64i32)), (&i).try_into());
|
||||
assert_eq!(Ok((&mut 42i32, &mut 64i32)), (&mut i).try_into());
|
||||
assert_eq!(
|
||||
<(i64, i64)>::try_from(i),
|
||||
Err("Only NamedBigInts can be converted to (i64, i64)")
|
||||
);
|
||||
assert_eq!(
|
||||
u32::try_from(i),
|
||||
Err("Only Unsigned, NamedUnsigned can be converted to u32")
|
||||
);
|
||||
assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()"));
|
||||
|
||||
let mut i = MixedInts::NamedBigInts { x: 42, y: 64 };
|
||||
assert_eq!(
|
||||
i32::try_from(i),
|
||||
Err("Only SmallInt can be converted to i32")
|
||||
);
|
||||
assert_eq!(
|
||||
i64::try_from(i),
|
||||
Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64")
|
||||
);
|
||||
assert_eq!(
|
||||
<(i32, i32)>::try_from(i),
|
||||
Err("Only TwoSmallInts can be converted to (i32, i32)")
|
||||
);
|
||||
assert_eq!(Ok((42i64, 64i64)), i.try_into());
|
||||
assert_eq!(Ok((&42i64, &64i64)), (&i).try_into());
|
||||
assert_eq!(Ok((&mut 42i64, &mut 64i64)), (&mut i).try_into());
|
||||
assert_eq!(
|
||||
u32::try_from(i),
|
||||
Err("Only Unsigned, NamedUnsigned can be converted to u32")
|
||||
);
|
||||
assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()"));
|
||||
|
||||
let mut i = MixedInts::Unsigned(42);
|
||||
assert_eq!(
|
||||
i32::try_from(i),
|
||||
Err("Only SmallInt can be converted to i32")
|
||||
);
|
||||
assert_eq!(
|
||||
i64::try_from(i),
|
||||
Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64")
|
||||
);
|
||||
assert_eq!(
|
||||
<(i32, i32)>::try_from(i),
|
||||
Err("Only TwoSmallInts can be converted to (i32, i32)")
|
||||
);
|
||||
assert_eq!(
|
||||
<(i64, i64)>::try_from(i),
|
||||
Err("Only NamedBigInts can be converted to (i64, i64)")
|
||||
);
|
||||
assert_eq!(Ok(42u32), i.try_into());
|
||||
assert_eq!(Ok(&42u32), (&i).try_into());
|
||||
assert_eq!(Ok(&mut 42u32), (&mut i).try_into());
|
||||
assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()"));
|
||||
|
||||
let mut i = MixedInts::NamedUnsigned { x: 42 };
|
||||
assert_eq!(
|
||||
i32::try_from(i),
|
||||
Err("Only SmallInt can be converted to i32")
|
||||
);
|
||||
assert_eq!(
|
||||
i64::try_from(i),
|
||||
Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64")
|
||||
);
|
||||
assert_eq!(
|
||||
i64::try_from(i),
|
||||
Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64")
|
||||
);
|
||||
assert_eq!(
|
||||
<(i32, i32)>::try_from(i),
|
||||
Err("Only TwoSmallInts can be converted to (i32, i32)")
|
||||
);
|
||||
assert_eq!(
|
||||
<(i64, i64)>::try_from(i),
|
||||
Err("Only NamedBigInts can be converted to (i64, i64)")
|
||||
);
|
||||
assert_eq!(Ok(42u32), i.try_into());
|
||||
assert_eq!(Ok(&42u32), (&i).try_into());
|
||||
assert_eq!(Ok(&mut 42u32), (&mut i).try_into());
|
||||
assert_eq!(<()>::try_from(i), Err("Only Unit can be converted to ()"));
|
||||
|
||||
let i = MixedInts::Unit;
|
||||
assert_eq!(
|
||||
i32::try_from(i),
|
||||
Err("Only SmallInt can be converted to i32")
|
||||
);
|
||||
assert_eq!(
|
||||
i64::try_from(i),
|
||||
Err("Only NamedBigInt, UnsignedWithIgnoredField, NamedUnsignedWithIgnnoredField can be converted to i64")
|
||||
);
|
||||
assert_eq!(
|
||||
<(i32, i32)>::try_from(i),
|
||||
Err("Only TwoSmallInts can be converted to (i32, i32)")
|
||||
);
|
||||
assert_eq!(
|
||||
<(i64, i64)>::try_from(i),
|
||||
Err("Only NamedBigInts can be converted to (i64, i64)")
|
||||
);
|
||||
assert_eq!(
|
||||
u32::try_from(i),
|
||||
Err("Only Unsigned, NamedUnsigned can be converted to u32")
|
||||
);
|
||||
assert_eq!(Ok(()), i.try_into());
|
||||
}
|
Загрузка…
Ссылка в новой задаче