datacard_rs/format.rs
1//! Card format trait - implementors define their card structure
2//!
3//! Each card format (Ternsig, CML, etc.) implements this trait to define:
4//! - Magic bytes for identification
5//! - Version constraints
6//! - Payload validation
7
8use crate::error::Result;
9
10/// Trait for defining card formats
11///
12/// Implementors define their magic bytes, version requirements, and validation logic.
13/// The datacard library handles generic I/O, checksums, and structure.
14///
15/// # Example
16///
17/// ```ignore
18/// use datacard_rs::{CardFormat, CardError};
19///
20/// pub struct TernsigFormat;
21///
22/// impl CardFormat for TernsigFormat {
23/// const MAGIC: [u8; 4] = *b"TERN";
24/// const VERSION_MAJOR: u8 = 1;
25/// const VERSION_MINOR: u8 = 0;
26///
27/// fn validate_payload(payload: &[u8]) -> Result<(), CardError> {
28/// // Ternsig-specific validation
29/// Ok(())
30/// }
31/// }
32/// ```
33pub trait CardFormat: Sized {
34 /// 4-byte magic identifier (e.g., b"TERN", b"CARD")
35 const MAGIC: [u8; 4];
36
37 /// Major version number
38 const VERSION_MAJOR: u8;
39
40 /// Minimum supported minor version
41 const VERSION_MINOR: u8;
42
43 /// Validate magic bytes match this format
44 fn validate_magic(magic: &[u8; 4]) -> Result<()> {
45 if magic != &Self::MAGIC {
46 return Err(crate::CardError::InvalidMagic(*magic));
47 }
48 Ok(())
49 }
50
51 /// Validate version is compatible
52 fn validate_version(major: u8, minor: u8) -> Result<()> {
53 if major != Self::VERSION_MAJOR {
54 return Err(crate::CardError::UnsupportedVersion { major, minor });
55 }
56 // Minor version must be >= our minimum
57 if minor < Self::VERSION_MINOR {
58 return Err(crate::CardError::UnsupportedVersion { major, minor });
59 }
60 Ok(())
61 }
62
63 /// Validate payload after reading (optional, default no-op)
64 fn validate_payload(_payload: &[u8]) -> Result<()> {
65 Ok(())
66 }
67
68 /// Format name for error messages
69 fn format_name() -> &'static str;
70}