Skip to content

Commit 7742c3b

Browse files
authored
Add Pointer::starts_with and Pointer::ends_with (#81)
* add starts_with and ends_with * update changelog
1 parent b423489 commit 7742c3b

File tree

2 files changed

+71
-4
lines changed

2 files changed

+71
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
- Adds method `into_buf` for `Box<Pointer>` and `impl From<PathBuf> for Box<Pointer>`.
1414
- Adds unsafe associated methods `Pointer::new_unchecked` and `PointerBuf::new_unchecked` for
1515
external zero-cost construction.
16+
- Adds `Pointer::starts_with` and `Pointer::ends_with` for prefix and suffix matching.
1617
- Adds new `ParseIndexError` variant to express the presence non-digit characters in the token.
1718
- Adds `Token::is_next` for checking if a token represents the `-` character.
1819

src/pointer.rs

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,26 @@ impl Pointer {
280280
.map(|s| unsafe { Self::new_unchecked(s) })
281281
}
282282

283-
/// Attempts to get a `Token` or a segment of the `Pointer`, depending on
284-
/// the type of index.
283+
/// Returns whether `self` has a suffix of `other`.
285284
///
286-
/// Returns `None` if the index is out of bounds.
285+
/// Note that `Pointer::root` is only a valid suffix of itself.
286+
pub fn ends_with(&self, other: &Self) -> bool {
287+
(self.is_root() && other.is_root())
288+
|| (!other.is_root() && self.as_str().ends_with(&other.0))
289+
}
290+
291+
/// Returns whether `self` has a prefix of `other.`
287292
///
288-
/// Note that this operation is O(n).
293+
/// Note that `Pointer::root` is a valid prefix of any `Pointer` (including
294+
/// itself).
295+
pub fn starts_with(&self, other: &Self) -> bool {
296+
self.as_str().starts_with(&other.0)
297+
// ensure we end at a token boundary
298+
&& (other.len() == self.len() || self.0.as_bytes()[other.len()] == b'/')
299+
}
300+
301+
/// Attempts to get a `Token` by the index. Returns `None` if the index is
302+
/// out of bounds.
289303
///
290304
/// ## Example
291305
/// ```rust
@@ -1372,6 +1386,58 @@ mod tests {
13721386
assert_eq!(stripped, "/to/some/value");
13731387
}
13741388

1389+
#[test]
1390+
fn ends_with() {
1391+
// positive cases
1392+
let p = Pointer::from_static("/foo/bar");
1393+
let q = Pointer::from_static("/bar");
1394+
assert!(p.ends_with(q));
1395+
let q = Pointer::from_static("/foo/bar");
1396+
assert!(p.ends_with(q));
1397+
1398+
// negative cases
1399+
let q = Pointer::from_static("/barz");
1400+
assert!(!p.ends_with(q));
1401+
let q = Pointer::from_static("/");
1402+
assert!(!p.ends_with(q));
1403+
let q = Pointer::from_static("");
1404+
assert!(!p.ends_with(q));
1405+
let q = Pointer::from_static("/qux/foo/bar");
1406+
assert!(!p.ends_with(q));
1407+
1408+
// edge case - both root
1409+
let p = Pointer::root();
1410+
let q = Pointer::root();
1411+
assert!(p.ends_with(q));
1412+
}
1413+
1414+
#[test]
1415+
fn starts_with() {
1416+
// positive cases
1417+
let p = Pointer::from_static("/foo/bar");
1418+
let q = Pointer::from_static("/foo");
1419+
assert!(p.starts_with(q));
1420+
let q = Pointer::from_static("/foo/bar");
1421+
assert!(p.starts_with(q));
1422+
1423+
// negative cases
1424+
let q = Pointer::from_static("/");
1425+
assert!(!p.starts_with(q));
1426+
let q = Pointer::from_static("/fo");
1427+
assert!(!p.starts_with(q));
1428+
let q = Pointer::from_static("/foo/");
1429+
assert!(!p.starts_with(q));
1430+
1431+
// edge cases: other is root
1432+
let p = Pointer::root();
1433+
let q = Pointer::root();
1434+
assert!(p.starts_with(q));
1435+
let p = Pointer::from_static("/");
1436+
assert!(p.starts_with(q));
1437+
let p = Pointer::from_static("/any/thing");
1438+
assert!(p.starts_with(q));
1439+
}
1440+
13751441
#[test]
13761442
fn parse_error_is_no_leading_backslash() {
13771443
let err = ParseError::NoLeadingBackslash;

0 commit comments

Comments
 (0)