try_specialize/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3
4//! The `try-specialize` crate provides limited, [zero-cost](#zero-cost)
5//! specialization in generic context on stable Rust.
6//!
7//! ```rust
8//! use try_specialize::TrySpecialize;
9//!
10//! fn example_specialize_by_value<T>(value: T) -> Result<u32, T> {
11//!     value.try_specialize()
12//!     // Same as: `<T as TrySpecialize>::try_specialize::<u32>(value)`.
13//!     // `try_specialize::<T>` specializes from `Self` to `T, where T: LifetimeFree`.
14//! }
15//!
16//! fn example_specialize_by_ref<T: ?Sized>(value: &T) -> Option<&str> {
17//!     value.try_specialize_ref()
18//!     // Same as: `<T as TrySpecialize>::try_specialize_ref::<str>(value)`.
19//!     // `try_specialize_ref::<T>` specializes from `&Self` to `&T, where T: LifetimeFree`.
20//! }
21//!
22//! assert_eq!(example_specialize_by_value(123_u32), Ok(123));
23//! assert_eq!(example_specialize_by_value(123_i32), Err(123));
24//! assert_eq!(example_specialize_by_ref("foo"), Some("foo"));
25//! assert_eq!(example_specialize_by_ref(&123_u32), None);
26//! assert_eq!(example_specialize_by_ref(&[1, 2, 3]), None);
27//! ```
28//!
29//! # Introduction
30//!
31//! While specialization in Rust can be a tempting solution in many use cases,
32//! it is usually more idiomatic to use traits instead. Traits are the idiomatic
33//! way to achieve polymorphism in Rust, promoting better code clarity,
34//! reusability, and maintainability.
35//!
36//! However, specialization can be suitable when you need to optimize
37//! performance by providing specialized implementations for some types without
38//! altering the code logic. It's also useful in specific, type-level
39//! programming use cases like comparisons between types from different
40//! libraries.
41//!
42//! For a simple use cases, consider the [`castaway`] crate, which offers a much
43//! simpler API. On nightly Rust, consider using [`min_specialization`] feature
44//! instead. The Rust standard library already uses [`min_specialization`] for
45//! many optimizations. For a more detailed comparison, see the
46//! [Alternative crates](#alternative-crates) section below.
47//!
48//! # About
49//!
50//! This crate offers a comprehensive API for addressing various specialization
51//! challenges, reducing the need for unsafe code. It provides specialization
52//! from unconstrained types, to unconstrained types, between 'static types,
53//! and between type references and mutable references, and more.
54//!
55//! <a name="zero-cost"></a> Library tests ensure that specializations are
56//! performed at compile time and are fully optimized with no runtime cost at
57//! `opt-level >= 1`. Note that the [release] profile uses `opt-level = 3`
58//! by default.
59//!
60//! # Usage
61//!
62//! Add this to your `Cargo.toml`:
63//!
64//! ```toml
65//! [dependencies]
66//! try-specialize = "0.1.2"
67//! ```
68//!
69//! Then, you can use [`TrySpecialize`] trait methods like
70//! [`TrySpecialize::try_specialize`], [`TrySpecialize::try_specialize_ref`] and
71//! [`TrySpecialize::try_specialize_static`]. To check the possibility of
72//! specialization in advance and use it infallibly multiple times, including
73//! reversed or mapped specialization, use [`Specialization`] struct methods.
74//!
75//! Note that unlike casting, [subtyping], and [coercion], specialization does
76//! not alter the underlying type or data. It merely qualifies the underlying
77//! types of generics, succeeding only when the underlying types of `T1` and
78//! `T2` are equal.
79//!
80//! # Examples
81//!
82//! Specialize type to any [`LifetimeFree`] type:
83//! ```rust
84//! # #[cfg(feature = "alloc")] {
85//! use try_specialize::TrySpecialize;
86//!
87//! fn func<T>(value: T) {
88//!     match value.try_specialize::<(u32, String)>() {
89//!         Ok(value) => specialized_impl(value),
90//!         Err(value) => default_impl(value),
91//!     }
92//! }
93//!
94//! fn specialized_impl(_value: (u32, String)) {}
95//! fn default_impl<T>(_value: T) {}
96//! # func((42_u32, "abc".to_owned()));
97//! # func((42_i32, "abc".to_owned()));
98//! # }
99//! ```
100//!
101//! Specialize `'static` type to any `'static` type:
102//! ```rust
103//! use try_specialize::TrySpecialize;
104//!
105//! fn func<T>(value: T)
106//! where
107//!     T: 'static,
108//! {
109//!     match value.try_specialize_static::<(u32, &'static str)>() {
110//!         Ok(value) => specialized_impl(value),
111//!         Err(value) => default_impl(value),
112//!     }
113//! }
114//!
115//! fn specialized_impl(_value: (u32, &'static str)) {}
116//! fn default_impl<T>(_value: T) {}
117//! # func((42_u32, "abc"));
118//! # func((42_i32, "abc"));
119//! ```
120//!
121//! Specialize `Sized` or `Unsized` type reference to any [`LifetimeFree`] type
122//! reference:
123//! ```rust
124//! use try_specialize::TrySpecialize;
125//!
126//! fn func<T>(value: &T)
127//! where
128//!     T: ?Sized, // Relax the implicit `Sized` bound.
129//! {
130//!     match value.try_specialize_ref::<str>() {
131//!         Some(value) => specialized_impl(value),
132//!         None => default_impl(value),
133//!     }
134//! }
135//!
136//! fn specialized_impl(_value: &str) {}
137//! fn default_impl<T: ?Sized>(_value: &T) {}
138//! # func("abc");
139//! # func(&42);
140//! ```
141//!
142//! Specialize `Sized` or `Unsized` type mutable reference to any
143//! [`LifetimeFree`] type mutable reference:
144//! ```rust
145//! use try_specialize::TrySpecialize;
146//!
147//! fn func<T>(value: &mut T)
148//! where
149//!     T: ?Sized, // Relax the implicit `Sized` bound.
150//! {
151//!     match value.try_specialize_mut::<[u8]>() {
152//!         Some(value) => specialized_impl(value),
153//!         None => default_impl(value),
154//!     }
155//! }
156//!
157//! fn specialized_impl(_value: &mut [u8]) {}
158//! fn default_impl<T: ?Sized>(_value: &mut T) {}
159//! # func(&mut [1_u8, 2, 3][..]);
160//! # func(&mut [1_i8, 2, 3][..]);
161//! ```
162//!
163//! Specialize a third-party library container with generic types:
164//! ```rust
165//! use try_specialize::{Specialization, TypeFn};
166//!
167//! fn func<K, V>(value: hashbrown::HashMap<K, V>) {
168//!     struct MapIntoHashMap;
169//!     impl<K, V> TypeFn<(K, V)> for MapIntoHashMap {
170//!         type Output = hashbrown::HashMap<K, V>;
171//!     }
172//!
173//!     if let Some(spec) = Specialization::<(K, V), (u32, char)>::try_new() {
174//!         let spec = spec.map::<MapIntoHashMap>();
175//!         let value: hashbrown::HashMap<u32, char> = spec.specialize(value);
176//!         specialized_impl(value);
177//!     } else {
178//!         default_impl(value);
179//!     }
180//! }
181//!
182//! fn default_impl<K, V>(_value: hashbrown::HashMap<K, V>) {}
183//! fn specialized_impl(_value: hashbrown::HashMap<u32, char>) {}
184//! # func([(12_u32, 'a'), (23_u32, 'b')].into_iter().collect());
185//! # func([(12_i32, 'a'), (23_i32, 'b')].into_iter().collect());
186//! ```
187//!
188//! For a more comprehensive example, see the [`examples/encode.rs`], which
189//! implements custom data encoders and decoders with per-type encoding and
190//! decoding errors and optimized byte array encoding and decoding.
191//! The part of this example related to the `Encode` implementation for a slice:
192//! ```rust
193//! # use core::convert::Infallible;
194//! # use core::{array, slice};
195//! # use std::io::{self, Read, Write};
196//! #
197//! # use try_specialize::{Specialization, TypeFn};
198//! #
199//! # pub trait Encode {
200//! #     type EncodeError;
201//! #     fn encode_to<W>(&self, writer: &mut W) -> Result<(), Self::EncodeError>
202//! #     where
203//! #         W: ?Sized + Write;
204//! # }
205//! #
206//! # pub trait Decode: Sized {
207//! #     type DecodeError;
208//! #     fn decode_from<R>(reader: &mut R) -> Result<Self, Self::DecodeError>
209//! #     where
210//! #         R: ?Sized + Read;
211//! # }
212//! #
213//! # impl Encode for () {
214//! #     type EncodeError = Infallible;
215//! #
216//! #     #[inline]
217//! #     fn encode_to<W>(&self, _writer: &mut W) -> Result<(), Self::EncodeError>
218//! #     where
219//! #         W: ?Sized + Write,
220//! #     {
221//! #         Ok(())
222//! #     }
223//! # }
224//! #
225//! # impl Decode for () {
226//! #     type DecodeError = Infallible;
227//! #
228//! #     #[inline]
229//! #     fn decode_from<R>(_reader: &mut R) -> Result<Self, Self::DecodeError>
230//! #     where
231//! #         R: ?Sized + Read,
232//! #     {
233//! #         Ok(())
234//! #     }
235//! # }
236//! #
237//! # impl<T> Encode for Box<T>
238//! # where
239//! #     T: Encode,
240//! # {
241//! #     type EncodeError = T::EncodeError;
242//! #
243//! #     #[inline]
244//! #     fn encode_to<W>(&self, writer: &mut W) -> Result<(), Self::EncodeError>
245//! #     where
246//! #         W: ?Sized + Write,
247//! #     {
248//! #         T::encode_to(self, writer)
249//! #     }
250//! # }
251//! #
252//! # impl<T> Decode for Box<T>
253//! # where
254//! #     T: Decode,
255//! # {
256//! #     type DecodeError = T::DecodeError;
257//! #
258//! #     #[inline]
259//! #     fn decode_from<R>(reader: &mut R) -> Result<Self, Self::DecodeError>
260//! #     where
261//! #         R: ?Sized + Read,
262//! #     {
263//! #         Ok(Self::new(T::decode_from(reader)?))
264//! #     }
265//! # }
266//! #
267//! # impl Encode for u8 {
268//! #     type EncodeError = io::Error;
269//! #
270//! #     #[inline]
271//! #     fn encode_to<W>(&self, writer: &mut W) -> Result<(), Self::EncodeError>
272//! #     where
273//! #         W: ?Sized + Write,
274//! #     {
275//! #         writer.write_all(&[*self])?;
276//! #         Ok(())
277//! #     }
278//! # }
279//! #
280//! # impl Decode for u8 {
281//! #     type DecodeError = io::Error;
282//! #
283//! #     #[inline]
284//! #     fn decode_from<R>(reader: &mut R) -> Result<Self, Self::DecodeError>
285//! #     where
286//! #         R: ?Sized + Read,
287//! #     {
288//! #         let mut byte: Self = 0;
289//! #         reader.read_exact(slice::from_mut(&mut byte))?;
290//! #         Ok(byte)
291//! #     }
292//! # }
293//! // ...
294//!
295//! impl<T> Encode for [T]
296//! where
297//!     T: Encode,
298//! {
299//!     type EncodeError = T::EncodeError;
300//!
301//!     #[inline]
302//!     fn encode_to<W>(&self, writer: &mut W) -> Result<(), Self::EncodeError>
303//!     where
304//!         W: ?Sized + Write,
305//!     {
306//!         if let Some(spec) = Specialization::<[T], [u8]>::try_new() {
307//!             // Specialize self from `[T; N]` to `[u32; N]`
308//!             let bytes: &[u8] = spec.specialize_ref(self);
309//!             // Map type specialization to its associated error specialization.
310//!             let spec_err = spec.rev().map::<MapToEncodeError>();
311//!             writer
312//!                 .write_all(bytes)
313//!                 // Specialize error from `io::Error` to `Self::EncodeError`.
314//!                 .map_err(|err| spec_err.specialize(err))?;
315//!         } else {
316//!             for item in self {
317//!                 item.encode_to(writer)?;
318//!             }
319//!         }
320//!         Ok(())
321//!     }
322//! }
323//!
324//! // ...
325//! # impl<T, const N: usize> Encode for [T; N]
326//! # where
327//! #     T: Encode,
328//! # {
329//! #     type EncodeError = T::EncodeError;
330//! #
331//! #     #[inline]
332//! #     fn encode_to<W>(&self, writer: &mut W) -> Result<(), Self::EncodeError>
333//! #     where
334//! #         W: ?Sized + Write,
335//! #     {
336//! #         self.as_slice().encode_to(writer)
337//! #     }
338//! # }
339//! #
340//! # impl<T, const N: usize> Decode for [T; N]
341//! # where
342//! #     T: Decode + Default,
343//! # {
344//! #     type DecodeError = T::DecodeError;
345//! #
346//! #     #[inline]
347//! #     fn decode_from<R>(reader: &mut R) -> Result<Self, Self::DecodeError>
348//! #     where
349//! #         R: ?Sized + Read,
350//! #     {
351//! #         let spec = Specialization::<[T; N], [u8; N]>::try_new();
352//! #
353//! #         if let Some(spec) = spec {
354//! #             let mut array = [0; N];
355//! #             reader
356//! #                 .read_exact(&mut array)
357//! #                 // Specialize `<[u8; N]>::Error` to `<[T; N]>::Error`
358//! #                 .map_err(|err| spec.rev().map::<MapToDecodeError>().specialize(err))?;
359//! #             // Specialize `[u8; N]` to `[T; N]`
360//! #             let array = spec.rev().specialize(array);
361//! #             Ok(array)
362//! #         } else {
363//! #             // In real code it can be done without `Default` bound.
364//! #             // But then the code would be unnecessarily complex for the example.
365//! #             let mut array = array::from_fn(|_| T::default());
366//! #             for item in &mut array {
367//! #                 *item = T::decode_from(reader)?;
368//! #             }
369//! #             Ok(array)
370//! #         }
371//! #     }
372//! # }
373//! #
374//! # struct MapToEncodeError;
375//! #
376//! # impl<T> TypeFn<T> for MapToEncodeError
377//! # where
378//! #     T: ?Sized + Encode,
379//! # {
380//! #     type Output = T::EncodeError;
381//! # }
382//! #
383//! # struct MapToDecodeError;
384//! # impl<T> TypeFn<T> for MapToDecodeError
385//! # where
386//! #     T: Decode,
387//! # {
388//! #     type Output = T::DecodeError;
389//! # }
390//! #
391//! # let mut array_buf = [0; 8];
392//! # let mut buf = &mut array_buf[..];
393//! # [1_u8, 2, 3].encode_to(&mut buf).unwrap();
394//! # 4_u8.encode_to(&mut buf).unwrap();
395//! # [(), (), (), ()].encode_to(&mut buf).unwrap();
396//! # [5_u8, 6, 7, 8].map(Box::new).encode_to(&mut buf).unwrap();
397//! # assert!(9_u8.encode_to(&mut buf).is_err());
398//! # assert!([9_u8, 10].encode_to(&mut buf).is_err());
399//! # ().encode_to(&mut buf).unwrap();
400//! # [(), (), ()].encode_to(&mut buf).unwrap();
401//! # assert!([9_u8, 10].map(Box::new).encode_to(&mut buf).is_err());
402//! # assert_eq!(array_buf, [1, 2, 3, 4, 5, 6, 7, 8]);
403//! #
404//! # let buf = &mut array_buf.as_slice();
405//! # assert_eq!(u8::decode_from(buf).unwrap(), 1);
406//! # assert_eq!(<[u8; 4]>::decode_from(buf).unwrap(), [2, 3, 4, 5]);
407//! # assert_eq!(<[(); 16]>::decode_from(buf).unwrap(), [(); 16]);
408//! # assert_eq!(<[u8; 1]>::decode_from(buf).unwrap(), [6]);
409//! # assert_eq!(
410//! #     <[Box<u8>; 2]>::decode_from(buf).unwrap(),
411//! #     [Box::new(7), Box::new(8)]
412//! # );
413//! # assert!(u8::decode_from(buf).is_err());
414//! # assert!(<[u8; 1]>::decode_from(buf).is_err());
415//! # assert_eq!(<[(); 2]>::decode_from(buf).unwrap(), [(); 2]);
416//! # assert!(<[Box<u8>; 2]>::decode_from(buf).is_err());
417//! ```
418//!
419//! Find values by type in generic composite types:
420//! ```rust
421//! use try_specialize::{LifetimeFree, TrySpecialize};
422//!
423//! pub trait ConsListLookup {
424//!     fn find<T>(&self) -> Option<&T>
425//!     where
426//!         T: ?Sized + LifetimeFree;
427//! }
428//!
429//! impl ConsListLookup for () {
430//!     #[inline]
431//!     fn find<T>(&self) -> Option<&T>
432//!     where
433//!         T: ?Sized + LifetimeFree,
434//!     {
435//!         None
436//!     }
437//! }
438//!
439//! impl<T1, T2> ConsListLookup for (T1, T2)
440//! where
441//!     T2: ConsListLookup,
442//! {
443//!     #[inline]
444//!     fn find<T>(&self) -> Option<&T>
445//!     where
446//!         T: ?Sized + LifetimeFree,
447//!     {
448//!         self.0.try_specialize_ref().or_else(|| self.1.find::<T>())
449//!     }
450//! }
451//!
452//! #[derive(Eq, PartialEq, Debug)]
453//! struct StaticStr(&'static str);
454//! // SAFETY: It is safe to implement `LifetimeFree` for structs with no
455//! // parameters.
456//! unsafe impl LifetimeFree for StaticStr {}
457//!
458//! let input = (
459//!     123_i32,
460//!     (
461//!         [1_u32, 2, 3, 4],
462//!         (1_i32, (StaticStr("foo"), (('a', false), ()))),
463//!     ),
464//! );
465//!
466//! assert_eq!(input.find::<u32>(), None);
467//! assert_eq!(input.find::<i32>(), Some(&123_i32));
468//! assert_eq!(input.find::<[u32; 4]>(), Some(&[1, 2, 3, 4]));
469//! assert_eq!(input.find::<[u32]>(), None);
470//! assert_eq!(input.find::<StaticStr>(), Some(&StaticStr("foo")));
471//! assert_eq!(input.find::<char>(), None);
472//! assert_eq!(input.find::<(char, bool)>(), Some(&('a', false)));
473//! ```
474//!
475//! # Documentation
476//!
477//! [API Documentation]
478//!
479//! # Feature flags
480//!
481//! - `alloc` (implied by `std`, enabled by default): enables [`LifetimeFree`]
482//!   implementations for `alloc` types, like `Box`, `Arc`, `String`, `Vec`,
483//!   `BTreeMap` etc.
484//! - `std` (enabled by default): enables `alloc` feature and [`LifetimeFree`]
485//!   implementations for `std` types, like `OsStr`, `Path`, `PathBuf`,
486//!   `Instant`, `HashMap` etc.
487//! - `unreliable`: enables functions, methods and macros that rely on Rust
488//!   standard library undocumented behavior. Refer to the [`unreliable`] module
489//!   documentation for details.
490//!
491//! # How it works
492//!
493//! - Type comparison between `'static` types compares their [`TypeId::of`]s.
494//! - Type comparison between unconstrained and [`LifetimeFree`] type treats
495//!   them as `'static` and compares their [`TypeId::of`]s.
496//! - Specialization relies on type comparison and [`transmute_copy`] when the
497//!   equality of types is established.
498//! - Unreliable trait implementation checks are performed using an expected,
499//!   but undocumented behavior of the Rust stdlib [`PartialEq`] implementation
500//!   for [`Arc<T>`]. [`Arc::eq`] uses fast path comparing references before
501//!   comparing data if `T` implements [`Eq`].
502//!
503//! # Alternative crates
504//!
505//! - [`castaway`]: A similar crate with a much simpler macro-based API. The
506//!   macro uses [Autoref-Based Specialization] and automatically determines the
507//!   appropriate type of specialization, making it much easier to use. However,
508//!   if no specialization is applicable because of the same [Autoref-Based
509//!   Specialization], the compiler generates completely unclear errors, which
510//!   makes it difficult to use it in complex cases. Internally uses `unsafe`
511//!   code for type comparison and specialization.
512//! - [`coe-rs`]: Smaller and simpler, but supports only static types and don't
513//!   safely combine type equality check and specialization. Internally uses
514//!   `unsafe` code for type specialization.
515//! - [`downcast-rs`]: Specialized on trait objects (`dyn`) downcasting. Can't
516//!   be used to specialize unconstrained types.
517//! - [`syllogism`] and [`syllogism_macro`]: Requires to provide all possible
518//!   types to macro that generate a lot of boilerplate code and can't be used
519//!   to specialize stdlib types because of orphan rules.
520//! - [`specialize`](https://crates.io/crates/specialize): Requires nightly.
521//!   Adds a simple macro to inline nightly [`min_specialization`] usage into
522//!   simple `if let` expressions.
523//! - [`specialized-dispatch`]: Requires nightly. Adds a macro to inline nightly
524//!   [`min_specialization`] usage into a `match`-like macro.
525//! - [`spez`]: Specializes expression types, using [Autoref-Based
526//!   Specialization]. It won't works in generic context but can be used in the
527//!   code generated by macros.
528//! - [`impls`]: Determine if a type implements a trait. Can't detect erased
529//!   type bounds, so not applicable in generic context, but can be used in the
530//!   code generated by macros.
531//!
532//! ## Comparison of libraries supporting specialization in generic context:
533//!
534//! |  | crate <br /> `try-specialize` | crate <br /> [`castaway`] | crate <br /> [`coe-rs`] | crate <br /> [`downcast-rs`] | crate <br /> [`syllogism`] | [`min_spec...`] <br /> nightly feature | crate <br /> [`specialize`](https://crates.io/crates/specialize) | crate <br /> [`spec...ch`]
535//! | --: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: |
536//! | Checked version | `0.1.2` | `0.2.3` | `0.1.2` | `1.2.1` | `0.1.3` | N/A | `0.0.3` | `0.2.1` |
537//! | Rust toolchain | **Stable** | **Stable** | **Stable** | **Stable** | **Stable** | Nightly | Nightly | Nightly |
538//! | API complexity | Complex | **Simple** | **Simple** | Moderate | **Simple** | **Simple** | **Simple** | **Simple** |
539//! | API difficulty | Difficult | **Easy** | **Easy** | Moderate | Moderate | **Easy** | **Easy** | Moderate |
540//! | Zero-cost (compile-time optimized) | **YES** | **YES** | **YES** | no | **YES** | **YES** | **YES** | **YES** |
541//! | Safely combines type eq check and specialization | **YES** | **YES** | no | **YES** | **YES** | **YES** |**YES** | **YES** |
542//! | Specialize value references | **YES** | **YES** | **YES** | N/A | **YES** | **YES** | **YES** | no |
543//! | Specialize values | **YES** | **YES** | no | N/A | **YES** | **YES** | **YES** | **YES** |
544//! | Specialize values without consume on failure | **YES** | **YES** | no | N/A | **YES** | **YES** | no | **YES** |
545//! | Limited non-static value specialization | **YES** | **YES** | no | N/A | **YES** | **YES** | **YES** | **YES** |
546//! | Full non-static value specialization | no | no | no | N/A | **YES** | no | no | no |
547//! | Specialize trait objects (`dyn`) | N/A | N/A | N/A | **YES** | N/A | N/A | N/A | N/A |
548//! | Compare types without instantiation | **YES** | no | **YES** | no | **YES** | **YES** | **YES** | no |
549//! | Support std types | **YES** | **YES** | **YES** | **YES** | no | **YES** | **YES** | **YES** |
550//! | Specialize from unconstrained type | **YES** | **YES** | no | no | no | **YES** | **YES** | **YES** |
551//! | Specialize to unconstrained type | **YES** | no | no | no | no | **YES** | **YES** | **YES** |
552//! | Check generic implements "erased" trait | **YES**, but [`unreliable`] | no | no | no | no | **YES** | **YES** | **YES** |
553//! | Specialize to generic with added bounds | no | no | no | no | no | **YES** | **YES** | **YES** |
554//! | API based on | Traits | Macros | Traits | Macros + Traits | Traits | Language | Macros | Macros |
555//! | Type comparison implementation based on | [`TypeId`] <br /> + [`transmute`] | [`TypeId`] <br /> + [`transmute`] |[`TypeId`] | N/A | Traits | Language | Nightly <br /> feature | Nightly <br /> feature |
556//! | Type casting implementation based on | [`transmute_copy`] | [`ptr::read`] | [`transmute`] | [`std::any::Any`] | Traits | Language | Nightly <br /> feature | Nightly <br /> feature |
557//! | Implementation free of `unsafe` | no | no | no | **YES** | **YES** | **YES** | **YES** | **YES** |
558//!
559//! ## Primitive example of the value specialization using different libraries
560//!
561//! <table><tbody><tr><td style="vertical-align: top">
562//!
563//! crate `try_specialize`:
564//!
565//! ```rust
566//! use try_specialize::TrySpecialize;
567//!
568//! fn spec<T>(value: T) -> Result<u32, T> {
569//!     value.try_specialize()
570//! }
571//!
572//! assert_eq!(spec(42_u32), Ok(42));
573//! assert_eq!(spec(42_i32), Err(42));
574//! assert_eq!(spec("abc"), Err("abc"));
575//! ```
576//!
577//! </td><td style="vertical-align: top">
578//!
579//! crate [`castaway`]:
580//!
581//! ```rust
582//! use castaway::cast;
583//!
584//! fn spec<T>(value: T) -> Result<u32, T> {
585//!     cast!(value, _)
586//! }
587//!
588//! assert_eq!(spec(42_u32), Ok(42));
589//! assert_eq!(spec(42_i32), Err(42));
590//! assert_eq!(spec("abc"), Err("abc"));
591//! ```
592//!
593//! </td></tr><tr><td style="vertical-align: top">
594//!
595//! crate [`coe-rs`]:
596//!
597//! ```rust
598//! use coe::{is_same, Coerce};
599//!
600//! // Library don't support non-reference.
601//! // specialization. Using reference.
602//! fn spec<T>(value: &T) -> Option<&u32>
603//! where
604//!     // Library don't support specialization of
605//!     // unconstrained non-static types.
606//!     T: 'static,
607//! {
608//!     is_same::<u32, T>().then(|| value.coerce())
609//! }
610//!
611//! fn main() {
612//!     assert_eq!(spec(&42_u32), Some(&42));
613//!     assert_eq!(spec(&42_i32), None);
614//!     assert_eq!(spec(&"abc"), None);
615//! }
616//! ```
617//!
618//! </td><td style="vertical-align: top">
619//!
620//! crates [`downcast-rs`]:
621//!
622//! ```rust
623//! use downcast_rs::{impl_downcast, DowncastSync};
624//!
625//! trait Base: DowncastSync {}
626//! impl_downcast!(sync Base);
627//!
628//! // Library requires all specializable
629//! // types to be defined in advance.
630//! impl Base for u32 {}
631//! impl Base for i32 {}
632//! impl Base for &'static str {}
633//!
634//! // Library support only trait objects (`dyn`).
635//! fn spec(value: &dyn Base) -> Option<&u32> {
636//!     value.downcast_ref::<u32>()
637//! }
638//!
639//! fn main() {
640//!     assert_eq!(spec(&42_u32), Some(&42));
641//!     assert_eq!(spec(&42_i32), None);
642//!     assert_eq!(spec(&"abc"), None);
643//! }
644//! ```
645//!
646//! </td></tr><tr><td style="vertical-align: top">
647//!
648//! crate [`specialize`](https://crates.io/crates/specialize):
649//!
650//! ```rust
651//! # #![cfg_attr(feature = "__test_nightly", feature(min_specialization))]
652//! # #[cfg(feature = "__test_nightly")] {
653//! // Requires nightly.
654//! #![feature(min_specialization)]
655//!
656//! use specialize::constrain;
657//!
658//! // Library don't support non-consuming
659//! // value specialization. Using reference.
660//! fn spec<T: ?Sized>(value: &T) -> Option<&u32> {
661//!     constrain!(ref value as u32)
662//! }
663//!
664//! assert_eq!(spec(&42_u32), Some(&42));
665//! assert_eq!(spec(&42_i32), None);
666//! assert_eq!(spec("abc"), None);
667//! # }
668//! ```
669//!
670//! </td><td style="vertical-align: top">
671//!
672//! crate [`specialized-dispatch`]:
673//! ```rust
674//! # #![cfg_attr(feature = "__test_nightly", feature(min_specialization))]
675//! # #[cfg(feature = "__test_nightly")] {
676//! // Requires nightly.
677//! #![feature(min_specialization)]
678//!
679//! use specialized_dispatch::specialized_dispatch;
680//!
681//! // The library don't support using generics.
682//! // from outer item. Using `Option`.
683//! fn spec<T>(value: T) -> Option<u32> {
684//!     specialized_dispatch! {
685//!         T -> Option<u32>,
686//!         fn (value: u32) => Some(value),
687//!         default fn <T>(_: T) => None,
688//!         value,
689//!     }
690//! }
691//!
692//! assert_eq!(spec(42_u32), Some(42));
693//! assert_eq!(spec(42_i32), None);
694//! assert_eq!(spec("abc"), None);
695//! # }
696//! ```
697//!
698//! </td></tr><tr><td style="vertical-align: top">
699//!
700//! crates [`syllogism`] and [`syllogism_macro`]:
701//!
702//! ```rust
703//! # #[rustfmt::skip]
704//! use syllogism::{Distinction, Specialize};
705//! use syllogism_macro::impl_specialization;
706//!
707//! // Library specialization can not be
708//! // implemented for std types because of
709//! // orphan rules. Using custom local types.
710//! #[derive(Eq, PartialEq, Debug)]
711//! struct U32(u32);
712//! #[derive(Eq, PartialEq, Debug)]
713//! struct I32(i32);
714//! #[derive(Eq, PartialEq, Debug)]
715//! struct Str<'a>(&'a str);
716//!
717//! // Library requires all specializable
718//! // types to be defined in one place.
719//! impl_specialization!(
720//!     type U32;
721//!     type I32;
722//!     type Str<'a>;
723//! );
724//!
725//! fn spec<T>(value: T) -> Result<U32, T>
726//! where
727//!     T: Specialize<U32>,
728//! {
729//!     match value.specialize() {
730//!         Distinction::Special(value) => Ok(value),
731//!         Distinction::Generic(value) => Err(value),
732//!     }
733//! }
734//!
735//! assert_eq!(spec(U32(42)), Ok(U32(42)));
736//! assert_eq!(spec(I32(42_i32)), Err(I32(42)));
737//! assert_eq!(spec(Str("abc")), Err(Str("abc")));
738//! ```
739//!
740//! </td><td style="vertical-align: top">
741//!
742//! [`min_specialization`] nightly feature:
743//!
744//! ```rust
745//! # #![cfg_attr(feature = "__test_nightly", feature(min_specialization))]
746//! # #[cfg(feature = "__test_nightly")] {
747//! // Requires nightly.
748//! #![feature(min_specialization)]
749//!
750//! // The artificial example looks a bit long.
751//! // More real-world use cases are usually
752//! // on the contrary more clear and understandable.
753//! pub trait Spec: Sized {
754//!     fn spec(self) -> Result<u32, Self>;
755//! }
756//!
757//! impl<T> Spec for T {
758//!     default fn spec(self) -> Result<u32, Self> {
759//!         Err(self)
760//!     }
761//! }
762//!
763//! impl Spec for u32 {
764//!     fn spec(self) -> Result<u32, Self> {
765//!         Ok(self)
766//!     }
767//! }
768//!
769//! assert_eq!(Spec::spec(42_u32), Ok(42));
770//! assert_eq!(Spec::spec(42_i32), Err(42));
771//! assert_eq!(Spec::spec("abc"), Err("abc"));
772//! # }
773//! ```
774//!
775//! </td></tr></tbody></table>
776//!
777//! # License
778//!
779//! Licensed under either of
780//!
781//! - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)
782//! - MIT license ([LICENSE-MIT](LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
783//!
784//! at your option.
785//!
786//! # Contribution
787//!
788//! Unless you explicitly state otherwise, any contribution intentionally
789//! submitted for inclusion in the work by you, as defined in the Apache-2.0
790//! license, shall be dual licensed as above, without any
791//! additional terms or conditions.
792//!
793//! [API Documentation]: https://docs.rs/try-specialize
794//! [subtyping]: https://doc.rust-lang.org/nomicon/subtyping.html
795//! [coercion]: https://doc.rust-lang.org/nomicon/coercions.html
796//! [release]: https://doc.rust-lang.org/cargo/reference/profiles.html#release
797//! [`min_specialization`]: https://github.com/rust-lang/rust/pull/68970
798//! [`min_spec...`]: https://github.com/rust-lang/rust/pull/68970 "min_specialization"
799//!
800//! [`examples/encode.rs`]: https://github.com/zheland/try-specialize/blob/v0.1.2/examples/encode.rs
801//!
802//! [`TypeId`]: std::any::TypeId
803//! [`TypeId::of`]: std::any::TypeId::of
804//! [`transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html "std::mem::transmute"
805//! [`transmute_copy`]: std::mem::transmute_copy
806//! [`ptr::read`]: std::ptr::read
807//! [`PartialEq`]: std::cmp::PartialEq
808//! [`Eq`]: std::cmp::Eq
809//! [`Arc::eq`]: std::sync::Arc::eq "<std::sync::Arc as PartialEq>::eq"
810//! [`Arc<T>`]: std::sync::Arc
811//!
812//! [`try_new`]: Specialization::try_new
813//! [`try_new_static`]: Specialization::try_new_static
814//! [`try_new_ignore_lifetimes`]: Specialization::try_new_ignore_lifetimes
815//! [`rev`]: Specialization::rev
816//! [`map`]: Specialization::map
817//! [`specialize`]: Specialization::specialize
818//! [`specialize_ref`]: Specialization::specialize_ref
819//! [`specialize_mut`]: Specialization::specialize_mut
820//!
821//! [`WeakSpecialization`]: unreliable::WeakSpecialization
822//! [`try_new_if_lifetime_free_weak`]: unreliable::WeakSpecialization::try_new_if_lifetime_free_weak
823//!
824//! [`try_specialize`]: TrySpecialize::try_specialize
825//! [`try_specialize_ref`]: TrySpecialize::try_specialize_ref
826//! [`try_specialize_from`]: TrySpecialize::try_specialize_from
827//! [`try_specialize_from_ref`]: TrySpecialize::try_specialize_from_ref
828//! [`try_specialize_static`]: TrySpecialize::try_specialize_static
829//! [`try_specialize_ref_static`]: TrySpecialize::try_specialize_ref_static
830//! [`..._ignore_lifetimes`]: TrySpecialize::try_specialize_ignore_lifetimes
831//! [`..._ref_ignore_lifetimes`]: TrySpecialize::try_specialize_ref_ignore_lifetimes
832//! [`..._mut_ignore_lifetimes`]: TrySpecialize::try_specialize_mut_ignore_lifetimes
833//!
834//! [`TrySpecializeWeak`]: unreliable::TrySpecializeWeak
835//! [`..._if_lifetime_free_weak`]: unreliable::TrySpecializeWeak::try_specialize_if_lifetime_free_weak
836//! [`..._ref_if_lifetime_free_weak`]: unreliable::TrySpecializeWeak::try_specialize_ref_if_lifetime_free_weak
837//! [`..._mut_if_lifetime_free_weak`]: unreliable::TrySpecializeWeak::try_specialize_mut_if_lifetime_free_weak
838//!
839//! [`castaway`]: https://crates.io/crates/castaway
840//! [`syllogism`]: https://crates.io/crates/syllogism
841//! [`syllogism_macro`]: https://crates.io/crates/syllogism_macro
842//! [`specialized-dispatch`]: https://crates.io/crates/specialized-dispatch
843//! [`spec...ch`]: https://crates.io/crates/specialized-dispatch "specialized-dispatch"
844//! [`spez`]: https://crates.io/crates/spez
845//! [`coe-rs`]: https://crates.io/crates/coe-rs
846//! [`downcast-rs`]: https://crates.io/crates/downcast-rs
847//! [`impls`]: https://crates.io/crates/impls
848//!
849//! [Autoref-Based Specialization]: https://lukaskalbertodt.github.io/2019/12/05/generalized-autoref-based-specialization.html
850
851#[cfg(feature = "alloc")]
852extern crate alloc;
853
854#[cfg(feature = "std")]
855extern crate std;
856
857mod lifetime_free;
858mod specialization;
859mod try_specialize;
860mod type_eq;
861mod type_fn;
862
863#[cfg(all(feature = "alloc", feature = "unreliable"))]
864#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "unreliable"))))]
865pub mod unreliable;
866
867pub use lifetime_free::*;
868pub use specialization::*;
869pub use try_specialize::*;
870pub use type_eq::*;
871pub use type_fn::*;
872
873#[cfg(all(test, not(doc)))]
874mod integration_tests_deps {
875    use {paste as _, rustversion as _, version_sync as _};
876}
877
878#[cfg(all(test, not(doc)))]
879mod doc_tests_deps {
880    use {
881        castaway as _, coe as _, downcast_rs as _, hashbrown as _, specialize as _,
882        specialized_dispatch as _, syllogism as _, syllogism_macro as _,
883    };
884}
885
886#[doc(hidden)]
887#[cfg(all(feature = "alloc", feature = "unreliable"))]
888pub mod macro_deps {
889    pub use alloc::rc::Rc;
890}