• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Alorel / delegate-display-rs / 11550909325

28 Oct 2024 09:19AM UTC coverage: 93.118%. First build
11550909325

Pull #13

github

web-flow
Merge 90c44bead into e44b91622
Pull Request #13: deps: bump alorel-actions/cargo from 1 to 2

433 of 465 relevant lines covered (93.12%)

8.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/lib.rs
1
//! Lets you derive [`fmt`](::core::fmt) traits on types wrapping types that already implement them.
2
//!
3
//! [![master CI badge](https://img.shields.io/github/actions/workflow/status/Alorel/delegate-display-rs/test.yml?label=master%20CI)](https://github.com/Alorel/delegate-display-rs/actions/workflows/test.yml?query=branch%3Amaster)
4
//! [![crates.io badge](https://img.shields.io/crates/v/delegate-display)](https://crates.io/crates/delegate-display)
5
//! [![Coverage Status](https://coveralls.io/repos/github/Alorel/delegate-display-rs/badge.svg?branch=master)](https://coveralls.io/github/Alorel/delegate-display-rs?branch=master)
6
//! [![dependencies badge](https://img.shields.io/librariesio/release/cargo/delegate-display)](https://libraries.io/cargo/delegate-display)
7
//!
8
//! # Examples
9

10
//! <details><summary>Newtype structs</summary>
11
//!
12
//! ```
1✔
13
//! # use delegate_display::*;
14
//! struct SomeType;
15
//! impl core::fmt::Display for SomeType {
16
//!   fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1✔
17
//!     f.write_str(">foo<")
1✔
18
//!   }
1✔
19
//! }
20
//!
21
//! #[derive(DelegateDisplay)]
22
//! struct Foo(SomeType);
23
//!
24
//! assert_eq!(format!("{}", Foo(SomeType)), ">foo<");
1✔
25
//! ```
1✔
26
//!
27
//! </details>
28

29
//! <details><summary>Structs with 0..=1 fields</summary>
30
//!
1✔
31
//! ```
32
//! # use delegate_display::*;
33
//! struct SomeType;
34
//! impl core::fmt::Debug for SomeType {
1✔
35
//!   fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1✔
36
//!     f.write_str(">foo<")
1✔
37
//!   }
38
//! }
39
//!
40
//! #[derive(DelegateDebug)]
41
//! struct Foo { some_field: SomeType }
42
//!
1✔
43
//! assert_eq!(format!("{:?}", Foo { some_field: SomeType }), ">foo<");
1✔
44
//! ```
45
//!
46
//! </details>
47

48
//! <details><summary>Enums with 0..=1 variants each</summary>
1✔
49
//!
50
//! ```
51
//! # use delegate_display::*;
52
//! struct SomeType;
53
//! struct AnotherType;
54
//!
1✔
55
//! impl core::fmt::Display for SomeType {
1✔
56
//!   fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1✔
57
//!     f.write_str(">foo<")
58
//!   }
59
//! }
1✔
60
//! impl core::fmt::Display for AnotherType {
1✔
61
//!   fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1✔
62
//!     f.write_str(">bar<")
63
//!   }
64
//! }
65
//!
66
//! #[derive(DelegateDisplay)]
67
//! enum MyEnum {
68
//!   Foo,
69
//!   Bar(SomeType),
70
//!   Qux { baz: AnotherType }
71
//! }
1✔
72
//!
1✔
73
//! assert_eq!(format!("{}", MyEnum::Bar(SomeType)), ">foo<");
1✔
74
//! assert_eq!(format!("{}", MyEnum::Qux { baz: AnotherType }), ">bar<");
75
//! ```
76
//!
77
//! </details>
78

