summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/values.rs1
-rw-r--r--src/values/length.rs145
-rw-r--r--src/values/padding.rs6
-rw-r--r--src/values/rotation.rs6
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))
}
}