diff --git a/apt-pkg-c/lib.cpp b/apt-pkg-c/lib.cpp index 77182c2..dedcf4e 100644 --- a/apt-pkg-c/lib.cpp +++ b/apt-pkg-c/lib.cpp @@ -3,8 +3,9 @@ #include -#include #include +#include +#include struct PCache { // Owned by us. @@ -48,6 +49,8 @@ extern "C" { PCache *pkg_cache_create(); + int32_t pkg_cache_compare_versions(PCache *cache, const char *left, const char *right); + // pkg_iter creation and deletion PPkgIterator *pkg_cache_pkg_iter(PCache *cache); PPkgIterator *pkg_cache_find_name(PCache *cache, const char *name); @@ -137,6 +140,11 @@ void pkg_cache_release(PCache *cache) { delete cache; } +int32_t pkg_cache_compare_versions(PCache *cache, const char *left, const char *right) { + // an int is returned here; presumably it will always be -1, 0 or 1. + return cache->cache->VS->DoCmpVersion(left, left+strlen(left), right, right+strlen(right)); +} + PPkgIterator *pkg_cache_pkg_iter(PCache *cache) { PPkgIterator *wrapper = new PPkgIterator(); wrapper->iterator = cache->cache->PkgBegin(); diff --git a/src/lib.rs b/src/lib.rs index 4ff621d..28a2068 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,4 +74,13 @@ mod tests { ); } + + #[test] + fn compare_versions() { + use std::cmp::Ordering; + let cache = Cache::get_singleton(); + assert_eq!(Ordering::Less, cache.compare_versions("3.0", "3.1")); + assert_eq!(Ordering::Greater, cache.compare_versions("3.1", "3.0")); + assert_eq!(Ordering::Equal, cache.compare_versions("3.0", "3.0")); + } } diff --git a/src/raw.rs b/src/raw.rs index 1b2a82e..d413fb5 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -19,6 +19,7 @@ extern "C" { fn init_config_system(); fn pkg_cache_create() -> PCache; + pub fn pkg_cache_compare_versions(cache: PCache, left: *const c_char, right: *const c_char) -> i32; // Package iterators // ================= diff --git a/src/sane.rs b/src/sane.rs index f3cdfd5..ea2a77f 100644 --- a/src/sane.rs +++ b/src/sane.rs @@ -1,3 +1,4 @@ +use std::cmp; use std::marker::PhantomData; use std::ffi; @@ -52,6 +53,29 @@ impl Cache { PkgIterator::new(self, ptr) } } + + /// Compare two versions, returning an `Ordering`, as used by most Rusty `sort()` methods. + /// + /// This uses the "versioning scheme" currently set, which, in theory, can change, + /// but in practice is always the "Standard .deb" scheme. As of 2017, there aren't even any + /// other implementations. As such, this may eventually become a static method somewhere. + /// + /// # Examples + /// + /// ```rust + /// # let mut cache = apt_pkg_native::Cache::get_singleton(); + /// let mut packages = vec!["3.0", "3.1", "3.0~1"]; + /// packages.sort_by(|left, right| cache.compare_versions(left, right)); + /// assert_eq!(vec!["3.0~1", "3.0", "3.1"], packages); + /// ``` + pub fn compare_versions(&self, left: &str, right: &str) -> cmp::Ordering { + unsafe { + let left = ffi::CString::new(left).unwrap(); + let right = ffi::CString::new(right).unwrap(); + + raw::pkg_cache_compare_versions(self.ptr, left.as_ptr(), right.as_ptr()).cmp(&0) + } + } } /// An "iterator"/pointer to a point in a package list.