reductionml_core/
config_schema.rs

1use schemars::{
2    gen::SchemaGenerator,
3    schema::{RootSchema, Schema, SchemaObject},
4    schema_for,
5};
6
7use crate::{reduction_factory::ReductionFactory, workspace::Configuration};
8
9pub struct ConfigSchema {
10    schema: RootSchema,
11}
12
13impl Default for ConfigSchema {
14    fn default() -> Self {
15        Self::new()
16    }
17}
18
19impl ConfigSchema {
20    pub fn new() -> Self {
21        let mut schema = schema_for!(Configuration);
22
23        // Create global all reductions schema
24        let mut any_reduction_config = SchemaObject::default();
25        any_reduction_config.subschemas().one_of = Some(vec![]);
26
27        schema.definitions.insert(
28            "any_reduction_config".to_owned(),
29            Schema::Object(any_reduction_config),
30        );
31
32        // Allow $schema to be set to anything
33        let mut schema_schema: SchemaObject = SchemaObject::default();
34        schema_schema.string().pattern = Some(".*".to_owned());
35        schema
36            .schema
37            .object()
38            .properties
39            .insert("$schema".to_owned(), schema_schema.into());
40
41        Self { schema }
42    }
43
44    pub fn schema(&self) -> &RootSchema {
45        &self.schema
46    }
47
48    pub fn add_reduction(&mut self, reduction_factory: &dyn ReductionFactory) {
49        let typename_constant = schemars::schema::SchemaObject {
50            const_value: Some(reduction_factory.typename().as_ref().into()),
51            ..Default::default()
52        };
53
54        let mut reduction_config_schema = SchemaObject::default();
55        reduction_config_schema
56            .object()
57            .properties
58            .insert("typename".to_owned(), Schema::Object(typename_constant));
59
60        let reductions_inner_schema = reduction_factory.get_config_schema();
61        reduction_config_schema.object().properties.insert(
62            "config".to_owned(),
63            Schema::Object(reductions_inner_schema.schema),
64        );
65        // Set additionalProperties to false
66        reduction_config_schema.object().additional_properties =
67            Some(Box::new(Schema::Bool(false)));
68
69        self.schema.definitions.insert(
70            reduction_factory.typename().as_ref().into(),
71            Schema::Object(reduction_config_schema),
72        );
73
74        match self
75            .schema
76            .definitions
77            .get_mut("any_reduction_config")
78            .unwrap()
79        {
80            Schema::Object(any_reduction_config) => {
81                let new_reduction_ref = schemars::schema::SchemaObject {
82                    reference: Some(format!("#/definitions/{}", reduction_factory.typename())),
83                    ..Default::default()
84                };
85                any_reduction_config
86                    .subschemas()
87                    .one_of
88                    .as_mut()
89                    .unwrap()
90                    .push(Schema::Object(new_reduction_ref));
91            }
92            _ => panic!("any_reduction_config is not an object"),
93        }
94
95        // TODO: Handle duplicate definitions
96        self.schema
97            .definitions
98            .extend(reductions_inner_schema.definitions);
99
100        // TODO handle "true" reduction
101    }
102}
103
104pub(crate) fn gen_json_reduction_config_schema(_gen: &mut SchemaGenerator) -> Schema {
105    schemars::schema::SchemaObject {
106        reference: Some("#/definitions/any_reduction_config".to_owned()),
107        ..Default::default()
108    }
109    .into()
110}