79
//! <details><summary>Generics</summary>
80
//!
1✔
81
//! Generics are handled automatically for you.
82
//!
83
//! ```
84
//! # use delegate_display::*;
85
//! #
86
//! #[derive(DelegateDisplay)]
87
//! struct MyStruct<T>(T);
88
//!
89
//! #[derive(DelegateDisplay)]
90
//! enum MyEnum<A, B> {
91
//!   A(A),
92
//!   B { value: B },
1✔
93
//! }
1✔
94
//!
1✔
95
//! assert_eq!(format!("{}", MyStruct(50)), "50");
1✔
96
//! assert_eq!(format!("{}", MyEnum::<u8, i8>::A(75)), "75");
97
//! assert_eq!(format!("{}", MyEnum::<u8, i8>::B { value: -1 }), "-1");
98
//! ```
99
//!
100
//! </details>
101

102
//! <details><summary>Structs & enums with 2+ fields</summary>
1✔
103
//!
104
//! The field being delegated to must be marked with the appropriate attribute.
105
//!
106
//! ```
107
//! # use delegate_display::*;
108
//!
109
//! #[derive(DelegateDisplay)]
110
//! struct MyStruct<T> {
111
//!   label: String,
112
//!   #[ddisplay]
113
//!   value: T,
114
//! }
115
//!
116
//! #[derive(DelegateDebug)]
117
//! enum MyEnum {
118
//!   Foo(#[ddebug] String, u8),
1✔
119
//!   Bar { baz: u8, #[ddebug] qux: u8 }
1✔
120
//! }
121
//!
1✔
122
//! let my_struct = MyStruct { label: "foo".into(), value: 42 };
1✔
123
//! assert_eq!(format!("{}", my_struct), "42");
124
//!
1✔
125
//! let my_enum = MyEnum::Foo(".".into(), 1);
1✔
126
//! assert_eq!(format!("{:?}", my_enum), "\".\"");
1✔
127
//!
128
//! let my_enum = MyEnum::Bar { baz: 2, qux: 3 };
129
//! assert_eq!(format!("{:?}", my_enum), "3");
130
//! ```
131
//!
1✔
132
//! </details>
133

134
//! <details><summary>Empty structs</summary>
135
//!
136
//! ```
137
//! # use delegate_display::*;
138
//! #
139
//! #[derive(DelegateDebug, DelegateDisplay)]
140
//! struct Foo;
141
//!
142
//! #[derive(DelegateDebug, DelegateDisplay)]
143
//! struct Bar{}
1✔
144
//!
1✔
145
//! #[derive(DelegateDebug, DelegateDisplay)]
1✔
146
//! struct Qux();
1✔
147
//!
148
//! assert_eq!(format!("{}-{:?}", Foo, Foo), "-");
149
//! assert_eq!(format!("{}-{:?}", Bar{}, Bar{}), "-");
150
//! assert_eq!(format!("{}-{:?}", Qux(), Qux()), "-");
151
//! ```
152
//!
153
//! </details>
1✔
154

155
//! <details><summary>Typed delegations</summary>
156
//!
157
//! Can be useful for further prettifying the output.
158
//!
159
//! ```
160
//! # use delegate_display::*;
161
//! #
1✔
162
//! /// Some type that `Deref`s to the type we want to use in our formatting, in this case, `str`.
1✔
163
//! #[derive(Debug)]
1✔
164
//! struct Wrapper(&'static str);
165
//! impl std::ops::Deref for Wrapper {
166
//!   type Target = str;
167
//!   fn deref(&self) -> &Self::Target {
168
//!     self.0
169
//!   }
170
//! }
171
//!
172
//! #[derive(DelegateDebug)]
173
//! #[ddebug(delegate_to(str))] // ignore `Wrapper` and debug the `str` it `Deref`s instead
1✔
174
//! struct Typed(Wrapper);
1✔
175
//!
1✔
176
//! #[derive(DelegateDebug)] // Included for comparison
177
//! struct Base(Wrapper);
178
//!
179
//! assert_eq!(format!("{:?}", Typed(Wrapper("foo"))), "\"foo\"");
180
//! assert_eq!(format!("{:?}", Base(Wrapper("bar"))), "Wrapper(\"bar\")");
1✔
181
//! ```
182
//!
183
//! </details>
184

