use std::num::ParseFloatError; use std::str::FromStr; use iced::Length; use iced::widget::grid::Sizing; use super::Value; use super::length::ParseLengthError; #[derive(Debug, thiserror::Error, Clone, PartialEq)] pub enum ParseSizingError { #[error("float parsing error: {0}")] ParseFloatError(ParseFloatError), #[error("length parsing error: {0}")] ParseLengthError(#[from] ParseLengthError), #[error("invalid prefix")] InvalidPrefix, #[error("missing prefix")] MissingPrefix, #[error("cannot parse sizing from empty string")] Empty, } impl From for ParseSizingError { fn from(value: ParseFloatError) -> Self { Self::ParseFloatError(value) } } impl Value for Sizing { type Err = ParseSizingError; fn from_str(s: &str) -> Result { let s = s.trim(); if s.is_empty() { return Err(ParseSizingError::Empty); } if s.starts_with(|c: char| c.is_ascii_digit()) { return Err(ParseSizingError::MissingPrefix); } let (prefix, value) = s.split_at(2); match prefix.to_lowercase().as_str() { "ar" => Ok(Self::AspectRatio(f32::from_str(value)?)), "ed" => Ok(Self::EvenlyDistribute(Length::from_str(value)?)), _ => Err(ParseSizingError::InvalidPrefix), } } fn to_string(&self) -> String { match self { Self::AspectRatio(ratio) => format!("ar{ratio}"), Self::EvenlyDistribute(length) => { format!("ed{}", length.to_string()) } } } } #[cfg(test)] mod tests { use super::*; #[test] fn can_parse_ratio() { assert_eq!(Sizing::from_str("ar5.1"), Ok(Sizing::AspectRatio(5.1))) } #[test] fn can_parse_distribute_with_space() { assert_eq!( Sizing::from_str(" edfp2 "), Ok(Sizing::EvenlyDistribute(Length::FillPortion(2))) ) } #[test] fn cant_parse_invalid_prefix() { assert_eq!( Sizing::from_str("bc4.1 "), Err(ParseSizingError::InvalidPrefix) ) } #[test] fn cant_parse_invalid_float() { assert_eq!( Sizing::from_str(" ar2.a"), Err(ParseSizingError::ParseFloatError( f32::from_str("2.a").expect_err("float parse should fail") )) ) } #[test] fn cant_parse_with_missing_prefix() { assert_eq!( Sizing::from_str("2.4"), Err(ParseSizingError::MissingPrefix) ) } #[test] fn cant_parse_empty_string() { assert_eq!(Sizing::from_str(" "), Err(ParseSizingError::Empty)) } }