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