summaryrefslogtreecommitdiff
path: root/src/values
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/values.rs8
-rw-r--r--src/values/padding.rs214
-rw-r--r--src/values/rotation.rs85
3 files changed, 257 insertions, 50 deletions
diff --git a/src/values.rs b/src/values.rs
index 23e47d7..e71a8c4 100644
--- a/src/values.rs
+++ b/src/values.rs
@@ -1,8 +1,12 @@
mod padding;
mod rotation;
-pub trait ValueFromStr: Sized {
+pub trait Value: Sized {
type Err;
- fn value_from_str(s: &str) -> Result<Self, Self::Err>;
+ fn from_str(s: &str) -> Result<Self, Self::Err>;
+
+ // TODO remove this once RenderedElement's options field is redone
+ #[allow(dead_code)]
+ fn to_string(&self) -> String;
}
diff --git a/src/values/padding.rs b/src/values/padding.rs
index 01e333b..12880a3 100644
--- a/src/values/padding.rs
+++ b/src/values/padding.rs
@@ -3,67 +3,197 @@ use std::str::FromStr;
use iced::Padding;
-use super::ValueFromStr;
+use super::Value;
-#[derive(Debug, thiserror::Error)]
-pub enum PaddingError {
- #[error("wrong number of values")]
- WrongNumberOfValues,
+#[derive(Debug, thiserror::Error, Clone, PartialEq)]
+pub enum ParsePaddingError {
+ #[error("wrong number of values: {0}, expected 1-4")]
+ WrongNumberOfValues(usize),
#[error("float parsing error: {0}")]
ParseFloatError(ParseFloatError),
#[error("missing bracket")]
MissingBracket,
- #[error("empty string given")]
+ #[error("cannot parse padding from empty string")]
Empty,
}
-impl From<ParseFloatError> for PaddingError {
+impl From<ParseFloatError> for ParsePaddingError {
fn from(value: ParseFloatError) -> Self {
Self::ParseFloatError(value)
}
}
-impl ValueFromStr for Padding {
- type Err = PaddingError;
+impl Value for Padding {
+ type Err = ParsePaddingError;
- fn value_from_str(s: &str) -> Result<Self, Self::Err> {
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
- return Err(PaddingError::Empty);
+ return Err(ParsePaddingError::Empty);
}
- let values = s
- .strip_prefix('[')
- .ok_or(PaddingError::MissingBracket)?
- .strip_suffix(']')
- .ok_or(PaddingError::MissingBracket)?
- .split(',')
- .map(|n| f32::from_str(n))
- .collect::<Result<Vec<_>, _>>()?;
- match values.len() {
- 1 => Ok(Padding {
- top: values[0],
- right: values[0],
- bottom: values[0],
- left: values[0],
+
+ if !s.contains(['[', ',', ']']) {
+ let value = f32::from_str(s)?;
+ Ok(Padding {
+ top: value,
+ right: value,
+ bottom: value,
+ left: value,
+ })
+ } else {
+ let values = s
+ .strip_prefix('[')
+ .and_then(|s| s.strip_suffix(']'))
+ .ok_or(ParsePaddingError::MissingBracket)?
+ .split(',')
+ .map(str::trim)
+ .map(f32::from_str)
+ .collect::<Result<Vec<_>, _>>()?;
+
+ match values.len() {
+ 1 => Ok(Padding {
+ top: values[0],
+ right: values[0],
+ bottom: values[0],
+ left: values[0],
+ }),
+ 2 => Ok(Padding {
+ top: values[0],
+ right: values[1],
+ bottom: values[0],
+ left: values[1],
+ }),
+ 3 => Ok(Padding {
+ top: values[0],
+ right: values[1],
+ bottom: values[2],
+ left: values[1],
+ }),
+ 4 => Ok(Padding {
+ top: values[0],
+ right: values[1],
+ bottom: values[2],
+ left: values[3],
+ }),
+ other => Err(ParsePaddingError::WrongNumberOfValues(other)),
+ }
+ }
+ }
+
+ fn to_string(&self) -> String {
+ format!(
+ "[{}, {}, {}, {}]",
+ self.top, self.right, self.bottom, self.left
+ )
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn can_parse_single_value() {
+ assert_eq!(
+ Padding::from_str("[1.5]"),
+ Ok(Padding {
+ top: 1.5,
+ right: 1.5,
+ bottom: 1.5,
+ left: 1.5,
}),
- 2 => Ok(Padding {
- top: values[0],
- right: values[1],
- bottom: values[0],
- left: values[1],
+ )
+ }
+
+ #[test]
+ fn can_parse_single_value_without_brackets() {
+ assert_eq!(
+ Padding::from_str("1.5"),
+ Ok(Padding {
+ top: 1.5,
+ right: 1.5,
+ bottom: 1.5,
+ left: 1.5,
}),
- 3 => Ok(Padding {
- top: values[0],
- right: values[1],
- bottom: values[2],
- left: values[1],
+ )
+ }
+
+ #[test]
+ fn can_parse_two_values() {
+ assert_eq!(
+ Padding::from_str("[3.2, 6.7]"),
+ Ok(Padding {
+ top: 3.2,
+ right: 6.7,
+ bottom: 3.2,
+ left: 6.7,
}),
- 4 => Ok(Padding {
- top: values[0],
- right: values[1],
- bottom: values[2],
- left: values[3],
+ )
+ }
+
+ #[test]
+ fn can_parse_three_values() {
+ assert_eq!(
+ Padding::from_str("[4.8, 8.1,5.9]"),
+ Ok(Padding {
+ top: 4.8,
+ right: 8.1,
+ bottom: 5.9,
+ left: 8.1,
}),
- _ => Err(PaddingError::WrongNumberOfValues),
- }
+ )
+ }
+
+ #[test]
+ fn can_parse_four_values() {
+ assert_eq!(
+ Padding::from_str("[35.4,74.6 ,53.1, 25.0]"),
+ Ok(Padding {
+ top: 35.4,
+ right: 74.6,
+ bottom: 53.1,
+ left: 25.0,
+ }),
+ )
+ }
+
+ #[test]
+ fn cant_parse_five_values() {
+ assert_eq!(
+ Padding::from_str("[1,2,3,4,5]"),
+ Err(ParsePaddingError::WrongNumberOfValues(5)),
+ )
+ }
+
+ #[test]
+ fn cant_parse_invalid_floats() {
+ assert_eq!(
+ Padding::from_str("[1f,2,3,4]"),
+ Err(ParsePaddingError::ParseFloatError(
+ f32::from_str("1f").expect_err("")
+ ))
+ )
+ }
+
+ #[test]
+ fn cant_parse_with_missing_bracket() {
+ assert_eq!(
+ Padding::from_str("1,2,3,4,5]"),
+ Err(ParsePaddingError::MissingBracket)
+ );
+
+ assert_eq!(
+ Padding::from_str("[1,2,3,4,5"),
+ Err(ParsePaddingError::MissingBracket)
+ );
+
+ assert_eq!(
+ Padding::from_str("1,2,3,4,5"),
+ Err(ParsePaddingError::MissingBracket)
+ )
+ }
+
+ #[test]
+ fn cant_parse_empty_string() {
+ assert_eq!(Padding::from_str(""), Err(ParsePaddingError::Empty))
}
}
diff --git a/src/values/rotation.rs b/src/values/rotation.rs
index 2b7a223..da291b2 100644
--- a/src/values/rotation.rs
+++ b/src/values/rotation.rs
@@ -3,14 +3,16 @@ use std::str::FromStr;
use iced::{Radians, Rotation};
-use super::ValueFromStr;
+use super::Value;
-#[derive(Debug, thiserror::Error)]
+#[derive(Debug, thiserror::Error, Clone, PartialEq)]
pub enum ParseRotationError {
#[error("float parsing error: {0}")]
ParseFloatError(ParseFloatError),
#[error("invalid prefix")]
InvalidPrefix,
+ #[error("cannot parse rotation from empty string")]
+ Empty,
}
impl From<ParseFloatError> for ParseRotationError {
@@ -19,13 +21,17 @@ impl From<ParseFloatError> for ParseRotationError {
}
}
-impl ValueFromStr for Rotation {
+impl Value for Rotation {
type Err = ParseRotationError;
- fn value_from_str(s: &str) -> Result<Self, Self::Err> {
- if s.starts_with(|c: char| !c.is_digit(10)) {
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ if s.is_empty() {
+ return Err(ParseRotationError::Empty);
+ }
+
+ if s.starts_with(|c: char| !c.is_ascii_digit()) {
let (prefix, value) = s.split_at(1);
- match prefix {
+ match prefix.to_lowercase().as_str() {
"s" => Ok(Rotation::Solid(Radians(f32::from_str(value)?))),
"f" => Ok(Rotation::Floating(Radians(f32::from_str(value)?))),
_ => Err(ParseRotationError::InvalidPrefix),
@@ -34,4 +40,71 @@ impl ValueFromStr for Rotation {
Ok(Rotation::Floating(Radians(f32::from_str(s)?)))
}
}
+
+ fn to_string(&self) -> String {
+ match self {
+ Self::Floating(value) => format!("f{}", value),
+ Self::Solid(value) => format!("s{}", value),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn can_parse_without_prefix() {
+ assert_eq!(
+ Rotation::from_str("10.5"),
+ Ok(Rotation::Floating(Radians(10.5)))
+ )
+ }
+
+ #[test]
+ fn can_parse_with_s_prefix() {
+ assert_eq!(
+ Rotation::from_str("s12.3"),
+ Ok(Rotation::Solid(Radians(12.3)))
+ )
+ }
+
+ #[test]
+ fn can_parse_with_f_prefix() {
+ assert_eq!(
+ Rotation::from_str("f16.9"),
+ Ok(Rotation::Floating(Radians(16.9)))
+ )
+ }
+
+ #[test]
+ fn can_parse_with_uppercase_prefix() {
+ assert_eq!(
+ Rotation::from_str("S9.4"),
+ Ok(Rotation::Solid(Radians(9.4)))
+ )
+ }
+
+ #[test]
+ fn cant_parse_invalid_prefix() {
+ assert_eq!(
+ Rotation::from_str("a6.0"),
+ Err(ParseRotationError::InvalidPrefix)
+ )
+ }
+
+ #[test]
+ fn cant_parse_invalid_float() {
+ assert_eq!(
+ Rotation::from_str("3.a"),
+ Err(ParseRotationError::ParseFloatError(
+ f32::from_str("3.a").expect_err("")
+ ))
+ )
+ }
+
+ #[test]
+ fn cant_parse_empty_string() {
+ assert_eq!(Rotation::from_str(""), Err(ParseRotationError::Empty))
+ }
}