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//! 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}