Skip to main content

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}