aflak_cake/
lib.rs

1//! # aflak - Computational mAKE
2//!
3//! A crate to manage a graph of interdependent functions.
4extern crate rayon;
5
6extern crate boow;
7extern crate serde;
8#[macro_use]
9extern crate serde_derive;
10extern crate variant_name;
11
12mod dst;
13mod export;
14mod transform;
15
16pub use dst::*;
17pub use export::*;
18pub use transform::*;
19
20pub use self::variant_name::VariantName;
21
22/// Trait to define a default value for each variant of an enumeration.
23pub trait DefaultFor: VariantName {
24    fn default_for(variant_name: &str) -> Self;
25}
26
27/// Trait to discriminate editable variants from constant variants of an
28/// enumeration.
29///
30/// Especially used for a node editor.
31pub trait EditableVariants: VariantName {
32    /// Get list of editable variants.
33    fn editable_variants() -> &'static [&'static str];
34    /// Check if given variant is editable or not.
35    fn editable(variant_name: &str) -> bool {
36        Self::editable_variants().contains(&variant_name)
37    }
38}
39
40/// Make it easier to define a function used for a transform. Used internally
41/// by [`cake_transform`]. You probably want to directly use [`cake_transform`].
42#[doc(hidden)]
43#[macro_export]
44macro_rules! cake_fn {
45    // Special case where no argument is provided
46    ($fn_name: ident<$enum_name: ident, $err_type: ty>() $fn_block: block) => {
47        fn $fn_name(
48            _: Vec<::std::borrow::Cow<$enum_name>>,
49        ) -> Vec<Result<$enum_name, $err_type>> {
50            $fn_block
51        }
52    };
53    // Standard case
54    ($fn_name: ident<$enum_name: ident, $err_type: ty>($($x: ident: $x_type: ident),*) $fn_block: block) => {
55        fn $fn_name(
56            input: Vec<::std::borrow::Cow<$enum_name>>,
57        ) -> Vec<Result<$enum_name, $err_type>> {
58            #[allow(non_camel_case_types)]
59            enum Args { $($x,)* }
60            if let ($(&$enum_name::$x_type(ref $x), )*) = ($(&*input[Args::$x as usize], )*) {
61                $fn_block
62            } else {
63                panic!("Unexpected argument!")
64            }
65        }
66    };
67}
68
69/// Create a new transform from a rust function.
70///
71/// # Example
72///
73/// ```rust
74/// #[macro_use] extern crate variant_name_derive;
75/// #[macro_use] extern crate aflak_cake;
76/// use aflak_cake::*;
77///
78/// #[derive(Clone, PartialEq, Debug, VariantName)]
79/// pub enum AlgoIO {
80///     Integer(u64),
81///     Image2d(Vec<Vec<f64>>),
82/// }
83///
84/// pub enum E {}
85///
86/// let plus_one_trans = cake_transform!(
87///     "Long description of the transform",
88/// // key identifying transformation   Input arguments with default value (optional)
89/// //   \  In/Out types /- Error type  /        _ Output type(s)
90/// //    \       /     / /------------/        /
91///     plus1<AlgoIO, E>(i: Integer = 0) -> Integer {
92///     // Define the body of the transformation.
93///     // Must return a Vec<Result<AlgoIO, !>>!
94///     vec![Ok(AlgoIO::Integer(i + 1))]
95/// });
96/// ```
97#[macro_export]
98macro_rules! cake_transform {
99    ($description: expr, $fn_name: ident<$enum_name: ident, $err_type: ty>($($x: ident: $x_type: ident $(= $x_default_val: expr), *),*) -> $($out_type: ident),* $fn_block: block) => {{
100        cake_fn!{$fn_name<$enum_name, $err_type>($($x: $x_type),*) $fn_block}
101        use std::borrow::Cow;
102
103        $crate::Transformation {
104            name: stringify!($fn_name),
105            description: Cow::Borrowed($description),
106            input: vec![$((stringify!($x_type), {
107                cake_some_first_value!($( $enum_name::$x_type($x_default_val) ),*)
108            }), )*],
109            output: vec![$(stringify!($out_type), )*],
110            algorithm: $crate::Algorithm::Function($fn_name),
111        }
112    }};
113}
114
115/// Make a constant.
116///
117/// Subject for deprecation.
118/// You'd probably better use [`Transformation::new_constant`].
119#[macro_export]
120macro_rules! cake_constant {
121    ($const_name: ident, $($x: expr),*) => {{
122        use std::borrow::Cow;
123        use $crate::VariantName;
124
125        let constant = vec![$($x, )*];
126        $crate::Transformation {
127            name: stringify!($const_name),
128            description: Cow::Borrowed(
129                concat!("Constant variable of type '", stringify!($const_name), "'")
130            ),
131            input: vec![],
132            output: constant.iter().map(|c| c.variant_name()).collect(),
133            algorithm: $crate::Algorithm::Constant(constant),
134        }
135    }};
136}
137
138/// Helper macro for internal use.
139#[doc(hidden)]
140#[macro_export]
141macro_rules! cake_some_first_value {
142    () => {
143        None
144    };
145    ($x:expr) => {
146        Some($x)
147    };
148    ($x:expr, $($xs:expr)+) => {
149        compile_error!("Only zero or one value is expected.")
150    };
151}