use std::convert::TryFrom;
#[derive(Clone, Debug, PartialEq)]
pub enum Size {
Pixel(Pixel),
Percent(Percent),
Raw(f32),
}
impl Size {
pub fn percent(value: f32) -> Self {
Self::Percent(Percent::new(value))
}
pub fn pixel(value: f32) -> Self {
Self::Pixel(Pixel::new(value))
}
pub fn as_percent(&self) -> Option<&Percent> {
match self {
Self::Percent(value) => Some(value),
_ => None,
}
}
pub fn is_percent(&self) -> bool {
matches!(self, Self::Percent(_))
}
pub fn as_pixel(&self) -> Option<&Pixel> {
match self {
Self::Pixel(value) => Some(value),
_ => None,
}
}
pub fn is_pixel(&self) -> bool {
matches!(self, Self::Pixel(_))
}
pub fn value(&self) -> f32 {
match self {
Self::Pixel(p) => p.value(),
Self::Percent(p) => p.value(),
Self::Raw(v) => *v,
}
}
pub fn from_border(input: &str) -> Option<Self> {
input
.split_whitespace()
.next()
.and_then(|value| Size::try_from(value).ok())
}
}
impl TryFrom<&str> for Size {
type Error = String;
fn try_from(value: &str) -> Result<Self, Self::Error> {
if value.ends_with("px") {
Ok(Self::Pixel(Pixel::try_from(value)?))
} else if value.ends_with('%') {
Ok(Self::Percent(Percent::try_from(value)?))
} else {
Ok(Self::Raw(
value.parse::<f32>().map_err(|err| err.to_string())?,
))
}
}
}
impl ToString for Size {
fn to_string(&self) -> String {
match self {
Self::Pixel(px) => px.to_string(),
Self::Percent(prc) => prc.to_string(),
Self::Raw(value) => value.to_string(),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Pixel(f32);
impl Pixel {
pub fn new(value: f32) -> Self {
Self(value)
}
pub fn value(&self) -> f32 {
self.0
}
pub fn from_border(input: &str) -> Option<Self> {
input
.split_whitespace()
.next()
.and_then(|value| Self::try_from(value).ok())
}
}
impl TryFrom<&str> for Pixel {
type Error = String;
fn try_from(value: &str) -> Result<Self, Self::Error> {
if let Some(value) = value.strip_suffix("px") {
value
.parse::<f32>()
.map(Pixel::new)
.map_err(|err| err.to_string())
} else {
Err(String::from("pixel value should end with px"))
}
}
}
impl Default for Pixel {
fn default() -> Self {
Self(0.0)
}
}
impl ToString for Pixel {
fn to_string(&self) -> String {
format!("{}px", self.0)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Percent(f32);
impl Percent {
pub fn new(value: f32) -> Self {
Self(value)
}
pub fn value(&self) -> f32 {
self.0
}
}
impl TryFrom<&str> for Percent {
type Error = String;
fn try_from(value: &str) -> Result<Self, Self::Error> {
if let Some(value) = value.strip_suffix('%') {
value
.parse::<f32>()
.map(Percent::new)
.map_err(|err| err.to_string())
} else {
Err(String::from("percent value should end with %"))
}
}
}
impl Default for Percent {
fn default() -> Self {
Self(0.0)
}
}
impl ToString for Percent {
fn to_string(&self) -> String {
format!("{}%", self.0)
}
}