From d05ea53b0b08c6c81cf075743ea98048b0ff3089 Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Sat, 24 Sep 2022 14:10:58 +0800 Subject: [PATCH 1/8] chore: allow empty str --- src/lib.rs | 17 ++++++++++++++--- src/node.rs | 14 +++++++------- tests/tree.rs | 10 ++++++++++ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3432952..02b4fab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -168,11 +168,21 @@ impl PathTree { } pub fn insert(&mut self, path: &str, value: T) -> usize { + let mut node = &mut self.node; + if path.is_empty() { - return self.id; + return if let Some(id) = node.value { + self.routes[id].0 = value; + id + } else { + self.routes.push((value, Vec::new())); + let id = self.id; + node.value = Some(id); + self.id += 1; + id + }; } - let mut node = &mut self.node; let pieces = Parser::new(path).collect::>(); for piece in &pieces { @@ -186,10 +196,11 @@ impl PathTree { } } - self.routes.push((value, pieces)); if let Some(id) = node.value { + self.routes[id] = (value, pieces); id } else { + self.routes.push((value, pieces)); let id = self.id; node.value = Some(id); self.id += 1; diff --git a/src/node.rs b/src/node.rs index 6d38d41..36ebabf 100644 --- a/src/node.rs +++ b/src/node.rs @@ -35,13 +35,13 @@ impl Node { pub fn insert_bytes(&mut self, mut bytes: &[u8]) -> &mut Self { let diff = match &mut self.kind { - NodeKind::String(p) => { - if p.is_empty() { - *p = bytes.to_vec(); + NodeKind::String(s) => { + if s.is_empty() { + *s = bytes.to_vec(); return self; } - let cursor = p + let cursor = s .iter() .zip(bytes.iter()) .take_while(|(a, b)| a == b) @@ -51,10 +51,10 @@ impl Node { true } else { // split node - if cursor < p.len() { - let (prefix, suffix) = p.split_at(cursor); + if cursor < s.len() { + let (prefix, suffix) = s.split_at(cursor); let mut node = Node::new(NodeKind::String(prefix.to_vec()), None); - *p = suffix.to_vec(); + *s = suffix.to_vec(); ::std::mem::swap(self, &mut node); self.nodes0.get_or_insert_with(Vec::new).push(node); } diff --git a/tests/tree.rs b/tests/tree.rs index 8e0e55c..0cd42cd 100644 --- a/tests/tree.rs +++ b/tests/tree.rs @@ -1693,6 +1693,16 @@ fn basic() { assert_eq!(r.value, &0); assert_eq!(r.params(), vec![]); + tree.insert("", 14); + let r = tree.find("/").unwrap(); + assert_eq!(r.value, &14); + assert_eq!(r.params(), vec![]); + + tree.insert("/", 15); + let r = tree.find("/").unwrap(); + assert_eq!(r.value, &15); + assert_eq!(r.params(), vec![]); + let r = tree.find("/login").unwrap(); assert_eq!(r.value, &1); assert_eq!(r.params(), vec![]); From baf89db144fef5e0ca607668eace110f1d457ada Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Sat, 24 Sep 2022 14:26:12 +0800 Subject: [PATCH 2/8] chore(tree): dont replace pieces --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 02b4fab..0b75e1b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -197,7 +197,7 @@ impl PathTree { } if let Some(id) = node.value { - self.routes[id] = (value, pieces); + self.routes[id].0 = value; id } else { self.routes.push((value, pieces)); From 1545a591d1e716ec62bb0b344028eae67a9a6620 Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Sat, 24 Sep 2022 14:45:30 +0800 Subject: [PATCH 3/8] chore: clean --- src/lib.rs | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0b75e1b..825c34f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -170,31 +170,22 @@ impl PathTree { pub fn insert(&mut self, path: &str, value: T) -> usize { let mut node = &mut self.node; - if path.is_empty() { - return if let Some(id) = node.value { - self.routes[id].0 = value; - id - } else { - self.routes.push((value, Vec::new())); - let id = self.id; - node.value = Some(id); - self.id += 1; - id - }; - } - - let pieces = Parser::new(path).collect::>(); - - for piece in &pieces { - match piece { - Piece::String(s) => { - node = node.insert_bytes(&s[..]); - } - Piece::Parameter(_, k) => { - node = node.insert_parameter(*k); + let pieces = if path.is_empty() { + Vec::new() + } else { + let pieces = Parser::new(path).collect::>(); + for piece in &pieces { + match piece { + Piece::String(s) => { + node = node.insert_bytes(&s[..]); + } + Piece::Parameter(_, k) => { + node = node.insert_parameter(*k); + } } } - } + pieces + }; if let Some(id) = node.value { self.routes[id].0 = value; From 86212677771d4cc20c7a4928432a61fc7dc34f6f Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Sat, 24 Sep 2022 02:21:06 -0500 Subject: [PATCH 4/8] add failing tests --- tests/tree.rs | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/tests/tree.rs b/tests/tree.rs index 0cd42cd..1a68fca 100644 --- a/tests/tree.rs +++ b/tests/tree.rs @@ -3,7 +3,9 @@ use rand::seq::SliceRandom; #[test] fn statics() { - const ROUTES: [&str; 11] = [ + const ROUTES: [&str; 13] = [ + "", + "/", "/hi", "/contact", "/co", @@ -128,6 +130,34 @@ fn single_named_parameter() { } } + +#[test] +fn repeated_single_named_param() { + // Pattern: /users/:id + // + // /users/gordon match + // /users/you match + // /users/gordon/profile no match + // /users/ no match + let mut tree = PathTree::new(); + + tree.insert("/users/:id", 0); + tree.insert("/users/:user_id", 1); + + let r = tree.find("/users/gordon"); + let path = r.unwrap(); + match (path.value, path.params()) { + (0, params) => { + assert_eq!(params, vec![("id", "gordon")]) + }, + (1, params) => { + assert_eq!(params, vec![("user_id", "gordon")]) + }, + _ => panic!() + }; +} + + #[test] fn static_and_named_parameter() { // Pattern: /a/b/c From 7b27d16b6133d34711aaa3a1b5829ee8f92378ae Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Sat, 24 Sep 2022 02:21:18 -0500 Subject: [PATCH 5/8] fmt --- tests/tree.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/tree.rs b/tests/tree.rs index 1a68fca..42b9d21 100644 --- a/tests/tree.rs +++ b/tests/tree.rs @@ -130,7 +130,6 @@ fn single_named_parameter() { } } - #[test] fn repeated_single_named_param() { // Pattern: /users/:id @@ -149,15 +148,14 @@ fn repeated_single_named_param() { match (path.value, path.params()) { (0, params) => { assert_eq!(params, vec![("id", "gordon")]) - }, + } (1, params) => { assert_eq!(params, vec![("user_id", "gordon")]) - }, - _ => panic!() + } + _ => panic!(), }; } - #[test] fn static_and_named_parameter() { // Pattern: /a/b/c From a1f13c5979ddf15a815fb80dafadcbc8df4481c0 Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Sat, 24 Sep 2022 15:57:44 +0800 Subject: [PATCH 6/8] chore: name and value should be overwritten --- src/lib.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 825c34f..aa1c003 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -170,8 +170,8 @@ impl PathTree { pub fn insert(&mut self, path: &str, value: T) -> usize { let mut node = &mut self.node; - let pieces = if path.is_empty() { - Vec::new() + let (overwritten, pieces) = if path.is_empty() { + (false, Vec::new()) } else { let pieces = Parser::new(path).collect::>(); for piece in &pieces { @@ -184,11 +184,14 @@ impl PathTree { } } } - pieces + (true, pieces) }; if let Some(id) = node.value { self.routes[id].0 = value; + if overwritten { + self.routes[id].1 = pieces; + } id } else { self.routes.push((value, pieces)); From d60978b78302d0baa60d3aee79cd7276e8431e41 Mon Sep 17 00:00:00 2001 From: Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com> Date: Sat, 24 Sep 2022 03:13:25 -0500 Subject: [PATCH 7/8] simplify test --- tests/tree.rs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/tests/tree.rs b/tests/tree.rs index 42b9d21..373245c 100644 --- a/tests/tree.rs +++ b/tests/tree.rs @@ -132,12 +132,6 @@ fn single_named_parameter() { #[test] fn repeated_single_named_param() { - // Pattern: /users/:id - // - // /users/gordon match - // /users/you match - // /users/gordon/profile no match - // /users/ no match let mut tree = PathTree::new(); tree.insert("/users/:id", 0); @@ -145,15 +139,8 @@ fn repeated_single_named_param() { let r = tree.find("/users/gordon"); let path = r.unwrap(); - match (path.value, path.params()) { - (0, params) => { - assert_eq!(params, vec![("id", "gordon")]) - } - (1, params) => { - assert_eq!(params, vec![("user_id", "gordon")]) - } - _ => panic!(), - }; + assert_eq!(*path.value, 1); + assert_eq!(path.params(), vec![("user_id", "gordon")]); } #[test] From 1fc018c2e8355ea6b4a40db4f2d9ceef8c3127ec Mon Sep 17 00:00:00 2001 From: Fangdun Tsai Date: Sat, 24 Sep 2022 14:10:58 +0800 Subject: [PATCH 8/8] chore: allow insert empty str --- src/lib.rs | 33 +++++++++++++++++++-------------- src/node.rs | 14 +++++++------- tests/tree.rs | 10 ++++++++++ 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3432952..aa1c003 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -168,28 +168,33 @@ impl PathTree { } pub fn insert(&mut self, path: &str, value: T) -> usize { - if path.is_empty() { - return self.id; - } - let mut node = &mut self.node; - let pieces = Parser::new(path).collect::>(); - for piece in &pieces { - match piece { - Piece::String(s) => { - node = node.insert_bytes(&s[..]); - } - Piece::Parameter(_, k) => { - node = node.insert_parameter(*k); + let (overwritten, pieces) = if path.is_empty() { + (false, Vec::new()) + } else { + let pieces = Parser::new(path).collect::>(); + for piece in &pieces { + match piece { + Piece::String(s) => { + node = node.insert_bytes(&s[..]); + } + Piece::Parameter(_, k) => { + node = node.insert_parameter(*k); + } } } - } + (true, pieces) + }; - self.routes.push((value, pieces)); if let Some(id) = node.value { + self.routes[id].0 = value; + if overwritten { + self.routes[id].1 = pieces; + } id } else { + self.routes.push((value, pieces)); let id = self.id; node.value = Some(id); self.id += 1; diff --git a/src/node.rs b/src/node.rs index 6d38d41..36ebabf 100644 --- a/src/node.rs +++ b/src/node.rs @@ -35,13 +35,13 @@ impl Node { pub fn insert_bytes(&mut self, mut bytes: &[u8]) -> &mut Self { let diff = match &mut self.kind { - NodeKind::String(p) => { - if p.is_empty() { - *p = bytes.to_vec(); + NodeKind::String(s) => { + if s.is_empty() { + *s = bytes.to_vec(); return self; } - let cursor = p + let cursor = s .iter() .zip(bytes.iter()) .take_while(|(a, b)| a == b) @@ -51,10 +51,10 @@ impl Node { true } else { // split node - if cursor < p.len() { - let (prefix, suffix) = p.split_at(cursor); + if cursor < s.len() { + let (prefix, suffix) = s.split_at(cursor); let mut node = Node::new(NodeKind::String(prefix.to_vec()), None); - *p = suffix.to_vec(); + *s = suffix.to_vec(); ::std::mem::swap(self, &mut node); self.nodes0.get_or_insert_with(Vec::new).push(node); } diff --git a/tests/tree.rs b/tests/tree.rs index 8e0e55c..0cd42cd 100644 --- a/tests/tree.rs +++ b/tests/tree.rs @@ -1693,6 +1693,16 @@ fn basic() { assert_eq!(r.value, &0); assert_eq!(r.params(), vec![]); + tree.insert("", 14); + let r = tree.find("/").unwrap(); + assert_eq!(r.value, &14); + assert_eq!(r.params(), vec![]); + + tree.insert("/", 15); + let r = tree.find("/").unwrap(); + assert_eq!(r.value, &15); + assert_eq!(r.params(), vec![]); + let r = tree.find("/login").unwrap(); assert_eq!(r.value, &1); assert_eq!(r.params(), vec![]);