structural_typing/
presence.rs

1//! Type-level markers for field presence states.
2
3use core::marker::PhantomData;
4
5use crate::{access::Access, extract::{Extract, TryExtract}};
6
7/// Marker indicating a field is present with a concrete value.
8pub struct Present;
9/// Marker indicating a field may or may not be present (Option).
10pub struct Optional;
11/// Marker indicating a field is absent (`PhantomData`).
12pub struct Absent;
13
14/// Trait for type-level presence markers with associated container types.
15pub trait Presence {
16    /// Presence when combined with Option.
17    type OptionOrSelf: Presence;
18    /// Result of merging this presence with another.
19    type Or<Other: Presence>: Presence;
20    /// Container type (T, Option\<T>, or `PhantomData`\<T>).
21    type Output<T>: Access<T>
22        + Extract<PhantomData<T>, T>
23        + Extract<Option<T>, T>
24        + Extract<Self::Output<T>, T>
25        + TryExtract<Option<T>, T>;
26
27    /// Merge two values, preferring the first if present.
28    fn or<T, Other: Presence>(
29        self_: <Self as Presence>::Output<T>,
30        other: Other::Output<T>,
31    ) -> <<Self as Presence>::Or<Other> as Presence>::Output<T>;
32
33    /// Convert an Option into the appropriate presence state.
34    fn option_or_self<T>(
35        option: Option<T>,
36        self_: <Self as Presence>::Output<T>,
37    ) -> <<Self as Presence>::OptionOrSelf as Presence>::Output<T>;
38}
39
40/// Infers presence state from value type: `T` → Present, `Option<T>` → Optional, `PhantomData<T>` → Absent.
41pub trait InferPresence<T> {
42    /// The presence state corresponding to this value type.
43    type Presence: Presence<Output<T> = Self>;
44}
45
46impl<T> InferPresence<T> for T {
47    type Presence = Present;
48}
49
50impl<T> InferPresence<T> for Option<T> {
51    type Presence = Optional;
52}
53
54impl<T> InferPresence<T> for PhantomData<T> {
55    type Presence = Absent;
56}
57
58impl Presence for Present {
59    type OptionOrSelf = Present;
60    type Or<Other: Presence> = Present;
61    type Output<T> = T;
62
63    #[inline]
64    fn or<T, Other: Presence>(
65        self_: <Self as Presence>::Output<T>,
66        _other: Other::Output<T>,
67    ) -> <<Self as Presence>::Or<Other> as Presence>::Output<T> {
68        self_
69    }
70
71    #[inline]
72    fn option_or_self<T>(
73        option: Option<T>,
74        self_: <Self as Presence>::Output<T>,
75    ) -> <<Self as Presence>::OptionOrSelf as Presence>::Output<T> {
76        option.unwrap_or(self_)
77    }
78}
79
80impl Presence for Optional {
81    type OptionOrSelf = Optional;
82    type Or<Other: Presence> = Other::OptionOrSelf;
83    type Output<T> = Option<T>;
84
85    #[inline]
86    fn or<T, Other: Presence>(
87        self_: <Self as Presence>::Output<T>,
88        other: Other::Output<T>,
89    ) -> <<Self as Presence>::Or<Other> as Presence>::Output<T> {
90        Other::option_or_self(self_, other)
91    }
92
93    #[inline]
94    fn option_or_self<T>(
95        option: Option<T>,
96        self_: <Self as Presence>::Output<T>,
97    ) -> <<Self as Presence>::OptionOrSelf as Presence>::Output<T> {
98        option.or(self_)
99    }
100}
101
102impl Presence for Absent {
103    type OptionOrSelf = Optional;
104    type Or<Other: Presence> = Other;
105    type Output<T> = PhantomData<T>;
106
107    #[inline]
108    fn or<T, Other: Presence>(
109        _self: <Self as Presence>::Output<T>,
110        other: Other::Output<T>,
111    ) -> <<Self as Presence>::Or<Other> as Presence>::Output<T> {
112        other
113    }
114
115    #[inline]
116    fn option_or_self<T>(
117        option: Option<T>,
118        _self_: <Self as Presence>::Output<T>,
119    ) -> <<Self as Presence>::OptionOrSelf as Presence>::Output<T> {
120        option
121    }
122}