smart_package_tracker/
barcode.rs1use crate::error::Result;
4use crate::render::{RenderOptions, Renderer};
5use crate::symbology::{Symbol, Symbology, SymbologyKind};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct Barcode {
33 symbol: Symbol,
34}
35
36impl Barcode {
37 #[cfg(feature = "code128")]
48 pub fn code128(data: impl AsRef<str>) -> Result<Self> {
49 Self::encode_with(&crate::symbology::Code128, data.as_ref())
50 }
51
52 pub fn encode_with<S: Symbology + ?Sized>(symbology: &S, data: &str) -> Result<Self> {
58 Ok(Self {
59 symbol: symbology.encode(data)?,
60 })
61 }
62
63 pub fn from_symbol(symbol: Symbol) -> Self {
65 Self { symbol }
66 }
67
68 pub fn symbol(&self) -> &Symbol {
70 &self.symbol
71 }
72
73 pub fn payload(&self) -> &str {
75 self.symbol.payload()
76 }
77
78 pub fn kind(&self) -> SymbologyKind {
80 self.symbol.kind()
81 }
82
83 pub fn render<R: Renderer>(&self, renderer: &R, options: &RenderOptions) -> Result<R::Output> {
89 renderer.render(&self.symbol, options)
90 }
91
92 #[cfg(feature = "png")]
98 pub fn to_png(&self, options: &RenderOptions) -> Result<alloc::vec::Vec<u8>> {
99 self.render(&crate::render::Png, options)
100 }
101
102 #[cfg(feature = "svg")]
108 pub fn to_svg(&self, options: &RenderOptions) -> Result<alloc::string::String> {
109 self.render(&crate::render::Svg, options)
110 }
111
112 #[cfg(all(feature = "png", feature = "std"))]
118 pub fn to_png_file(
119 &self,
120 path: impl AsRef<std::path::Path>,
121 options: &RenderOptions,
122 ) -> Result<()> {
123 std::fs::write(path, self.to_png(options)?)?;
124 Ok(())
125 }
126
127 #[cfg(all(feature = "svg", feature = "std"))]
133 pub fn to_svg_file(
134 &self,
135 path: impl AsRef<std::path::Path>,
136 options: &RenderOptions,
137 ) -> Result<()> {
138 std::fs::write(path, self.to_svg(options)?)?;
139 Ok(())
140 }
141
142 #[cfg(feature = "code128")]
154 pub fn decode(&self) -> Result<alloc::string::String> {
155 crate::symbology::code128::decode(&self.symbol)
156 }
157}
158
159#[cfg(all(test, feature = "code128"))]
160mod tests {
161 use super::*;
162 use crate::TrackingId;
163
164 #[test]
165 fn encodes_a_tracking_id_by_reference_or_value() {
166 let id = TrackingId::parse("PKG-9ED9285C").unwrap();
167 let a = Barcode::code128(&id).unwrap();
168 let b = Barcode::code128("PKG-9ED9285C").unwrap();
169 let c = Barcode::code128(id.as_str()).unwrap();
170 assert_eq!(a, b);
171 assert_eq!(b, c);
172 assert_eq!(a.payload(), "PKG-9ED9285C");
173 assert_eq!(a.kind(), SymbologyKind::Code128);
174 }
175
176 #[test]
177 fn round_trips_through_the_module_grid() {
178 let barcode = Barcode::code128("PKG-9ED9285C").unwrap();
179 assert_eq!(barcode.decode().unwrap(), "PKG-9ED9285C");
180 }
181
182 #[test]
183 #[cfg(all(feature = "png", feature = "svg"))]
184 fn renders_both_formats_from_one_encode() {
185 let barcode = Barcode::code128("PKG-9ED9285C").unwrap();
186 let options = RenderOptions::default();
187 assert!(!barcode.to_png(&options).unwrap().is_empty());
188 assert!(barcode.to_svg(&options).unwrap().contains("<svg"));
189 }
190
191 #[test]
192 fn from_symbol_preserves_the_symbol() {
193 let symbol = crate::symbology::Code128.encode("PKG-9ED9285C").unwrap();
194 let barcode = Barcode::from_symbol(symbol.clone());
195 assert_eq!(barcode.symbol(), &symbol);
196 }
197
198 #[test]
199 fn rejects_an_empty_payload() {
200 assert!(Barcode::code128("").is_err());
201 }
202}