185
//! <details><summary>Custom generic bounds</summary>
186
//!
187
//! ```
188
//! # use delegate_display::*;
1✔
189
//! # use core::fmt::{Display, Formatter, self};
1✔
190
//! # use std::ops::Deref;
1✔
191
//! #
192
//! struct CopyDisplayable<T>(T); // Implements Deref
193
//! # impl<T> Deref for CopyDisplayable<T> {
194
//! #   type Target = T;
195
//! #   fn deref(&self) -> &Self::Target {
196
//! #     &self.0
197
//! #   }
198
//! # }
199
//!
200
//! impl<T: Copy> Display for CopyDisplayable<T> {
201
//!   fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
202
//!     unimplemented!("Nonsense generic bound - base bounds don't work.");
203
//!   }
204
//! }
205
//!
1✔
206
//! // Without these options the implementation would have a predicate of `CopyDisplayable<T>: Debug` which would
1✔
207
//! // effectively mean `T: Copy`; we can transform it to `T: Display` because `CopyDisplayable` derefs to `T`.
1✔
208
//! #[derive(DelegateDisplay)]
209
//! #[ddisplay(bounds(T: Display), delegate_to(T))]
210
//! struct Displayable<T>(CopyDisplayable<T>);
211
//!
212
//! let dbg = Displayable::<String>(CopyDisplayable("cdbg".into()));
213
//! assert_eq!(format!("{}", dbg), "cdbg");
214
//! ```
215
//!
1✔
216
//! </details>
217

218
//! <details><summary>Multiple traits at once</summary>
219
//!
220
//! Instead of re-parsing your struct/enum multiple times, you can instead derive `DelegateFmt`.
221
//! It supports every individual macro's attribute along with `dany` as a catch-all default.
3✔
222
//!
3✔
223
//! ```
3✔
224
//! # use delegate_display::*;
225
//! #
226
//! struct Wrapper(u8); // implements Deref
227
//! # impl ::std::ops::Deref for Wrapper {
228
//! #   type Target = u8;
229
//! #   fn deref(&self) -> &Self::Target {
230
//! #     &self.0
3✔
231
//! #   }
3✔
232
//! # }
3✔
233
//!
234
//! #[derive(DelegateFmt)]
235
//! #[dfmt(dany(delegate_to(u8)), ddebug, ddisplay, dbinary)]
1✔
236
//! struct MyStruct(#[dany] Wrapper, #[dbinary] Wrapper);
1✔
237
//! # impl MyStruct {
1✔
238
//! #   fn new(a: u8, b: u8) -> Self {
1✔
239
//! #     Self(Wrapper(a), Wrapper(b))
240
//! #   }
241
//! # }
242
//!
243
//! assert_eq!(format!("{:?}", MyStruct::new(1, 2)), "1");
244
//! assert_eq!(format!("{}", MyStruct::new(3, 4)), "3");
245
//! assert_eq!(format!("{:b}", MyStruct::new(5, 6)), "110");
246
//! ```
247
//!
248
//! </details>
249

250
//! <details><summary>Invalid inputs</summary>
251
//!
252
//! ```compile_fail
253
//! #[derive(delegate_display::DelegateDebug)]
254
//! struct TooManyFields1 {
255
//!   foo: u8,
256
//!   bar: u8, // No fields marked with `#[ddebug]` or `#[dany]`
257
//! }
258
//! ```
259
//!
260
//! ```compile_fail
261
//! #[derive(delegate_display::DelegateDebug)]
262
//! struct TooManyFields2(u8, u8); // No fields marked with `#[ddebug]` or `#[dany]`
263
//! ```
264
//!
265
//! ```compile_fail
266
//! #[derive(delegate_display::DelegateDebug)]
267
//! enum SomeEnum {
268
//!   A, // this is ok
269
//!   B(u8), // this is ok
270
//!   C { foo: u8 }, // this is ok
271
//!   D(u8, u8), // ERR: No fields marked with `#[ddebug]` or `#[dany]`
272
//!   E { foo: u8, bar: u8 } // ERR: No fields marked with `#[ddebug]` or `#[dany]`
273
//! }
274
//! ```
275
//!
276
//! ```compile_fail
277
//! #[derive(delegate_display::DelegateDebug)]
278
//! union Foo { bar: u8 } // Unions are not supported
279
//! ```
280
//!
281
//! ```compile_fail
282
//! # use delegate_display::*;
283
//! #
284
//! struct NonDebug;
285
//!
286
//! #[derive(DelegateDebug)]
287
//! struct Foo<A, B>(A, B);
288
//!
289
//! format!("{:?}", Foo(NonDebug, 1)); // NonDebug does not implement Debug
290
//! ```
291
//!
292
//! </details>
293

