Skip to content

Commit

Permalink
Path: Add ordering comparison function
Browse files Browse the repository at this point in the history
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 littlefs-project/littlefs#923
  • Loading branch information
sosthene-nitrokey committed Feb 2, 2024
1 parent ebd27e4 commit d691b90
Showing 1 changed file with 122 additions and 1 deletion.
123 changes: 122 additions & 1 deletion src/path.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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.
///
/// <div class="warning">
/// This ordering does not match the ordering obsvered when iterating over a directory.
///
/// See <a href="#method.cmp_lfs">cmp_lfs</a> and <a href = "https://github.com/littlefs-project/littlefs/issues/923">littlefs#923</a>.
/// </div>
///
/// ```
///# 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`][]
Expand Down Expand Up @@ -589,6 +652,8 @@ pub type Result<T> = core::result::Result<T, Error>;

#[cfg(test)]
mod tests {
use core::cmp::Ordering;

use super::{Path, PathBuf};
use crate::path;

Expand Down Expand Up @@ -750,4 +815,60 @@ mod tests {
let path = path!("/some/path/.././file.extension/");
assert_eq!(path.file_name(), None);
}

#[test]
fn path_cmp_str() {
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
);
}

#[test]
fn path_cmp_lfs() {
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
);
}
}

0 comments on commit d691b90

Please sign in to comment.