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//! enum MyEnum {
27//!     Bar,
28//!     Qux,
29//! }
30//!
31//! impl_more::impl_display_enum!(MyEnum: Bar => "bar", Qux => "qux");
32//!
33//! enum Coords {
34//!     Xy(i64, i64),
35//!     Xyz(i64, i64, i64),
36//!     Uv(i64, i64),
37//! }
38//!
39//! impl_more::impl_display_enum!(
40//!     Coords:
41//!     Xy(x, y) => "{x}, {y}",
42//!     Xyz(x, y, z) => "{x}, {y}, {z}",
43//!     Uv(u, _) => "{u}",
44//! );
45//!
46//! #[derive(Debug)]
47//! struct MyError(eyre::Report);
48//!
49//! impl_more::forward_display!(MyError);
50//! impl_more::forward_error!(MyError);
51//!
52//! let err = MyError(eyre::eyre!("something went wrong"));
53//! assert_eq!(err.source().unwrap().to_string(), "something went wrong");
54//!
55//! #[derive(Debug)]
56//! struct MyFieldError {
57//!     cause: eyre::Report,
58//! }
59//!
60//! impl_more::forward_display!(MyFieldError => cause);
61//! impl_more::forward_error!(MyFieldError => cause);
62//!
63//! let err = MyFieldError {
64//!     cause: eyre::eyre!("something else went wrong"),
65//! };
66//! assert_eq!(
67//!     err.source().unwrap().to_string(),
68//!     "something else went wrong"
69//! );
70//!
71//! #[derive(Debug)]
72//! enum Err {
73//!     Io(std::io::Error),
74//!     Generic(String),
75//! }
76//!
77//! impl_more::impl_display_enum! {
78//!     Err:
79//!     Io(err) => "{err}",
80//!     Generic(msg) => "{msg}",
81//! }
82//! impl_more::impl_error_enum!(Err: Io(err) => err);
83//! ```
84
85#![cfg_attr(not(docsrs), no_std)]
86#![cfg_attr(docsrs, feature(doc_cfg))]
87
88#[cfg(test)]
89extern crate alloc;
90#[cfg(test)]
91extern crate std;
92
93#[macro_use]
94mod as_ref;
95#[macro_use]
96mod deref;
97#[macro_use]
98mod display;
99#[macro_use]
100mod error;
101#[macro_use]
102mod from;
103
104#[cfg(test)]
105mod tests {
106    #![allow(dead_code, clippy::from_over_into)]
107
108    use alloc::string::{String, ToString as _};
109    use core::ops::{Deref, DerefMut};
110
111    #[derive(Debug)]
112    struct Foo(String);
113
114    crate::impl_as_ref!(Foo => String);
115    crate::impl_as_mut!(Foo => String);
116
117    crate::impl_deref!(Foo => String);
118    crate::impl_deref_mut!(Foo);
119
120    static_assertions::assert_impl_all!(
121        Foo:
122        // impls
123        AsRef<String>,
124        AsMut<String>,
125        Deref<Target = String>,
126        DerefMut,
127    );
128
129    #[derive(Debug)]
130    struct Bar {
131        foo: Foo,
132    }
133
134    crate::impl_as_ref!(Bar => foo: Foo);
135    crate::impl_as_mut!(Bar => foo: Foo);
136
137    crate::impl_deref!(Bar => foo: String);
138    crate::impl_deref_mut!(Bar => foo);
139
140    static_assertions::assert_impl_all!(
141        Bar:
142        // impls
143        AsRef<Foo>,
144        AsMut<Foo>,
145        Deref<Target = String>,
146        DerefMut,
147    );
148
149    #[allow(dead_code)]
150    #[test]
151    fn impl_display() {
152        enum Foo {
153            Bar,
154            Qux,
155        }
156        crate::impl_display_enum!(Foo: Bar => "bar", Qux => "qux");
157        assert_eq!(Foo::Bar.to_string(), "bar");
158        assert_eq!(Foo::Qux.to_string(), "qux");
159
160        enum FooComma {
161            Bar,
162            Qux,
163        }
164        crate::impl_display_enum!(FooComma: Bar => "bar", Qux => "qux",);
165
166        enum FooContents {
167            Bar(u64, u64),
168        }
169        crate::impl_display_enum!(FooContents: Bar (x, y) => "x: {x}; y: {y}");
170        assert_eq!(FooContents::Bar(4, 2).to_string(), "x: 4; y: 2");
171
172        enum FooContents2 {
173            Qux { msg: &'static str },
174        }
175        crate::impl_display_enum!(FooContents2: Qux { msg } => "msg: {msg}");
176        assert_eq!(FooContents2::Qux { msg: "foo" }.to_string(), "msg: foo");
177
178        // not supported yet
179        // enum FooContents3 {
180        //     Bar(u64, u64),
181        //     Qux { msg: &'static str },
182        // }
183        // impl_display_enum!(FooContents3, Bar (x, y) => "x: {x}; y: {y}", Qux { msg } => "{msg}");
184        // assert_eq!(FooContents3::Bar(4, 2).to_string(), "x: 4; y: 2");
185        // assert_eq!(FooContents3::Qux { msg: "foo" }.to_string(), "x: 4; y: 2");
186    }
187}