use std::cmp;
use std::ffi;
use std::marker::PhantomData;
use std::sync::MutexGuard;
use crate::citer::CIterator;
use crate::citer::RawIterator;
use crate::raw;
#[derive(Debug)]
pub struct Cache {
ptr_mutex: &'static raw::CACHE_SINGLETON,
}
impl Cache {
pub fn get_singleton() -> Cache {
Cache {
ptr_mutex: raw::pkg_cache_get_singleton(),
}
}
pub fn reload(&mut self) {
self.ptr_mutex.lock().expect("poisoned mutex").re_up()
}
pub fn iter(&mut self) -> CIterator<PkgIterator> {
let lock = self.ptr_mutex.lock().expect("poisoned mutex");
unsafe {
let raw_iter = raw::pkg_cache_pkg_iter(lock.ptr);
PkgIterator::new(lock, raw_iter)
}
}
pub fn find_by_name(&mut self, name: &str) -> CIterator<PkgIterator> {
let lock = self.ptr_mutex.lock().expect("poisoned mutex");
unsafe {
let name = ffi::CString::new(name).unwrap();
let ptr = raw::pkg_cache_find_name(lock.ptr, name.as_ptr());
PkgIterator::new(lock, ptr)
}
}
pub fn find_by_name_arch(&mut self, name: &str, arch: &str) -> CIterator<PkgIterator> {
let lock = self.ptr_mutex.lock().expect("poisoned mutex");
unsafe {
let name = ffi::CString::new(name).unwrap();
let arch = ffi::CString::new(arch).unwrap();
let ptr = raw::pkg_cache_find_name_arch(lock.ptr, name.as_ptr(), arch.as_ptr());
PkgIterator::new(lock, ptr)
}
}
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();
let lock = self.ptr_mutex.lock().expect("poisoned mutex");
raw::pkg_cache_compare_versions(lock.ptr, left.as_ptr(), right.as_ptr()).cmp(&0)
}
}
}
#[derive(Debug)]
pub struct PkgIterator<'c> {
cache: MutexGuard<'c, raw::CacheHolder>,
ptr: raw::PPkgIterator,
}
impl<'c> PkgIterator<'c> {
fn new(cache: MutexGuard<'c, raw::CacheHolder>, ptr: raw::PCache) -> CIterator<Self> {
CIterator {
first: true,
raw: PkgIterator { cache, ptr },
}
}
}
pub struct PkgView<'c> {
cache: PhantomData<&'c MutexGuard<'c, raw::CacheHolder>>,
ptr: raw::PPkgIterator,
}
impl<'c> RawIterator for PkgIterator<'c> {
type View = PkgView<'c>;
fn is_end(&self) -> bool {
unsafe { raw::pkg_iter_end(self.ptr) }
}
fn next(&mut self) {
unsafe { raw::pkg_iter_next(self.ptr) }
}
fn as_view(&self) -> Self::View {
assert!(!self.is_end());
PkgView {
ptr: self.ptr,
cache: PhantomData,
}
}
fn release(&mut self) {
unsafe { raw::pkg_iter_release(self.ptr) }
}
}
impl<'c> PkgView<'c> {
pub fn name(&self) -> String {
unsafe {
make_owned_ascii_string(raw::pkg_iter_name(self.ptr))
.expect("packages always have names")
}
}
pub fn arch(&self) -> String {
unsafe {
make_owned_ascii_string(raw::pkg_iter_arch(self.ptr))
.expect("packages always have architectures")
}
}
pub fn current_version(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::pkg_iter_current_version(self.ptr)) }
}
pub fn candidate_version(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::pkg_iter_candidate_version(self.ptr)) }
}
pub fn versions(&self) -> CIterator<VerIterator> {
CIterator {
first: true,
raw: VerIterator {
cache: PhantomData,
ptr: unsafe { raw::pkg_iter_ver_iter(self.ptr) },
},
}
}
}
pub struct SinglePkgView<'c> {
view: PkgView<'c>,
}
impl<'c> std::ops::Deref for SinglePkgView<'c> {
type Target = PkgView<'c>;
fn deref(&self) -> &Self::Target {
&self.view
}
}
impl<'c> Drop for SinglePkgView<'c> {
fn drop(&mut self) {
unsafe {
raw::pkg_iter_release(self.view.ptr);
}
}
}
pub struct VerIterator<'c> {
cache: PhantomData<&'c MutexGuard<'c, raw::CacheHolder>>,
ptr: raw::PVerIterator,
}
pub struct VerView<'c> {
cache: PhantomData<&'c MutexGuard<'c, raw::CacheHolder>>,
ptr: raw::PVerIterator,
}
impl<'c> RawIterator for VerIterator<'c> {
type View = VerView<'c>;
fn is_end(&self) -> bool {
unsafe { raw::ver_iter_end(self.ptr) }
}
fn next(&mut self) {
unsafe { raw::ver_iter_next(self.ptr) }
}
fn as_view(&self) -> Self::View {
assert!(!self.is_end());
VerView {
ptr: self.ptr,
cache: self.cache,
}
}
fn release(&mut self) {
unsafe { raw::ver_iter_release(self.ptr) }
}
}
impl<'c> VerView<'c> {
pub fn version(&self) -> String {
unsafe {
make_owned_ascii_string(raw::ver_iter_version(self.ptr))
.expect("versions always have a version")
}
}
pub fn arch(&self) -> String {
unsafe {
make_owned_ascii_string(raw::ver_iter_arch(self.ptr))
.expect("versions always have an arch")
}
}
pub fn section(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::ver_iter_section(self.ptr)) }
}
pub fn priority_type(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::ver_iter_priority_type(self.ptr)) }
}
#[cfg(not(feature = "ye-olde-apt"))]
pub fn source_package(&self) -> String {
unsafe {
make_owned_ascii_string(raw::ver_iter_source_package(self.ptr))
.expect("versions always have a source package")
}
}
#[cfg(not(feature = "ye-olde-apt"))]
pub fn source_version(&self) -> String {
unsafe {
make_owned_ascii_string(raw::ver_iter_source_version(self.ptr))
.expect("versions always have a source_version")
}
}
#[cfg(not(feature = "ye-olde-apt"))]
pub fn priority(&self) -> i32 {
unsafe { raw::ver_iter_priority(self.ptr) }
}
pub fn origin_iter(&self) -> CIterator<VerFileIterator> {
CIterator {
first: true,
raw: VerFileIterator {
cache: PhantomData,
ptr: unsafe { raw::ver_iter_ver_file_iter(self.ptr) },
},
}
}
pub fn dep_iter(&self) -> CIterator<DepIterator> {
CIterator {
first: true,
raw: DepIterator {
cache: PhantomData,
ptr: unsafe { raw::ver_iter_dep_iter(self.ptr) },
},
}
}
}
pub struct DepIterator<'c> {
cache: PhantomData<&'c MutexGuard<'c, raw::CacheHolder>>,
ptr: raw::PDepIterator,
}
pub struct DepView<'c> {
cache: PhantomData<&'c MutexGuard<'c, raw::CacheHolder>>,
ptr: raw::PDepIterator,
}
impl<'c> RawIterator for DepIterator<'c> {
type View = DepView<'c>;
fn is_end(&self) -> bool {
unsafe { raw::dep_iter_end(self.ptr) }
}
fn next(&mut self) {
unsafe { raw::dep_iter_next(self.ptr) }
}
fn as_view(&self) -> Self::View {
assert!(!self.is_end());
DepView {
ptr: self.ptr,
cache: self.cache,
}
}
fn release(&mut self) {
unsafe { raw::dep_iter_release(self.ptr) }
}
}
impl<'c> DepView<'c> {
pub fn target_pkg(&self) -> SinglePkgView {
let ptr = unsafe { raw::dep_iter_target_pkg(self.ptr) };
SinglePkgView {
view: PkgView {
cache: self.cache,
ptr,
},
}
}
pub fn target_ver(&self) -> String {
unsafe {
make_owned_ascii_string(raw::dep_iter_target_ver(self.ptr))
.expect("dependency always has target version")
}
}
pub fn comp_type(&self) -> String {
unsafe {
make_owned_ascii_string(raw::dep_iter_comp_type(self.ptr))
.expect("dependency always has comp type")
}
}
pub fn dep_type(&self) -> String {
unsafe {
make_owned_ascii_string(raw::dep_iter_dep_type(self.ptr))
.expect("dependency always has dep type")
}
}
}
pub struct VerFileIterator<'c> {
cache: PhantomData<&'c MutexGuard<'c, raw::CacheHolder>>,
ptr: raw::PVerFileIterator,
}
pub struct VerFileView<'c> {
cache: PhantomData<&'c MutexGuard<'c, raw::CacheHolder>>,
ptr: raw::PVerFileIterator,
parser: raw::PVerFileParser,
}
impl<'c> RawIterator for VerFileIterator<'c> {
type View = VerFileView<'c>;
fn is_end(&self) -> bool {
unsafe { raw::ver_file_iter_end(self.ptr) }
}
fn next(&mut self) {
unsafe { raw::ver_file_iter_next(self.ptr) }
}
fn as_view(&self) -> Self::View {
assert!(!self.is_end());
let parser = unsafe { raw::ver_file_iter_get_parser(self.ptr) };
VerFileView {
ptr: self.ptr,
cache: self.cache,
parser,
}
}
fn release(&mut self) {
unsafe { raw::ver_file_iter_release(self.ptr) }
}
}
impl<'c> VerFileView<'c> {
pub fn file(&self) -> CIterator<PkgFileIterator> {
CIterator {
first: true,
raw: PkgFileIterator {
cache: PhantomData,
ptr: unsafe { raw::ver_file_iter_pkg_file_iter(self.ptr) },
},
}
}
pub fn short_desc(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::ver_file_parser_short_desc(self.parser)) }
}
pub fn long_desc(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::ver_file_parser_long_desc(self.parser)) }
}
pub fn maintainer(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::ver_file_parser_maintainer(self.parser)) }
}
pub fn homepage(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::ver_file_parser_homepage(self.parser)) }
}
}
pub struct PkgFileIterator<'c> {
cache: PhantomData<&'c MutexGuard<'c, raw::CacheHolder>>,
ptr: raw::PPkgFileIterator,
}
pub struct PkgFileView<'c> {
cache: PhantomData<&'c MutexGuard<'c, raw::CacheHolder>>,
ptr: raw::PPkgFileIterator,
}
impl<'c> RawIterator for PkgFileIterator<'c> {
type View = PkgFileView<'c>;
fn is_end(&self) -> bool {
unsafe { raw::pkg_file_iter_end(self.ptr) }
}
fn next(&mut self) {
unsafe { raw::pkg_file_iter_next(self.ptr) }
}
fn as_view(&self) -> Self::View {
assert!(!self.is_end());
PkgFileView {
ptr: self.ptr,
cache: self.cache,
}
}
fn release(&mut self) {
unsafe { raw::pkg_file_iter_release(self.ptr) }
}
}
impl<'c> PkgFileView<'c> {
pub fn file_name(&self) -> String {
unsafe {
make_owned_ascii_string(raw::pkg_file_iter_file_name(self.ptr))
.expect("package file always has a file name")
}
}
pub fn archive(&self) -> String {
unsafe {
make_owned_ascii_string(raw::pkg_file_iter_archive(self.ptr))
.expect("package file always has an archive")
}
}
pub fn version(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::pkg_file_iter_version(self.ptr)) }
}
pub fn origin(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::pkg_file_iter_origin(self.ptr)) }
}
pub fn codename(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::pkg_file_iter_codename(self.ptr)) }
}
pub fn label(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::pkg_file_iter_label(self.ptr)) }
}
pub fn site(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::pkg_file_iter_site(self.ptr)) }
}
pub fn component(&self) -> String {
unsafe {
make_owned_ascii_string(raw::pkg_file_iter_component(self.ptr))
.expect("package file always has a component")
}
}
pub fn architecture(&self) -> Option<String> {
unsafe { make_owned_ascii_string(raw::pkg_file_iter_architecture(self.ptr)) }
}
pub fn index_type(&self) -> String {
unsafe {
make_owned_ascii_string(raw::pkg_file_iter_index_type(self.ptr))
.expect("package file always has a index_type")
}
}
}
unsafe fn make_owned_ascii_string(ptr: *const libc::c_char) -> Option<String> {
if ptr.is_null() {
None
} else {
Some(
ffi::CStr::from_ptr(ptr)
.to_str()
.expect("value should always be low-ascii")
.to_string(),
)
}
}