mago_codex/ttype/template/
variance.rs1use mago_phpdoc_syntax::cst::TemplateTagValueVariance;
2use mago_phpdoc_syntax::cst::r#type::GenericParameterVariance;
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub enum Variance {
7 Invariant,
8 Covariant,
9 Contravariant,
10 Bivariant,
11}
12
13impl From<GenericParameterVariance<'_>> for Variance {
14 fn from(variance: GenericParameterVariance<'_>) -> Self {
15 match variance {
16 GenericParameterVariance::Covariant(_) => Variance::Covariant,
17 GenericParameterVariance::Contravariant(_) => Variance::Contravariant,
18 }
19 }
20}
21
22impl From<TemplateTagValueVariance> for Variance {
23 fn from(variance: TemplateTagValueVariance) -> Self {
24 match variance {
25 TemplateTagValueVariance::Invariant => Variance::Invariant,
26 TemplateTagValueVariance::Covariant => Variance::Covariant,
27 TemplateTagValueVariance::Contravariant => Variance::Contravariant,
28 }
29 }
30}
31
32impl Variance {
33 #[inline]
34 #[must_use]
35 pub const fn is_invariant(&self) -> bool {
36 matches!(self, Variance::Invariant)
37 }
38
39 #[inline]
40 #[must_use]
41 pub const fn is_covariant(&self) -> bool {
42 matches!(self, Variance::Covariant)
43 }
44
45 #[inline]
46 #[must_use]
47 pub const fn is_bivariant(&self) -> bool {
48 matches!(self, Variance::Bivariant)
49 }
50
51 #[inline]
52 #[must_use]
53 pub const fn flip(self) -> Self {
54 match self {
55 Variance::Covariant => Variance::Contravariant,
56 Variance::Contravariant => Variance::Covariant,
57 other => other,
58 }
59 }
60
61 #[inline]
62 #[must_use]
63 pub const fn is_readonly(&self) -> bool {
64 matches!(self, Variance::Covariant | Variance::Invariant)
65 }
66
67 #[inline]
68 #[must_use]
69 pub const fn project(self, polarity: Variance) -> Option<bool> {
70 let reads = matches!(self, Variance::Covariant | Variance::Invariant);
71 let writes = matches!(self, Variance::Contravariant | Variance::Invariant);
72
73 match polarity {
74 Variance::Contravariant => {
75 if writes {
76 Some(true)
77 } else {
78 None
79 }
80 }
81 _ => {
82 if reads {
83 Some(true)
84 } else {
85 Some(false)
86 }
87 }
88 }
89 }
90}
91
92impl std::fmt::Display for Variance {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 match self {
95 Variance::Invariant => write!(f, "invariant"),
96 Variance::Covariant => write!(f, "covariant"),
97 Variance::Contravariant => write!(f, "contravariant"),
98 Variance::Bivariant => write!(f, "*"),
99 }
100 }
101}