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}