use crate::error::Result;
use crate::render::{RenderOptions, Renderer};
use crate::symbology::{Symbol, Symbology, SymbologyKind};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Barcode {
symbol: Symbol,
}
impl Barcode {
#[cfg(feature = "code128")]
pub fn code128(data: impl AsRef<str>) -> Result<Self> {
Self::encode_with(&crate::symbology::Code128, data.as_ref())
}
#[cfg(feature = "qr")]
pub fn qr(data: impl AsRef<str>) -> Result<Self> {
Self::encode_with(&crate::symbology::Qr::new(), data.as_ref())
}
#[cfg(feature = "qr")]
pub fn qr_with(encoder: crate::symbology::Qr, data: impl AsRef<str>) -> Result<Self> {
Self::encode_with(&encoder, data.as_ref())
}
pub fn encode_with<S: Symbology + ?Sized>(symbology: &S, data: &str) -> Result<Self> {
Ok(Self {
symbol: symbology.encode(data)?,
})
}
pub fn from_symbol(symbol: Symbol) -> Self {
Self { symbol }
}
pub fn symbol(&self) -> &Symbol {
&self.symbol
}
pub fn payload(&self) -> &str {
self.symbol.payload()
}
pub fn kind(&self) -> SymbologyKind {
self.symbol.kind()
}
pub fn render<R: Renderer>(&self, renderer: &R, options: &RenderOptions) -> Result<R::Output> {
renderer.render(&self.symbol, options)
}
#[cfg(feature = "png")]
pub fn to_png(&self, options: &RenderOptions) -> Result<alloc::vec::Vec<u8>> {
self.render(&crate::render::Png, options)
}
#[cfg(feature = "svg")]
pub fn to_svg(&self, options: &RenderOptions) -> Result<alloc::string::String> {
self.render(&crate::render::Svg, options)
}
#[cfg(all(feature = "png", feature = "std"))]
pub fn to_png_file(
&self,
path: impl AsRef<std::path::Path>,
options: &RenderOptions,
) -> Result<()> {
std::fs::write(path, self.to_png(options)?)?;
Ok(())
}
#[cfg(all(feature = "svg", feature = "std"))]
pub fn to_svg_file(
&self,
path: impl AsRef<std::path::Path>,
options: &RenderOptions,
) -> Result<()> {
std::fs::write(path, self.to_svg(options)?)?;
Ok(())
}
#[cfg(feature = "code128")]
pub fn decode(&self) -> Result<alloc::string::String> {
crate::symbology::code128::decode(&self.symbol)
}
}
#[cfg(all(test, feature = "code128"))]
mod tests {
use super::*;
use crate::TrackingId;
#[test]
fn encodes_a_tracking_id_by_reference_or_value() {
let id = TrackingId::parse("PKG-9ED9285C").unwrap();
let a = Barcode::code128(&id).unwrap();
let b = Barcode::code128("PKG-9ED9285C").unwrap();
let c = Barcode::code128(id.as_str()).unwrap();
assert_eq!(a, b);
assert_eq!(b, c);
assert_eq!(a.payload(), "PKG-9ED9285C");
assert_eq!(a.kind(), SymbologyKind::Code128);
}
#[test]
fn round_trips_through_the_module_grid() {
let barcode = Barcode::code128("PKG-9ED9285C").unwrap();
assert_eq!(barcode.decode().unwrap(), "PKG-9ED9285C");
}
#[test]
#[cfg(all(feature = "png", feature = "svg"))]
fn renders_both_formats_from_one_encode() {
let barcode = Barcode::code128("PKG-9ED9285C").unwrap();
let options = RenderOptions::default();
assert!(!barcode.to_png(&options).unwrap().is_empty());
assert!(barcode.to_svg(&options).unwrap().contains("<svg"));
}
#[test]
fn from_symbol_preserves_the_symbol() {
let symbol = crate::symbology::Code128.encode("PKG-9ED9285C").unwrap();
let barcode = Barcode::from_symbol(symbol.clone());
assert_eq!(barcode.symbol(), &symbol);
}
#[test]
fn rejects_an_empty_payload() {
assert!(Barcode::code128("").is_err());
}
}