use std::borrow::Cow;
use std::fmt;
use crate::arguments::{ArgumentScanner, ExpectArg, FromArgs};
use crate::keyword::ImageKeyword;
use crate::screen::{Align, Dimension};
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct Image<S = String> {
pub fname: S,
pub url: Option<S>,
pub class: Option<S>,
pub height: Option<Dimension<u32>>,
pub width: Option<Dimension<u32>>,
pub hspace: Option<Dimension<u32>>,
pub vspace: Option<Dimension<u32>>,
pub align: Option<Align>,
pub is_map: bool,
}
impl<S> Image<S> {
pub fn map_text<T, F>(self, mut f: F) -> Image<T>
where
F: FnMut(S) -> T,
{
Image {
fname: f(self.fname),
url: self.url.map(&mut f),
class: self.class.map(f),
height: self.height,
width: self.width,
hspace: self.hspace,
vspace: self.vspace,
align: self.align,
is_map: self.is_map,
}
}
}
impl_into_owned!(Image);
impl<S: AsRef<str>> Image<S> {
pub fn borrow_text(&self) -> Image<&str> {
Image {
fname: self.fname.as_ref(),
url: self.url.as_ref().map(AsRef::as_ref),
class: self.class.as_ref().map(AsRef::as_ref),
height: self.height,
width: self.width,
hspace: self.hspace,
vspace: self.vspace,
align: self.align,
is_map: self.is_map,
}
}
pub fn uri(&self) -> Cow<'_, str> {
let fname = self.fname.as_ref();
if self.url.is_none() && self.class.is_none() {
return Cow::Borrowed(fname);
}
let url = match &self.url {
Some(url) => url.as_ref(),
None => "",
};
let class = match &self.class {
Some(class) => class.as_ref(),
None => "",
};
let mut buf = String::with_capacity(url.len() + class.len() + fname.len() + 2);
for part in [url, class] {
if part.is_empty() {
continue;
}
buf.push_str(part);
if !part.ends_with('/') {
buf.push('/');
}
}
buf.push_str(fname);
Cow::Owned(buf)
}
}
impl_partial_eq!(Image);
impl<'a, S: AsRef<str>> FromArgs<'a, S> for Image<S> {
fn from_args<A: ArgumentScanner<'a, Decoded = S>>(scanner: A) -> crate::Result<Self> {
let mut scanner = scanner.with_keywords();
let fname = scanner.get_next_or("fname")?.expect_some("fname")?;
let url = scanner.get_next_or("url")?;
let class = scanner.get_next_or("t")?;
let height = scanner.get_next_or("h")?.expect_number()?;
let width = scanner.get_next_or("w")?.expect_number()?;
let hspace = scanner.get_next_or("hspace")?.expect_number()?;
let vspace = scanner.get_next_or("vspace")?.expect_number()?;
let align = scanner.get_next_or("align")?.expect_variant()?;
let keywords = scanner.into_keywords()?;
let is_map = keywords.contains(ImageKeyword::IsMap);
Ok(Self {
fname,
url,
class,
height,
width,
hspace,
vspace,
align,
is_map,
})
}
}
impl_from_str!(Image);
impl<S: AsRef<str>> fmt::Display for Image<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Image {
fname,
url,
class,
height,
width,
hspace,
vspace,
align,
is_map,
} = self.borrow_text();
crate::display::ElementFormatter {
name: "IMAGE",
arguments: &[
&fname, &url, &class, &height, &width, &hspace, &vspace, &align,
],
keywords: &[("ISMAP", is_map)],
}
.fmt(f)
}
}