use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq)]
pub struct SandboxSection {
#[serde(default)]
pub enabled: bool,
#[serde(default)]
pub deterministic: bool,
#[serde(default)]
pub seed: Option<u64>,
#[serde(default)]
pub memory_limit: Option<String>,
#[serde(default)]
pub time_limit: Option<String>,
#[serde(default)]
pub virtual_fs: bool,
#[serde(default)]
pub seed_files: HashMap<String, String>,
}
impl SandboxSection {
pub fn memory_limit_bytes(&self) -> Option<u64> {
self.memory_limit.as_ref().and_then(|s| parse_byte_size(s))
}
pub fn time_limit_ms(&self) -> Option<u64> {
self.time_limit.as_ref().and_then(|s| parse_duration_ms(s))
}
}
pub(crate) fn parse_byte_size(s: &str) -> Option<u64> {
let s = s.trim();
let (num_part, suffix) = split_numeric_suffix(s)?;
let value: u64 = num_part.parse().ok()?;
let multiplier = match suffix.to_uppercase().as_str() {
"B" | "" => 1,
"KB" | "K" => 1024,
"MB" | "M" => 1024 * 1024,
"GB" | "G" => 1024 * 1024 * 1024,
_ => return None,
};
Some(value * multiplier)
}
pub(crate) fn parse_duration_ms(s: &str) -> Option<u64> {
let s = s.trim();
let (num_part, suffix) = split_numeric_suffix(s)?;
let value: u64 = num_part.parse().ok()?;
let multiplier = match suffix.to_lowercase().as_str() {
"ms" => 1,
"s" | "" => 1000,
"m" | "min" => 60_000,
_ => return None,
};
Some(value * multiplier)
}
fn split_numeric_suffix(s: &str) -> Option<(&str, &str)> {
let idx = s
.find(|c: char| !c.is_ascii_digit() && c != '.')
.unwrap_or(s.len());
if idx == 0 {
return None;
}
Some((&s[..idx], &s[idx..]))
}