diff --git a/packages/cargo/goodrouter/src/route_node.rs b/packages/cargo/goodrouter/src/route_node.rs index ed1c07b..e39dbef 100644 --- a/packages/cargo/goodrouter/src/route_node.rs +++ b/packages/cargo/goodrouter/src/route_node.rs @@ -1,8 +1,8 @@ -pub mod route_node_merge; -pub mod route_node_rc; -pub mod route_node_utility; +mod functions; +mod merge; +mod traits; -use std::{cell, cmp, collections::BTreeSet, rc}; +use std::{cell, collections::BTreeSet, rc}; #[derive(Debug)] pub struct RouteNodeRc<'r, K>(pub rc::Rc>>); @@ -25,151 +25,3 @@ pub struct RouteNode<'r, K> { // parent node, should only be null for the root node parent: Option>, } - -impl<'r, K> TryFrom<&RouteNodeWeak<'r, K>> for RouteNodeRc<'r, K> { - type Error = (); - - fn try_from(value: &RouteNodeWeak<'r, K>) -> Result { - Ok(Self(value.0.upgrade().ok_or(())?)) - } -} - -impl<'r, K> From> for RouteNodeRc<'r, K> { - fn from(value: RouteNode<'r, K>) -> Self { - Self(rc::Rc::new(cell::RefCell::new(value))) - } -} - -impl<'r, K> From<&RouteNodeRc<'r, K>> for RouteNodeWeak<'r, K> { - fn from(value: &RouteNodeRc<'r, K>) -> Self { - Self(rc::Rc::downgrade(&value.0)) - } -} - -impl<'r, K> Ord for RouteNode<'r, K> { - fn cmp(&self, other: &Self) -> cmp::Ordering { - if self.anchor.len() < other.anchor.len() { - return cmp::Ordering::Greater; - } - if self.anchor.len() > other.anchor.len() { - return cmp::Ordering::Less; - } - - if !self.has_parameter && other.has_parameter { - return cmp::Ordering::Less; - } - if self.has_parameter && !other.has_parameter { - return cmp::Ordering::Greater; - } - - if self.anchor < other.anchor { - return cmp::Ordering::Less; - } - if self.anchor > other.anchor { - return cmp::Ordering::Greater; - } - - cmp::Ordering::Equal - } -} - -impl<'r, K> PartialOrd for RouteNode<'r, K> { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl<'r, K> Ord for RouteNodeRc<'r, K> { - fn cmp(&self, other: &Self) -> cmp::Ordering { - self.0.cmp(&other.0) - } -} - -impl<'r, K> PartialOrd for RouteNodeRc<'r, K> { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl<'r, K> Eq for RouteNode<'r, K> {} - -impl<'r, K> PartialEq for RouteNode<'r, K> { - fn eq(&self, other: &Self) -> bool { - self.anchor == other.anchor && self.has_parameter == other.has_parameter - } -} - -impl<'r, K> Eq for RouteNodeRc<'r, K> {} - -impl<'r, K> PartialEq for RouteNodeRc<'r, K> { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} - -impl<'r, K> Default for RouteNode<'r, K> { - fn default() -> Self { - Self { - route_key: None, - route_parameter_names: Default::default(), - anchor: Default::default(), - has_parameter: Default::default(), - children: Default::default(), - parent: Default::default(), - } - } -} - -impl<'r, K> Default for RouteNodeRc<'r, K> { - fn default() -> Self { - Self(Default::default()) - } -} - -impl<'r, K> Clone for RouteNodeRc<'r, K> { - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use itertools::Itertools; - use std::iter::FromIterator; - - #[test] - fn route_ordering() { - let nodes = vec![ - RouteNode { - route_key: None, - has_parameter: false, - anchor: "aa", - ..Default::default() - }, - RouteNode { - route_key: Some(&1), - has_parameter: false, - anchor: "xx", - ..Default::default() - }, - RouteNode { - route_key: None, - has_parameter: true, - anchor: "aa", - ..Default::default() - }, - RouteNode { - route_key: None, - has_parameter: false, - anchor: "x", - ..Default::default() - }, - ]; - - let nodes_expected = nodes.iter(); - let nodes_actual = nodes.iter().sorted(); - - assert_eq!(Vec::from_iter(nodes_actual), Vec::from_iter(nodes_expected)); - } -} diff --git a/packages/cargo/goodrouter/src/route_node/route_node_rc.rs b/packages/cargo/goodrouter/src/route_node/functions.rs similarity index 86% rename from packages/cargo/goodrouter/src/route_node/route_node_rc.rs rename to packages/cargo/goodrouter/src/route_node/functions.rs index 42c5dea..e858154 100644 --- a/packages/cargo/goodrouter/src/route_node/route_node_rc.rs +++ b/packages/cargo/goodrouter/src/route_node/functions.rs @@ -1,5 +1,5 @@ -use super::route_node_merge::*; use super::*; +use crate::string_utility::find_common_prefix_length; use crate::template::template_pairs::parse_template_pairs; use regex::Regex; use std::borrow::Cow; @@ -145,8 +145,7 @@ impl<'r, K> RouteNodeRc<'r, K> { .borrow() .find_similar_child(anchor, has_parameter); - node_current_rc = route_node_merge( - &node_current_rc, + node_current_rc = node_current_rc.merge( child_node_rc.as_ref(), anchor, has_parameter, @@ -160,6 +159,34 @@ impl<'r, K> RouteNodeRc<'r, K> { } } +impl<'r, K> RouteNode<'r, K> { + pub fn find_similar_child( + &self, + anchor: &'r str, + has_parameter: bool, + ) -> (usize, Option>) { + let anchor_chars: Vec<_> = anchor.chars().collect(); + + for child_node_rc in self.children.iter() { + if child_node_rc.0.borrow().has_parameter != has_parameter { + continue; + } + + let child_anchor_chars: Vec<_> = child_node_rc.0.borrow().anchor.chars().collect(); + + let common_prefix_length = find_common_prefix_length(&anchor_chars, &child_anchor_chars); + + if common_prefix_length == 0 { + continue; + } + + return (common_prefix_length, Some(child_node_rc.clone())); + } + + Default::default() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/packages/cargo/goodrouter/src/route_node/route_node_merge.rs b/packages/cargo/goodrouter/src/route_node/merge.rs similarity index 76% rename from packages/cargo/goodrouter/src/route_node/route_node_merge.rs rename to packages/cargo/goodrouter/src/route_node/merge.rs index 2e2e6c3..fbddc30 100644 --- a/packages/cargo/goodrouter/src/route_node/route_node_merge.rs +++ b/packages/cargo/goodrouter/src/route_node/merge.rs @@ -1,59 +1,61 @@ use super::*; -pub fn route_node_merge<'r, K>( - parent_node_rc: &RouteNodeRc<'r, K>, - child_node_rc: Option<&RouteNodeRc<'r, K>>, - anchor: &'r str, - has_parameter: bool, - route_key: Option, - route_parameter_names: Vec<&'r str>, - common_prefix_length: usize, -) -> RouteNodeRc<'r, K> { - if let Some(child_node_rc) = child_node_rc { - let common_prefix = &anchor[..common_prefix_length]; - let child_anchor = child_node_rc.0.borrow().anchor; - - if child_anchor == anchor { - return route_node_merge_join(child_node_rc, route_key, route_parameter_names.clone()); - } else if child_anchor == common_prefix { - return route_node_merge_add_to_child( - parent_node_rc, - child_node_rc, - anchor, - has_parameter, - route_key, - route_parameter_names.clone(), - common_prefix_length, - ); - } else if anchor == common_prefix { - return route_node_merge_add_to_new( - parent_node_rc, - child_node_rc, - anchor, - has_parameter, - route_key, - route_parameter_names.clone(), - common_prefix_length, - ); +impl<'r, K> RouteNodeRc<'r, K> { + pub fn merge( + &self, + child_node_rc: Option<&RouteNodeRc<'r, K>>, + anchor: &'r str, + has_parameter: bool, + route_key: Option, + route_parameter_names: Vec<&'r str>, + common_prefix_length: usize, + ) -> RouteNodeRc<'r, K> { + if let Some(child_node_rc) = child_node_rc { + let common_prefix = &anchor[..common_prefix_length]; + let child_anchor = child_node_rc.0.borrow().anchor; + + if child_anchor == anchor { + return route_node_merge_join(child_node_rc, route_key, route_parameter_names.clone()); + } else if child_anchor == common_prefix { + return route_node_merge_add_to_child( + self, + child_node_rc, + anchor, + has_parameter, + route_key, + route_parameter_names.clone(), + common_prefix_length, + ); + } else if anchor == common_prefix { + return route_node_merge_add_to_new( + self, + child_node_rc, + anchor, + has_parameter, + route_key, + route_parameter_names.clone(), + common_prefix_length, + ); + } else { + return route_node_merge_intermediate( + self, + child_node_rc, + anchor, + has_parameter, + route_key, + route_parameter_names.clone(), + common_prefix_length, + ); + } } else { - return route_node_merge_intermediate( - parent_node_rc, - child_node_rc, + return route_node_merge_new( + self, anchor, has_parameter, route_key, route_parameter_names.clone(), - common_prefix_length, ); } - } else { - return route_node_merge_new( - parent_node_rc, - anchor, - has_parameter, - route_key, - route_parameter_names.clone(), - ); } } @@ -182,8 +184,7 @@ fn route_node_merge_add_to_child<'r, K>( .borrow() .find_similar_child(anchor, has_parameter); - return route_node_merge( - child_node_rc, + return child_node_rc.merge( child_node_rc_similar.as_ref(), anchor, has_parameter, diff --git a/packages/cargo/goodrouter/src/route_node/route_node_utility.rs b/packages/cargo/goodrouter/src/route_node/route_node_utility.rs deleted file mode 100644 index 22f9c3f..0000000 --- a/packages/cargo/goodrouter/src/route_node/route_node_utility.rs +++ /dev/null @@ -1,30 +0,0 @@ -use super::*; -use crate::string_utility::find_common_prefix_length; - -impl<'r, K> RouteNode<'r, K> { - pub fn find_similar_child( - &self, - anchor: &'r str, - has_parameter: bool, - ) -> (usize, Option>) { - let anchor_chars: Vec<_> = anchor.chars().collect(); - - for child_node_rc in self.children.iter() { - if child_node_rc.0.borrow().has_parameter != has_parameter { - continue; - } - - let child_anchor_chars: Vec<_> = child_node_rc.0.borrow().anchor.chars().collect(); - - let common_prefix_length = find_common_prefix_length(&anchor_chars, &child_anchor_chars); - - if common_prefix_length == 0 { - continue; - } - - return (common_prefix_length, Some(child_node_rc.clone())); - } - - Default::default() - } -} diff --git a/packages/cargo/goodrouter/src/route_node/traits.rs b/packages/cargo/goodrouter/src/route_node/traits.rs new file mode 100644 index 0000000..3d65ad2 --- /dev/null +++ b/packages/cargo/goodrouter/src/route_node/traits.rs @@ -0,0 +1,150 @@ +use super::*; +use std::{cell, cmp, rc}; + +impl<'r, K> TryFrom<&RouteNodeWeak<'r, K>> for RouteNodeRc<'r, K> { + type Error = (); + + fn try_from(value: &RouteNodeWeak<'r, K>) -> Result { + Ok(Self(value.0.upgrade().ok_or(())?)) + } +} + +impl<'r, K> From> for RouteNodeRc<'r, K> { + fn from(value: RouteNode<'r, K>) -> Self { + Self(rc::Rc::new(cell::RefCell::new(value))) + } +} + +impl<'r, K> From<&RouteNodeRc<'r, K>> for RouteNodeWeak<'r, K> { + fn from(value: &RouteNodeRc<'r, K>) -> Self { + Self(rc::Rc::downgrade(&value.0)) + } +} + +impl<'r, K> Ord for RouteNode<'r, K> { + fn cmp(&self, other: &Self) -> cmp::Ordering { + if self.anchor.len() < other.anchor.len() { + return cmp::Ordering::Greater; + } + if self.anchor.len() > other.anchor.len() { + return cmp::Ordering::Less; + } + + if !self.has_parameter && other.has_parameter { + return cmp::Ordering::Less; + } + if self.has_parameter && !other.has_parameter { + return cmp::Ordering::Greater; + } + + if self.anchor < other.anchor { + return cmp::Ordering::Less; + } + if self.anchor > other.anchor { + return cmp::Ordering::Greater; + } + + cmp::Ordering::Equal + } +} + +impl<'r, K> PartialOrd for RouteNode<'r, K> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl<'r, K> Ord for RouteNodeRc<'r, K> { + fn cmp(&self, other: &Self) -> cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl<'r, K> PartialOrd for RouteNodeRc<'r, K> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl<'r, K> Eq for RouteNode<'r, K> {} + +impl<'r, K> PartialEq for RouteNode<'r, K> { + fn eq(&self, other: &Self) -> bool { + self.anchor == other.anchor && self.has_parameter == other.has_parameter + } +} + +impl<'r, K> Eq for RouteNodeRc<'r, K> {} + +impl<'r, K> PartialEq for RouteNodeRc<'r, K> { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl<'r, K> Default for RouteNode<'r, K> { + fn default() -> Self { + Self { + route_key: None, + route_parameter_names: Default::default(), + anchor: Default::default(), + has_parameter: Default::default(), + children: Default::default(), + parent: Default::default(), + } + } +} + +impl<'r, K> Default for RouteNodeRc<'r, K> { + fn default() -> Self { + Self(Default::default()) + } +} + +impl<'r, K> Clone for RouteNodeRc<'r, K> { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use itertools::Itertools; + use std::iter::FromIterator; + + #[test] + fn route_ordering() { + let nodes = vec![ + RouteNode { + route_key: None, + has_parameter: false, + anchor: "aa", + ..Default::default() + }, + RouteNode { + route_key: Some(&1), + has_parameter: false, + anchor: "xx", + ..Default::default() + }, + RouteNode { + route_key: None, + has_parameter: true, + anchor: "aa", + ..Default::default() + }, + RouteNode { + route_key: None, + has_parameter: false, + anchor: "x", + ..Default::default() + }, + ]; + + let nodes_expected = nodes.iter(); + let nodes_actual = nodes.iter().sorted(); + + assert_eq!(Vec::from_iter(nodes_actual), Vec::from_iter(nodes_expected)); + } +}