Skip to main content

structural_typing/
presence.rs

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