morphix/helper/deref.rs
1//! Traits for recursive dereferencing with type-level natural numbers.
2//!
3//! This module provides two pairs of traits for expressing "can be dereferenced N times":
4//! - [`AsDeref`] / [`AsDerefMut`]: Inductive version
5//! - [`AsDerefCoinductive`] / [`AsDerefMutCoinductive`]: Coinductive version
6//!
7//! ## Inductive vs. Coinductive
8//!
9//! The key difference lies in their induction direction:
10//!
11//! - **Inductive**: If `T` can be dereferenced `N` times to reach a type that implements [`Deref`],
12//! then `T` can be dereferenced `N + 1` times.
13//! - **Coinductive**: If `T` implements [`Deref`] to reach a type that can be dereferenced `N`
14//! times, then `T` can be dereferenced `N + 1` times.
15//!
16//! While these definitions are mathematically equivalent, Rust's type system cannot simply
17//! recognize this equivalence. Implementing both patterns would cause conflicts, so we provide
18//! separate traits. Choose the appropriate trait based on your actual induction direction in the
19//! code.
20//!
21//! ## Type-level Natural Numbers
22//!
23//! These traits use [`Zero`] and [`Succ`] to represent the depth of dereferencing at the type
24//! level, enabling compile-time verification of dereference chains.
25
26use std::ops::{Deref, DerefMut};
27
28use crate::helper::unsigned::{Succ, Unsigned, Zero};
29
30/// Trait for types that can be dereferenced `N` times (inductive version).
31///
32/// See the [module documentation](self) for details about inductive vs. coinductive.
33pub trait AsDeref<N: Unsigned> {
34 /// The target type after `N` dereferences.
35 type Target: ?Sized;
36
37 /// Dereferences self `N` times.
38 fn as_deref(&self) -> &Self::Target;
39}
40
41/// Trait for types that can be mutably dereferenced `N` times (inductive version).
42///
43/// See the [module documentation](self) for details about inductive vs. coinductive.
44pub trait AsDerefMut<N: Unsigned>: AsDeref<N> {
45 /// Mutably dereferences self `N` times.
46 fn as_deref_mut(&mut self) -> &mut Self::Target;
47}
48
49impl<T: ?Sized> AsDeref<Zero> for T {
50 type Target = T;
51
52 #[inline]
53 fn as_deref(&self) -> &T {
54 self
55 }
56}
57
58impl<T: ?Sized> AsDerefMut<Zero> for T {
59 #[inline]
60 fn as_deref_mut(&mut self) -> &mut T {
61 self
62 }
63}
64
65impl<T: AsDeref<N, Target: Deref> + ?Sized, N: Unsigned> AsDeref<Succ<N>> for T {
66 type Target = <T::Target as Deref>::Target;
67
68 #[inline]
69 fn as_deref(&self) -> &Self::Target {
70 self.as_deref().deref()
71 }
72}
73
74impl<T: AsDerefMut<N, Target: DerefMut> + ?Sized, N: Unsigned> AsDerefMut<Succ<N>> for T {
75 #[inline]
76 fn as_deref_mut(&mut self) -> &mut Self::Target {
77 self.as_deref_mut().deref_mut()
78 }
79}
80
81/// Trait for types that can be dereferenced `N` times (coinductive version).
82///
83/// See the [module documentation](self) for details about inductive vs. coinductive.
84pub trait AsDerefCoinductive<N: Unsigned> {
85 /// The target type after `N` dereferences.
86 type Target: ?Sized;
87
88 /// Dereferences self `N` times.
89 fn as_deref_coinductive(&self) -> &Self::Target;
90}
91
92/// Trait for types that can be mutably dereferenced `N` times (coinductive version).
93///
94/// See the [module documentation](self) for details about inductive vs. coinductive.
95pub trait AsDerefMutCoinductive<N: Unsigned>: AsDerefCoinductive<N> {
96 /// Mutably dereferences self `N` times.
97 fn as_deref_mut_coinductive(&mut self) -> &mut Self::Target;
98}
99
100impl<T: ?Sized> AsDerefCoinductive<Zero> for T {
101 type Target = T;
102
103 #[inline]
104 fn as_deref_coinductive(&self) -> &T {
105 self
106 }
107}
108
109impl<T: ?Sized> AsDerefMutCoinductive<Zero> for T {
110 #[inline]
111 fn as_deref_mut_coinductive(&mut self) -> &mut T {
112 self
113 }
114}
115
116impl<T: Deref<Target: AsDerefCoinductive<N>> + ?Sized, N: Unsigned> AsDerefCoinductive<Succ<N>> for T {
117 type Target = <T::Target as AsDerefCoinductive<N>>::Target;
118
119 #[inline]
120 fn as_deref_coinductive(&self) -> &Self::Target {
121 self.deref().as_deref_coinductive()
122 }
123}
124
125impl<T: DerefMut<Target: AsDerefMutCoinductive<N>> + ?Sized, N: Unsigned> AsDerefMutCoinductive<Succ<N>> for T {
126 #[inline]
127 fn as_deref_mut_coinductive(&mut self) -> &mut Self::Target {
128 self.deref_mut().as_deref_mut_coinductive()
129 }
130}