risingwave_frontend/utils/
mod.rs1mod pretty_serde;
16pub use pretty_serde::PrettySerde;
17mod column_index_mapping;
18use std::any::Any;
19use std::hash::{Hash, Hasher};
20use std::sync::LazyLock;
21
22pub use column_index_mapping::*;
23mod condition;
24pub mod data_type;
25pub use condition::*;
26mod connected_components;
27pub(crate) use connected_components::*;
28mod stream_graph_formatter;
29pub use stream_graph_formatter::*;
30mod with_options;
31use tokio::runtime::Runtime;
32pub use with_options::*;
33mod rewrite_index;
34pub use rewrite_index::*;
35mod index_set;
36pub use index_set::*;
37pub(crate) mod group_by;
38pub mod overwrite_options;
39pub use group_by::*;
40pub use overwrite_options::*;
41mod iceberg_predicate;
42pub use iceberg_predicate::*;
43
44use crate::expr::{Expr, ExprImpl, ExprRewriter, InputRef};
45
46pub static FRONTEND_RUNTIME: LazyLock<Runtime> = LazyLock::new(|| {
47 tokio::runtime::Builder::new_multi_thread()
48 .thread_name("rw-frontend")
49 .enable_all()
50 .build()
51 .expect("failed to build frontend runtime")
52});
53
54pub struct Substitute {
56 pub mapping: Vec<ExprImpl>,
57}
58
59impl ExprRewriter for Substitute {
60 fn rewrite_input_ref(&mut self, input_ref: InputRef) -> ExprImpl {
61 assert!(
62 input_ref
63 .return_type()
64 .equals_datatype(&self.mapping[input_ref.index()].return_type()),
65 "Type mismatch when substituting {:?} of {:?} with {:?} of {:?}",
66 input_ref,
67 input_ref.return_type(),
68 self.mapping[input_ref.index()],
69 self.mapping[input_ref.index()].return_type()
70 );
71 self.mapping[input_ref.index()].clone()
72 }
73}
74
75pub trait Layer: Sized {
86 type Sub;
87
88 fn map<F>(self, f: F) -> Self
91 where
92 F: FnMut(Self::Sub) -> Self::Sub;
93
94 fn descent<F>(&self, f: F)
98 where
99 F: FnMut(&Self::Sub);
100}
101
102pub trait Tree = Layer<Sub = Self>;
104
105pub trait Endo<T: Tree> {
114 fn pre(&mut self, t: T) -> T {
115 t
116 }
117
118 fn post(&mut self, t: T) -> T {
119 t
120 }
121
122 fn apply(&mut self, t: T) -> T;
128
129 fn tree_apply(&mut self, t: T) -> T {
131 let t = self.pre(t).map(|s| self.apply(s));
132 self.post(t)
133 }
134}
135
136#[allow(unused_variables)]
139pub trait Visit<T: Tree> {
140 fn pre(&mut self, t: &T) {}
141
142 fn post(&mut self, t: &T) {}
143
144 fn visit(&mut self, t: &T);
145
146 fn tree_visit(&mut self, t: &T) {
147 self.pre(t);
148 t.descent(|i| self.visit(i));
149 self.post(t);
150 }
151}
152
153pub trait DynEq: Any {
159 fn as_any(&self) -> &dyn Any;
160 fn dyn_eq(&self, other: &dyn DynEq) -> bool;
161}
162
163impl<T: Any + Eq> DynEq for T {
164 fn as_any(&self) -> &dyn Any {
165 self
166 }
167
168 fn dyn_eq(&self, other: &dyn DynEq) -> bool {
169 let other = other.as_any().downcast_ref::<T>();
170 other.is_some_and(|other| self == other)
171 }
172}
173
174impl PartialEq<dyn DynEq + 'static> for dyn DynEq {
175 fn eq(&self, other: &Self) -> bool {
176 self.dyn_eq(other)
177 }
178}
179
180impl Eq for dyn DynEq {
181 fn assert_receiver_is_total_eq(&self) {}
182}
183
184pub trait DynHash: DynEq {
187 fn as_dyn_eq(&self) -> &dyn DynEq;
188 fn dyn_hash(&self, state: &mut dyn Hasher);
189}
190
191impl<T: DynEq + Hash> DynHash for T {
192 fn as_dyn_eq(&self) -> &dyn DynEq {
193 self
194 }
195
196 fn dyn_hash(&self, mut state: &mut dyn Hasher) {
197 T::hash(self, &mut state);
198 self.type_id().hash(&mut state);
199 }
200}
201
202impl Hash for dyn DynHash {
203 fn hash<H: Hasher>(&self, state: &mut H) {
204 self.dyn_hash(state);
205 }
206}
207
208pub fn ordinal(i: usize) -> String {
209 let s = i.to_string();
210 let suffix = if s.ends_with('1') && !s.ends_with("11") {
211 "st"
212 } else if s.ends_with('2') && !s.ends_with("12") {
213 "nd"
214 } else if s.ends_with('3') && !s.ends_with("13") {
215 "rd"
216 } else {
217 "th"
218 };
219 s + suffix
220}