`.
//! Essentially, we want to take a generic type parameter `P` and treat it as if
//! it were an instance of a specific `Pin` type.
//!
//! We can start by defining a trait alias to recover the specific `Pin` type.
//!
//! ```ignore
//! type SpecificPin = Pin<
::Id,
::Mode>;
//! ```
//!
//! With this new definition, we can rephrase our statement above. We need some
//! way to tell the compiler that when `P` implements `AnyPin`,
//! `P == SpecificPin
`. There's no way to do that exactly, but we can come
//! close with some useful trait bounds: [`From`], [`Into`], [`AsRef`] and
//! [`AsMut`].
//!
//! ```ignore
//! trait AnyPin
//! where
//! Self: From>,
//! Self: Into>,
//! Self: AsRef>,
//! Self: AsMut>,
//! {
//! type Id: PinId;
//! type Mode: PinMode;
//! }
//! ```
//!
//! Now we've given the compiler some useful information. When a type implements
//! `AnyPin`, it can be converted from and into instances of `Pin`. And
//! references to types that implement `AnyPin` can be converted into references
//! to `Pin`s.
//!
//! ```ignore
//! fn example(mut any_pin: P) {
//! // None of the type annotations here are necessary
//! // Everything can be inferred
//! // Remember that SpecificPin is Pin
//! let pin_mut: &mut SpecificPin = any_pin.as_mut();
//! let pin_ref: &SpecificPin
= any_pin.as_ref();
//! let pin: SpecificPin
= any_pin.into();
//! }
//! ```
//!
//! Finally, to simplify this pattern, we can gather all of the super trait
//! bounds into a single, reusable trait.
//!
//! ```ignore
//! trait Is
//! where
//! Self: From>,
//! Self: Into>,
//! Self: AsRef>,
//! Self: AsMut>,
//! {
//! type Type;
//! }
//!
//! type IsType = ::Type;
//!
//! impl + AsMut> Is for T {
//! type Type = T;
//! }
//! ```
//!
//! And we can rewrite our `AnyPin` trait as
//!
//! ```ignore
//! trait AnyPin: Is> {
//! type Id: PinId;
//! type Mode: PinMode;
//! }
//! ```
//!
//! ## Using an `AnyKind` trait
//!
//! If a type takes multiple type parameters, storing it within a container
//! requires repeating all of the corresponding type parameters. For instance,
//! imagine a container that stores two completely generic `Pin` types.
//!
//! ```ignore
//! struct TwoPins
//! where
//! I1: PinId,
//! I2: PinId,
//! M1: PinMode,
//! M2: PinMode,
//! {
//! pin1: Pin,
//! pin2: Pin,
//! }
//! ```
//!
//! This struct has already ballooned to four type parameters, without even
//! doing much useful work. Given its heavy use of type parameters, this
//! limitation can make type-level programming tedious, cumbersome and
//! error-prone.
//!
//! Instead, we can use the `AnyKind` trait pattern to encapsulate each `Pin`
//! with a single type parameter.
//!
//! ```ignore
//! struct TwoPins
//! where
//! P1: AnyPin,
//! P2: AnyPin,
//! {
//! pin1: P1,
//! pin2: P2,
//! }
//! ```
//!
//! The result is far more readable and generally more comprehensible. Moreover,
//! although we no longer have direct access to the `PinId` and `PinMode` type
//! parameters, we haven't actually lost any expressive power.
//!
//! In the first version of `TwoPins`, suppose we wanted to implement a method
//! for pins in `FloatingInput` mode while simultaneously restricting the
//! possible `PinId`s based on some type class. The result might look like
//! this.
//!
//! ```ignore
//! impl for TwoPins
//! where
//! I1: PinId + Class,
//! I2: PinId + Class,
//! {
//! fn method(&self) {
//! // ...
//! }
//! }
//! ```
//!
//! The same method could be expressed with the `AnyPin` approach like so
//!
//! ```ignore
//! impl for TwoPins
//! where
//! P1: AnyPin,
//! P2: AnyPin,
//! P1::Id: Class,
//! P2::Id: Class,
//! {
//! fn method(&self) {
//! // ...
//! }
//! }
//! ```
//!
//! This example demonstrates the simultaneous readability and expressive power
//! of the `AnyKind` pattern.
//!
//! However, remember that when working with a type `P` that implements
//! `AnyPin`, the compiler can only use what it knows about the `AnyPin` trait.
//! But all of the functionality for GPIO pins is defined on the `Pin` type. To
//! make use of a generic type `P` implementing `AnyPin`, you must first convert
//! it to its corresponding `SpecificPin` using [`Into`], [`AsRef`] or
//! [`AsMut`]. And, in some instances, you may also need to convert back to the
//! type `P`.
//!
//! Suppose you wanted to store a completely generic `Pin` within a struct.
//!
//! ```ignore
//! pub struct Example {
//! pin: P,
//! }
//! ```
//!
//! Next, suppose you want to create a method that would take the `Pin` out of
//! the struct, perform some operations in different `PinMode`s, and put it back
//! into the struct before returning. The `elided` method below shows such an
//! example. However, it can be a bit tricky to follow all of the type
//! conversions here. For clarity, the `expanded` method shows the same behavior
//! with each transformation given its proper type annotation.
//!
//! ```ignore
//! impl Example {
//! pub fn elided(mut self) -> Self {
//! let pin = self.pin.into();
//! let mut pin = pin.into_push_pull_output();
//! pin.set_high().ok();
//! let pin = pin.into_floating_input();
//! let _bit = pin.is_low().unwrap();
//! let pin = pin.into_mode();
//! self.pin = pin.into();
//! self
//! }
//! pub fn expanded(mut self) -> Self {
//! let pin: SpecificPin
= self.pin.into();
//! let mut pin: Pin = pin.into_push_pull_output();
//! pin.set_high().ok();
//! let pin: Pin = pin.into_floating_input();
//! let _bit = pin.is_low().unwrap();
//! let pin: SpecificPin = pin.into_mode::();
//! self.pin = pin.into();
//! self
//! }
//! }
//! ```
//!
//! Notice that it is not enough to simply put back the correct `SpecificPin`.
//! Even though the `SpecificPin` implements
//! `AnyPin` the compiler doesn't understand that
//! `SpecificPin == P` for all `P`. As far as the compiler is concerned,
//! there could be several different types that implement
//! `AnyPin`. Instead, the compiler requires that
//! you put back an instance of `P` exactly. The final use of [`Into`] is key
//! here. It transforms the `SpecificPin` back into `P` itself.
mod private {
/// Super trait used to mark traits with an exhaustive set of
/// implementations
pub trait Sealed {}
}
pub(crate) use private::Sealed;
/// Type-level version of the [None] variant
#[derive(Default)]
pub struct NoneT;
impl Sealed for NoneT {}
/// Marker trait for type identity
///
/// This trait is used as part of the [`AnyKind`] trait pattern. It represents
/// the concept of type identity, because all implementors have
/// `::Type == Self`. When used as a trait bound with a specific
/// type, it guarantees that the corresponding type parameter is exactly the
/// specific type. Stated differently, it guarantees that `T == Specific` in
/// the following example.
///
/// ```ignore
/// where T: Is
/// ```
///
/// Moreover, the super traits guarantee that any instance of or reference to a
/// type `T` can be converted into the `Specific` type.
///
/// ```ignore
/// fn example(mut any: T)
/// where
/// T: Is,
/// {
/// let specific_mut: &mut Specific = any.as_mut();
/// let specific_ref: &Specific = any.as_ref();
/// let specific: Specific = any.into();
/// }
/// ```
///
/// [`AnyKind`]: #anykind-trait-pattern
pub trait Is
where
Self: Sealed,
Self: From>,
Self: Into>,
Self: AsRef>,
Self: AsMut>,
{
#[allow(missing_docs)]
type Type;
}
/// Type alias for [`Is::Type`]
pub type IsType = ::Type;
impl Is for T
where
T: Sealed + AsRef + AsMut,
{
type Type = T;
}