1use crate::Env;
22use crate::source::Location;
23use std::borrow::Borrow;
24use std::collections::HashSet;
25use std::fmt::Debug;
26use std::fmt::Display;
27use std::hash::Hash;
28use std::hash::Hasher;
29use std::iter::FusedIterator;
30use std::pin::Pin;
31use std::rc::Rc;
32use thiserror::Error;
33
34pub trait FunctionBody: Debug + Display {
36 #[allow(async_fn_in_trait)] async fn execute(&self, env: &mut Env) -> crate::semantics::Result;
42}
43
44pub trait FunctionBodyObject: Debug + Display {
51 fn execute<'a>(
56 &'a self,
57 env: &'a mut Env,
58 ) -> Pin<Box<dyn Future<Output = crate::semantics::Result> + 'a>>;
59}
60
61impl<T: FunctionBody + ?Sized> FunctionBodyObject for T {
62 fn execute<'a>(
63 &'a self,
64 env: &'a mut Env,
65 ) -> Pin<Box<dyn Future<Output = crate::semantics::Result> + 'a>> {
66 Box::pin(self.execute(env))
67 }
68}
69
70#[derive(Clone, Debug)]
72pub struct Function {
73 pub name: String,
75
76 pub body: Rc<dyn FunctionBodyObject>,
83
84 pub origin: Location,
86
87 pub read_only_location: Option<Location>,
93}
94
95impl Function {
96 #[inline]
101 #[must_use]
102 pub fn new<N: Into<String>, B: Into<Rc<dyn FunctionBodyObject>>>(
103 name: N,
104 body: B,
105 origin: Location,
106 ) -> Self {
107 Function {
108 name: name.into(),
109 body: body.into(),
110 origin,
111 read_only_location: None,
112 }
113 }
114
115 #[inline]
120 #[must_use]
121 pub fn make_read_only(mut self, location: Location) -> Self {
122 self.read_only_location = Some(location);
123 self
124 }
125
126 #[must_use]
128 pub const fn is_read_only(&self) -> bool {
129 self.read_only_location.is_some()
130 }
131}
132
133impl PartialEq for Function {
138 fn eq(&self, other: &Self) -> bool {
139 self.name == other.name
140 && Rc::ptr_eq(&self.body, &other.body)
141 && self.origin == other.origin
142 && self.read_only_location == other.read_only_location
143 }
144}
145
146impl Eq for Function {}
147
148#[derive(Clone, Debug, Eq)]
159struct HashEntry(Rc<Function>);
160
161impl PartialEq for HashEntry {
162 fn eq(&self, other: &HashEntry) -> bool {
167 self.0.name == other.0.name
168 }
169}
170
171impl Hash for HashEntry {
172 fn hash<H: Hasher>(&self, state: &mut H) {
177 self.0.name.hash(state)
178 }
179}
180
181impl Borrow<str> for HashEntry {
182 fn borrow(&self) -> &str {
183 &self.0.name
184 }
185}
186
187#[derive(Clone, Debug, Default)]
189pub struct FunctionSet {
190 entries: HashSet<HashEntry>,
191}
192
193#[derive(Clone, Debug, Eq, Error, PartialEq)]
195#[error("cannot redefine read-only function `{}`", .existing.name)]
196#[non_exhaustive]
197pub struct DefineError {
198 pub existing: Rc<Function>,
200 pub new: Rc<Function>,
202}
203
204#[derive(Clone, Debug, Eq, Error, PartialEq)]
206#[error("cannot unset read-only function `{}`", .existing.name)]
207#[non_exhaustive]
208pub struct UnsetError {
209 pub existing: Rc<Function>,
211}
212
213#[derive(Clone, Debug)]
217pub struct Iter<'a> {
218 inner: std::collections::hash_set::Iter<'a, HashEntry>,
219}
220
221impl FunctionSet {
222 #[must_use]
224 pub fn new() -> Self {
225 FunctionSet::default()
226 }
227
228 #[must_use]
230 pub fn get(&self, name: &str) -> Option<&Rc<Function>> {
231 self.entries.get(name).map(|entry| &entry.0)
232 }
233
234 #[inline]
236 #[must_use]
237 pub fn len(&self) -> usize {
238 self.entries.len()
239 }
240
241 #[inline]
243 #[must_use]
244 pub fn is_empty(&self) -> bool {
245 self.entries.is_empty()
246 }
247
248 pub fn define<F: Into<Rc<Function>>>(
254 &mut self,
255 function: F,
256 ) -> Result<Option<Rc<Function>>, DefineError> {
257 #[allow(clippy::mutable_key_type)]
258 fn inner(
259 entries: &mut HashSet<HashEntry>,
260 new: Rc<Function>,
261 ) -> Result<Option<Rc<Function>>, DefineError> {
262 match entries.get(new.name.as_str()) {
263 Some(existing) if existing.0.is_read_only() => Err(DefineError {
264 existing: Rc::clone(&existing.0),
265 new,
266 }),
267
268 _ => Ok(entries.replace(HashEntry(new)).map(|entry| entry.0)),
269 }
270 }
271 inner(&mut self.entries, function.into())
272 }
273
274 pub fn unset(&mut self, name: &str) -> Result<Option<Rc<Function>>, UnsetError> {
279 match self.entries.get(name) {
280 Some(entry) if entry.0.is_read_only() => Err(UnsetError {
281 existing: Rc::clone(&entry.0),
282 }),
283
284 _ => Ok(self.entries.take(name).map(|entry| entry.0)),
285 }
286 }
287
288 pub fn iter(&self) -> Iter<'_> {
292 let inner = self.entries.iter();
293 Iter { inner }
294 }
295}
296
297impl<'a> Iterator for Iter<'a> {
298 type Item = &'a Rc<Function>;
299
300 fn next(&mut self) -> Option<Self::Item> {
301 self.inner.next().map(|entry| &entry.0)
302 }
303}
304
305impl ExactSizeIterator for Iter<'_> {
306 #[inline]
307 fn len(&self) -> usize {
308 self.inner.len()
309 }
310}
311
312impl FusedIterator for Iter<'_> {}
313
314impl<'a> IntoIterator for &'a FunctionSet {
315 type Item = &'a Rc<Function>;
316 type IntoIter = Iter<'a>;
317
318 fn into_iter(self) -> Self::IntoIter {
319 self.iter()
320 }
321}
322
323#[cfg(test)]
324mod tests {
325 use super::*;
326
327 #[derive(Clone, Debug)]
328 struct FunctionBodyStub;
329
330 impl std::fmt::Display for FunctionBodyStub {
331 fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
332 unreachable!()
333 }
334 }
335 impl FunctionBody for FunctionBodyStub {
336 async fn execute(&self, _: &mut Env) -> crate::semantics::Result {
337 unreachable!()
338 }
339 }
340
341 fn function_body_stub() -> Rc<dyn FunctionBodyObject> {
342 Rc::new(FunctionBodyStub)
343 }
344
345 #[test]
346 fn defining_new_function() {
347 let mut set = FunctionSet::new();
348 let function = Rc::new(Function::new(
349 "foo",
350 function_body_stub(),
351 Location::dummy("foo"),
352 ));
353
354 let result = set.define(function.clone());
355 assert_eq!(result, Ok(None));
356 assert_eq!(set.get("foo"), Some(&function));
357 }
358
359 #[test]
360 fn redefining_existing_function() {
361 let mut set = FunctionSet::new();
362 let function1 = Rc::new(Function::new(
363 "foo",
364 function_body_stub(),
365 Location::dummy("foo 1"),
366 ));
367 let function2 = Rc::new(Function::new(
368 "foo",
369 function_body_stub(),
370 Location::dummy("foo 2"),
371 ));
372 set.define(function1.clone()).unwrap();
373
374 let result = set.define(function2.clone());
375 assert_eq!(result, Ok(Some(function1)));
376 assert_eq!(set.get("foo"), Some(&function2));
377 }
378
379 #[test]
380 fn redefining_readonly_function() {
381 let mut set = FunctionSet::new();
382 let function1 = Rc::new(
383 Function::new("foo", function_body_stub(), Location::dummy("foo 1"))
384 .make_read_only(Location::dummy("readonly")),
385 );
386 let function2 = Rc::new(Function::new(
387 "foo",
388 function_body_stub(),
389 Location::dummy("foo 2"),
390 ));
391 set.define(function1.clone()).unwrap();
392
393 let error = set.define(function2.clone()).unwrap_err();
394 assert_eq!(error.existing, function1);
395 assert_eq!(error.new, function2);
396 assert_eq!(set.get("foo"), Some(&function1));
397 }
398
399 #[test]
400 fn unsetting_existing_function() {
401 let mut set = FunctionSet::new();
402 let function = Rc::new(Function::new(
403 "foo",
404 function_body_stub(),
405 Location::dummy("foo"),
406 ));
407 set.define(function.clone()).unwrap();
408
409 let result = set.unset("foo").unwrap();
410 assert_eq!(result, Some(function));
411 assert_eq!(set.get("foo"), None);
412 }
413
414 #[test]
415 fn unsetting_nonexisting_function() {
416 let mut set = FunctionSet::new();
417
418 let result = set.unset("foo").unwrap();
419 assert_eq!(result, None);
420 assert_eq!(set.get("foo"), None);
421 }
422
423 #[test]
424 fn unsetting_readonly_function() {
425 let mut set = FunctionSet::new();
426 let function = Rc::new(
427 Function::new("foo", function_body_stub(), Location::dummy("foo"))
428 .make_read_only(Location::dummy("readonly")),
429 );
430 set.define(function.clone()).unwrap();
431
432 let error = set.unset("foo").unwrap_err();
433 assert_eq!(error.existing, function);
434 }
435
436 #[test]
437 fn iteration() {
438 let mut set = FunctionSet::new();
439 let function1 = Rc::new(Function::new(
440 "foo",
441 function_body_stub(),
442 Location::dummy("foo"),
443 ));
444 let function2 = Rc::new(Function::new(
445 "bar",
446 function_body_stub(),
447 Location::dummy("bar"),
448 ));
449 set.define(function1.clone()).unwrap();
450 set.define(function2.clone()).unwrap();
451
452 let functions = set.iter().collect::<Vec<_>>();
453 assert!(
454 functions[..] == [&function1, &function2] || functions[..] == [&function2, &function1],
455 "{functions:?}"
456 );
457 }
458}