diff options
Diffstat (limited to '')
| -rw-r--r-- | src/values.rs | 1 | ||||
| -rw-r--r-- | src/values/length.rs | 145 | ||||
| -rw-r--r-- | src/values/padding.rs | 6 | ||||
| -rw-r--r-- | src/values/rotation.rs | 6 |
4 files changed, 154 insertions, 4 deletions
diff --git a/src/values.rs b/src/values.rs index e71a8c4..31ee7bb 100644 --- a/src/values.rs +++ b/src/values.rs @@ -1,3 +1,4 @@ +mod length; mod padding; mod rotation; diff --git a/src/values/length.rs b/src/values/length.rs new file mode 100644 index 0000000..28a7156 --- /dev/null +++ b/src/values/length.rs @@ -0,0 +1,145 @@ +use std::num::{ParseFloatError, ParseIntError}; +use std::str::FromStr; + +use iced::Length; + +use super::Value; + +#[derive(Debug, thiserror::Error, Clone, PartialEq)] +pub enum ParseLengthError { + #[error("float parsing error: {0}")] + ParseFloatError(ParseFloatError), + #[error("int parsing error: {0}")] + ParseIntError(ParseIntError), + #[error("invalid type")] + InvalidType, + #[error("invalid prefix")] + InvalidPrefix, + #[error("missing prefix")] + MissingPrefix, + #[error("cannot parse length from empty string")] + Empty, +} + +impl From<ParseFloatError> for ParseLengthError { + fn from(value: ParseFloatError) -> Self { + Self::ParseFloatError(value) + } +} + +impl From<ParseIntError> for ParseLengthError { + fn from(value: ParseIntError) -> Self { + Self::ParseIntError(value) + } +} + +impl Value for Length { + type Err = ParseLengthError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let s = s.trim(); + + if s.is_empty() { + return Err(ParseLengthError::Empty); + } + + if !s.contains(|c: char| c.is_ascii_digit()) { + match s { + "fill" => Ok(Self::Fill), + "shrink" => Ok(Self::Shrink), + _ => Err(ParseLengthError::InvalidType), + } + } else { + if s.starts_with(|c: char| !c.is_alphabetic()) { + return Err(ParseLengthError::MissingPrefix); + } + + let (prefix, value) = s.split_at(2); + match prefix.to_lowercase().as_str() { + "fx" => Ok(Self::Fixed(f32::from_str(value)?)), + "fp" => Ok(Self::FillPortion(u16::from_str(value)?)), + _ => Err(ParseLengthError::InvalidPrefix), + } + } + } + + fn to_string(&self) -> String { + match self { + Self::Fill => String::from("fill"), + Self::Shrink => String::from("shrink"), + Self::Fixed(value) => format!("fx{}", value), + Self::FillPortion(value) => format!("fp{}", value), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn can_parse_fill() { + assert_eq!(Length::from_str("fill"), Ok(Length::Fill)) + } + + #[test] + fn can_parse_shrink_with_space() { + assert_eq!(Length::from_str("shrink "), Ok(Length::Shrink)) + } + + #[test] + fn can_parse_fill_portion() { + assert_eq!(Length::from_str("fp15"), Ok(Length::FillPortion(15))) + } + + #[test] + fn can_parse_fixed_with_spaces() { + assert_eq!(Length::from_str(" fx3.1 "), Ok(Length::Fixed(3.1))) + } + + #[test] + fn cant_parse_invalid_type() { + assert_eq!( + Length::from_str("fillportion"), + Err(ParseLengthError::InvalidType) + ) + } + + #[test] + fn cant_parse_invalid_prefix() { + assert_eq!( + Length::from_str("f2.0"), + Err(ParseLengthError::InvalidPrefix), + ) + } + + #[test] + fn cant_parse_invalid_float() { + assert_eq!( + Length::from_str(" fx2.a"), + Err(ParseLengthError::ParseFloatError( + f32::from_str("2.a").expect_err("float parse should fail") + )) + ) + } + + #[test] + fn cant_parse_invalid_integer() { + assert_eq!( + Length::from_str("fp1a "), + Err(ParseLengthError::ParseIntError( + u16::from_str("1a").expect_err("integer parse should fail") + )) + ) + } + + #[test] + fn cant_parse_with_missing_prefix() { + assert_eq!(Length::from_str("24"), Err(ParseLengthError::MissingPrefix)) + } + + #[test] + fn cant_parse_empty_string() { + assert_eq!(Length::from_str(" "), Err(ParseLengthError::Empty)) + } +} diff --git a/src/values/padding.rs b/src/values/padding.rs index 12880a3..b6d3947 100644 --- a/src/values/padding.rs +++ b/src/values/padding.rs @@ -27,6 +27,8 @@ impl Value for Padding { type Err = ParsePaddingError; fn from_str(s: &str) -> Result<Self, Self::Err> { + let s = s.trim(); + if s.is_empty() { return Err(ParsePaddingError::Empty); } @@ -169,7 +171,7 @@ mod tests { assert_eq!( Padding::from_str("[1f,2,3,4]"), Err(ParsePaddingError::ParseFloatError( - f32::from_str("1f").expect_err("") + f32::from_str("1f").expect_err("float parse should fail") )) ) } @@ -194,6 +196,6 @@ mod tests { #[test] fn cant_parse_empty_string() { - assert_eq!(Padding::from_str(""), Err(ParsePaddingError::Empty)) + assert_eq!(Padding::from_str(" "), Err(ParsePaddingError::Empty)) } } diff --git a/src/values/rotation.rs b/src/values/rotation.rs index da291b2..2b609d3 100644 --- a/src/values/rotation.rs +++ b/src/values/rotation.rs @@ -25,6 +25,8 @@ impl Value for Rotation { type Err = ParseRotationError; fn from_str(s: &str) -> Result<Self, Self::Err> { + let s = s.trim(); + if s.is_empty() { return Err(ParseRotationError::Empty); } @@ -98,13 +100,13 @@ mod tests { assert_eq!( Rotation::from_str("3.a"), Err(ParseRotationError::ParseFloatError( - f32::from_str("3.a").expect_err("") + f32::from_str("3.a").expect_err("float parse should fail") )) ) } #[test] fn cant_parse_empty_string() { - assert_eq!(Rotation::from_str(""), Err(ParseRotationError::Empty)) + assert_eq!(Rotation::from_str(" "), Err(ParseRotationError::Empty)) } } |