294
#![deny(clippy::correctness, clippy::suspicious)]
295
#![warn(clippy::complexity, clippy::perf, clippy::style, clippy::pedantic)]
296
#![allow(
297
    clippy::wildcard_imports,
298
    clippy::default_trait_access,
299
    clippy::single_match_else
300
)]
301
#![warn(missing_docs)]
302

303
mod implementation;
304

305
const ATTR_ANY: &str = "dany";
306
const ATTR_FMT: &str = "dfmt";
307

308
macro_rules! alias {
309
    ($($delegate_name: ident ($attr_name: ident) => $fmt_trait: literal),+ $(,)?) => {
310
        /// Derive multiple [`fmt`](::core::fmt) traits at once without needing to repeatedly parse the struct/enum.
311
        ///
312
        /// See "Multiple traits at once" example in [crate-level documentation](crate).
313
        #[proc_macro_derive(DelegateFmt, attributes(dfmt, dany, $($attr_name),+))]
314
        #[inline]
315
        pub fn dfmt(input: ::proc_macro::TokenStream) -> ::proc_macro::TokenStream {
1✔
316
            implementation::Implementation::exec_compound(input)
1✔
317
        }
1✔
318

319
       $(
320
            #[doc = concat!(" Derive the [`", $fmt_trait, "`](::core::fmt::", $fmt_trait, ") trait.")]
321
            #[doc = ""]
322
            #[doc = concat!(" Its config attribute is `", stringify!($attr_name) ,"`; alternatively, `dany` can be used")]
323
            #[doc = " to configure all derived [`fmt`](::core::fmt) traits."]
324
            #[doc = ""]
325
            #[doc = " See [crate-level documentation](crate) for config examples."]
326
            #[proc_macro_derive($delegate_name, attributes($attr_name, dany))]
327
            #[inline]
328
            pub fn $attr_name(input: ::proc_macro::TokenStream) -> ::proc_macro::TokenStream {
21✔
329
                implementation::Implementation::exec(
21✔
330
                    input,
21✔
331
                    implementation::Alias::$attr_name.attr_name,
21✔
332
                    implementation::Alias::$attr_name.trait_name,
21✔
333
                )
21✔
334
            }
21✔
335
        )+
336

337
        impl implementation::Alias<'static> {
338
            $(
339
                #[allow(non_upper_case_globals)]
340
                const $attr_name: implementation::Alias<'static> = implementation::Alias {
341
                    attr_name: stringify!($attr_name),
342
                    trait_name: $fmt_trait,
343
                };
344
            )+
345
        }
346
    };
347
}
348

349
alias! {
350
    DelegateBinary(dbinary) => "Binary",
351
    DelegateDebug(ddebug) => "Debug",
352
    DelegateDisplay(ddisplay) => "Display",
353
    DelegateLowerExp(dlexp) => "LowerExp",
354
    DelegateLowerHex(dlhex) => "LowerHex",
355
    DelegateOctal(doctal) => "Octal",
356
    DelegatePointer(dpointer) => "Pointer",
357
    DelegateUpperExp(duexp) => "UpperExp",
358
    DelegateUpperHex(duhex) => "UpperHex",
359
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc