Skip to main content

geop_core_program/
operation.rs

1use geop_core_math::geop_error::{GeopError, GeopResult};
2use serde::{Deserialize, Serialize, de::DeserializeOwned};
3
4use crate::part::StepContext;
5
6/// One kind of step. An operation is a unit struct: everything a step of
7/// it needs is in its arguments.
8pub trait Operation: 'static {
9    /// The name programs store its steps under.
10    const KIND: &'static str;
11    /// What a step of the operation is given. It is saved with the program,
12    /// so it names targets and elements, never holds their internal ids.
13    type Args: Serialize + DeserializeOwned + 'static;
14
15    /// Declares what the step produces, through `ctx` (see
16    /// [`StepContext::produce`]): cheap, since it runs in every run. What
17    /// takes work is done in the makes, which run only when what they read
18    /// changed.
19    fn run(ctx: &mut StepContext, args: &Self::Args) -> GeopResult<()>;
20}
21
22/// Arguments that say which operation they are for: what a program written
23/// in Rust — an example, a standard part, a test — pushes as a step without
24/// naming the operation again.
25pub trait StepArgs: Serialize {
26    /// The kind of the operation they are for (see [`Operation::KIND`]).
27    const KIND: &'static str;
28}
29
30/// An [`Operation`] with its types erased, so that operations of all kinds
31/// can be kept in one [`crate::operation_registry::OperationRegistry`].
32/// Every operation is one, through its value. Arguments come as saved.
33pub trait ErasedOperation {
34    fn kind(&self) -> &'static str;
35    /// Whether `args` are arguments of the operation, as saved.
36    fn check_args(&self, args: &serde_json::Value) -> GeopResult<()>;
37    fn run(&self, ctx: &mut StepContext, args: &serde_json::Value) -> GeopResult<()>;
38}
39
40/// The arguments of `O` from their saved form.
41pub fn args<O: Operation>(json: &serde_json::Value) -> GeopResult<O::Args> {
42    O::Args::deserialize(json)
43        .map_err(|e| GeopError::new(format!("arguments of operation `{}`: {e}", O::KIND)))
44}
45
46/// The saved form of `args`.
47pub fn saved<O: Operation>(args: &O::Args) -> GeopResult<serde_json::Value> {
48    serde_json::to_value(args)
49        .map_err(|e| GeopError::new(format!("arguments of operation `{}`: {e}", O::KIND)))
50}
51
52impl<O: Operation> ErasedOperation for O {
53    fn kind(&self) -> &'static str {
54        O::KIND
55    }
56
57    fn check_args(&self, args: &serde_json::Value) -> GeopResult<()> {
58        self::args::<O>(args).map(|_| ())
59    }
60
61    fn run(&self, ctx: &mut StepContext, args: &serde_json::Value) -> GeopResult<()> {
62        <O as Operation>::run(ctx, &self::args::<O>(args)?)
63    }
64}