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}