json_utils/schema/
query_for_schema_node.rs

1use std::fmt;
2
3use crate::query::Path;
4use crate::query::PathComponent;
5use crate::query::Query;
6
7use super::SchemaNode;
8use super::ValidNode;
9
10#[derive(Debug, Clone, PartialEq)]
11pub struct QueryNode<T: fmt::Debug + Clone + PartialEq> {
12    pub schema: T,
13    pub is_required: bool,
14}
15
16impl<'v> Query<'v> for SchemaNode {
17    type Item = QueryNode<SchemaNode>;
18    type ItemRef = QueryNode<&'v SchemaNode>;
19
20    fn lookup<'p, P>(&'v self, path: P) -> Option<Self::ItemRef>
21    where
22        P: Path<'p>,
23    {
24        lookup(self, true, path.path())
25    }
26
27    fn take<'p, P>(self, path: P) -> (Option<Self>, Option<Self::Item>)
28    where
29        P: Path<'p>,
30    {
31        take(self, true, path.path())
32    }
33
34    fn insert<'p, P>(&mut self, path: P, insertee: Self::Item) -> Result<(), Self::Item>
35    where
36        P: Path<'p>,
37    {
38        insert(self, path.path(), insertee)
39    }
40}
41
42fn lookup<'v, 'p, P: PathComponent<'p>, I: Iterator<Item = P>>(
43    v: &'v SchemaNode,
44    is_required: bool,
45    mut components: I,
46) -> Option<QueryNode<&'v SchemaNode>> {
47    if let Some(component) = components.next() {
48        if let SchemaNode::ValidNode(ValidNode::ObjectNode(ref object_node)) = *v {
49            let child_key = component.as_str_slice();
50            let child_is_required = object_node.required.contains(child_key);
51            object_node
52                .properties
53                .get(child_key)
54                .and_then(move |ref child| lookup(child, child_is_required, components))
55        } else {
56            None
57        }
58    } else {
59        let qn = QueryNode {
60            is_required,
61            schema: v,
62        };
63        Some(qn)
64    }
65}
66
67fn take<'v, 'p, P: PathComponent<'p>, I: Iterator<Item = P>>(
68    v: SchemaNode,
69    is_required: bool,
70    mut components: I,
71) -> (Option<SchemaNode>, Option<QueryNode<SchemaNode>>) {
72    if let Some(component) = components.next() {
73        match v {
74            SchemaNode::ValidNode(ValidNode::ObjectNode(mut object_node)) => {
75                let child_key = component.as_str_slice();
76                if let Some(child) = object_node.properties.remove(child_key) {
77                    let child_is_required = object_node.required.contains(child_key);
78                    let (child_opt, taken_opt) = take(child, child_is_required, components);
79                    if let Some(child) = child_opt {
80                        object_node.properties.insert(child_key.to_owned(), child);
81                    };
82                    if object_node.properties.is_empty() {
83                        (None, taken_opt)
84                    } else {
85                        (Some(object_node.into()), taken_opt)
86                    }
87                } else {
88                    (Some(object_node.into()), None)
89                }
90            }
91            as_is => (Some(as_is), None),
92        }
93    } else {
94        let qn = QueryNode {
95            is_required,
96            schema: v,
97        };
98        (None, Some(qn))
99    }
100}
101
102fn insert<'v, 'p, P: PathComponent<'p>, I: Iterator<Item = P>>(
103    v: &'v mut SchemaNode,
104    mut components: I,
105    insertee: QueryNode<SchemaNode>,
106) -> Result<(), QueryNode<SchemaNode>> {
107    if let Some(component) = components.next() {
108        match *v {
109            SchemaNode::ValidNode(ValidNode::ObjectNode(ref mut object_node)) => {
110                let child_key = component.as_str_slice();
111
112                if let Some(ref mut child) = object_node.properties.get_mut(child_key) {
113                    insert(child, components, insertee)
114                } else {
115                    let mut child = SchemaNode::object().into();
116                    let () = insert(&mut child, components, insertee)
117                        .expect("Failed to insert into a newly created node");
118
119                    object_node.properties.insert(child_key.to_owned(), child);
120                    Ok(())
121                }
122            }
123            _ => Err(insertee),
124        }
125    } else {
126        *v = insertee.schema;
127        Ok(())
128    }
129}