atsamd_hal/typelevel.rs
1//! Module supporting type-level programming
2//!
3//! # Introduction
4//!
5//! Embedded software is often difficult to debug, so there is a strong
6//! motivation to catch as many bugs as possible at compile-time. However, the
7//! performance requirements of embedded software also make it difficult to
8//! justify changes that impose additional overhead in terms of size or speed.
9//! Ideally, we would like to add as many compile-time checks as possible, while
10//! also producing the fewest possible assembly instructions.
11//!
12//! The Rust type system can help accomplish this goal. By expressing software
13//! constraints within the type system, developers can enforce invariants at
14//! compile-time.
15//!
16//! Sometimes this is done using Rust macros. However, that approach can produce
17//! code that is difficult to read and understand. Moreover, macro-generated
18//! code can only be extended by *more* macros, which further spreads the
19//! problem. In `atsamd-hal` specifically, issue
20//! [#214](https://github.com/atsamd-rs/atsamd/issues/214) discussed the extent
21//! to which macros were once used in the repository.
22//!
23//! Alternatively, many of the same goals can be accomplished with the Rust
24//! type & trait system directly, which is quite powerful. In fact, it is
25//! [turing complete](https://sdleffler.github.io/RustTypeSystemTuringComplete/).
26//! By expressing our invariants entirely within the type system, we can encode
27//! the desired compile-time checks in a form that is easier to read, understand
28//! and document.
29//!
30//! This module documents some of the type-level programming techniques used
31//! throughout this HAL, and it contains a few items used to implement them.
32//!
33//! ## Contents
34//!
35//! - [Basics of type-level programming](#basics-of-type-level-programming)
36//! - [Type-level enums](#type-level-enums)
37//! - [Type classes](#type-classes)
38//! - [Type-level containers](#type-level-containers)
39//! - [Type-level functions](#type-level-functions)
40//! - [`OptionalKind` trait pattern](#optionalkind-trait-pattern)
41//! - [`AnyKind` trait pattern](#anykind-trait-pattern)
42//! - [Defining an `AnyKind` trait](#defining-an-anykind-trait)
43//! - [Using an `AnyKind` trait](#using-an-anykind-trait)
44//!
45//! # Basics of type-level programming
46//!
47//! Type-level programming aims to execute a form of compile-time computation.
48//! But to perform such computation, we need to map our traditional notions of
49//! programming to the Rust type system.
50//!
51//! In normal Rust, individual values are grouped or categorized into types. For
52//! example, `0`, `1`, `2`, etc. are all members of the `usize` type. Similarly,
53//! `Enum::A` and `Enum::B` are members of the `Enum` type, defined as
54//!
55//! ```
56//! enum Enum { A, B }
57//! ```
58//!
59//! We use composite types and containers to create more complex data
60//! structures, and we use functions to map between values.
61//!
62//! All of these concepts can also be expressed within the Rust type system.
63//! However, in this case, types are grouped and categorized into traits. For
64//! instance, the [`typenum`](https://docs.rs/typenum/1.13.0/typenum/index.html)
65//! crate provides the types `U0`, `U1`, `U2`, etc., which are all members of
66//! the `Unsigned` trait. Similarly, the following sections will illustrate how
67//! to define type-level enums, containers and functions.
68//!
69//! ## Type-level enums
70//!
71//! Type-level enums are one of the foundational concepts of type-level
72//! programming used in this HAL.
73//!
74//! At the value-level, a typical Rust enum represents some set of variants that
75//! can be assigned to a particular variable. Similarly, a type-level enum
76//! represents some set of types that can be assigned to a particular type
77//! parameter.
78//!
79//! To lift an enum from the value level to the type level, you typically map
80//! the enum variants to types and the enum itself to a trait. For instance, the
81//! value-level enum
82//!
83//! ```
84//! enum Enum {
85//! A,
86//! B,
87//! }
88//! ```
89//!
90//! would be mapped to the type level like so.
91//!
92//! ```
93//! trait Enum {}
94//!
95//! enum A {}
96//! enum B {}
97//!
98//! impl Enum for A {}
99//! impl Enum for B {}
100//! ```
101//!
102//! At the value level, the variants `A` and `B` are grouped by the `Enum` type,
103//! while at the type level, the types `A` and `B` are grouped by the `Enum`
104//! trait.
105//!
106//! ## Type classes
107//!
108//! At the value-level, a type restricts the possible values that can be taken
109//! by some free variable. While at the type-level, a trait bound restricts the
110//! possible types that can be taken by some free type parameter. In effect,
111//! trait bounds can be used to create a kind of meta-type, or type class. The
112//! type-level enums in the previous section represent the most primitive
113//! application of the concept, but type classes can take other forms. The
114//! `OptionalKind` and `AnyKind` trait patterns discussed below are more
115//! advanced applications of the same concept.
116//!
117//! ## Type-level containers
118//!
119//! To represent more complex relationships, we need a way to form composite
120//! data structures at the type level.
121//!
122//! At the value level, a container holds an instance of a particular type. The
123//! exact value of that instance is usually not known to the author, it is only
124//! known at run-time.
125//!
126//! At the type level, we don't have the same notion of "run-time", but we do
127//! have two different notions of "compile-time" that form a similar
128//! relationship. There is compile time for the HAL authors, and there is a
129//! separate compile-time for the HAL users. We want to create a type-level
130//! container where the exact type is not known at author-time, but it is known
131//! at user-time.
132//!
133//! For example, take the following, value-level container struct. It contains
134//! two fields, `a` and `b`, of different types, `EnumOne` and `EnumTwo`.
135//!
136//! ```
137//! struct Container {
138//! a: EnumOne,
139//! b: EnumTwo,
140//! }
141//! ```
142//!
143//! We can create an instance of this container with specific values.
144//!
145//! ```
146//! let x = Container { a: EnumOne::VariantX, b: EnumTwo::VariantY };
147//! ```
148//!
149//! Next, suppose we had already translated `EnumOne` and `EnumTwo` to the type
150//! level using the technique in the previous section. If we wanted to create a
151//! similar, composite data structure at the type level, we could use type
152//! parameters in place of struct fields to represent the unknown types.
153//!
154//! ```
155//! struct Container<A, B>
156//! where
157//! A: EnumOne,
158//! B: EnumTwo,
159//! {
160//! a: PhantomData<A>,
161//! b: PhantomData<B>,
162//! }
163//! ```
164//!
165//! And we could create an instance of this container with specific types.
166//!
167//! ```
168//! type X = Container<VariantX, VariantY>;
169//! ```
170//!
171//! You might notice the use of `PhantomData` in the definition of the
172//! type-level container. Because it is geared more toward value-level
173//! programming, Rust requires all type parameters actually be used by the
174//! corresponding type. However, we don't need to "store" a type in the same way
175//! we store values. The compiler is responsible for tracking the concrete type
176//! for each type parameter. But the language still requires us to act as if we
177//! used each type parameter. `PhantomData` is the solution here, because it
178//! lets us make use of the type parameters without actually storing any values.
179//!
180//! Separately, `PhantomData` also allows us to create "instances" of types that
181//! normally can't be instantiated, like empty enums. For example, instances of
182//! `Enum` below can never exist directly.
183//!
184//! ```
185//! enum Enum {}
186//! ```
187//!
188//! But instances of `PhantomData<Enum>` are perfectly valid. In this way,
189//! library authors can create types that only exist at the type level, which
190//! can sometimes simplify a design.
191//!
192//! ## Type-level functions
193//!
194//! To perform type-level computations, we need some way to map or transform
195//! types into other types.
196//!
197//! At the value level, functions and methods map values of the input types to
198//! values of the output types. The same can be accomplished at the type level
199//! using traits and associated types. Type-level functions are implemented as
200//! traits, where the implementing type and any type parameters are the inputs,
201//! and associated types are the outputs.
202//!
203//! For example, consider the value level `not` method below.
204//!
205//! ```
206//! enum Bool {
207//! False,
208//! True,
209//! }
210//!
211//! impl Bool {
212//! fn not(self) -> Self {
213//! use Bool::*;
214//! match self {
215//! True => False,
216//! False => True,
217//! }
218//! }
219//! }
220//! ```
221//!
222//! We can translate this example to the type level like so.
223//!
224//! ```
225//! trait Bool {}
226//!
227//! enum True {}
228//! enum False {}
229//!
230//! impl Bool for True {}
231//! impl Bool for False {}
232//!
233//! trait Not: Bool {
234//! type Result: Bool;
235//! }
236//!
237//! impl Not for True {
238//! type Result = False;
239//! }
240//!
241//! impl Not for False {
242//! type Result = True;
243//! }
244//! ```
245//!
246//! We can use the `Not` trait bound to transform one type to another. For
247//! instance, we can create a container that accepts one type parameter but
248//! stores a different one.
249//!
250//! ```
251//! struct Container<B: Not> {
252//! not: PhantomData<B::Result>;
253//! }
254//! ```
255//!
256//! Alternatively, we could redefine the trait and declar a corresponding type
257//! alias as
258//!
259//! ```
260//! trait NotFunction: Bool {
261//! type Result: Bool;
262//! }
263//!
264//! type Not<B> = <B as NotFunction>::Result;
265//! ```
266//!
267//! Doing so would allow us to us reframe the last example as
268//!
269//! ```
270//! struct Container<B: NotFunction> {
271//! not: PhantomData<Not<B>>;
272//! }
273//! ```
274//!
275//! Type-level functions can be more complicated than this example, but they
276//! ultimately represent a mapping from a set of input types (the implementing
277//! type and any type parameters) to a set of output types (the associated
278//! types).
279//!
280//! # `OptionalKind` trait pattern
281//!
282//! As mentioned above, traits can be used to define a kind of meta-type or type
283//! class, essentially forming a set of valid types for a given type parameter.
284//! They also represent the concept of types lifted from the value level to the
285//! type level.
286//!
287//! What if we want to define a type class representing either a set of useful
288//! types or some useless, null type? Essentially, how do we take the notion of
289//! an [`Option`] type and raise it to the type level?
290//!
291//! Suppose we have some existing type class, defined by the `Class` trait, that
292//! we want to make optional. We can define a new type class that includes all
293//! instances of `Class` as well as some null type. For the latter we use
294//! [`NoneT`], defined in this module.
295//!
296//! ```
297//! trait OptionalClass {}
298//!
299//! impl OptionalClass for NoneT {}
300//! impl<C: Class> OptionalClass for C {}
301//! ```
302//!
303//! We can use this new type class to store an optional instance of a `Class`
304//! type in a struct.
305//!
306//! ```
307//! struct Container<C: OptionalClass> {
308//! class: PhantomData<C>,
309//! }
310//! ```
311//!
312//! And we can restrict some of its methods to only operate on instances with a
313//! valid `Class`.
314//!
315//! ```
316//! impl<C: Class> Container<C> {
317//! fn method(self) { ... }
318//! }
319//! ```
320//!
321//! Although it is not strictly necessary, we can also introduce a new type
322//! class to differentiate the bare usage of `Class` from instances of some
323//! `Class` where an `OptionalClass` is accepted.
324//!
325//! ```
326//! trait SomeClass: OptionalClass + Class {}
327//!
328//! impl<C: Class> SomeClass for C {}
329//! ```
330//!
331//! This new trait doesn't add any new information, but it can still help
332//! readers understand that a particular type parameter is restricted to an
333//! instances of `Class` when an `OptionalClass` could be accepted.
334//!
335//! Note that when `Class` and `OptionalClass` contain associated types, name
336//! clashes may occur when using `SomeClass` as a trait bound. This can be
337//! avoided by removing the `OptionalClass` super trait from `SomeClass`.
338//! Ultimately, it is redundant anyway, because any implementer of `Class` also
339//! implements `OptionalClass`.
340//!
341//! # `AnyKind` trait pattern
342//!
343//! The `AnyKind` trait pattern allows you to encapsulate types with multiple
344//! type parameters and represent them with only a single type parameter. It
345//! lets you introduce a layer of abstraction, which can simplify interfaces and
346//! make them more readable. But most of all, it does so without sacrificing any
347//! of our normal, type-level abilities.
348//!
349//! ## Defining an `AnyKind` trait
350//!
351//! Suppose you had a composite, type-level data structure. For example, the
352//! GPIO `Pin` struct contains instances of two type-level enums, a `PinId` and
353//! a `PinMode`. It looks something like this.
354//!
355//! ```
356//! struct Pin<I: PinId, M: PinMode> {
357//! // ...
358//! }
359//! ```
360//!
361//! Rust does not provide any way to speak about a `Pin` generally. Any mention
362//! of the `Pin` type must also include its type parameters, i.e. `Pin<I, M>`.
363//! This is not a deal-breaker, but it is less than ideal for type-level
364//! programming. It would be nice if there were a way to succinctly refer to any
365//! `Pin`, regardless of its type parameters.
366//!
367//! We've seen above that we can use traits to form a type class. What if we
368//! were to introduce a new trait to label all instances of `Pin`? It would look
369//! something like this.
370//!
371//! ```
372//! trait AnyPin {}
373//!
374//! impl<I: PinId, M: PinMode> AnyPin for Pin<I, M> {}
375//! ```
376//!
377//! Now, instead of refering to `Pin<I, M>`, we can refer to instances of the
378//! `AnyPin` type class.
379//!
380//! ```
381//! fn example<P: AnyPin>(pin: P) { ... }
382//! ```
383//!
384//! Unfortunately, while this is more ergonomic, it is not very useful. As
385//! authors of the code, we know that `AnyPin` is only implemented for `Pin`
386//! types. But the compiler doesn't know that. Traits in Rust are open, so the
387//! compiler must consider that `AnyPin` could be implemented for other types.
388//!
389//! As a consequence, the compiler knows very little about the type `P` in the
390//! function above. In fact, because the `AnyPin` trait is completely empty, the
391//! compiler knows *absolutely nothing* about the type `P`.
392//!
393//! Is there a way to make the `AnyPin` trait more useful? We can see from the
394//! current implementation that we are throwing away information.
395//!
396//! ```
397//! impl<I: PinId, M: PinMode> AnyPin for Pin<I, M> {}
398//! ```
399//!
400//! The implementation of `AnyPin` is identical for every `Pin`, regardless of
401//! the type parameters `I` and `M`, which erases that information. Instead, we
402//! could choose to save that information in the form of associated types.
403//!
404//! Let's redesign the `AnyPin` trait to record the `PinId` and `PinMode`.
405//!
406//! ```
407//! trait AnyPin {
408//! type Id: PinId;
409//! type Mode: PinMode;
410//! }
411//!
412//! impl<I: PinId, M: PinMode> AnyPin for Pin<I, M> {
413//! type Id = I;
414//! type Mode = M;
415//! }
416//! ```
417//!
418//! This is better. When `P` implements `AnyPin`, we can at least recover the
419//! corresponding `PinId` and `PinMode` types. However, `AnyPin` still doesn't
420//! include any trait methods nor any super traits, so the compiler won't allow
421//! us to do anything useful with an instances of `P`.
422//!
423//! We need some way to tell the compiler that when `P` implements `AnyPin`,
424//! it is equivalent to saying `P` is exactly `Pin<P::Id, P::Mode>`.
425//! Essentially, we want to take a generic type parameter `P` and treat it as if
426//! it were an instance of a specific `Pin` type.
427//!
428//! We can start by defining a trait alias to recover the specific `Pin` type.
429//!
430//! ```
431//! type SpecificPin<P> = Pin<<P as AnyPin>::Id, <P as AnyPin>::Mode>;
432//! ```
433//!
434//! With this new definition, we can rephrase our statement above. We need some
435//! way to tell the compiler that when `P` implements `AnyPin`,
436//! `P == SpecificPin<P>`. There's no way to do that exactly, but we can come
437//! close with some useful trait bounds: [`From`], [`Into`], [`AsRef`] and
438//! [`AsMut`].
439//!
440//! ```
441//! trait AnyPin
442//! where
443//! Self: From<SpecificPin<Self>>,
444//! Self: Into<SpecificPin<Self>>,
445//! Self: AsRef<SpecificPin<Self>>,
446//! Self: AsMut<SpecificPin<Self>>,
447//! {
448//! type Id: PinId;
449//! type Mode: PinMode;
450//! }
451//! ```
452//!
453//! Now we've given the compiler some useful information. When a type implements
454//! `AnyPin`, it can be converted from and into instances of `Pin`. And
455//! references to types that implement `AnyPin` can be converted into references
456//! to `Pin`s.
457//!
458//! ```
459//! fn example<P: AnyPin>(mut any_pin: P) {
460//! // None of the type annotations here are necessary
461//! // Everything can be inferred
462//! // Remember that SpecificPin<P> is Pin<P::Id, P::Mode>
463//! let pin_mut: &mut SpecificPin<P> = any_pin.as_mut();
464//! let pin_ref: &SpecificPin<P> = any_pin.as_ref();
465//! let pin: SpecificPin<P> = any_pin.into();
466//! }
467//! ```
468//!
469//! Finally, to simplify this pattern, we can gather all of the super trait
470//! bounds into a single, reusable trait.
471//!
472//! ```
473//! trait Is
474//! where
475//! Self: From<IsType<Self>>,
476//! Self: Into<IsType<Self>>,
477//! Self: AsRef<IsType<Self>>,
478//! Self: AsMut<IsType<Self>>,
479//! {
480//! type Type;
481//! }
482//!
483//! type IsType<T> = <T as Is>::Type;
484//!
485//! impl<T: AsRef<T> + AsMut<T>> Is for T {
486//! type Type = T;
487//! }
488//! ```
489//!
490//! And we can rewrite our `AnyPin` trait as
491//!
492//! ```
493//! trait AnyPin: Is<Type = SpecificPin<Self>> {
494//! type Id: PinId;
495//! type Mode: PinMode;
496//! }
497//! ```
498//!
499//! ## Using an `AnyKind` trait
500//!
501//! If a type takes multiple type parameters, storing it within a container
502//! requires repeating all of the corresponding type parameters. For instance,
503//! imagine a container that stores two completely generic `Pin` types.
504//!
505//! ```
506//! struct TwoPins<I1, I2, M1, M2>
507//! where
508//! I1: PinId,
509//! I2: PinId,
510//! M1: PinMode,
511//! M2: PinMode,
512//! {
513//! pin1: Pin<I1, M1>,
514//! pin2: Pin<I2, M2>,
515//! }
516//! ```
517//!
518//! This struct has already ballooned to four type parameters, without even
519//! doing much useful work. Given its heavy use of type parameters, this
520//! limitation can make type-level programming tedious, cumbersome and
521//! error-prone.
522//!
523//! Instead, we can use the `AnyKind` trait pattern to encapsulate each `Pin`
524//! with a single type parameter.
525//!
526//! ```
527//! struct TwoPins<P1, P2>
528//! where
529//! P1: AnyPin,
530//! P2: AnyPin,
531//! {
532//! pin1: P1,
533//! pin2: P2,
534//! }
535//! ```
536//!
537//! The result is far more readable and generally more comprehensible. Moreover,
538//! although we no longer have direct access to the `PinId` and `PinMode` type
539//! parameters, we haven't actually lost any expressive power.
540//!
541//! In the first version of `TwoPins`, suppose we wanted to implement a method
542//! for pins in `FloatingInput` mode while simultaneously restricting the
543//! possible `PinId`s based on some type class. The result might look like
544//! this.
545//!
546//! ```
547//! impl<I1, I2> for TwoPins<I1, I2, FloatingInput, FloatingInput>
548//! where
549//! I1: PinId + Class,
550//! I2: PinId + Class,
551//! {
552//! fn method(&self) {
553//! // ...
554//! }
555//! }
556//! ```
557//!
558//! The same method could be expressed with the `AnyPin` approach like so
559//!
560//! ```
561//! impl<P1, P2> for TwoPins<P1, P2>
562//! where
563//! P1: AnyPin<Mode = FloatingInput>,
564//! P2: AnyPin<Mode = FloatingInput>,
565//! P1::Id: Class,
566//! P2::Id: Class,
567//! {
568//! fn method(&self) {
569//! // ...
570//! }
571//! }
572//! ```
573//!
574//! This example demonstrates the simultaneous readability and expressive power
575//! of the `AnyKind` pattern.
576//!
577//! However, remember that when working with a type `P` that implements
578//! `AnyPin`, the compiler can only use what it knows about the `AnyPin` trait.
579//! But all of the functionality for GPIO pins is defined on the `Pin` type. To
580//! make use of a generic type `P` implementing `AnyPin`, you must first convert
581//! it to its corresponding `SpecificPin` using [`Into`], [`AsRef`] or
582//! [`AsMut`]. And, in some instances, you may also need to convert back to the
583//! type `P`.
584//!
585//! Suppose you wanted to store a completely generic `Pin` within a struct.
586//!
587//! ```
588//! pub struct Example<P: AnyPin> {
589//! pin: P,
590//! }
591//! ```
592//!
593//! Next, suppose you want to create a method that would take the `Pin` out of
594//! the struct, perform some operations in different `PinMode`s, and put it back
595//! into the struct before returning. The `elided` method below shows such an
596//! example. However, it can be a bit tricky to follow all of the type
597//! conversions here. For clarity, the `expanded` method shows the same behavior
598//! with each transformation given its proper type annotation.
599//!
600//! ```
601//! impl<P: AnyPin> Example<P> {
602//! pub fn elided(mut self) -> Self {
603//! let pin = self.pin.into();
604//! let mut pin = pin.into_push_pull_output();
605//! pin.set_high().ok();
606//! let pin = pin.into_floating_input();
607//! let _bit = pin.is_low().unwrap();
608//! let pin = pin.into_mode();
609//! self.pin = pin.into();
610//! self
611//! }
612//! pub fn expanded(mut self) -> Self {
613//! let pin: SpecificPin<P> = self.pin.into();
614//! let mut pin: Pin<P::Id, PushPullOutput> = pin.into_push_pull_output();
615//! pin.set_high().ok();
616//! let pin: Pin<P::Id, FloatingInput> = pin.into_floating_input();
617//! let _bit = pin.is_low().unwrap();
618//! let pin: SpecificPin<P> = pin.into_mode::<P::Mode>();
619//! self.pin = pin.into();
620//! self
621//! }
622//! }
623//! ```
624//!
625//! Notice that it is not enough to simply put back the correct `SpecificPin`.
626//! Even though the `SpecificPin` implements
627//! `AnyPin<Id = P::Id, Mode = P::Mode>` the compiler doesn't understand that
628//! `SpecificPin<P> == P` for all `P`. As far as the compiler is concerned,
629//! there could be several different types that implement
630//! `AnyPin<Id = P::Id, Mode = P::Mode>`. Instead, the compiler requires that
631//! you put back an instance of `P` exactly. The final use of [`Into`] is key
632//! here. It transforms the `SpecificPin` back into `P` itself.
633
634use core::ops::{Add, Sub};
635
636use typenum::{Add1, Bit, Sub1, UInt, Unsigned, B1, U0};
637
638mod private {
639 /// Super trait used to mark traits with an exhaustive set of
640 /// implementations
641 pub trait Sealed {}
642
643 impl Sealed for u8 {}
644 impl Sealed for i8 {}
645 impl Sealed for u16 {}
646 impl Sealed for i16 {}
647 impl Sealed for u32 {}
648 impl Sealed for i32 {}
649 impl Sealed for f32 {}
650
651 /// Mapping from an instance of a countable type to its successor
652 pub trait Increment {
653 /// Successor type of `Self`
654 type Inc;
655 /// Consume an instance of `Self` and return its successor
656 fn inc(self) -> Self::Inc;
657 }
658
659 /// Mapping from an instance of a countable type to its predecessor
660 pub trait Decrement {
661 /// Predecessor type of `Self`
662 type Dec;
663 /// Consume an instance of `Self` and return its predecessor
664 fn dec(self) -> Self::Dec;
665 }
666}
667
668pub(crate) use private::Decrement as PrivateDecrement;
669pub(crate) use private::Increment as PrivateIncrement;
670pub(crate) use private::Sealed;
671
672/// Type-level version of the [`None`] variant
673#[derive(Default)]
674pub struct NoneT;
675
676impl Sealed for NoneT {}
677
678//==============================================================================
679// Is
680//==============================================================================
681
682/// Marker trait for type identity
683///
684/// This trait is used as part of the [`AnyKind`] trait pattern. It represents
685/// the concept of type identity, because all implementors have
686/// `<Self as Is>::Type == Self`. When used as a trait bound with a specific
687/// type, it guarantees that the corresponding type parameter is exactly the
688/// specific type. Stated differently, it guarantees that `T == Specific` in
689/// the following example.
690///
691/// ```
692/// where T: Is<Type = Specific>
693/// ```
694///
695/// Moreover, the super traits guarantee that any instance of or reference to a
696/// type `T` can be converted into the `Specific` type.
697///
698/// ```
699/// fn example<T>(mut any: T)
700/// where
701/// T: Is<Type = Specific>,
702/// {
703/// let specific_mut: &mut Specific = any.as_mut();
704/// let specific_ref: &Specific = any.as_ref();
705/// let specific: Specific = any.into();
706/// }
707/// ```
708///
709/// [`AnyKind`]: #anykind-trait-pattern
710pub trait Is
711where
712 Self: Sealed,
713 Self: From<IsType<Self>>,
714 Self: Into<IsType<Self>>,
715 Self: AsRef<IsType<Self>>,
716 Self: AsMut<IsType<Self>>,
717{
718 type Type;
719}
720
721/// Type alias for [`Is::Type`]
722pub type IsType<T> = <T as Is>::Type;
723
724impl<T> Is for T
725where
726 T: Sealed + AsRef<T> + AsMut<T>,
727{
728 type Type = T;
729}
730
731//==============================================================================
732// Counting
733//==============================================================================
734
735/// Implement `Sealed` for [`U0`]
736impl Sealed for U0 {}
737
738/// Implement `Sealed` for all type-level, [`Unsigned`] integers *except* [`U0`]
739impl<U: Unsigned, B: Bit> Sealed for UInt<U, B> {}
740
741/// Trait mapping each countable type to its successor
742///
743/// This trait maps each countable type to its corresponding successor type. The
744/// actual implementation of this trait is contained within `PrivateIncrement`.
745/// Access to `PrivateIncrement` is restricted, so that safe HAL APIs can be
746/// built with it.
747pub trait Increment: PrivateIncrement {}
748
749impl<T: PrivateIncrement> Increment for T {}
750
751/// Trait mapping each countable type to its predecessor
752///
753/// This trait maps each countable type to its corresponding predecessor type.
754/// The actual implementation of this trait is contained within
755/// `PrivateDecrement`. Access to `PrivateDecrement` is restricted, so that safe
756/// HAL APIs can be built with it.
757pub trait Decrement: PrivateDecrement {}
758
759impl<T: PrivateDecrement> Decrement for T {}
760
761impl<N> PrivateIncrement for N
762where
763 N: Unsigned + Add<B1>,
764 Add1<N>: Unsigned,
765{
766 type Inc = Add1<N>;
767 #[inline]
768 fn inc(self) -> Self::Inc {
769 Self::Inc::default()
770 }
771}
772
773impl<N> PrivateDecrement for N
774where
775 N: Unsigned + Sub<B1>,
776 Sub1<N>: Unsigned,
777{
778 type Dec = Sub1<N>;
779 #[inline]
780 fn dec(self) -> Self::Dec {
781 Self::Dec::default()
782 }
783}