From fcbdf2137302145e6cc8463565abf7248e4bfe00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 31 Jan 2024 17:34:59 +0100 Subject: [PATCH] Path: Add ordering comparison functions The ordering of path (as obtained when iterating over a directory) in Littlefs is not exactly what is expected. This implementation contains 2 comparision functions, one matching what is expected, and one matching the iteration order of littlefs directories, as described in https://github.com/littlefs-project/littlefs/issues/923 The fact that directories are ordered is documented: https://github.com/littlefs-project/littlefs/blob/f53a0cc961a8acac85f868b431d2f3e58e447ba3/SPEC.md?plain=1#L304 --- src/path.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/path.rs b/src/path.rs index 06082e1b2..21c1defff 100644 --- a/src/path.rs +++ b/src/path.rs @@ -1,6 +1,9 @@ //! Paths -use core::{convert::TryFrom, fmt, iter::FusedIterator, marker::PhantomData, ops, ptr, slice, str}; +use core::{ + cmp::Ordering, convert::TryFrom, fmt, iter::FusedIterator, marker::PhantomData, ops, ptr, + slice, str, +}; use cstr_core::CStr; use cty::{c_char, size_t}; @@ -20,6 +23,66 @@ pub struct Path { inner: CStr, } +impl Path { + /// Compare the path using their string representation + /// This comarison function as would be expected for a `String` type. + /// + ///
+ /// This ordering does not match the ordering obsvered when iterating over a directory. + /// + /// See cmp_lfs and littlefs#923. + ///
+ /// + /// ``` + ///# use std::cmp::Ordering; + ///# use littlefs2::path; + /// assert_eq!(path!("some_path_a").cmp_str(path!("some_path_b")), Ordering::Less); + /// assert_eq!(path!("some_path_b").cmp_str(path!("some_path_a")), Ordering::Greater); + /// assert_eq!(path!("some_path").cmp_str(path!("some_path_a")), Ordering::Less); + /// assert_eq!(path!("some_path").cmp_str(path!("some_path_b")), Ordering::Less); + /// assert_eq!(path!("some_path").cmp_str(path!("some_path")), Ordering::Equal); + ///``` + pub fn cmp_str(&self, other: &Path) -> Ordering { + self.inner.cmp(&other.inner) + } + + /// Compare the path using their string representation + /// + /// This comparison function matches the iteration order of `littlefs` when iterating over directory. + /// For more information, see [littlefs#923](https://github.com/littlefs-project/littlefs/issues/923) + /// + /// ``` + ///# use std::cmp::Ordering; + ///# use littlefs2::path; + /// assert_eq!(path!("some_path_a").cmp_lfs(path!("some_path_b")), Ordering::Less); + /// assert_eq!(path!("some_path_b").cmp_lfs(path!("some_path_a")), Ordering::Greater); + /// assert_eq!(path!("some_path").cmp_lfs(path!("some_path_a")), Ordering::Greater); + /// assert_eq!(path!("some_path").cmp_lfs(path!("some_path_b")), Ordering::Greater); + /// assert_eq!(path!("some_path_a").cmp_lfs(path!("some_path")), Ordering::Less); + /// assert_eq!(path!("some_path_b").cmp_lfs(path!("some_path")), Ordering::Less); + /// assert_eq!(path!("some_path").cmp_lfs(path!("some_path")), Ordering::Equal); + ///``` + pub fn cmp_lfs(&self, other: &Path) -> Ordering { + let this = self.inner.to_bytes(); + let other = other.inner.to_bytes(); + + let min_len = this.len().min(other.len()); + + match this[0..min_len].cmp(&other[0..min_len]) { + Ordering::Less => Ordering::Less, + Ordering::Greater => Ordering::Greater, + Ordering::Equal if this.len() != other.len() => { + if this.len() < other.len() { + Ordering::Greater + } else { + Ordering::Less + } + } + Ordering::Equal => Ordering::Equal, + } + } +} + /// Iterator over the ancestors of a Path /// /// See documentation for [`Path::ancestors`][] @@ -587,6 +650,8 @@ pub type Result = core::result::Result; #[cfg(test)] mod tests { + use core::cmp::Ordering; + use super::{Path, PathBuf}; use crate::path;