1use crate::types::{QrError, QrResult, Version};
4
5pub const DEFAULT_MAX_DATA_LENGTH: usize = 7_089;
11
12pub const DEFAULT_MAX_RENDER_SIZE: (u32, u32) = (4_096, 4_096);
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct ResourceLimits {
27 pub max_data_length: usize,
29 pub max_version: Version,
31 pub max_render_size: (u32, u32),
33 pub encoding_timeout: Option<u64>,
38}
39
40impl Default for ResourceLimits {
41 fn default() -> Self {
42 Self {
43 max_data_length: DEFAULT_MAX_DATA_LENGTH,
44 max_version: Version::Normal(40),
45 max_render_size: DEFAULT_MAX_RENDER_SIZE,
46 encoding_timeout: None,
47 }
48 }
49}
50
51impl ResourceLimits {
52 #[must_use]
54 pub const fn new(max_data_length: usize, max_version: Version, max_render_size: (u32, u32)) -> Self {
55 Self { max_data_length, max_version, max_render_size, encoding_timeout: None }
56 }
57
58 #[must_use]
63 pub const fn with_encoding_timeout_millis(mut self, timeout_ms: u64) -> Self {
64 self.encoding_timeout = Some(timeout_ms);
65 self
66 }
67
68 pub fn validate(self) -> QrResult<()> {
74 let valid_version = matches!(self.max_version, Version::Normal(1..=40));
75 let valid_render_size = self.max_render_size.0 != 0 && self.max_render_size.1 != 0;
76 let valid_timeout = self.encoding_timeout != Some(0);
77 if valid_version && valid_render_size && valid_timeout { Ok(()) } else { Err(QrError::InvalidResourceLimits) }
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::{DEFAULT_MAX_DATA_LENGTH, DEFAULT_MAX_RENDER_SIZE, ResourceLimits};
84 use crate::types::Version;
85
86 #[test]
87 fn default_budget_is_bounded() {
88 let limits = ResourceLimits::default();
89 assert_eq!(limits.max_data_length, DEFAULT_MAX_DATA_LENGTH);
90 assert_eq!(limits.max_version, Version::Normal(40));
91 assert_eq!(limits.max_render_size, DEFAULT_MAX_RENDER_SIZE);
92 assert_eq!(limits.encoding_timeout, None);
93 assert!(limits.validate().is_ok());
94 }
95
96 #[test]
97 fn invalid_budget_is_rejected() {
98 assert!(ResourceLimits::new(1, Version::Micro(4), (1, 1)).validate().is_err());
99 assert!(ResourceLimits::new(1, Version::Normal(1), (0, 1)).validate().is_err());
100 assert!(ResourceLimits::new(1, Version::Normal(1), (1, 1)).with_encoding_timeout_millis(0).validate().is_err());
101 }
102
103 #[test]
104 fn timeout_budget_is_optional() {
105 let limits = ResourceLimits::new(1, Version::Normal(1), (1, 1)).with_encoding_timeout_millis(10);
106
107 assert_eq!(limits.encoding_timeout, Some(10));
108 assert!(limits.validate().is_ok());
109 }
110}