Skip to main content

nu_protocol/
one_of.rs

1use std::fmt::Display;
2
3use crate::{CompareTypes, Type, TypeRelation, TypeSet};
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, Hash, Ord, PartialOrd)]
7#[serde(transparent)]
8pub struct OneOf {
9    items: Box<[Type]>,
10}
11
12impl OneOf {
13    pub fn add_ty(self, ty: Type) -> Self {
14        let OneOf { items } = self;
15        let mut items = items.into_vec();
16        Self::add_ty_inner(&mut items, ty);
17        Self {
18            items: items.into(),
19        }
20    }
21
22    pub fn iter(&self) -> impl Iterator<Item = &Type> + Clone {
23        self.into_iter()
24    }
25
26    fn add_ty_inner(this: &mut Vec<Type>, mut ty: Type) {
27        // handle nested unions first
28        if let Type::OneOf(inner) = ty {
29            for sub_t in inner.items {
30                Self::add_ty_inner(this, sub_t);
31            }
32            return;
33        }
34
35        for this_ty in this.iter_mut() {
36            let one = std::mem::replace(this_ty, Type::Any);
37            match Type::flat_widen(one, ty) {
38                Ok(new_wide) => {
39                    *this_ty = new_wide;
40                    return;
41                }
42                Err((old_one, old_ty)) => {
43                    *this_ty = old_one;
44                    ty = old_ty;
45                }
46            }
47        }
48
49        this.push(ty);
50    }
51
52    pub fn is_empty(&self) -> bool {
53        self.items.is_empty()
54    }
55}
56
57impl IntoIterator for OneOf {
58    type Item = Type;
59    type IntoIter = std::vec::IntoIter<Type>;
60
61    fn into_iter(self) -> Self::IntoIter {
62        self.items.into_iter()
63    }
64}
65
66impl<'a> IntoIterator for &'a OneOf {
67    type Item = &'a Type;
68    type IntoIter = std::slice::Iter<'a, Type>;
69
70    fn into_iter(self) -> Self::IntoIter {
71        self.items.iter()
72    }
73}
74
75impl FromIterator<Type> for OneOf {
76    fn from_iter<I: IntoIterator<Item = Type>>(iter: I) -> Self {
77        let mut vec = Vec::new();
78        for ty in iter {
79            Self::add_ty_inner(&mut vec, ty);
80        }
81        Self { items: vec.into() }
82    }
83}
84
85impl TypeSet for OneOf {
86    fn union(self, other: Self) -> Self {
87        let OneOf { items: ts } = self;
88        let OneOf { items: us } = other;
89        let (big, small) = match ts.len() >= us.len() {
90            true => (ts, us),
91            false => (us, ts),
92        };
93        let mut out = big.into_vec();
94        for t in small {
95            Self::add_ty_inner(&mut out, t);
96        }
97        Self { items: out.into() }
98    }
99}
100
101impl CompareTypes for OneOf {
102    fn compare_types(&self, other: &Self) -> Option<TypeRelation> {
103        Some(match (self.is_empty(), other.is_empty()) {
104            (true, true) => TypeRelation::Equal,
105            (true, false) => TypeRelation::Subtype,
106            (false, true) => TypeRelation::Supertype,
107            (false, false) => match (self.is_subtype_of(other), self.is_supertype_of(other)) {
108                (true, true) => TypeRelation::Equal,
109                (true, false) => TypeRelation::Subtype,
110                (false, true) => TypeRelation::Supertype,
111                (false, false) => return None,
112            },
113        })
114    }
115
116    fn is_subtype_of(&self, other: &Self) -> bool {
117        match (self.is_empty(), other.is_empty()) {
118            (true, _) => true,
119            (_, true) => false,
120            _ => self.iter().all(|ty| ty.is_subtype_of(other)),
121        }
122    }
123
124    fn is_supertype_of(&self, other: &Self) -> bool {
125        other.is_subtype_of(self)
126    }
127
128    fn is_assignable_to(&self, dst: &Self) -> bool {
129        let dst_tys = dst;
130        let src_tys = self;
131        match (dst_tys.is_empty(), src_tys.is_empty()) {
132            (_, true) => true,
133            (true, _) => false,
134            _ => src_tys
135                .iter()
136                .any(|src_ty| dst_tys.iter().any(|dst_ty| src_ty.is_assignable_to(dst_ty))),
137        }
138    }
139}
140
141impl CompareTypes<Type> for OneOf {
142    fn compare_types(&self, other: &Type) -> Option<TypeRelation> {
143        Some(match other {
144            Type::OneOf(other) => return self.compare_types(other),
145            Type::Any => TypeRelation::Subtype,
146            // `oneof<>` is an uninhibited type, so it's kind of like our bottom type
147            _ if self.is_empty() => TypeRelation::Subtype,
148            _ => match (self.is_subtype_of(other), self.is_supertype_of(other)) {
149                (true, true) => TypeRelation::Equal,
150                (true, false) => TypeRelation::Subtype,
151                (false, true) => TypeRelation::Supertype,
152                (false, false) => return None,
153            },
154        })
155    }
156
157    fn is_subtype_of(&self, other: &Type) -> bool {
158        let sub_tys = self;
159        let super_ty = other;
160        sub_tys.iter().all(|sub_ty| sub_ty.is_subtype_of(super_ty))
161    }
162
163    fn is_supertype_of(&self, other: &Type) -> bool {
164        let super_tys = self;
165        let sub_ty = other;
166        super_tys
167            .iter()
168            .any(|super_ty| super_ty.is_supertype_of(sub_ty))
169    }
170
171    fn is_assignable_to(&self, dst: &Type) -> bool {
172        let src = self;
173
174        if src.is_empty() {
175            true
176        } else {
177            src.iter().any(|src_ty| src_ty.is_assignable_to(dst))
178        }
179    }
180}
181
182impl CompareTypes<OneOf> for Type {
183    fn compare_types(&self, other: &OneOf) -> Option<TypeRelation> {
184        Some(
185            match (self.is_subtype_of(other), self.is_supertype_of(other)) {
186                (true, true) => TypeRelation::Equal,
187                (true, false) => TypeRelation::Subtype,
188                (false, true) => TypeRelation::Supertype,
189                (false, false) => return None,
190            },
191        )
192    }
193
194    fn is_subtype_of(&self, other: &OneOf) -> bool {
195        other.is_supertype_of(self)
196    }
197
198    fn is_supertype_of(&self, other: &OneOf) -> bool {
199        other.is_subtype_of(self)
200    }
201
202    fn is_assignable_to(&self, dst: &OneOf) -> bool {
203        let src = self;
204        dst.iter().any(|dst_ty| src.is_assignable_to(dst_ty))
205    }
206}
207
208impl Display for OneOf {
209    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210        let types = self.items.as_ref();
211        write!(f, "oneof")?;
212        let [first, rest @ ..] = types else {
213            return Ok(());
214        };
215        write!(f, "<{first}")?;
216        for t in rest {
217            write!(f, ", {t}")?;
218        }
219        f.write_str(">")
220    }
221}