summaryrefslogtreecommitdiffstats
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs118
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()) };
+ }
+}