Skip to main content

impl_more/
lib.rs

1//! Concise, declarative trait implementation macros.
2//!
3//! # `#[no_std]`
4//!
5//! Where possible, these macros emit `#[no_std]`-compatible code.
6//!
7//! # Usage
8//!
9//! ```
10//! # use std::error::Error as _;
11//! struct MyNewTypeStruct(String);
12//!
13//! impl_more::impl_as_ref!(MyNewTypeStruct => String);
14//! impl_more::impl_as_mut!(MyNewTypeStruct => String);
15//! impl_more::forward_as_ref!(MyNewTypeStruct => str);
16//! impl_more::forward_as_mut!(MyNewTypeStruct => str);
17//!
18//! impl_more::impl_deref!(MyNewTypeStruct => String);
19//! impl_more::impl_deref_mut!(MyNewTypeStruct);
20//! // or, to deref through String too:
21//! // impl_more::forward_deref_and_mut!(MyNewTypeStruct => ref str);
22//!
23//! impl_more::impl_from!(String => MyNewTypeStruct);
24//! impl_more::impl_into!(MyNewTypeStruct => String);
25//!
26//! impl_more::forward_display!(MyNewTypeStruct);
27//! impl_more::forward_from_str!(MyNewTypeStruct => String);
28//!
29//! struct Items<T>(Vec<T>);
30//!
31//! impl_more::forward_into_iterator!(<T> in Items<T> => Vec<T>; owned, ref, ref_mut);
32//! impl_more::forward_from_iterator!(<T> in Items<T> => Vec<T>);
33//! impl_more::forward_extend!(<T> in Items<T> => Vec<T>);
34//!
35//! struct Mask(u32);
36//!
37//! impl_more::forward_debug!(Mask);
38//! impl_more::forward_lower_hex!(Mask);
39//! impl_more::forward_binary!(Mask);
40//!
41//! enum MyEnum {
42//!     Bar,
43//!     Qux,
44//! }
45//!
46//! impl_more::impl_display_enum!(MyEnum: Bar => "bar", Qux => "qux");
47//!
48//! enum Coords {
49//!     Xy(i64, i64),
50//!     Xyz(i64, i64, i64),
51//!     Uv(i64, i64),
52//! }
53//!
54//! impl_more::impl_display_enum!(
55//!     Coords:
56//!     Xy(x, y) => "{x}, {y}",
57//!     Xyz(x, y, z) => "{x}, {y}, {z}",
58//!     Uv(u, _) => "{u}",
59//! );
60//!
61//! #[derive(Debug)]
62//! struct MyError(eyre::Report);
63//!
64//! impl_more::forward_display!(MyError);
65//! impl_more::forward_error!(MyError);
66//!
67//! let err = MyError(eyre::eyre!("something went wrong"));
68//! assert_eq!(err.source().unwrap().to_string(), "something went wrong");
69//!
70//! #[derive(Debug)]
71//! struct MyFieldError {
72//!     cause: eyre::Report,
73//! }
74//!
75//! impl_more::forward_display!(MyFieldError => cause);
76//! impl_more::forward_error!(MyFieldError => cause);
77//!
78//! let err = MyFieldError {
79//!     cause: eyre::eyre!("something else went wrong"),
80//! };
81//! assert_eq!(
82//!     err.source().unwrap().to_string(),
83//!     "something else went wrong"
84//! );
85//!
86//! #[derive(Debug)]
87//! enum Err {
88//!     Io(std::io::Error),
89//!     Generic(String),
90//! }
91//!
92//! impl_more::impl_display_enum! {
93//!     Err:
94//!     Io(err) => "{err}",
95//!     Generic(msg) => "{msg}",
96//! }
97//! impl_more::impl_error_enum!(Err: Io(err) => err);
98//! ```
99//!
100//! Declare type and const parameters before `in`:
101//!
102//! ```
103//! struct Array<T, const N: usize>([T; N]);
104//!
105//! impl_more::impl_as_ref!(<T, const N: usize> in Array<T, N> => [T; N]);
106//! impl_more::impl_from!(<T, const N: usize> in [T; N] => Array<T, N>);
107//! impl_more::forward_into_iterator!(<T, const N: usize> in Array<T, N> => [T; N]; owned);
108//!
109//! let value = Array::from([1, 2, 3]);
110//! assert_eq!(value.as_ref(), &[1, 2, 3]);
111//! assert_eq!(value.into_iter().sum::<u32>(), 6);
112//! ```
113
114#![cfg_attr(not(docsrs), no_std)]
115#![cfg_attr(docsrs, feature(doc_cfg))]
116
117#[cfg(test)]
118extern crate alloc;
119#[cfg(test)]
120extern crate std;
121
122#[macro_use]
123mod as_ref;
124#[macro_use]
125mod deref;
126#[macro_use]
127mod display;
128#[macro_use]
129mod error;
130#[macro_use]
131mod fmt;
132#[macro_use]
133mod from;
134#[macro_use]
135mod enum_from;
136#[macro_use]
137mod from_str;
138#[macro_use]
139mod iter;
140#[macro_use]
141mod generics;
142
143#[cfg(test)]
144mod tests {
145    #![allow(dead_code, clippy::from_over_into)]
146
147    use alloc::string::{String, ToString as _};
148    use core::ops::{Deref, DerefMut};
149
150    #[derive(Debug)]
151    struct Foo(String);
152
153    crate::impl_as_ref!(Foo => String);
154    crate::impl_as_mut!(Foo => String);
155
156    crate::impl_deref!(Foo => String);
157    crate::impl_deref_mut!(Foo);
158
159    static_assertions::assert_impl_all!(
160        Foo:
161        // impls
162        AsRef<String>,
163        AsMut<String>,
164        Deref<Target = String>,
165        DerefMut,
166    );
167
168    #[derive(Debug)]
169    struct Bar {
170        foo: Foo,
171    }
172
173    crate::impl_as_ref!(Bar => foo: Foo);
174    crate::impl_as_mut!(Bar => foo: Foo);
175
176    crate::impl_deref!(Bar => foo: String);
177    crate::impl_deref_mut!(Bar => foo);
178
179    static_assertions::assert_impl_all!(
180        Bar:
181        // impls
182        AsRef<Foo>,
183        AsMut<Foo>,
184        Deref<Target = String>,
185        DerefMut,
186    );
187
188    #[allow(dead_code)]
189    #[test]
190    fn impl_display() {
191        enum Foo {
192            Bar,
193            Qux,
194        }
195        crate::impl_display_enum!(Foo: Bar => "bar", Qux => "qux");
196        assert_eq!(Foo::Bar.to_string(), "bar");
197        assert_eq!(Foo::Qux.to_string(), "qux");
198
199        enum FooComma {
200            Bar,
201            Qux,
202        }
203        crate::impl_display_enum!(FooComma: Bar => "bar", Qux => "qux",);
204
205        enum FooContents {
206            Bar(u64, u64),
207        }
208        crate::impl_display_enum!(FooContents: Bar (x, y) => "x: {x}; y: {y}");
209        assert_eq!(FooContents::Bar(4, 2).to_string(), "x: 4; y: 2");
210
211        enum FooContents2 {
212            Qux { msg: &'static str },
213        }
214        crate::impl_display_enum!(FooContents2: Qux { msg } => "msg: {msg}");
215        assert_eq!(FooContents2::Qux { msg: "foo" }.to_string(), "msg: foo");
216    }
217}