murrelet_livecode/
types.rs

1use std::collections::HashSet;
2
3use evalexpr::{build_operator_tree, EvalexprError, HashMapContext, Node};
4use itertools::Itertools;
5use lerpable::{step, Lerpable};
6use murrelet_common::IdxInRange2d;
7use serde::{Deserialize, Deserializer};
8use serde_yaml::Location;
9
10use crate::{
11    expr::IntoExprWorldContext,
12    livecode::{GetLivecodeIdentifiers, LivecodeFromWorld},
13    state::LivecodeWorldState,
14    unitcells::UnitCellExprWorldContext,
15};
16
17#[derive(Debug)]
18pub enum LivecodeError {
19    Raw(String), // my custom errors
20    EvalExpr(String, EvalexprError),
21    Io(String, std::io::Error),
22    NestGetExtra(String),
23    NestGetInvalid(String),
24    SerdeLoc(Location, String),
25    WGPU(String),
26}
27impl LivecodeError {}
28impl std::fmt::Display for LivecodeError {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        match self {
31            LivecodeError::Raw(msg) => write!(f, "{}", msg),
32            LivecodeError::EvalExpr(msg, err) => write!(f, "{}: {}", msg, err),
33            LivecodeError::Io(msg, err) => write!(f, "{}: {}", msg, err),
34            LivecodeError::NestGetExtra(err) => {
35                write!(f, "nest get has unusable tokens...: {}", err)
36            }
37            LivecodeError::NestGetInvalid(err) => {
38                write!(f, "nest get requested for odd thing...: {}", err)
39            }
40            LivecodeError::SerdeLoc(location, err) => {
41                // if it's err, hrm, remove the controlvec ones
42                let loc = format!("{},{}", location.line(), location.column());
43                write!(f, "parse_error :: loc: {}, err: {}", loc, err)
44            }
45            LivecodeError::WGPU(err) => write!(f, "shader parse error: {}", err),
46        }
47    }
48}
49
50impl std::error::Error for LivecodeError {}
51
52pub type LivecodeResult<T> = Result<T, LivecodeError>;
53
54#[derive(Debug, Clone, Deserialize)]
55#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
56#[serde(transparent)]
57pub struct AdditionalContextNode(#[cfg_attr(feature = "schemars", schemars(with = "String"))] Node);
58
59impl Default for AdditionalContextNode {
60    fn default() -> Self {
61        Self(build_operator_tree("").unwrap())
62    }
63}
64
65impl AdditionalContextNode {
66    pub fn eval_raw(&self, ctx: &mut HashMapContext) -> LivecodeResult<()> {
67        self.0
68            .eval_empty_with_context_mut(ctx)
69            .map_err(|err| LivecodeError::EvalExpr("error evaluating ctx".to_owned(), err))
70    }
71}
72
73impl Lerpable for AdditionalContextNode {
74    fn lerpify<T: lerpable::IsLerpingMethod>(&self, other: &Self, pct: &T) -> Self {
75        step(self, other, pct)
76    }
77}
78
79#[derive(Debug, Clone, Deserialize)]
80#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
81#[serde(untagged)]
82pub enum ControlVecElementRepeatMethod {
83    Single(usize),
84    Rect([usize; 2]),
85}
86impl ControlVecElementRepeatMethod {
87    fn len(&self) -> usize {
88        match self {
89            ControlVecElementRepeatMethod::Single(s) => *s,
90            ControlVecElementRepeatMethod::Rect(r) => r[0] * r[1],
91        }
92    }
93    fn iter(&self) -> Vec<IdxInRange2d> {
94        match self {
95            ControlVecElementRepeatMethod::Single(s) => {
96                let mut v = vec![];
97                for i in 0..*s {
98                    v.push(IdxInRange2d::new(i, 1, *s));
99                }
100                v
101            }
102            ControlVecElementRepeatMethod::Rect(s) => {
103                let mut v = vec![];
104                for i in 0..s[0] {
105                    for j in 0..s[1] {
106                        v.push(IdxInRange2d::new_rect(i, j, s[0], s[1]));
107                    }
108                }
109                v
110            }
111        }
112    }
113}
114
115#[derive(Debug, Clone, Deserialize)]
116#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
117pub struct ControlVecElementRepeat<Source> {
118    repeat: ControlVecElementRepeatMethod,
119    // #[serde(default)]
120    prefix: String,
121    what: Vec<Source>,
122}
123
124impl<T: GetLivecodeIdentifiers> GetLivecodeIdentifiers for ControlVecElement<T> {
125    fn variable_identifiers(&self) -> Vec<crate::livecode::LivecodeVariable> {
126        match self {
127            ControlVecElement::Single(c) => c.variable_identifiers(),
128            ControlVecElement::Repeat(c) => c
129                .what
130                .iter()
131                .flat_map(|x| x.variable_identifiers())
132                .collect::<HashSet<_>>()
133                .into_iter()
134                .collect_vec(),
135        }
136    }
137
138    fn function_identifiers(&self) -> Vec<crate::livecode::LivecodeFunction> {
139        match self {
140            ControlVecElement::Single(c) => c.function_identifiers(),
141            ControlVecElement::Repeat(c) => c
142                .what
143                .iter()
144                .flat_map(|x| x.function_identifiers())
145                .collect::<HashSet<_>>()
146                .into_iter()
147                .collect_vec(),
148        }
149    }
150}
151
152impl<Source> ControlVecElementRepeat<Source> {
153    pub fn eval_and_expand_vec<Target>(&self, w: &LivecodeWorldState) -> LivecodeResult<Vec<Target>>
154    where
155        Source: LivecodeFromWorld<Target>,
156    {
157        let mut result = Vec::with_capacity(self.repeat.len() * self.what.len());
158
159        let prefix = if self.prefix.is_empty() {
160            "i_".to_string()
161        } else {
162            format!("{}_", self.prefix)
163        };
164
165        for idx in self.repeat.iter() {
166            let expr =
167                UnitCellExprWorldContext::from_idx2d(idx, 1.0).as_expr_world_context_values();
168            let new_w = w.clone_with_vals(expr, &prefix)?;
169
170            for src in &self.what {
171                let o = src.o(&new_w)?;
172                result.push(o);
173            }
174        }
175        Ok(result)
176    }
177}
178
179#[derive(Debug, Clone)]
180#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
181pub enum ControlVecElement<Source> {
182    Single(Source),
183    Repeat(ControlVecElementRepeat<Source>),
184}
185
186impl<Source> ControlVecElement<Source> {
187    pub fn raw(c: Source) -> Self {
188        Self::Single(c)
189    }
190
191    pub fn eval_and_expand_vec<Target>(&self, w: &LivecodeWorldState) -> LivecodeResult<Vec<Target>>
192    where
193        Source: LivecodeFromWorld<Target>,
194    {
195        match self {
196            ControlVecElement::Single(c) => Ok(vec![c.o(w)?]),
197            ControlVecElement::Repeat(r) => r.eval_and_expand_vec(w),
198        }
199    }
200}
201
202// chatgpt
203impl<'de, Source> Deserialize<'de> for ControlVecElement<Source>
204where
205    Source: Deserialize<'de>,
206{
207    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
208    where
209        D: Deserializer<'de>,
210    {
211        let value = serde_yaml::Value::deserialize(deserializer)?;
212
213        let mut errors = Vec::new();
214
215        // try the simple one
216        match Source::deserialize(value.clone()) {
217            Ok(single) => return Ok(ControlVecElement::Single(single)),
218            Err(e) => errors.push(format!("{}", e)),
219        }
220
221        //
222        match ControlVecElementRepeat::deserialize(value.clone()) {
223            Ok(repeat) => return Ok(ControlVecElement::Repeat(repeat)),
224            Err(e) => {
225                // it's gonna fail, so just check what
226                errors.push(format!("(repeat {})", e))
227            }
228        }
229
230        // Both variants failed, return an error with detailed messages
231        Err(serde::de::Error::custom(format!(
232            "ControlVecElement {}",
233            errors.join(" ")
234        )))
235    }
236}