bluejay_validator/executable/operation/
variable_values.rs

1use bluejay_core::executable::{
2    OperationDefinition, VariableDefinition, VariableType, VariableTypeReference,
3};
4use bluejay_core::{AsIter, BuiltinScalarDefinition, Value, Variable};
5
6pub trait VariableValues {
7    type Key: AsRef<str>;
8    type Value: Value<true>;
9    type Iterator<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)>
10    where
11        Self: 'a;
12
13    fn iter(&self) -> Self::Iterator<'_>;
14
15    fn get(&self, key: &str) -> Option<&Self::Value> {
16        self.iter().find(|(k, _)| k.as_ref() == key).map(|(_, v)| v)
17    }
18}
19
20pub trait OperationDefinitionValueEvaluationExt: OperationDefinition {
21    fn evaluate_bool<V: Variable, VV: VariableValues>(
22        &self,
23        variable: &V,
24        variable_values: &VV,
25    ) -> Option<bool>;
26
27    fn evaluate_int<V: Variable, VV: VariableValues>(
28        &self,
29        variable: &V,
30        variable_values: &VV,
31    ) -> Option<i32>;
32}
33
34impl<T: OperationDefinition> OperationDefinitionValueEvaluationExt for T {
35    fn evaluate_bool<V: Variable, VV: VariableValues>(
36        &self,
37        variable: &V,
38        variable_values: &VV,
39    ) -> Option<bool> {
40        let variable_definitions = self.as_ref().variable_definitions()?;
41        let variable_definition = variable_definitions.iter().find(|variable_definition| {
42            variable_definition.variable() == variable.name()
43                && matches!(
44                    variable_definition.r#type().as_ref(),
45                    VariableTypeReference::Named(type_name, _) if type_name == BuiltinScalarDefinition::Boolean.as_ref()
46                )
47        })?;
48
49        let value = variable_values
50            .iter()
51            .find(|(key, _)| key.as_ref() == variable.name())
52            .map(|(_, value)| value);
53
54        if let Some(value) = value {
55            value.as_ref().as_boolean().copied()
56        } else {
57            variable_definition
58                .default_value()
59                .and_then(|value| value.as_ref().as_boolean().copied())
60        }
61    }
62
63    fn evaluate_int<V: Variable, VV: VariableValues>(
64        &self,
65        variable: &V,
66        variable_values: &VV,
67    ) -> Option<i32> {
68        let variable_definitions = self.as_ref().variable_definitions()?;
69        let variable_definition = variable_definitions.iter().find(|variable_definition| {
70            variable_definition.variable() == variable.name()
71                && matches!(
72                    variable_definition.r#type().as_ref(),
73                    VariableTypeReference::Named(type_name, _) if type_name == BuiltinScalarDefinition::Int.as_ref()
74                )
75        })?;
76
77        let value = variable_values
78            .iter()
79            .find(|(key, _)| key.as_ref() == variable.name())
80            .map(|(_, value)| value);
81
82        if let Some(value) = value {
83            value.as_ref().as_integer().copied()
84        } else {
85            variable_definition
86                .default_value()
87                .and_then(|value| value.as_ref().as_integer().copied())
88        }
89    }
90}
91
92#[cfg(feature = "serde_json")]
93impl VariableValues for serde_json::Map<String, serde_json::Value> {
94    type Key = String;
95    type Value = serde_json::Value;
96    type Iterator<'a> = serde_json::map::Iter<'a>;
97
98    fn iter(&self) -> Self::Iterator<'_> {
99        self.iter()
100    }
101}