diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ddb4405 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,118 @@ +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<Self, EncodeError> { + 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()) }; + } +} |
