use ecow::EcoString;
use crate::diag::{bail, HintedStrResult, SourceResult};
use crate::engine::Engine;
use crate::foundations::{
cast, elem, Args, Array, Construct, Content, Datetime, Fields, Smart, StyleChain,
Styles, Value,
};
use crate::introspection::Introspector;
use crate::layout::Page;
#[elem(Construct)]
pub struct DocumentElem {
#[ghost]
pub title: Option<Content>,
#[ghost]
pub author: Author,
#[ghost]
pub keywords: Keywords,
#[ghost]
pub date: Smart<Option<Datetime>>,
}
impl Construct for DocumentElem {
fn construct(_: &mut Engine, args: &mut Args) -> SourceResult<Content> {
bail!(args.span, "can only be used in set rules")
}
}
#[derive(Debug, Default, Clone, PartialEq, Hash)]
pub struct Author(Vec<EcoString>);
cast! {
Author,
self => self.0.into_value(),
v: EcoString => Self(vec![v]),
v: Array => Self(v.into_iter().map(Value::cast).collect::<HintedStrResult<_>>()?),
}
#[derive(Debug, Default, Clone, PartialEq, Hash)]
pub struct Keywords(Vec<EcoString>);
cast! {
Keywords,
self => self.0.into_value(),
v: EcoString => Self(vec![v]),
v: Array => Self(v.into_iter().map(Value::cast).collect::<HintedStrResult<_>>()?),
}
#[derive(Debug, Default, Clone)]
pub struct Document {
pub pages: Vec<Page>,
pub info: DocumentInfo,
pub introspector: Introspector,
}
#[derive(Debug, Default, Clone, PartialEq, Hash)]
pub struct DocumentInfo {
pub title: Option<EcoString>,
pub author: Vec<EcoString>,
pub keywords: Vec<EcoString>,
pub date: Smart<Option<Datetime>>,
}
impl DocumentInfo {
pub fn populate(&mut self, styles: &Styles) {
let chain = StyleChain::new(styles);
let has = |field| styles.has::<DocumentElem>(field as _);
if has(<DocumentElem as Fields>::Enum::Title) {
self.title =
DocumentElem::title_in(chain).map(|content| content.plain_text());
}
if has(<DocumentElem as Fields>::Enum::Author) {
self.author = DocumentElem::author_in(chain).0;
}
if has(<DocumentElem as Fields>::Enum::Keywords) {
self.keywords = DocumentElem::keywords_in(chain).0;
}
if has(<DocumentElem as Fields>::Enum::Date) {
self.date = DocumentElem::date_in(chain);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_document_is_send_and_sync() {
fn ensure_send_and_sync<T: Send + Sync>() {}
ensure_send_and_sync::<Document>();
}
}