use std::ffi; use std::ptr; use std::slice; #[link(name = "iec16022")] unsafe extern "C" { /// encoding function /// /// Returns the grid (malloced) containing the matrix. L corner at 0,0. /// Takes suggested size in `w_ptr`, `h_ptr`, or 0,0. Fills in actual size. /// Takes `barcodelen` and `barcode` to be encoded /// Note, if `encodingptr` is null, then fills with auto picked (malloced) /// encoding. /// If `lenp` not null, then the length of encoded data before any final unlatch /// or pad is stored. /// If `maxp` not null, then the max storage of this size code is stored /// If `eccp` not null, then the number of ecc bytes used in this size is stored /// Returns 0 on error (writes to stderr with details). fn iec16022ecc200f( w_ptr: *mut ffi::c_int, h_ptr: *mut ffi::c_int, encodingptr: *mut *mut ffi::c_char, barcodelen: ffi::c_int, barcode: *const ffi::c_uchar, lenp: *mut ffi::c_int, maxp: *mut ffi::c_int, eccp: *mut ffi::c_int, flags: ffi::c_int, ) -> *mut ffi::c_uchar; } #[derive(PartialEq, Eq, Debug)] pub enum EncodeError { DataTooLong, Encoder, DimensionsTooLarge, } #[derive(Debug)] pub struct DataMatrix { width: usize, height: usize, grid_ptr: *mut ffi::c_uchar, } impl DataMatrix { /// Encodes data as a data matrix pub fn encode(data: &[u8]) -> Result { let mut width = 0; let mut height = 0; let data_ptr = data.as_ptr(); let data_len = data .len() .try_into() .map_err(|_| EncodeError::DataTooLong)?; // SAFETY: ffi let grid_ptr = unsafe { iec16022ecc200f( &raw mut width, &raw mut height, ptr::null_mut(), data_len, data_ptr, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), 0, ) }; if grid_ptr.is_null() || width == 0 || height == 0 { Err(EncodeError::Encoder) } else { Ok(Self { width: width .try_into() .map_err(|_| EncodeError::DimensionsTooLarge)?, height: height .try_into() .map_err(|_| EncodeError::DimensionsTooLarge)?, grid_ptr, }) } } #[must_use] pub const fn width(&self) -> usize { self.width } #[must_use] pub const fn height(&self) -> usize { self.height } #[must_use] const fn grid(&self) -> &[bool] { // SAFETY: returned grid consists only contains values 0 and 1 unsafe { slice::from_raw_parts(self.grid_ptr as *const bool, self.width * self.height) } } #[must_use] pub const fn get(&self, row: usize, col: usize) -> bool { assert!(row < self.height(), "row index out of bounds"); assert!(col < self.width(), "col index out of bounds"); let idx = row * self.width + col; self.grid()[idx] } } impl Drop for DataMatrix { fn drop(&mut self) { // SAFETY: self.ptr malloc'ed in ffi unsafe { libc::free(self.grid_ptr.cast()) }; } }