1use std::any::Any;
2use std::fmt::Display;
3use std::str::FromStr;
4use std::sync::Arc;
5
6use itertools::Itertools;
7use vortex_array::{Array, ArrayRef};
8use vortex_dtype::{DType, FieldPathSet};
9use vortex_error::{VortexError, VortexResult, vortex_bail, vortex_err};
10use vortex_utils::aliases::hash_map::HashMap;
11
12type ExprScope<T> = HashMap<Identifier, T>;
13
14#[derive(Clone, Debug, Eq, PartialEq, Hash)]
15pub enum Identifier {
16 Identity,
17 Other(Arc<str>),
18}
19
20impl FromStr for Identifier {
21 type Err = VortexError;
22
23 fn from_str(s: &str) -> Result<Self, Self::Err> {
24 if s.is_empty() {
25 vortex_bail!("Empty strings aren't allowed in identifiers")
26 } else {
27 Ok(Identifier::Other(s.into()))
28 }
29 }
30}
31
32impl PartialEq<str> for Identifier {
33 fn eq(&self, other: &str) -> bool {
34 match self {
35 Identifier::Identity => other.is_empty(),
36 Identifier::Other(str) => str.as_ref() == other,
37 }
38 }
39}
40
41impl From<&str> for Identifier {
42 fn from(value: &str) -> Self {
43 if value.is_empty() {
44 Identifier::Identity
45 } else {
46 Identifier::Other(Arc::from(value))
47 }
48 }
49}
50
51impl Identifier {
52 pub fn is_identity(&self) -> bool {
53 matches!(self, Self::Identity)
54 }
55}
56
57impl Display for Identifier {
58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 match self {
60 Identifier::Identity => write!(f, ""),
61 Identifier::Other(v) => write!(f, "{v}"),
62 }
63 }
64}
65
66#[derive(Clone, Default)]
83pub struct Scope {
84 array_len: usize,
85 root_scope: Option<ArrayRef>,
86 arrays: ExprScope<ArrayRef>,
88 vars: ExprScope<Arc<dyn Any + Send + Sync>>,
91}
92
93pub type ScopeElement = (Identifier, ArrayRef);
94
95impl Scope {
96 pub fn new(arr: ArrayRef) -> Self {
97 Self {
98 array_len: arr.len(),
99 root_scope: Some(arr),
100 ..Default::default()
101 }
102 }
103
104 pub fn empty(len: usize) -> Self {
105 Self {
106 array_len: len,
107 ..Default::default()
108 }
109 }
110
111 pub fn array(&self, id: &Identifier) -> Option<&ArrayRef> {
113 if id.is_identity() {
114 return self.root_scope.as_ref();
115 }
116 self.arrays.get(id)
117 }
118
119 pub fn vars(&self, id: Identifier) -> VortexResult<&Arc<dyn Any + Send + Sync>> {
120 self.vars
121 .get(&id)
122 .ok_or_else(|| vortex_err!("cannot find {} in var scope", id))
123 }
124
125 pub fn is_empty(&self) -> bool {
126 self.array_len == 0
127 }
128
129 pub fn len(&self) -> usize {
130 self.array_len
131 }
132
133 pub fn copy_with_array(&self, ident: Identifier, value: ArrayRef) -> Self {
134 self.clone().with_array(ident, value)
135 }
136
137 pub fn with_array(mut self, ident: Identifier, value: ArrayRef) -> Self {
139 assert_eq!(value.len(), self.len());
140
141 if ident.is_identity() {
142 self.root_scope = Some(value);
143 } else {
144 self.arrays.insert(ident, value);
145 }
146 self
147 }
148
149 pub fn with_array_pair(self, (ident, value): ScopeElement) -> Self {
151 self.with_array(ident, value)
152 }
153
154 pub fn with_var(mut self, ident: Identifier, var: Arc<dyn Any + Send + Sync>) -> Self {
155 self.vars.insert(ident, var);
156 self
157 }
158
159 pub fn iter(&self) -> impl Iterator<Item = (&Identifier, &ArrayRef)> {
160 let values = self.arrays.iter();
161
162 self.root_scope
163 .iter()
164 .map(|s| (&Identifier::Identity, s))
165 .chain(values)
166 }
167}
168
169impl From<ArrayRef> for Scope {
170 fn from(value: ArrayRef) -> Self {
171 Self::new(value)
172 }
173}
174
175#[derive(Clone, Default, Debug)]
176pub struct ScopeDType {
177 root: Option<DType>,
178 types: ExprScope<DType>,
179}
180
181impl Display for ScopeDType {
182 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183 if let Some(root) = self.root.as_ref() {
184 write!(f, "$: {}", root)?;
185 }
186 if !self.types.is_empty() {
187 write!(f, ". ")?;
188 write!(
189 f,
190 "{}",
191 self.types
192 .iter()
193 .format_with(",", |x, f| f(&format_args!("{}: {}", x.0, x.1)))
194 )?;
195 }
196 Ok(())
197 }
198}
199
200pub type ScopeDTypeElement = (Identifier, DType);
201
202impl From<&Scope> for ScopeDType {
203 fn from(ctx: &Scope) -> Self {
204 Self {
205 root: ctx.root_scope.as_ref().map(|s| s.dtype().clone()),
206 types: HashMap::from_iter(
207 ctx.arrays
208 .iter()
209 .map(|(k, v)| (k.clone(), v.dtype().clone())),
210 ),
211 }
212 }
213}
214
215impl ScopeDType {
216 pub fn new(dtype: DType) -> Self {
217 Self {
218 root: Some(dtype),
219 ..Default::default()
220 }
221 }
222
223 pub fn dtype(&self, id: &Identifier) -> Option<&DType> {
224 if id.is_identity() {
225 return self.root.as_ref();
226 }
227 self.types.get(id)
228 }
229
230 pub fn copy_with_dtype(&self, ident: Identifier, dtype: DType) -> Self {
231 self.clone().with_dtype(ident, dtype)
232 }
233
234 pub fn with_dtype(mut self, ident: Identifier, dtype: DType) -> Self {
235 if ident.is_identity() {
236 self.root = Some(dtype);
237 } else {
238 self.types.insert(ident, dtype);
239 }
240 self
241 }
242
243 pub fn with_dtype_element(self, (ident, dtype): ScopeDTypeElement) -> Self {
244 self.with_dtype(ident, dtype)
245 }
246}
247
248#[derive(Default, Clone, Debug)]
249pub struct ScopeFieldPathSet {
250 root: Option<FieldPathSet>,
251 sets: ExprScope<FieldPathSet>,
252}
253
254pub type ScopeFieldPathSetElement = (Identifier, FieldPathSet);
255
256impl ScopeFieldPathSet {
257 pub fn new(path_set: FieldPathSet) -> Self {
258 Self {
259 root: Some(path_set),
260 ..Default::default()
261 }
262 }
263
264 pub fn set(&self, id: &Identifier) -> Option<&FieldPathSet> {
265 if id.is_identity() {
266 return self.root.as_ref();
267 }
268 self.sets.get(id)
269 }
270
271 pub fn copy_with_set(&self, ident: Identifier, set: FieldPathSet) -> Self {
272 self.clone().with_set(ident, set)
273 }
274
275 pub fn with_set(mut self, ident: Identifier, set: FieldPathSet) -> Self {
276 if ident.is_identity() {
277 self.root = Some(set);
278 } else {
279 self.sets.insert(ident, set);
280 }
281 self
282 }
283
284 pub fn with_set_element(self, (ident, set): ScopeFieldPathSetElement) -> Self {
285 self.with_set(ident, set)
286 }
287}