#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Margins {
pub left: f64,
pub top: f64,
pub right: f64,
pub bottom: f64,
}
impl Margins {
pub fn none() -> Self {
Self {
left: 0.0,
top: 0.0,
right: 0.0,
bottom: 0.0,
}
}
pub fn uniform(value: f64) -> Self {
Self {
left: value,
top: value,
right: value,
bottom: value,
}
}
pub fn new(left: f64, top: f64, right: f64, bottom: f64) -> Self {
Self {
left,
top,
right,
bottom,
}
}
pub fn from_str(s: &str) -> Result<Self, String> {
let parts: Vec<&str> = s.split_whitespace().collect();
match parts.len() {
1 => {
let value = parts[0]
.parse::<f64>()
.map_err(|e| format!("Invalid margin value: {}", e))?;
Ok(Self::uniform(value))
}
2 => {
let h = parts[0]
.parse::<f64>()
.map_err(|e| format!("Invalid horizontal margin: {}", e))?;
let v = parts[1]
.parse::<f64>()
.map_err(|e| format!("Invalid vertical margin: {}", e))?;
Ok(Self {
left: h,
top: v,
right: h,
bottom: v,
})
}
4 => {
let left = parts[0]
.parse::<f64>()
.map_err(|e| format!("Invalid left margin: {}", e))?;
let top = parts[1]
.parse::<f64>()
.map_err(|e| format!("Invalid top margin: {}", e))?;
let right = parts[2]
.parse::<f64>()
.map_err(|e| format!("Invalid right margin: {}", e))?;
let bottom = parts[3]
.parse::<f64>()
.map_err(|e| format!("Invalid bottom margin: {}", e))?;
Ok(Self::new(left, top, right, bottom))
}
_ => Err(format!(
"Invalid margin specification: expected 1, 2, or 4 values, got {}",
parts.len()
)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_margins_none() {
let m = Margins::none();
assert_eq!(m.left, 0.0);
assert_eq!(m.top, 0.0);
assert_eq!(m.right, 0.0);
assert_eq!(m.bottom, 0.0);
}
#[test]
fn test_margins_uniform() {
let m = Margins::uniform(10.0);
assert_eq!(m.left, 10.0);
assert_eq!(m.top, 10.0);
assert_eq!(m.right, 10.0);
assert_eq!(m.bottom, 10.0);
}
#[test]
fn test_margins_from_str_single() {
let m = Margins::from_str("15").unwrap();
assert_eq!(m, Margins::uniform(15.0));
}
#[test]
fn test_margins_from_str_two_values() {
let m = Margins::from_str("10 20").unwrap();
assert_eq!(m.left, 10.0);
assert_eq!(m.right, 10.0);
assert_eq!(m.top, 20.0);
assert_eq!(m.bottom, 20.0);
}
#[test]
fn test_margins_from_str_four_values() {
let m = Margins::from_str("10 20 30 40").unwrap();
assert_eq!(m.left, 10.0);
assert_eq!(m.top, 20.0);
assert_eq!(m.right, 30.0);
assert_eq!(m.bottom, 40.0);
}
#[test]
fn test_margins_from_str_invalid() {
assert!(Margins::from_str("10 20 30").is_err());
assert!(Margins::from_str("invalid").is_err());
}
}