1use std::cmp::Ordering;
2use std::sync::Arc;
3
4use revision::{DeserializeRevisioned, Revisioned, SerializeRevisioned};
5use storekey::{BorrowDecode, Encode};
6use surrealdb_types::{SqlFormat, ToSql, write_sql};
7
8use crate::expr::variables::Variables;
9use crate::expr::{ClosureExpr, Expr, Kind, Param};
10
11pub trait BuiltinClosureObj: Send + Sync + 'static {
17 fn as_any(&self) -> &dyn std::any::Any;
18
19 fn captured_values(&self) -> Vec<&crate::val::Value> {
27 Vec::new()
28 }
29}
30
31#[derive(Clone)]
32pub enum Closure {
33 Expr {
34 args: Vec<(Param, Kind)>,
35 returns: Option<Kind>,
36 body: Expr,
37 captures: Variables,
38 },
39 Builtin(Arc<dyn BuiltinClosureObj>),
40}
41
42impl std::fmt::Debug for Closure {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 match self {
45 Closure::Expr {
46 args,
47 returns,
48 body,
49 captures,
50 } => f
51 .debug_struct("Closure::Expr")
52 .field("args", args)
53 .field("returns", returns)
54 .field("body", body)
55 .field("captures", captures)
56 .finish(),
57 Closure::Builtin(_) => {
58 f.debug_tuple("Closure::Builtin")
59 .finish()
61 }
62 }
63 }
64}
65
66impl PartialEq for Closure {
67 fn eq(&self, other: &Self) -> bool {
68 match (self, other) {
69 (
70 Closure::Expr {
71 args: args1,
72 returns: returns1,
73 body: body1,
74 captures: captures1,
75 },
76 Closure::Expr {
77 args: args2,
78 returns: returns2,
79 body: body2,
80 captures: captures2,
81 },
82 ) => args1 == args2 && returns1 == returns2 && body1 == body2 && captures1 == captures2,
83 (
84 Closure::Builtin {
85 ..
86 },
87 Closure::Builtin {
88 ..
89 },
90 ) => {
91 false
93 }
94 _ => false,
95 }
96 }
97}
98
99impl Eq for Closure {}
100
101impl std::hash::Hash for Closure {
102 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
103 match self {
104 Closure::Expr {
105 args,
106 returns,
107 body,
108 captures,
109 } => {
110 0u8.hash(state); args.hash(state);
112 returns.hash(state);
113 body.hash(state);
114 captures.hash(state);
115 }
116 Closure::Builtin(_) => {
117 1u8.hash(state); }
120 }
121 }
122}
123
124impl PartialOrd for Closure {
125 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
126 Some(self.cmp(other))
127 }
128}
129
130impl Ord for Closure {
131 fn cmp(&self, _other: &Self) -> Ordering {
132 Ordering::Equal
134 }
135}
136
137impl Closure {
138 pub fn into_expr(self) -> Expr {
139 match self {
140 Closure::Expr {
141 args,
142 returns,
143 body,
144 ..
145 } => Expr::Closure(Box::new(ClosureExpr {
146 args,
147 returns,
148 body,
149 })),
150 Closure::Builtin {
151 ..
152 } => Expr::Closure(Box::new(ClosureExpr {
153 args: vec![],
154 returns: None,
155 body: Expr::Block(Box::default()),
156 })),
157 }
158 }
159}
160
161impl ToSql for Closure {
162 fn fmt_sql(&self, f: &mut String, sql_fmt: SqlFormat) {
163 match self {
164 Closure::Expr {
165 args,
166 returns,
167 body,
168 ..
169 } => {
170 write_sql!(f, sql_fmt, "|");
171 for (i, (name, kind)) in args.iter().enumerate() {
172 if i > 0 {
173 write_sql!(f, sql_fmt, ", ");
174 }
175 write_sql!(f, sql_fmt, "{name}: ");
176 match kind {
177 k @ Kind::Either(_) => write_sql!(f, sql_fmt, "<{k}>"),
178 k => write_sql!(f, sql_fmt, "{k}"),
179 }
180 }
181 write_sql!(f, sql_fmt, "|");
182 if let Some(returns) = &returns {
183 write_sql!(f, sql_fmt, " -> {returns}");
184 }
185 write_sql!(f, sql_fmt, " {}", body);
186 }
187 Closure::Builtin {
188 ..
189 } => {
190 write_sql!(f, sql_fmt, r#"|| THROW "builtin""#);
191 }
192 }
193 }
194}
195
196impl<F> Encode<F> for Closure {
197 fn encode<W: std::io::Write>(
198 &self,
199 _: &mut storekey::Writer<W>,
200 ) -> Result<(), storekey::EncodeError> {
201 Err(storekey::EncodeError::message("Closure cannot be encoded"))
202 }
203}
204
205impl<'de, F> BorrowDecode<'de, F> for Closure {
206 fn borrow_decode(_: &mut storekey::BorrowReader<'de>) -> Result<Self, storekey::DecodeError> {
207 Err(storekey::DecodeError::message("Closure cannot be decoded"))
208 }
209}
210
211impl Revisioned for Closure {
212 fn revision() -> u16 {
213 1
214 }
215}
216
217impl SerializeRevisioned for Closure {
218 fn serialize_revisioned<W: std::io::Write>(
219 &self,
220 _writer: &mut W,
221 ) -> Result<(), revision::Error> {
222 Err(revision::Error::Conversion("Closures cannot be stored on disk".to_string()))
223 }
224}
225
226impl DeserializeRevisioned for Closure {
227 fn deserialize_revisioned<R: std::io::Read>(_reader: &mut R) -> Result<Self, revision::Error> {
228 Err(revision::Error::Conversion("Closures cannot be deserialized from disk".to_string()))
229 }
230}
231
232impl revision::SkipRevisioned for Closure {
233 fn skip_revisioned<R: std::io::Read>(_reader: &mut R) -> Result<(), revision::Error> {
234 Err(revision::Error::Conversion("Closures cannot be skipped on the wire".to_string()))
235 }
236}
237
238impl revision::WalkRevisioned for Closure {
239 type Walker<'r, R: revision::BorrowedReader + 'r> = revision::LeafWalker<'r, Closure, R>;
240
241 fn walk_revisioned<'r, R: revision::BorrowedReader>(
242 reader: &'r mut R,
243 ) -> Result<Self::Walker<'r, R>, revision::Error> {
244 Ok(revision::LeafWalker::new(reader))
248 }
249}