ryg_rans_rs_cli/
limits.rs1use crate::error::{AppError, ResourceLimitError};
11use std::time::Duration;
12
13pub const DEFAULT_MAX_INPUT: u64 = 16 * 1024 * 1024 * 1024;
15
16pub const DEFAULT_MAX_OUTPUT: u64 = 16 * 1024 * 1024 * 1024;
18
19pub const DEFAULT_BLOCK_SIZE: u32 = 1024 * 1024;
21
22pub const HARD_MAX_BLOCK_SIZE: u32 = 64 * 1024 * 1024;
24
25pub const DEFAULT_MAX_PAYLOAD: u32 = 1024 * 1024;
27
28pub const DEFAULT_MAX_MODEL: u32 = 2048;
30
31pub const DEFAULT_MAX_BLOCKS: u64 = 1_000_000;
33
34pub const DEFAULT_MAX_TRACE_SYMBOLS: u64 = 256;
36
37pub const DEFAULT_MAX_ORACLE_OUTPUT: u64 = 64 * 1024 * 1024;
39
40pub const DEFAULT_ORACLE_TIMEOUT: Duration = Duration::from_secs(60);
42
43#[derive(Debug, Clone)]
45pub struct Limits {
46 pub max_input_bytes: u64,
48 pub max_output_bytes: u64,
50 pub max_block_bytes: u32,
52 pub max_payload_bytes: u32,
54 pub max_model_bytes: u32,
56 pub max_blocks: u64,
58 pub max_trace_symbols: u64,
60 pub max_oracle_output_bytes: u64,
62 pub oracle_timeout: Duration,
64}
65
66impl Default for Limits {
67 fn default() -> Self {
68 Self {
69 max_input_bytes: DEFAULT_MAX_INPUT,
70 max_output_bytes: DEFAULT_MAX_OUTPUT,
71 max_block_bytes: DEFAULT_BLOCK_SIZE,
72 max_payload_bytes: DEFAULT_MAX_PAYLOAD,
73 max_model_bytes: DEFAULT_MAX_MODEL,
74 max_blocks: DEFAULT_MAX_BLOCKS,
75 max_trace_symbols: DEFAULT_MAX_TRACE_SYMBOLS,
76 max_oracle_output_bytes: DEFAULT_MAX_ORACLE_OUTPUT,
77 oracle_timeout: DEFAULT_ORACLE_TIMEOUT,
78 }
79 }
80}
81
82impl Limits {
83 pub fn check_block_size(&self, size: u32) -> Result<(), AppError> {
85 if size > self.max_block_bytes {
86 return Err(AppError::ResourceLimit(ResourceLimitError {
87 detail: "block size exceeds limit".into(),
88 limit: self.max_block_bytes as u64,
89 requested: size as u64,
90 }));
91 }
92 Ok(())
93 }
94
95 pub fn check_payload_size(&self, size: u32) -> Result<(), AppError> {
97 if size > self.max_payload_bytes {
98 return Err(AppError::ResourceLimit(ResourceLimitError {
99 detail: "payload size exceeds limit".into(),
100 limit: self.max_payload_bytes as u64,
101 requested: size as u64,
102 }));
103 }
104 Ok(())
105 }
106
107 pub fn check_model_size(&self, size: u32) -> Result<(), AppError> {
109 if size > self.max_model_bytes {
110 return Err(AppError::ResourceLimit(ResourceLimitError {
111 detail: "model size exceeds limit".into(),
112 limit: self.max_model_bytes as u64,
113 requested: size as u64,
114 }));
115 }
116 Ok(())
117 }
118
119 pub fn check_block_count(&self, count: u64) -> Result<(), AppError> {
121 if count > self.max_blocks {
122 return Err(AppError::ResourceLimit(ResourceLimitError {
123 detail: "block count exceeds limit".into(),
124 limit: self.max_blocks,
125 requested: count,
126 }));
127 }
128 Ok(())
129 }
130
131 pub fn check_output_total(&self, current: u64, additional: u64) -> Result<u64, AppError> {
134 let new_total = current.checked_add(additional).ok_or_else(|| {
135 AppError::ResourceLimit(ResourceLimitError {
136 detail: "output total overflow".into(),
137 limit: self.max_output_bytes,
138 requested: current.saturating_add(additional),
139 })
140 })?;
141 if new_total > self.max_output_bytes {
142 return Err(AppError::ResourceLimit(ResourceLimitError {
143 detail: "output total exceeds limit".into(),
144 limit: self.max_output_bytes,
145 requested: new_total,
146 }));
147 }
148 Ok(new_total)
149 }
150
151 pub fn parse_size(s: &str) -> Result<u64, String> {
154 let s = s.trim();
155 if s.is_empty() {
156 return Err("empty size string".into());
157 }
158
159 let num_end = s.find(|c: char| !c.is_ascii_digit()).unwrap_or(s.len());
161 let num_part = &s[..num_end];
162 let suffix = s[num_end..].trim();
163
164 let value: u64 = num_part
165 .parse()
166 .map_err(|_| format!("invalid number: '{}'", num_part))?;
167
168 match suffix.to_lowercase().as_str() {
169 "" | "b" => Ok(value),
170 "kib" | "ki" => value.checked_mul(1024).ok_or("overflow".into()),
171 "mib" | "mi" => value.checked_mul(1024 * 1024).ok_or("overflow".into()),
172 "gib" | "gi" => value
173 .checked_mul(1024 * 1024 * 1024)
174 .ok_or("overflow".into()),
175 _ => Err(format!("unknown size suffix: '{}'", suffix)),
176 }
177 }
178}