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    fn as_deref(&self) -> &T {
53        self
54    }
55}
56
57impl<T: ?Sized> AsDerefMut<Zero> for T {
58    fn as_deref_mut(&mut self) -> &mut T {
59        self
60    }
61}
62
63impl<T: AsDeref<N, Target: Deref> + ?Sized, N: Unsigned> AsDeref<Succ<N>> for T {
64    type Target = <T::Target as Deref>::Target;
65
66    fn as_deref(&self) -> &Self::Target {
67        self.as_deref().deref()
68    }
69}
70
71impl<T: AsDerefMut<N, Target: DerefMut> + ?Sized, N: Unsigned> AsDerefMut<Succ<N>> for T {
72    fn as_deref_mut(&mut self) -> &mut Self::Target {
73        self.as_deref_mut().deref_mut()
74    }
75}
76
77/// Trait for types that can be dereferenced `N` times (coinductive version).
78///
79/// See the [module documentation](self) for details about inductive vs. coinductive.
80pub trait AsDerefCoinductive<N: Unsigned> {
81    /// The target type after `N` dereferences.
82    type Target: ?Sized;
83
84    /// Dereferences self `N` times.
85    fn as_deref_coinductive(&self) -> &Self::Target;
86}
87
88/// Trait for types that can be mutably dereferenced `N` times (coinductive version).
89///
90/// See the [module documentation](self) for details about inductive vs. coinductive.
91pub trait AsDerefMutCoinductive<N: Unsigned>: AsDerefCoinductive<N> {
92    /// Mutably dereferences self `N` times.
93    fn as_deref_mut_coinductive(&mut self) -> &mut Self::Target;
94}
95
96impl<T: ?Sized> AsDerefCoinductive<Zero> for T {
97    type Target = T;
98
99    fn as_deref_coinductive(&self) -> &T {
100        self
101    }
102}
103
104impl<T: ?Sized> AsDerefMutCoinductive<Zero> for T {
105    fn as_deref_mut_coinductive(&mut self) -> &mut T {
106        self
107    }
108}
109
110impl<T: Deref<Target: AsDerefCoinductive<N>> + ?Sized, N: Unsigned> AsDerefCoinductive<Succ<N>> for T {
111    type Target = <T::Target as AsDerefCoinductive<N>>::Target;
112
113    fn as_deref_coinductive(&self) -> &Self::Target {
114        self.deref().as_deref_coinductive()
115    }
116}
117
118impl<T: DerefMut<Target: AsDerefMutCoinductive<N>> + ?Sized, N: Unsigned> AsDerefMutCoinductive<Succ<N>> for T {
119    fn as_deref_mut_coinductive(&mut self) -> &mut Self::Target {
120        self.deref_mut().as_deref_mut_coinductive()
121    }
122}