diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-10-10 22:19:36 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-10-10 22:19:36 +0200 |
| commit | 92c01da36016e94ff20163806ddcbcf7e33d4031 (patch) | |
| tree | 1a900b3c11edcc93e9153fada3ce92310db5768b /src/length.rs | |
| parent | 42500d5ed85539c5ab04dd3544beaf802da29be9 (diff) | |
Switch back to custom geometry types, unified with layout primitives 🏞
Diffstat (limited to 'src/length.rs')
| -rw-r--r-- | src/length.rs | 203 |
1 files changed, 0 insertions, 203 deletions
diff --git a/src/length.rs b/src/length.rs deleted file mode 100644 index 437c741d..00000000 --- a/src/length.rs +++ /dev/null @@ -1,203 +0,0 @@ -//! A length type with a unit. - -use std::fmt::{self, Debug, Display, Formatter}; -use std::str::FromStr; - -/// A length with a unit. -#[derive(Copy, Clone, PartialEq)] -pub struct Length { - /// The length in the given unit. - pub val: f64, - /// The unit of measurement. - pub unit: Unit, -} - -/// Different units of measurement. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] -pub enum Unit { - /// Points. - Pt, - /// Millimeters. - Mm, - /// Centimeters. - Cm, - /// Inches. - In, - /// Raw units (the implicit unit of all bare `f64` lengths). - Raw, -} - -impl Length { - /// Create a length from a value with a unit. - pub const fn new(val: f64, unit: Unit) -> Self { - Self { val, unit } - } - - /// Create a length from a number of points. - pub const fn pt(pt: f64) -> Self { - Self::new(pt, Unit::Pt) - } - - /// Create a length from a number of millimeters. - pub const fn mm(mm: f64) -> Self { - Self::new(mm, Unit::Mm) - } - - /// Create a length from a number of centimeters. - pub const fn cm(cm: f64) -> Self { - Self::new(cm, Unit::Cm) - } - - /// Create a length from a number of inches. - pub const fn inches(inches: f64) -> Self { - Self::new(inches, Unit::In) - } - - /// Create a length from a number of raw units. - pub const fn raw(raw: f64) -> Self { - Self::new(raw, Unit::Raw) - } - - /// Convert this to a number of points. - pub fn as_pt(self) -> f64 { - self.with_unit(Unit::Pt).val - } - - /// Convert this to a number of millimeters. - pub fn as_mm(self) -> f64 { - self.with_unit(Unit::Mm).val - } - - /// Convert this to a number of centimeters. - pub fn as_cm(self) -> f64 { - self.with_unit(Unit::Cm).val - } - - /// Convert this to a number of inches. - pub fn as_inches(self) -> f64 { - self.with_unit(Unit::In).val - } - - /// Get the value of this length in raw units. - pub fn as_raw(self) -> f64 { - self.with_unit(Unit::Raw).val - } - - /// Convert this to a length with a different unit. - pub fn with_unit(self, unit: Unit) -> Self { - Self { - val: self.val * self.unit.raw_scale() / unit.raw_scale(), - unit, - } - } -} - -impl Unit { - /// How many raw units correspond to a value of `1.0` in this unit. - fn raw_scale(self) -> f64 { - match self { - Unit::Pt => 1.0, - Unit::Mm => 2.83465, - Unit::Cm => 28.3465, - Unit::In => 72.0, - Unit::Raw => 1.0, - } - } -} - -impl Display for Length { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{:.2}{}", self.val, self.unit) - } -} - -impl Debug for Length { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(self, f) - } -} - -impl Display for Unit { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.pad(match self { - Unit::Mm => "mm", - Unit::Pt => "pt", - Unit::Cm => "cm", - Unit::In => "in", - Unit::Raw => "rw", - }) - } -} - -impl Debug for Unit { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(self, f) - } -} - -impl FromStr for Length { - type Err = ParseLengthError; - - fn from_str(src: &str) -> Result<Self, Self::Err> { - let len = src.len(); - - // We need at least some number and the unit. - if len <= 2 { - return Err(ParseLengthError); - } - - // We can view the string as bytes since a multibyte UTF-8 char cannot - // have valid ASCII chars as subbytes. - let split = len - 2; - let bytes = src.as_bytes(); - let unit = match &bytes[split ..] { - b"pt" => Unit::Pt, - b"mm" => Unit::Mm, - b"cm" => Unit::Cm, - b"in" => Unit::In, - _ => return Err(ParseLengthError), - }; - - src[.. split] - .parse::<f64>() - .map(|val| Self::new(val, unit)) - .map_err(|_| ParseLengthError) - } -} - -/// The error when parsing a length fails. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct ParseLengthError; - -impl std::error::Error for ParseLengthError {} - -impl Display for ParseLengthError { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - f.pad("invalid string for length") - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_length_from_str_parses_correct_value_and_unit() { - assert_eq!(Length::from_str("2.5cm"), Ok(Length::cm(2.5))); - } - - #[test] - fn test_length_from_str_works_with_non_ascii_chars() { - assert_eq!(Length::from_str("123🚚"), Err(ParseLengthError)); - } - - #[test] - fn test_length_formats_correctly() { - assert_eq!(Length::cm(12.728).to_string(), "12.73cm".to_string()); - } - - #[test] - fn test_length_unit_conversion() { - assert!((Length::mm(150.0).as_cm() - 15.0) < 1e-4); - } -} |
