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