diff options
author | Melody Horn <melody@boringcactus.com> | 2022-03-27 16:45:40 -0600 |
---|---|---|
committer | Melody Horn <melody@boringcactus.com> | 2022-03-27 16:45:40 -0600 |
commit | bb4738da611b46504176ae4dad3670be4e3b034e (patch) | |
tree | e41c245a356b1ce076f96948e55eb3bee0df805e /src | |
parent | 4a8a749233c8142417c0c541a7be27d8db5ab4e9 (diff) | |
download | kdl-schema-bb4738da611b46504176ae4dad3670be4e3b034e.tar.gz kdl-schema-bb4738da611b46504176ae4dad3670be4e3b034e.zip |
add API to resolve refs
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 146 |
1 files changed, 146 insertions, 0 deletions
@@ -11,6 +11,12 @@ pub trait BuildFromRef { fn ref_to(query: impl Into<String>) -> Self; } +fn get_id_from_ref(r#ref: &str) -> Option<&str> { + r#ref + .strip_prefix(r#"[id=""#) + .and_then(|r#ref| r#ref.strip_suffix(r#""]"#)) +} + #[derive(Debug, PartialEq, Eq, Default)] #[cfg_attr(feature = "parse-knuffel", derive(Decode))] pub struct Schema { @@ -18,6 +24,48 @@ pub struct Schema { pub document: Document, } +impl Schema { + /// Panics if ref is not of the form `[id="foo"]`. + pub fn resolve_node_ref(&self, r#ref: &str) -> Option<&Node> { + let id = get_id_from_ref(r#ref).expect("invalid ref"); + self.document + .nodes + .iter() + .filter_map(|node| node.find_node_by_id(id)) + .next() + } + + /// Panics if ref is not of the form `[id="foo"]`. + pub fn resolve_prop_ref(&self, r#ref: &str) -> Option<&Prop> { + let id = get_id_from_ref(r#ref).expect("invalid ref"); + self.document + .nodes + .iter() + .filter_map(|node| node.find_prop_by_id(id)) + .next() + } + + /// Panics if ref is not of the form `[id="foo"]`. + pub fn resolve_value_ref(&self, r#ref: &str) -> Option<&Value> { + let id = get_id_from_ref(r#ref).expect("invalid ref"); + self.document + .nodes + .iter() + .filter_map(|node| node.find_value_by_id(id)) + .next() + } + + /// Panics if ref is not of the form `[id="foo"]`. + pub fn resolve_children_ref(&self, r#ref: &str) -> Option<&Children> { + let id = get_id_from_ref(r#ref).expect("invalid ref"); + self.document + .nodes + .iter() + .filter_map(|node| node.find_children_by_id(id)) + .next() + } +} + #[cfg(feature = "parse-knuffel")] impl Schema { pub fn parse( @@ -131,6 +179,50 @@ pub struct Node { pub children: Vec<Children>, } +impl Node { + fn find_node_by_id(&self, id: &str) -> Option<&Node> { + if self.id.as_deref() == Some(id) { + Some(self) + } else { + self.children + .iter() + .filter_map(|children| children.find_node_by_id(id)) + .next() + } + } + + fn find_prop_by_id(&self, id: &str) -> Option<&Prop> { + self.props + .iter() + .filter_map(|prop| prop.find_prop_by_id(id)) + .chain( + self.children + .iter() + .filter_map(|children| children.find_prop_by_id(id)), + ) + .next() + } + + fn find_value_by_id(&self, id: &str) -> Option<&Value> { + self.values + .iter() + .filter_map(|value| value.find_value_by_id(id)) + .chain( + self.children + .iter() + .filter_map(|children| children.find_value_by_id(id)), + ) + .next() + } + + fn find_children_by_id(&self, id: &str) -> Option<&Children> { + self.children + .iter() + .filter_map(|children| children.find_children_by_id(id)) + .next() + } +} + impl BuildFromRef for Node { fn ref_to(query: impl Into<String>) -> Self { Self { @@ -157,6 +249,16 @@ pub struct Prop { pub validations: Vec<Validation>, } +impl Prop { + fn find_prop_by_id(&self, id: &str) -> Option<&Prop> { + if self.id.as_deref() == Some(id) { + Some(self) + } else { + None + } + } +} + impl BuildFromRef for Prop { fn ref_to(query: impl Into<String>) -> Self { Self { @@ -183,6 +285,16 @@ pub struct Value { pub validations: Vec<Validation>, } +impl Value { + fn find_value_by_id(&self, id: &str) -> Option<&Value> { + if self.id.as_deref() == Some(id) { + Some(self) + } else { + None + } + } +} + impl BuildFromRef for Value { fn ref_to(query: impl Into<String>) -> Self { Self { @@ -205,6 +317,40 @@ pub struct Children { pub nodes: Vec<Node>, } +impl Children { + fn find_node_by_id(&self, id: &str) -> Option<&Node> { + self.nodes + .iter() + .filter_map(|node| node.find_node_by_id(id)) + .next() + } + + fn find_prop_by_id(&self, id: &str) -> Option<&Prop> { + self.nodes + .iter() + .filter_map(|node| node.find_prop_by_id(id)) + .next() + } + + fn find_value_by_id(&self, id: &str) -> Option<&Value> { + self.nodes + .iter() + .filter_map(|node| node.find_value_by_id(id)) + .next() + } + + fn find_children_by_id(&self, id: &str) -> Option<&Children> { + if self.id.as_deref() == Some(id) { + Some(self) + } else { + self.nodes + .iter() + .filter_map(|node| node.find_children_by_id(id)) + .next() + } + } +} + impl BuildFromRef for Children { fn ref_to(query: impl Into<String>) -> Self { Self { |