Skip to content

Commit

Permalink
Switch terminology to "transparency"
Browse files Browse the repository at this point in the history
  • Loading branch information
tyranron committed Dec 20, 2023
1 parent 1a30168 commit 0fee2bc
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 79 deletions.
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
`#[display(fmt = "...", ("<expr>"),*)]`, and `#[display(bound(<bound>))]`
instead of `#[display(bound = "<bound>")]`. So without the double quotes
around the expressions and bounds.
- The `Display` derive (and other `fmt`-like ones) now delegates to the inner type
when `#[display("...", (<expr>),*)]` attribute is trivially substitutable with such
call. ([#322](https://github.com/JelteF/derive_more/pull/322))
- The `Debug` and `Display` derives (and other `fmt`-like ones) now transparently
delegates to the inner type when `#[display("...", (<expr>),*)]` attribute is
trivially substitutable with a transparent call.
([#322](https://github.com/JelteF/derive_more/pull/322))
- The `DebugCustom` derive is renamed to just `Debug` (gated now under a separate
`debug` feature), and its semantics were changed to be a superset of `std` variant
of `Debug`.
Expand Down
24 changes: 18 additions & 6 deletions impl/doc/debug.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ trait MyTrait { fn my_function(&self) -> i32; }
```


### Delegation
### Transparency

If the top-level `#[debug("...", args...)]` attribute (the one for a whole struct or variant) is specified
and can be trivially substituted with a delegation call to the inner type, then all the additional
and can be trivially substituted with a transparent delegation call to the inner type, then all the additional
[formatting parameters][1] do work as expected:
```rust
# use derive_more::Debug;
Expand All @@ -100,24 +100,36 @@ struct MyOctalInt(i32);
assert_eq!(format!("{:03?}", MyOctalInt(9)), "011");

#[derive(Debug)]
#[debug("{_0:02b}")] // cannot be trivially substituted with `Binary::fmt()`
struct MyBinaryInt(i32);
#[debug("{_0:02b}")] // cannot be trivially substituted with `Binary::fmt()`,
struct MyBinaryInt(i32); // because of specified formatting parameters

// so, additional formatting parameters have no effect
assert_eq!(format!("{:07?}", MyBinaryInt(2)), "10");
```

If, for some reason, delegation in trivial cases is not desired, it may be suppressed explicitly:
If, for some reason, transparency in trivial cases is not desired, it may be suppressed explicitly
either with the [`format_args!()`] macro usage:
```rust
# use derive_more::Debug;
#
#[derive(Debug)]
#[debug("{}", format_args!("{_0:o}"))] // `format_args!()` opaques the inner type
#[debug("{}", format_args!("{_0:o}"))] // `format_args!()` obscures the inner type
struct MyOctalInt(i32);

// so, additional formatting parameters have no effect
assert_eq!(format!("{:07?}", MyOctalInt(9)), "11");
```
Or by adding [formatting parameters][1] which cause no visual effects:
```rust
# use derive_more::Debug;
#
#[derive(Debug)]
#[debug("{_0:^o}")] // `^` is centering, but in absence of additional width has no effect
struct MyOctalInt(i32);

// and so, additional formatting parameters have no effect
assert_eq!(format!("{:07?}", MyOctalInt(9)), "11");
```



Expand Down
32 changes: 23 additions & 9 deletions impl/doc/display.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ the supplied format, or an automatically inferred one.
You specify the format on each variant by writing e.g. `#[display("my val: {}", some_val * 2)]`.
For enums, you can either specify it on each variant, or on the enum as a whole.

For variants that don't have a format specified, it will simply delegate to the format of the
For variants that don't have a format specified, it will simply defer to the format of the
inner variable. If there is no such variable, or there is more than 1, an error is generated.


Expand Down Expand Up @@ -97,9 +97,9 @@ struct MyStruct<T, U, V> {
```


### Delegation
### Transparency

If the `#[display("...", args...)]` attribute is omitted, the implementation simply delegates to the format
If the `#[display("...", args...)]` attribute is omitted, the implementation transparently delegates to the format
of the inner type, so all the additional [formatting parameters][1] do work as expected:
```rust
# use derive_more::Display;
Expand All @@ -110,8 +110,8 @@ struct MyInt(i32);
assert_eq!(format!("{:03}", MyInt(7)), "007");
```

If the `#[display("...", args...)]` attribute is specified and can be trivially substituted with a delegation
call to the inner type, then delegation will work too:
If the `#[display("...", args...)]` attribute is specified and can be trivially substituted with a transparent
delegation call to the inner type, then additional [formatting parameters][1] will work too:
```rust
# use derive_more::Display;
#
Expand All @@ -123,24 +123,36 @@ struct MyOctalInt(i32);
assert_eq!(format!("{:03}", MyOctalInt(9)), "011");

#[derive(Display)]
#[display("{_0:02b}")] // cannot be trivially substituted with `Binary::fmt()`
struct MyBinaryInt(i32);
#[display("{_0:02b}")] // cannot be trivially substituted with `Binary::fmt()`,
struct MyBinaryInt(i32); // because of specified formatting parameters

// so, additional formatting parameters have no effect
assert_eq!(format!("{:07}", MyBinaryInt(2)), "10");
```

If, for some reason, delegation in trivial cases is not desired, it may be suppressed explicitly:
If, for some reason, transparency in trivial cases is not desired, it may be suppressed explicitly
either with the [`format_args!()`] macro usage:
```rust
# use derive_more::Display;
#
#[derive(Display)]
#[display("{}", format_args!("{_0:o}"))] // `format_args!()` opaques the inner type
#[display("{}", format_args!("{_0:o}"))] // `format_args!()` obscures the inner type
struct MyOctalInt(i32);

// so, additional formatting parameters have no effect
assert_eq!(format!("{:07}", MyOctalInt(9)), "11");
```
Or by adding [formatting parameters][1] which cause no visual effects:
```rust
# use derive_more::Display;
#
#[derive(Display)]
#[display("{_0:^o}")] // `^` is centering, but in absence of additional width has no effect
struct MyOctalInt(i32);

// and so, additional formatting parameters have no effect
assert_eq!(format!("{:07?}", MyOctalInt(9)), "11");
```



Expand Down Expand Up @@ -226,4 +238,6 @@ assert_eq!(PositiveOrNegative { x: -1 }.to_string(), "Negative");



[`format_args!()`]: https://doc.rust-lang.org/stable/std/macro.format_args.html

[1]: https://doc.rust-lang.org/stable/std/fmt/index.html#formatting-parameters
2 changes: 1 addition & 1 deletion impl/src/fmt/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ impl<'a> Expansion<'a> {
/// [`Debug::fmt()`]: std::fmt::Debug::fmt()
fn generate_body(&self) -> syn::Result<TokenStream> {
if let Some(fmt) = &self.attr.fmt {
return Ok(if let Some((expr, trait_ident)) = fmt.delegatable() {
return Ok(if let Some((expr, trait_ident)) = fmt.transparent_call() {
quote! { ::core::fmt::#trait_ident::fmt(&(#expr), __derive_more_f) }
} else {
quote! { ::core::write!(__derive_more_f, #fmt) }
Expand Down
2 changes: 1 addition & 1 deletion impl/src/fmt/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ impl<'a> Expansion<'a> {
/// [`Display::fmt()`]: fmt::Display::fmt()
fn generate_body(&self) -> syn::Result<TokenStream> {
match &self.attrs.fmt {
Some(fmt) => Ok(if let Some((expr, trait_ident)) = fmt.delegatable() {
Some(fmt) => Ok(if let Some((expr, trait_ident)) = fmt.transparent_call() {
quote! { ::core::fmt::#trait_ident::fmt(&(#expr), __derive_more_f) }
} else {
quote! { ::core::write!(__derive_more_f, #fmt) }
Expand Down
12 changes: 6 additions & 6 deletions impl/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,15 +133,15 @@ impl ToTokens for FmtAttribute {
}

impl FmtAttribute {
/// Checks whether this [`FmtAttribute`] can be replaced with a trivial delegation (calling a formatting trait
/// directly instead of interpolation syntax).
/// Checks whether this [`FmtAttribute`] can be replaced with a transparent delegation (calling
/// a formatting trait directly instead of interpolation syntax).
///
/// If delegation is possible, returns an [`Ident`] of the delegated trait and an [`Expr`] to pass into the
/// delegation call.
/// If such transparent call is possible, the returns an [`Ident`] of the delegated trait and
/// the [`Expr`] to pass into the call, otherwise [`None`].
///
/// [`Ident`]: struct@syn::Ident
fn delegatable(&self) -> Option<(Expr, syn::Ident)> {
// `FmtAttribute` is delegatable when:
fn transparent_call(&self) -> Option<(Expr, syn::Ident)> {
// `FmtAttribute` is transparent when:

// (1) There is exactly one formatting parameter.
let lit = self.lit.value();
Expand Down
Loading

0 comments on commit 0fee2bc

Please sign in to comment.