use std::fmt;
use std::str::FromStr;
use crate::parse::UnrecognizedVariant;
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub enum Align {
#[default]
Top,
Bottom,
Left,
Right,
Middle,
}
impl_parse_enum!(Align, Top, Bottom, Left, Right, Middle);
impl fmt::Display for Align {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub enum DimensionUnit {
#[default]
Pixel,
Percentage = b'%' as _,
CharacterSpacing = b'c' as _,
}
impl fmt::Display for DimensionUnit {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Pixel => Ok(()),
Self::Percentage => "%".fmt(f),
Self::CharacterSpacing => "c".fmt(f),
}
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct Dimension<T = u32> {
pub amount: T,
pub unit: DimensionUnit,
}
impl<T> Dimension<T> {
pub const fn pixels(amount: T) -> Self {
Self {
amount,
unit: DimensionUnit::Pixel,
}
}
pub const fn character_spacing(amount: T) -> Self {
Self {
amount,
unit: DimensionUnit::CharacterSpacing,
}
}
pub const fn percentage(amount: T) -> Self {
Self {
amount,
unit: DimensionUnit::Percentage,
}
}
}
impl<T: fmt::Display> fmt::Display for Dimension<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Self { amount, unit } = self;
write!(f, "{amount}{unit}")
}
}
impl<T: FromStr> FromStr for Dimension<T> {
type Err = T::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (amount, unit) = match s.split_at_checked(s.len().saturating_sub(1)) {
Some((amount, "%")) => (amount, DimensionUnit::Percentage),
Some((amount, "c")) => (amount, DimensionUnit::CharacterSpacing),
_ => (s, DimensionUnit::Pixel),
};
Ok(Self {
amount: amount.parse()?,
unit,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::{StringPair, format_from_pairs, parse_from_pairs};
const DIMENSION_PAIRS: &[StringPair<Dimension>] = &[
(Dimension::pixels(10), "10"),
(Dimension::character_spacing(20), "20c"),
(Dimension::percentage(30), "30%"),
];
#[test]
fn fmt_dimension() {
let (actual, expected) = format_from_pairs(DIMENSION_PAIRS);
assert_eq!(actual, expected);
}
#[test]
fn parse_dimension() {
let (actual, expected) = parse_from_pairs(DIMENSION_PAIRS);
assert_eq!(actual, expected);
}
}