use std::ptr;
use std::usize;
use std::ffi::CStr;
use libc::c_int;
use geom::{ Image, QrCode };
use quirc_sys::{ quirc, quirc_version, quirc_new, quirc_destroy };
use quirc_sys::{ quirc_resize, quirc_begin, quirc_end };
use quirc_sys::{ quirc_code, quirc_count, quirc_extract };
use util::{ usize_to_int, int_to_usize };
use error::{ Error, Result };
#[derive(Debug)]
pub struct Decoder {
inner: *mut quirc,
}
impl Decoder {
pub fn new() -> Result<Self> {
let inner = unsafe { quirc_new() };
if inner.is_null() {
Err(Error::AllocFailed)
} else {
Ok(Decoder { inner })
}
}
pub fn version() -> &'static str {
let version_ptr = unsafe { quirc_version() };
if version_ptr.is_null() {
""
} else {
unsafe {
CStr::from_ptr(version_ptr).to_str().unwrap_or_default()
}
}
}
pub fn decode_image(&mut self, image: &Image) -> Result<Iter> {
let width = usize_to_int(image.width())?;
let height = usize_to_int(image.height())?;
let image_data = image.data();
unsafe {
if quirc_resize(self.inner, width, height) != 0 {
return Err(Error::AllocFailed);
}
let buf_ptr = quirc_begin(
self.inner,
ptr::null_mut(),
ptr::null_mut(),
);
assert!(!buf_ptr.is_null(), "quirc_begin() returned null pointer");
ptr::copy_nonoverlapping(
image_data.as_ptr(),
buf_ptr,
image_data.len(),
);
quirc_end(self.inner);
}
Ok(Iter {
decoder: self,
index: 0,
})
}
}
impl Drop for Decoder {
fn drop(&mut self) {
unsafe {
quirc_destroy(self.inner);
}
}
}
#[derive(Debug)]
pub struct Iter<'a> {
decoder: &'a mut Decoder,
index: c_int,
}
impl<'a> Iter<'a> {
fn count_and_index(&self) -> (c_int, c_int) {
let count = unsafe {
quirc_count(self.decoder.inner)
};
let index = self.index;
assert!(count >= 0, "quirc_count() was negative");
assert!(index >= 0, "current index was negative");
(count, index)
}
}
impl<'a> Iterator for Iter<'a> {
type Item = Result<QrCode>;
fn next(&mut self) -> Option<Self::Item> {
let (count, index) = self.count_and_index();
if index < count {
let mut raw = quirc_code::default();
unsafe {
quirc_extract(self.decoder.inner, index, &mut raw);
}
self.index += 1;
Some(QrCode::from_raw(raw))
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (count, index) = self.count_and_index();
int_to_usize(count - index)
.map(|n| (n, Some(n)))
.unwrap_or_default() }
}