From 8c525dcc2d444d8561dad2ee12dc9afb334ea709 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Mon, 14 Apr 2025 15:09:00 +0200 Subject: [PATCH] feat(snix/castore/PathComponent): add extension() method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This returns the file extension. Change-Id: I488cbadbce027a37d53cee808bcf7a95283ed07d Reviewed-on: https://cl.snix.dev/c/snix/+/30319 Tested-by: besadii Reviewed-by: Domen Kožar Reviewed-by: Stefan Junker --- snix/castore/src/path/component.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/snix/castore/src/path/component.rs b/snix/castore/src/path/component.rs index 78aca03c5..7ed8409cd 100644 --- a/snix/castore/src/path/component.rs +++ b/snix/castore/src/path/component.rs @@ -12,6 +12,18 @@ pub struct PathComponent { pub(super) inner: bytes::Bytes, } +impl PathComponent { + /// Extracts the extension (without leading dot) of a [PathComponent], if possible. + pub fn extension(&self) -> Option<&[u8]> { + let mut iter = self.inner[..].rsplitn(2, |b| *b == b'.'); + let e = iter.next(); + // Return None if there's no dot. + iter.next()?; + + e + } +} + /// The maximum length an individual path component can have. /// Linux allows 255 bytes of actual name, so we pick that. pub const MAX_NAME_LEN: usize = 255; @@ -212,6 +224,15 @@ mod tests { } } + #[rstest] + #[case::without_dot(PathComponent { inner: "foo".into()}, None)] + #[case::simple(PathComponent { inner: "foo.txt".into()}, Some(&b"txt"[..]))] + #[case::empty(PathComponent { inner: "foo.".into()}, Some(&b""[..]))] + #[case::multiple(PathComponent { inner: "foo.bar.txt".into()}, Some(&b"txt"[..]))] + fn extension(#[case] p: PathComponent, #[case] exp_extension: Option<&[u8]>) { + assert_eq!(exp_extension, p.extension()) + } + #[test] fn error_toolong() { assert_eq!(