From 2b45a7559ff44260c6dd693e4cb61f54ae5efc53 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 | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/path.rs b/src/path.rs index 06082e1b2..719d42e33 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,62 @@ 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]) { + // if they have a clear ordering, return this ordering + Ordering::Less => Ordering::Less, + // if they have a clear ordering, return this ordering + Ordering::Greater => Ordering::Greater, + // If one is a prefix of the other, the longest on is the first + Ordering::Equal => other.len().cmp(&this.len()), + } + } +} + /// Iterator over the ancestors of a Path /// /// See documentation for [`Path::ancestors`][]