facet_spez/
lib.rs

1#![warn(missing_docs)]
2#![doc = include_str!("../README.md")]
3pub use ::impls::impls;
4use core::fmt::{self, Debug};
5use facet_types::ParseError;
6
7use facet_opaque::{Opaque, OpaqueUninit};
8
9/// A wrapper type used for auto-deref specialization.
10///
11/// This struct is a core part of the auto-deref-based specialization technique which allows
12/// conditionally implementing functionality based on what traits a type implements, without
13/// requiring the unstable `specialization` feature.
14///
15/// It wraps a value and is used in conjunction with trait implementations that leverage
16/// Rust's method resolution rules to select different implementations based on available traits.
17pub struct Spez<T>(pub T);
18
19//////////////////////////////////////////////////////////////////////////////////////
20// Debug πŸ›πŸ”
21//////////////////////////////////////////////////////////////////////////////////////
22
23/// Specialization proxy for [`core::fmt::Debug`]
24pub trait SpezDebugYes {
25    /// Delegates to the inner type's `Debug` implementation.
26    ///
27    /// This method is called when the wrapped type implements `Debug`.
28    /// It forwards the formatting request to the inner value's `Debug` implementation.
29    fn spez_debug(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>;
30}
31impl<T: Debug> SpezDebugYes for &Spez<T> {
32    fn spez_debug(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
33        Debug::fmt(&self.0, f)
34    }
35}
36
37/// Specialization proxy for [`core::fmt::Debug`]
38pub trait SpezDebugNo {
39    /// Fallback implementation when the type doesn't implement `Debug`.
40    ///
41    /// This method is used as a fallback and is designed to be unreachable in practice.
42    /// It's only selected when the wrapped type doesn't implement `Debug`.
43    fn spez_debug(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>;
44}
45impl<T> SpezDebugNo for Spez<T> {
46    fn spez_debug(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
47        unreachable!()
48    }
49}
50
51//////////////////////////////////////////////////////////////////////////////////////
52// Display πŸ“ΊπŸ–₯️
53//////////////////////////////////////////////////////////////////////////////////////
54
55/// Specialization proxy for [`core::fmt::Display`]
56pub trait SpezDisplayYes {
57    /// Delegates to the inner type's `Display` implementation.
58    ///
59    /// This method is called when the wrapped type implements `Display`.
60    /// It forwards the formatting request to the inner value's `Display` implementation.
61    fn spez_display(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>;
62}
63impl<T: fmt::Display> SpezDisplayYes for &Spez<T> {
64    fn spez_display(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
65        fmt::Display::fmt(&self.0, f)
66    }
67}
68
69/// Specialization proxy for [`core::fmt::Display`]
70pub trait SpezDisplayNo {
71    /// Fallback implementation when the type doesn't implement `Display`.
72    ///
73    /// This method is used as a fallback and is designed to be unreachable in practice.
74    /// It's only selected when the wrapped type doesn't implement `Display`.
75    fn spez_display(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error>;
76}
77impl<T> SpezDisplayNo for Spez<T> {
78    fn spez_display(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
79        unreachable!()
80    }
81}
82
83//////////////////////////////////////////////////////////////////////////////////////
84// Default (in place, because we can't have sized) πŸ πŸ”„
85//////////////////////////////////////////////////////////////////////////////////////
86
87/// Specialization proxy for [`core::default::Default`]
88pub trait SpezDefaultInPlaceYes {
89    /// Creates a default value for the inner type in place.
90    ///
91    /// This method is called when the wrapped type implements `Default`.
92    /// It writes the default value into the provided uninitialized memory.
93    fn spez_default_in_place<'mem>(&self, target: OpaqueUninit<'mem>) -> Opaque<'mem>;
94}
95impl<T: Default> SpezDefaultInPlaceYes for &Spez<T> {
96    fn spez_default_in_place<'mem>(&self, target: OpaqueUninit<'mem>) -> Opaque<'mem> {
97        unsafe { target.write(<T as Default>::default()) }
98    }
99}
100
101/// Specialization proxy for [`core::default::Default`]
102pub trait SpezDefaultInPlaceNo {
103    /// Fallback implementation when the type doesn't implement `Default`.
104    ///
105    /// This method is used as a fallback and is designed to be unreachable in practice.
106    /// It's only selected when the wrapped type doesn't implement `Default`.
107    fn spez_default_in_place<'mem>(&self, _target: OpaqueUninit<'mem>) -> Opaque<'mem>;
108}
109impl<T> SpezDefaultInPlaceNo for Spez<T> {
110    fn spez_default_in_place<'mem>(&self, _target: OpaqueUninit<'mem>) -> Opaque<'mem> {
111        unreachable!()
112    }
113}
114
115//////////////////////////////////////////////////////////////////////////////////////
116// Clone into πŸ‘πŸ“₯
117//////////////////////////////////////////////////////////////////////////////////////
118
119/// Specialization proxy for [`core::clone::Clone`]
120pub trait SpezCloneIntoYes {
121    /// Clones the inner value into the provided uninitialized memory.
122    ///
123    /// This method is called when the wrapped type implements `Clone`.
124    /// It creates a clone of the inner value and writes it into the target memory.
125    fn spez_clone_into<'mem>(&self, target: OpaqueUninit<'mem>) -> Opaque<'mem>;
126}
127impl<T: Clone> SpezCloneIntoYes for &Spez<T> {
128    fn spez_clone_into<'mem>(&self, target: OpaqueUninit<'mem>) -> Opaque<'mem> {
129        unsafe { target.write(self.0.clone()) }
130    }
131}
132
133/// Specialization proxy for [`core::clone::Clone`]
134pub trait SpezCloneIntoNo {
135    /// Fallback implementation when the type doesn't implement `Clone`.
136    ///
137    /// This method is used as a fallback and is designed to be unreachable in practice.
138    /// It's only selected when the wrapped type doesn't implement `Clone`.
139    fn spez_clone_into<'mem>(&self, _target: OpaqueUninit<'mem>) -> Opaque<'mem>;
140}
141impl<T> SpezCloneIntoNo for Spez<T> {
142    fn spez_clone_into<'mem>(&self, _target: OpaqueUninit<'mem>) -> Opaque<'mem> {
143        unreachable!()
144    }
145}
146
147//////////////////////////////////////////////////////////////////////////////////////
148// Parse πŸ“πŸ”
149//////////////////////////////////////////////////////////////////////////////////////
150
151/// Specialization proxy for [`core::str::FromStr`]
152pub trait SpezParseYes {
153    /// Parses a string slice into the inner type.
154    ///
155    /// This method is called when the wrapped type implements `FromStr`.
156    /// It attempts to parse the provided string and write the result into the target memory.
157    fn spez_parse(&self, s: &str, target: OpaqueUninit) -> Result<(), ParseError>;
158}
159impl<T: core::str::FromStr> SpezParseYes for &Spez<T> {
160    fn spez_parse(&self, s: &str, target: OpaqueUninit) -> Result<(), ParseError> {
161        match <T as core::str::FromStr>::from_str(s) {
162            Ok(value) => {
163                unsafe { target.write(value) };
164                Ok(())
165            }
166            Err(_) => Err(ParseError::Generic(
167                const { concat!("parse error for ", stringify!(T)) },
168            )),
169        }
170    }
171}
172
173/// Specialization proxy for [`core::str::FromStr`]
174pub trait SpezParseNo {
175    /// Fallback implementation when the type doesn't implement `FromStr`.
176    ///
177    /// This method is used as a fallback and is designed to be unreachable in practice.
178    /// It's only selected when the wrapped type doesn't implement `FromStr`.
179    fn spez_parse(&self, _s: &str, _target: OpaqueUninit) -> Result<(), ParseError>;
180}
181impl<T> SpezParseNo for Spez<T> {
182    fn spez_parse(&self, _s: &str, _target: OpaqueUninit) -> Result<(), ParseError> {
183        unreachable!()
184    }
185}
186
187//////////////////////////////////////////////////////////////////////////////////////
188// PartialEq 🟰🀝
189//////////////////////////////////////////////////////////////////////////////////////
190
191/// Specialization proxy for [`core::cmp::PartialEq`]
192pub trait SpezPartialEqYes {
193    /// Checks if two values are equal.
194    ///
195    /// This method is called when the wrapped type implements `PartialEq`.
196    /// It compares the inner values for equality.
197    fn spez_eq(&self, other: &Self) -> bool;
198}
199impl<T: PartialEq> SpezPartialEqYes for &Spez<T> {
200    fn spez_eq(&self, other: &Self) -> bool {
201        self.0 == other.0
202    }
203}
204
205/// Specialization proxy for [`core::cmp::PartialEq`]
206pub trait SpezPartialEqNo {
207    /// Fallback implementation when the type doesn't implement `PartialEq`.
208    ///
209    /// This method is used as a fallback and is designed to be unreachable in practice.
210    /// It's only selected when the wrapped type doesn't implement `PartialEq`.
211    fn spez_eq(&self, _other: &Self) -> bool;
212}
213impl<T> SpezPartialEqNo for Spez<T> {
214    fn spez_eq(&self, _other: &Self) -> bool {
215        unreachable!()
216    }
217}
218
219//////////////////////////////////////////////////////////////////////////////////////
220// PartialOrd πŸ”’β†•οΈ
221//////////////////////////////////////////////////////////////////////////////////////
222
223/// Specialization proxy for [`core::cmp::PartialOrd`]
224pub trait SpezPartialOrdYes {
225    /// Compares two values for ordering.
226    ///
227    /// This method is called when the wrapped type implements `PartialOrd`.
228    /// It compares the inner values and returns their ordering.
229    fn spez_partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering>;
230}
231impl<T: PartialOrd> SpezPartialOrdYes for &Spez<T> {
232    fn spez_partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
233        self.0.partial_cmp(&other.0)
234    }
235}
236
237/// Specialization proxy for [`core::cmp::PartialOrd`]
238pub trait SpezPartialOrdNo {
239    /// Fallback implementation when the type doesn't implement `PartialOrd`.
240    ///
241    /// This method is used as a fallback and is designed to be unreachable in practice.
242    /// It's only selected when the wrapped type doesn't implement `PartialOrd`.
243    fn spez_partial_cmp(&self, _other: &Self) -> Option<core::cmp::Ordering>;
244}
245impl<T> SpezPartialOrdNo for Spez<T> {
246    fn spez_partial_cmp(&self, _other: &Self) -> Option<core::cmp::Ordering> {
247        unreachable!()
248    }
249}
250
251//////////////////////////////////////////////////////////////////////////////////////
252// Ord πŸ“ŠπŸ”€
253//////////////////////////////////////////////////////////////////////////////////////
254
255/// Specialization proxy for [`core::cmp::Ord`]
256pub trait SpezOrdYes {
257    /// Compares two values for ordering.
258    ///
259    /// This method is called when the wrapped type implements `Ord`.
260    /// It compares the inner values and returns their ordering.
261    fn spez_cmp(&self, other: &Self) -> core::cmp::Ordering;
262}
263impl<T: Ord> SpezOrdYes for &Spez<T> {
264    fn spez_cmp(&self, other: &Self) -> core::cmp::Ordering {
265        self.0.cmp(&other.0)
266    }
267}
268
269/// Specialization proxy for [`core::cmp::Ord`]
270pub trait SpezOrdNo {
271    /// Fallback implementation when the type doesn't implement `Ord`.
272    ///
273    /// This method is used as a fallback and is designed to be unreachable in practice.
274    /// It's only selected when the wrapped type doesn't implement `Ord`.
275    fn spez_cmp(&self, _other: &Self) -> core::cmp::Ordering;
276}
277impl<T> SpezOrdNo for Spez<T> {
278    fn spez_cmp(&self, _other: &Self) -> core::cmp::Ordering {
279        unreachable!()
280    }
281}
282
283//////////////////////////////////////////////////////////////////////////////////////
284// Hash #οΈβƒ£πŸ”
285//////////////////////////////////////////////////////////////////////////////////////
286
287/// Specialization proxy for [`core::hash::Hash`]
288pub trait SpezHashYes {
289    /// Hashes the inner value.
290    ///
291    /// This method is called when the wrapped type implements `Hash`.
292    /// It hashes the inner value using the provided hasher.
293    fn spez_hash<H: core::hash::Hasher>(&self, state: &mut H);
294}
295impl<T: core::hash::Hash> SpezHashYes for &Spez<T> {
296    fn spez_hash<H: core::hash::Hasher>(&self, state: &mut H) {
297        self.0.hash(state)
298    }
299}
300
301/// Specialization proxy for [`core::hash::Hash`]
302pub trait SpezHashNo {
303    /// Fallback implementation when the type doesn't implement `Hash`.
304    ///
305    /// This method is used as a fallback and is designed to be unreachable in practice.
306    /// It's only selected when the wrapped type doesn't implement `Hash`.
307    fn spez_hash<H: core::hash::Hasher>(&self, _state: &mut H);
308}
309impl<T> SpezHashNo for Spez<T> {
310    fn spez_hash<H: core::hash::Hasher>(&self, _state: &mut H) {
311        unreachable!()
312    }
313}