cas_compute/numerical/
func.rs

1use std::collections::{HashMap, HashSet};
2use super::{builtin::Builtin, value::Value};
3
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Deserializer, Serialize, Serializer};
6
7#[cfg(feature = "serde")]
8fn serialize_builtin<S>(builtin: &dyn Builtin, serializer: S) -> Result<S::Ok, S::Error>
9where
10    S: Serializer,
11{
12    serializer.serialize_str(builtin.name())
13}
14
15#[cfg(feature = "serde")]
16fn deserialize_builtin<'de, 'a, D>(deserializer: D) -> Result<&'a dyn Builtin, D::Error>
17where
18    D: Deserializer<'de>,
19{
20    let name = String::deserialize(deserializer)?;
21    let functions = crate::funcs::all();
22    functions.get(name.as_str())
23        .map(|f| &**f)
24        .ok_or_else(|| serde::de::Error::custom("unknown function"))
25}
26
27/// A function.
28///
29/// Functions are treated as values just like any other value in `cas-rs`; they can be stored
30/// in variables, passed as arguments to other functions, and returned from functions.
31#[derive(Debug, Clone)]
32#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33pub enum Function {
34    /// A user-defined function.
35    ///
36    /// The inner value is a `usize` that represents the index of the function's chunk.
37    User(User),
38
39    /// A built-in function.
40    #[cfg_attr(feature = "serde", serde(
41        serialize_with = "serialize_builtin",
42        deserialize_with = "deserialize_builtin"
43    ))]
44    Builtin(&'static dyn Builtin),
45}
46
47/// A user-defined function.
48#[derive(Debug, Clone, PartialEq)]
49#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50pub struct User {
51    /// The index of the function's chunk.
52    ///
53    /// TODO: comparing index is not enough to compare two functions
54    pub index: usize,
55
56    /// The variables captured by the function from the environment.
57    ///
58    /// This is determined at compile time.
59    pub captures: HashSet<usize>,
60
61    /// The values of the variables in the function's environment at the time of the function's
62    /// creation.
63    ///
64    /// This is determined at runtime.
65    pub environment: HashMap<usize, Value>,
66}
67
68impl User {
69    /// Creates a new user-defined function with the given chunk index an captured variables.
70    pub fn new(index: usize, captures: HashSet<usize>) -> Self {
71        Self { index, captures, environment: HashMap::new() }
72    }
73}
74
75/// Manual implementation of [`PartialEq`] to support `dyn Builtin` by comparing pointers.
76impl PartialEq for Function {
77    fn eq(&self, other: &Self) -> bool {
78        match (self, other) {
79            (Self::User(a), Self::User(b)) => a == b,
80            (Self::Builtin(a), Self::Builtin(b)) => std::ptr::eq(*a, *b),
81            _ => false,
82        }
83    }
84}