use std::fmt;
use std::num::NonZero;
use crate::arguments::{ArgumentScanner, ExpectArg, FromArgs};
use crate::keyword::DestKeyword;
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct Dest<S = String> {
pub name: Option<S>,
pub column: Option<NonZero<u32>>,
pub line: Option<NonZero<u32>>,
pub eof: bool,
pub eol: bool,
}
impl<S> Dest<S> {
pub fn map_text<T, F>(self, f: F) -> Dest<T>
where
F: FnOnce(S) -> T,
{
Dest {
name: self.name.map(f),
column: self.column,
line: self.line,
eof: self.eof,
eol: self.eol,
}
}
}
impl_into_owned!(Dest);
impl<S: AsRef<str>> Dest<S> {
pub fn borrow_text(&self) -> Dest<&str> {
Dest {
name: self.name.as_ref().map(AsRef::as_ref),
column: self.column,
line: self.line,
eof: self.eof,
eol: self.eol,
}
}
}
impl_partial_eq!(Dest);
impl<S> From<Option<S>> for Dest<S> {
fn from(name: Option<S>) -> Self {
Self {
name,
column: None,
line: None,
eof: false,
eol: false,
}
}
}
impl<S: AsRef<str>> From<S> for Dest<S> {
fn from(name: S) -> Self {
if name.as_ref().is_empty() {
Self::from(None)
} else {
Self::from(Some(name))
}
}
}
impl<'a, S: AsRef<str>> FromArgs<'a, S> for Dest<S> {
fn from_args<A: ArgumentScanner<'a, Decoded = S>>(scanner: A) -> crate::Result<Self> {
let mut scanner = scanner.with_keywords();
let name = scanner.get_next()?;
let column = scanner
.get_next_or("x")?
.expect_number()?
.and_then(NonZero::new);
let line = scanner
.get_next_or("y")?
.expect_number()?
.and_then(NonZero::new);
let keywords = scanner.into_keywords()?;
Ok(Self {
name,
column,
line,
eof: keywords.contains(DestKeyword::Eof),
eol: keywords.contains(DestKeyword::Eol),
})
}
}
impl_from_str!(Dest);
impl<S: AsRef<str>> fmt::Display for Dest<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Dest {
name,
column,
line,
eof,
eol,
} = self.borrow_text();
crate::display::ElementFormatter {
name: "DEST",
arguments: &[&name, &column, &line],
keywords: &[("EOF", eof), ("EOL", eol)],
}
.fmt(f)
}
}