aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMelody Horn <melody@boringcactus.com>2022-03-27 16:45:40 -0600
committerMelody Horn <melody@boringcactus.com>2022-03-27 16:45:40 -0600
commitbb4738da611b46504176ae4dad3670be4e3b034e (patch)
treee41c245a356b1ce076f96948e55eb3bee0df805e /src
parent4a8a749233c8142417c0c541a7be27d8db5ab4e9 (diff)
downloadkdl-schema-bb4738da611b46504176ae4dad3670be4e3b034e.tar.gz
kdl-schema-bb4738da611b46504176ae4dad3670be4e3b034e.zip
add API to resolve refs
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
index c724687..6b61dea 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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 {