use crate::types::{BarcodeConfig, BarcodeType, ExportFormat, QRErrorCorrection};
use crate::{generate as rust_generate, generate_to_file as rust_generate_to_file};
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3::types::{PyBytes, PyModule};
#[pyclass(name = "BarcodeType")]
#[derive(Clone)]
pub struct PyBarcodeType {
inner: BarcodeType,
}
#[pymethods]
impl PyBarcodeType {
#[classattr]
const QR_CODE: &'static str = "QRCode";
#[classattr]
const EAN13: &'static str = "EAN13";
#[classattr]
const UPC_A: &'static str = "UPCA";
#[classattr]
const CODE128: &'static str = "Code128";
#[classattr]
const DATA_MATRIX: &'static str = "DataMatrix";
#[classattr]
const PDF417: &'static str = "PDF417";
#[classattr]
const AZTEC: &'static str = "Aztec";
#[new]
fn new(barcode_type: &str) -> PyResult<Self> {
let inner = match barcode_type {
"QRCode" => BarcodeType::QRCode,
"EAN13" => BarcodeType::EAN13,
"UPCA" => BarcodeType::UPCA,
"Code128" => BarcodeType::Code128,
"DataMatrix" => BarcodeType::DataMatrix,
"PDF417" => BarcodeType::PDF417,
"Aztec" => BarcodeType::Aztec,
_ => {
return Err(PyValueError::new_err(format!(
"Unknown barcode type: {}",
barcode_type
)))
}
};
Ok(PyBarcodeType { inner })
}
fn __str__(&self) -> String {
format!("{:?}", self.inner)
}
fn __repr__(&self) -> String {
format!("BarcodeType('{:?}')", self.inner)
}
}
#[pyclass(name = "ExportFormat")]
#[derive(Clone)]
pub struct PyExportFormat {
inner: ExportFormat,
}
#[pymethods]
impl PyExportFormat {
#[classattr]
const SVG: &'static str = "SVG";
#[classattr]
const PNG: &'static str = "PNG";
#[classattr]
const PDF: &'static str = "PDF";
#[new]
fn new(format: &str) -> PyResult<Self> {
let inner = match format {
"SVG" => ExportFormat::SVG,
"PNG" => ExportFormat::PNG,
"PDF" => ExportFormat::PDF,
_ => {
return Err(PyValueError::new_err(format!(
"Unknown export format: {}",
format
)))
}
};
Ok(PyExportFormat { inner })
}
fn __str__(&self) -> String {
format!("{:?}", self.inner)
}
fn __repr__(&self) -> String {
format!("ExportFormat('{:?}')", self.inner)
}
}
#[pyclass(name = "QRErrorCorrection")]
#[derive(Clone)]
pub struct PyQRErrorCorrection {
inner: QRErrorCorrection,
}
#[pymethods]
impl PyQRErrorCorrection {
#[classattr]
const LOW: &'static str = "Low";
#[classattr]
const MEDIUM: &'static str = "Medium";
#[classattr]
const QUARTILE: &'static str = "Quartile";
#[classattr]
const HIGH: &'static str = "High";
#[new]
fn new(level: &str) -> PyResult<Self> {
let inner = match level {
"Low" => QRErrorCorrection::Low,
"Medium" => QRErrorCorrection::Medium,
"Quartile" => QRErrorCorrection::Quartile,
"High" => QRErrorCorrection::High,
_ => {
return Err(PyValueError::new_err(format!(
"Unknown error correction level: {}",
level
)))
}
};
Ok(PyQRErrorCorrection { inner })
}
fn __str__(&self) -> String {
format!("{:?}", self.inner)
}
fn __repr__(&self) -> String {
format!("QRErrorCorrection('{:?}')", self.inner)
}
}
#[pyfunction]
#[pyo3(signature = (barcode_type, data, format, error_correction=None, margin=None))]
fn generate(
py: Python,
barcode_type: &str,
data: &str,
format: &str,
error_correction: Option<&str>,
margin: Option<u32>,
) -> PyResult<PyObject> {
let bt = match barcode_type {
"QRCode" => BarcodeType::QRCode,
"EAN13" => BarcodeType::EAN13,
"UPCA" => BarcodeType::UPCA,
"Code128" => BarcodeType::Code128,
_ => {
return Err(PyValueError::new_err(format!(
"Unsupported barcode type: {}",
barcode_type
)))
}
};
let fmt = match format {
"SVG" => ExportFormat::SVG,
"PNG" => ExportFormat::PNG,
_ => {
return Err(PyValueError::new_err(format!(
"Unsupported export format: {}",
format
)))
}
};
let mut config = BarcodeConfig::default();
if let Some(m) = margin {
config.margin = m;
}
if let Some(ec) = error_correction {
config.qr_config.error_correction = match ec {
"Low" => QRErrorCorrection::Low,
"Medium" => QRErrorCorrection::Medium,
"Quartile" => QRErrorCorrection::Quartile,
"High" => QRErrorCorrection::High,
_ => {
return Err(PyValueError::new_err(format!(
"Unknown error correction: {}",
ec
)))
}
};
}
match rust_generate(bt, data, fmt) {
Ok(bytes) => Ok(PyBytes::new(py, &bytes).into()),
Err(e) => Err(PyValueError::new_err(format!("Generation failed: {}", e))),
}
}
#[pyfunction]
fn generate_to_file(barcode_type: &str, data: &str, output_path: &str) -> PyResult<()> {
let bt = match barcode_type {
"QRCode" => BarcodeType::QRCode,
"EAN13" => BarcodeType::EAN13,
"UPCA" => BarcodeType::UPCA,
"Code128" => BarcodeType::Code128,
_ => {
return Err(PyValueError::new_err(format!(
"Unsupported barcode type: {}",
barcode_type
)))
}
};
match rust_generate_to_file(bt, data, output_path) {
Ok(_) => Ok(()),
Err(e) => Err(PyValueError::new_err(format!("Generation failed: {}", e))),
}
}
#[pymodule]
fn quickcodes(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add("__version__", "0.1.0")?;
m.add("__author__", "Márcio Reck")?;
m.add_class::<PyBarcodeType>()?;
m.add_class::<PyExportFormat>()?;
m.add_class::<PyQRErrorCorrection>()?;
m.add_function(wrap_pyfunction!(generate, m)?)?;
m.add_function(wrap_pyfunction!(generate_to_file, m)?)?;
m.add("QR_CODE", "QRCode")?;
m.add("EAN13", "EAN13")?;
m.add("UPC_A", "UPCA")?;
m.add("CODE128", "Code128")?;
m.add("SVG", "SVG")?;
m.add("PNG", "PNG")?;
m.add("LOW", "Low")?;
m.add("MEDIUM", "Medium")?;
m.add("QUARTILE", "Quartile")?;
m.add("HIGH", "High")?;
Ok(())
}