Skip to content

Commit b122a1a

Browse files
authored
ResourceDef::join (#380)
1 parent 4303058 commit b122a1a

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

actix-router/CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Changes
22

33
## Unreleased - 2021-xx-xx
4+
* Introduce `ResourceDef::join`. [#380]
5+
6+
[#380]: https://github.com/actix/actix-net/pull/380
47

58

69
## 0.5.0-beta.1 - 2021-07-20

actix-router/src/resource.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,29 @@ impl ResourceDef {
525525
}
526526
}
527527

528+
/// Joins two resources.
529+
///
530+
/// Resulting resource is prefix if `other` is prefix.
531+
///
532+
/// # Examples
533+
/// ```
534+
/// # use actix_router::ResourceDef;
535+
/// let joined = ResourceDef::prefix("/root").join(&ResourceDef::prefix("/seg"));
536+
/// assert_eq!(joined, ResourceDef::prefix("/root/seg"));
537+
/// ```
538+
pub fn join(&self, other: &ResourceDef) -> ResourceDef {
539+
let patterns = self
540+
.pattern_iter()
541+
.flat_map(move |this| other.pattern_iter().map(move |other| (this, other)))
542+
.map(|(this, other)| [this, other].join(""))
543+
.collect::<Vec<_>>();
544+
545+
match patterns.len() {
546+
1 => ResourceDef::from_single_pattern(&patterns[0], other.is_prefix()),
547+
_ => ResourceDef::new(patterns),
548+
}
549+
}
550+
528551
/// Returns `true` if `path` matches this resource.
529552
///
530553
/// The behavior of this method depends on how the `ResourceDef` was constructed. For example,
@@ -1636,6 +1659,51 @@ mod tests {
16361659
assert_eq!(re.find_match("/abc/def"), result);
16371660
}
16381661

1662+
#[test]
1663+
fn join() {
1664+
// test joined defs match the same paths as each component separately
1665+
1666+
fn seq_find_match(re1: &ResourceDef, re2: &ResourceDef, path: &str) -> Option<usize> {
1667+
let len1 = re1.find_match(path)?;
1668+
let len2 = re2.find_match(&path[len1..])?;
1669+
Some(len1 + len2)
1670+
}
1671+
1672+
macro_rules! join_test {
1673+
($pat1:expr, $pat2:expr => $($test:expr),+) => {{
1674+
let pat1 = $pat1;
1675+
let pat2 = $pat2;
1676+
$({
1677+
let _path = $test;
1678+
let (re1, re2) = (ResourceDef::prefix(pat1), ResourceDef::new(pat2));
1679+
let _seq = seq_find_match(&re1, &re2, _path);
1680+
let _join = re1.join(&re2).find_match(_path);
1681+
assert_eq!(
1682+
_seq, _join,
1683+
"patterns: prefix {:?}, {:?}; mismatch on \"{}\"; seq={:?}; join={:?}",
1684+
pat1, pat2, _path, _seq, _join
1685+
);
1686+
assert!(!re1.join(&re2).is_prefix());
1687+
1688+
let (re1, re2) = (ResourceDef::prefix(pat1), ResourceDef::prefix(pat2));
1689+
let _seq = seq_find_match(&re1, &re2, _path);
1690+
let _join = re1.join(&re2).find_match(_path);
1691+
assert_eq!(
1692+
_seq, _join,
1693+
"patterns: prefix {:?}, prefix {:?}; mismatch on \"{}\"; seq={:?}; join={:?}",
1694+
pat1, pat2, _path, _seq, _join
1695+
);
1696+
assert!(re1.join(&re2).is_prefix());
1697+
})+
1698+
}}
1699+
}
1700+
1701+
join_test!("", "" => "", "/hello", "/");
1702+
join_test!("/user", "" => "", "/user", "/user/123", "/user11", "user", "user/123");
1703+
join_test!("", "/user"=> "", "/user", "foo", "/user11", "user", "user/123");
1704+
join_test!("/user", "/xx"=> "", "", "/", "/user", "/xx", "/userxx", "/user/xx");
1705+
}
1706+
16391707
#[test]
16401708
fn match_methods_agree() {
16411709
macro_rules! match_methods_agree {

0 commit comments

Comments
 (0)