More natural interface; no idea why it needs that annotation

This commit is contained in:
Chris West (Faux) 2017-07-13 11:03:31 +01:00
parent e3f5bd3633
commit e90ee73dc8
4 changed files with 151 additions and 7 deletions

View File

@ -29,7 +29,8 @@ extern "C" {
PPkgIterator *pkg_cache_pkg_iter(PCache *cache);
void pkg_iter_release(PPkgIterator *iterator);
bool pkg_iter_next(PPkgIterator *iterator);
void pkg_iter_next(PPkgIterator *iterator);
bool pkg_iter_end(PPkgIterator *iterator);
const char *pkg_iter_name(PPkgIterator *iterator);
@ -68,9 +69,12 @@ void pkg_iter_release(PPkgIterator *wrapper) {
delete wrapper;
}
bool pkg_iter_next(PPkgIterator *wrapper) {
void pkg_iter_next(PPkgIterator *wrapper) {
++wrapper->iterator;
return wrapper->cache->PkgEnd() != wrapper->iterator;
}
bool pkg_iter_end(PPkgIterator *wrapper) {
return wrapper->cache->PkgEnd() == wrapper->iterator;
}
const char *pkg_iter_name(PPkgIterator *wrapper) {

View File

@ -1,6 +1,7 @@
extern crate libc;
pub mod raw;
pub mod sane;
#[cfg(test)]
mod tests {
@ -19,7 +20,8 @@ mod tests {
let pretty = raw::pkg_iter_pretty(cache, iter);
println!("{}", CStr::from_ptr(pretty).to_str().expect("package names are always valid utf-8, in that they're always valid low ascii"));
libc::free(pretty as *mut libc::c_void);
if !raw::pkg_iter_next(iter) {
raw::pkg_iter_next(iter);
if raw::pkg_iter_end(iter) {
break;
}
}
@ -27,4 +29,12 @@ mod tests {
raw::pkg_cache_release(cache);
}
}
#[test]
fn list_all() {
let mut cache = sane::Cache::new();
for name in cache.iter().map(|item: &sane::PkgIterator| item.pretty_print()) {
println!("{}", name);
}
}
}

View File

@ -6,8 +6,8 @@
use libc::c_void;
use libc::c_char;
type PCache = *mut c_void;
type PPkgIterator = *mut c_void;
pub type PCache = *mut c_void;
pub type PPkgIterator = *mut c_void;
#[link(name = "apt-c")]
#[link(name = "apt-pkg")]
@ -19,7 +19,8 @@ extern {
pub fn pkg_cache_pkg_iter(cache: PCache) -> PPkgIterator;
pub fn pkg_iter_release(iterator: PPkgIterator);
pub fn pkg_iter_next(iterator: PPkgIterator) -> bool;
pub fn pkg_iter_next(iterator: PPkgIterator);
pub fn pkg_iter_end(iterator: PPkgIterator) -> bool;
pub fn pkg_iter_name(iterator: PPkgIterator) -> *const c_char;
pub fn pkg_iter_pretty(cache: PCache, iterator: PPkgIterator) -> *mut c_char;

129
src/sane.rs Normal file
View File

@ -0,0 +1,129 @@
use std::ffi;
use libc;
use raw;
// Probably not cloneable / copyable.
#[derive(Debug)]
pub struct Cache {
ptr: raw::PCache
}
impl Drop for Cache {
fn drop(&mut self) {
unsafe {
raw::pkg_cache_release(self.ptr)
}
}
}
impl Cache {
pub fn new() -> Cache {
Cache {
ptr: unsafe { raw::pkg_cache_create() }
}
}
pub fn iter(&mut self) -> PkgIterator {
unsafe {
PkgIterator {
cache: self,
ptr: raw::pkg_cache_pkg_iter(self.ptr)
}
}
}
}
#[derive(Debug)]
pub struct PkgIterator<'c> {
cache: &'c Cache,
ptr: raw::PPkgIterator
}
impl<'c> Drop for PkgIterator<'c> {
fn drop(&mut self) {
unsafe {
raw::pkg_iter_release(self.ptr)
}
}
}
/// Iterator-like interface.
/// Can't implement Iterator due to the mutation / lifetime constraints?
impl<'c> PkgIterator<'c> {
pub fn next<'i>(&'i mut self) -> Option<&'i Self> {
unsafe {
// we were at the end last time, leave us alone!
if raw::pkg_iter_end(self.ptr) {
return None;
}
raw::pkg_iter_next(self.ptr);
// we don't want to observe the end marker
if raw::pkg_iter_end(self.ptr) {
None
} else {
Some(self)
}
}
}
pub fn count(mut self) -> usize {
let mut count = 0;
loop {
if self.next().is_none() {
break;
}
count += 1;
}
count
}
pub fn map<F>(self, f: F) -> PkgMap<'c, F> {
PkgMap {
it: self,
f,
}
}
}
/// Actual accessors
impl<'c> PkgIterator<'c> {
pub fn name(&self) -> String {
unsafe {
ffi::CStr::from_ptr(raw::pkg_iter_name(self.ptr))
}.to_str().expect("package names are always low-ascii").to_string()
}
pub fn pretty_print(&self) -> String {
unsafe {
let ptr = raw::pkg_iter_pretty(self.cache.ptr, self.ptr);
let result = ffi::CStr::from_ptr(ptr)
.to_str()
.expect("package names are always low-ascii")
.to_string();
libc::free(ptr as *mut libc::c_void);
return result;
}
}
}
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct PkgMap<'c, F> {
it: PkgIterator<'c>,
f: F,
}
impl<'c, B, F> Iterator for PkgMap<'c, F>
where F: FnMut(&PkgIterator) -> B {
type Item = B;
fn next(&mut self) -> Option<Self::Item> {
self.it.next().map(&mut self.f)
}
}