use std::any::Any; use std::fmt::{self, Debug, Formatter}; use std::hash::Hash; use std::iter; use std::marker::PhantomData; use std::sync::Arc; use super::{Content, Show, ShowNode}; use crate::diag::{At, TypResult}; use crate::eval::{Args, Func, Node, Smart, Value}; use crate::geom::{Length, Numeric, Relative, Sides, Spec}; use crate::library::layout::PageNode; use crate::library::structure::{EnumNode, ListNode}; use crate::library::text::{FontFamily, ParNode, TextNode}; use crate::syntax::Span; use crate::util::{Prehashed, ReadableTypeId}; use crate::Context; /// A map of style properties. #[derive(Default, Clone, PartialEq, Hash)] pub struct StyleMap(Vec); impl StyleMap { /// Create a new, empty style map. pub fn new() -> Self { Self::default() } /// Whether this map contains no styles. pub fn is_empty(&self) -> bool { self.0.is_empty() } /// Push an arbitary style entry. pub fn push(&mut self, style: StyleEntry) { self.0.push(style); } /// Create a style map from a single property-value pair. pub fn with<'a, K: Key<'a>>(key: K, value: K::Value) -> Self { let mut styles = Self::new(); styles.set(key, value); styles } /// Set an inner value for a style property. /// /// If the property needs folding and the value is already contained in the /// style map, `self` contributes the outer values and `value` is the inner /// one. pub fn set<'a, K: Key<'a>>(&mut self, key: K, value: K::Value) { self.push(StyleEntry::Property(Property::new(key, value))); } /// Set an inner value for a style property if it is `Some(_)`. pub fn set_opt<'a, K: Key<'a>>(&mut self, key: K, value: Option) { if let Some(value) = value { self.set(key, value); } } /// Set a font family composed of a preferred family and existing families /// from a style chain. pub fn set_family(&mut self, preferred: FontFamily, existing: StyleChain) { self.set( TextNode::FAMILY, iter::once(preferred) .chain(existing.get(TextNode::FAMILY).iter().cloned()) .collect(), ); } /// Set a show rule recipe for a node. pub fn set_recipe(&mut self, func: Func, span: Span) { self.push(StyleEntry::Recipe(Recipe::new::(func, span))); } /// Whether the map contains a style property for the given key. pub fn contains<'a, K: Key<'a>>(&self, _: K) -> bool { self.0 .iter() .filter_map(|entry| entry.property()) .any(|property| property.key == KeyId::of::()) } /// Make `self` the first link of the `tail` chain. /// /// The resulting style chain contains styles from `self` as well as /// `tail`. The ones from `self` take precedence over the ones from /// `tail`. For folded properties `self` contributes the inner value. pub fn chain<'a>(&'a self, tail: &'a StyleChain<'a>) -> StyleChain<'a> { if self.is_empty() { *tail } else { StyleChain { head: &self.0, tail: Some(tail) } } } /// Set an outer value for a style property. /// /// If the property needs folding and the value is already contained in the /// style map, `self` contributes the inner values and `value` is the outer /// one. /// /// Like [`chain`](Self::chain) or [`apply_map`](Self::apply_map), but with /// only a single property. pub fn apply<'a, K: Key<'a>>(&mut self, key: K, value: K::Value) { self.0.insert(0, StyleEntry::Property(Property::new(key, value))); } /// Apply styles from `tail` in-place. The resulting style map is equivalent /// to the style chain created by `self.chain(StyleChain::new(tail))`. /// /// This is useful over `chain` when you want to combine two maps, but you /// still need an owned map without a lifetime. pub fn apply_map(&mut self, tail: &Self) { self.0.splice(0 .. 0, tail.0.iter().cloned()); } /// Mark all contained properties as _scoped_. This means that they only /// apply to the first descendant node (of their type) in the hierarchy and /// not its children, too. This is used by [constructors](Node::construct). pub fn scoped(mut self) -> Self { for entry in &mut self.0 { if let StyleEntry::Property(property) = entry { property.scoped = true; } } self } /// The highest-level kind of of structure the map interrupts. pub fn interruption(&self) -> Option { self.0 .iter() .filter_map(|entry| entry.property()) .filter_map(|property| property.interruption()) .max() } } impl From for StyleMap { fn from(entry: StyleEntry) -> Self { Self(vec![entry]) } } impl Debug for StyleMap { fn fmt(&self, f: &mut Formatter) -> fmt::Result { for entry in self.0.iter().rev() { writeln!(f, "{:?}", entry)?; } Ok(()) } } /// A unique identifier for a node. #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct NodeId(ReadableTypeId); impl NodeId { /// The id of the given node. pub fn of() -> Self { Self(ReadableTypeId::of::()) } } impl Debug for NodeId { fn fmt(&self, f: &mut Formatter) -> fmt::Result { self.0.fmt(f) } } /// A unique identifier for a property key. #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct KeyId(ReadableTypeId); impl KeyId { /// The id of the given key. pub fn of<'a, T: Key<'a>>() -> Self { Self(ReadableTypeId::of::()) } } impl Debug for KeyId { fn fmt(&self, f: &mut Formatter) -> fmt::Result { self.0.fmt(f) } } /// An entry for a single style property, recipe or barrier. #[derive(Clone, PartialEq, Hash)] pub enum StyleEntry { /// A style property originating from a set rule or constructor. Property(Property), /// A barrier for scoped styles. Barrier(Barrier), /// A show rule recipe. Recipe(Recipe), } impl StyleEntry { /// If this is a property, return it. pub fn property(&self) -> Option<&Property> { match self { Self::Property(property) => Some(property), _ => None, } } /// If this is a recipe, return it. pub fn recipe(&self) -> Option<&Recipe> { match self { Self::Recipe(recipe) => Some(recipe), _ => None, } } /// Make this style the first link of the `tail` chain. pub fn chain<'a>(&'a self, tail: &'a StyleChain) -> StyleChain<'a> { if let StyleEntry::Barrier(barrier) = self { if !tail .entries() .filter_map(StyleEntry::property) .any(|p| p.scoped && p.node == barrier.0) { return *tail; } } StyleChain { head: std::slice::from_ref(self), tail: Some(tail), } } } impl Debug for StyleEntry { fn fmt(&self, f: &mut Formatter) -> fmt::Result { f.write_str("#[")?; match self { Self::Property(property) => property.fmt(f)?, Self::Recipe(recipe) => recipe.fmt(f)?, Self::Barrier(barrier) => barrier.fmt(f)?, } f.write_str("]") } } /// A style property originating from a set rule or constructor. #[derive(Clone, Hash)] pub struct Property { /// The id of the property's [key](Key). key: KeyId, /// The id of the node the property belongs to. node: NodeId, /// The name of the property. #[cfg(debug_assertions)] name: &'static str, /// The property's value. value: Arc>, /// Whether the property should only affects the first node down the /// hierarchy. Used by constructors. scoped: bool, } impl Property { /// Create a new property from a key-value pair. pub fn new<'a, K: Key<'a>>(_: K, value: K::Value) -> Self { Self { key: KeyId::of::(), node: K::node(), #[cfg(debug_assertions)] name: K::NAME, value: Arc::new(Prehashed::new(value)), scoped: false, } } /// What kind of structure the property interrupts. pub fn interruption(&self) -> Option { if self.is_of::() { Some(Interruption::Page) } else if self.is_of::() { Some(Interruption::Par) } else if self.is_of::() || self.is_of::() { Some(Interruption::List) } else { None } } /// Access the property's value if it is of the given key. pub fn downcast<'a, K: Key<'a>>(&'a self) -> Option<&'a K::Value> { if self.key == KeyId::of::() { (**self.value).as_any().downcast_ref() } else { None } } /// Whether this property belongs to the node `T`. pub fn is_of(&self) -> bool { self.node == NodeId::of::() } } impl Debug for Property { fn fmt(&self, f: &mut Formatter) -> fmt::Result { #[cfg(debug_assertions)] write!(f, "{} = ", self.name)?; write!(f, "{:?}", self.value)?; if self.scoped { write!(f, " [scoped]")?; } Ok(()) } } impl PartialEq for Property { fn eq(&self, other: &Self) -> bool { self.key == other.key && self.value.eq(&other.value) && self.scoped == other.scoped } } trait Bounds: Debug + Sync + Send + 'static { fn as_any(&self) -> &dyn Any; } impl Bounds for T where T: Debug + Sync + Send + 'static, { fn as_any(&self) -> &dyn Any { self } } /// Style property keys. /// /// This trait is not intended to be implemented manually, but rather through /// the `#[node]` proc-macro. pub trait Key<'a>: Copy + 'static { /// The unfolded type which this property is stored as in a style map. For /// example, this is [`Toggle`](crate::geom::Length) for the /// [`STRONG`](TextNode::STRONG) property. type Value: Debug + Clone + Hash + Sync + Send + 'static; /// The folded type of value that is returned when reading this property /// from a style chain. For example, this is [`bool`] for the /// [`STRONG`](TextNode::STRONG) property. For non-copy, non-folding /// properties this is a reference type. type Output; /// The name of the property, used for debug printing. const NAME: &'static str; /// The ids of the key and of the node the key belongs to. fn node() -> NodeId; /// Compute an output value from a sequence of values belong to this key, /// folding if necessary. fn get( chain: StyleChain<'a>, values: impl Iterator, ) -> Self::Output; } /// A property that is resolved with other properties from the style chain. pub trait Resolve { /// The type of the resolved output. type Output; /// Resolve the value using the style chain. fn resolve(self, styles: StyleChain) -> Self::Output; } impl Resolve for Option { type Output = Option; fn resolve(self, styles: StyleChain) -> Self::Output { self.map(|v| v.resolve(styles)) } } impl Resolve for Smart { type Output = Smart; fn resolve(self, styles: StyleChain) -> Self::Output { self.map(|v| v.resolve(styles)) } } impl Resolve for Spec { type Output = Spec; fn resolve(self, styles: StyleChain) -> Self::Output { self.map(|v| v.resolve(styles)) } } impl Resolve for Sides { type Output = Sides; fn resolve(self, styles: StyleChain) -> Self::Output { Sides { left: self.left.resolve(styles), right: self.right.resolve(styles), top: self.top.resolve(styles), bottom: self.bottom.resolve(styles), } } } impl Resolve for Relative where T: Resolve + Numeric, ::Output: Numeric, { type Output = Relative<::Output>; fn resolve(self, styles: StyleChain) -> Self::Output { self.map(|abs| abs.resolve(styles)) } } /// A property that is folded to determine its final value. pub trait Fold { /// The type of the folded output. type Output; /// Fold this inner value with an outer folded value. fn fold(self, outer: Self::Output) -> Self::Output; } impl Fold for Option where T: Fold, T::Output: Default, { type Output = Option; fn fold(self, outer: Self::Output) -> Self::Output { self.map(|inner| inner.fold(outer.unwrap_or_default())) } } impl Fold for Smart where T: Fold, T::Output: Default, { type Output = Smart; fn fold(self, outer: Self::Output) -> Self::Output { self.map(|inner| inner.fold(outer.unwrap_or_default())) } } impl Fold for Sides where T: Fold, { type Output = Sides; fn fold(self, outer: Self::Output) -> Self::Output { Sides { left: self.left.fold(outer.left), top: self.top.fold(outer.top), right: self.right.fold(outer.right), bottom: self.bottom.fold(outer.bottom), } } } impl Fold for Sides>> { type Output = Sides>; fn fold(self, outer: Self::Output) -> Self::Output { Sides { left: self.left.unwrap_or(outer.left), top: self.top.unwrap_or(outer.top), right: self.right.unwrap_or(outer.right), bottom: self.bottom.unwrap_or(outer.bottom), } } } /// A scoped property barrier. /// /// Barriers interact with [scoped](StyleMap::scoped) styles: A scoped style /// can still be read through a single barrier (the one of the node it /// _should_ apply to), but a second barrier will make it invisible. #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct Barrier(NodeId); impl Barrier { /// Create a new barrier for the given node. pub fn new(node: NodeId) -> Self { Self(node) } } impl Debug for Barrier { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "Barrier for {:?}", self.0) } } /// A show rule recipe. #[derive(Clone, PartialEq, Hash)] pub struct Recipe { /// The affected node. node: NodeId, /// The function that defines the recipe. func: Func, /// The span to report all erros with. span: Span, } impl Recipe { /// Create a new recipe for the node `T`. pub fn new(func: Func, span: Span) -> Self { Self { node: NodeId::of::(), func, span } } } impl Debug for Recipe { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "Recipe for {:?} from {:?}", self.node, self.span) } } /// Determines whether a style could interrupt some composable structure. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] pub enum Interruption { /// The style forces a list break. List, /// The style forces a paragraph break. Par, /// The style forces a page break. Page, } /// A chain of style maps, similar to a linked list. /// /// A style chain allows to combine properties from multiple style maps in a /// node hierarchy in a non-allocating way. Rather than eagerly merging the /// maps, each access walks the hierarchy from the innermost to the outermost /// map, trying to find a match and then folding it with matches further up the /// chain. #[derive(Default, Clone, Copy, Hash)] pub struct StyleChain<'a> { /// The first link of this chain. head: &'a [StyleEntry], /// The remaining links in the chain. tail: Option<&'a Self>, } impl<'a> StyleChain<'a> { /// Create a new, empty style chain. pub fn new() -> Self { Self::default() } /// Start a new style chain with a root map. pub fn with_root(root: &'a StyleMap) -> Self { Self { head: &root.0, tail: None } } /// Get the output value of a style property. /// /// Returns the property's default value if no map in the chain contains an /// entry for it. Also takes care of resolving and folding and returns /// references where applicable. pub fn get>(self, key: K) -> K::Output { K::get(self, self.values(key)) } /// Realize a node with a user recipe. pub fn realize( self, ctx: &mut Context, node: &ShowNode, ) -> TypResult> { let id = node.id(); if let Some(recipe) = self .entries() .filter_map(StyleEntry::recipe) .find(|recipe| recipe.node == id) { let dict = node.encode(); let args = Args::from_values(recipe.span, [Value::Dict(dict)]); Ok(Some(recipe.func.call(ctx, args)?.cast().at(recipe.span)?)) } else { Ok(None) } } /// Return the chain, but without trailing scoped properties for the given /// `node`. pub fn unscoped(mut self, node: NodeId) -> Self { while self .head .last() .and_then(StyleEntry::property) .map_or(false, |p| p.scoped && p.node == node) { let len = self.head.len(); self.head = &self.head[.. len - 1] } self } /// Remove the last link from the chain. fn pop(&mut self) { *self = self.tail.copied().unwrap_or_default(); } /// Build a style map from the suffix (all links beyond the `len`) of the /// chain. fn suffix(self, len: usize) -> StyleMap { let mut suffix = StyleMap::new(); let take = self.links().count().saturating_sub(len); for link in self.links().take(take) { suffix.0.splice(0 .. 0, link.iter().cloned()); } suffix } /// Iterate over all values for the given property in the chain. fn values>(self, _: K) -> Values<'a, K> { Values { entries: self.entries(), depth: 0, key: PhantomData, } } /// Iterate over the entries of the chain. fn entries(self) -> Entries<'a> { Entries { inner: [].as_slice().iter(), links: self.links(), } } /// Iterate over the links of the chain. fn links(self) -> Links<'a> { Links(Some(self)) } } impl Debug for StyleChain<'_> { fn fmt(&self, f: &mut Formatter) -> fmt::Result { for entry in self.entries() { writeln!(f, "{:?}", entry)?; } Ok(()) } } impl PartialEq for StyleChain<'_> { fn eq(&self, other: &Self) -> bool { let as_ptr = |s| s as *const _; self.head.as_ptr() == other.head.as_ptr() && self.head.len() == other.head.len() && self.tail.map(as_ptr) == other.tail.map(as_ptr) } } /// An iterator over the values in a style chain. struct Values<'a, K> { entries: Entries<'a>, depth: usize, key: PhantomData, } impl<'a, K: Key<'a>> Iterator for Values<'a, K> { type Item = &'a K::Value; fn next(&mut self) -> Option { while let Some(entry) = self.entries.next() { match entry { StyleEntry::Property(property) => { if let Some(value) = property.downcast::() { if !property.scoped || self.depth <= 1 { return Some(value); } } } StyleEntry::Barrier(barrier) => { self.depth += (barrier.0 == K::node()) as usize; } StyleEntry::Recipe(_) => {} } } None } } /// An iterator over the entries in a style chain. struct Entries<'a> { inner: std::slice::Iter<'a, StyleEntry>, links: Links<'a>, } impl<'a> Iterator for Entries<'a> { type Item = &'a StyleEntry; fn next(&mut self) -> Option { loop { if let Some(entry) = self.inner.next_back() { return Some(entry); } match self.links.next() { Some(next) => self.inner = next.iter(), None => return None, } } } } /// An iterator over the links of a style chain. struct Links<'a>(Option>); impl<'a> Iterator for Links<'a> { type Item = &'a [StyleEntry]; fn next(&mut self) -> Option { let StyleChain { head, tail } = self.0?; self.0 = tail.copied(); Some(head) } } /// A sequence of items with associated styles. #[derive(Hash)] pub struct StyleVec { items: Vec, maps: Vec<(StyleMap, usize)>, } impl StyleVec { /// Whether there are any items in the sequence. pub fn is_empty(&self) -> bool { self.items.is_empty() } /// Number of items in the sequence. pub fn len(&self) -> usize { self.items.len() } /// Insert an element in the front. The element will share the style of the /// current first element. /// /// This method has no effect if the vector is empty. pub fn push_front(&mut self, item: T) { if !self.maps.is_empty() { self.items.insert(0, item); self.maps[0].1 += 1; } } /// Iterate over the contained maps. Note that zipping this with `items()` /// does not yield the same result as calling `iter()` because this method /// only returns maps once that are shared by consecutive items. This method /// is designed for use cases where you want to check, for example, whether /// any of the maps fulfills a specific property. pub fn maps(&self) -> impl Iterator { self.maps.iter().map(|(map, _)| map) } /// Iterate over the contained items. pub fn items(&self) -> std::slice::Iter<'_, T> { self.items.iter() } /// Iterate over references to the contained items and associated style maps. pub fn iter(&self) -> impl Iterator + '_ { self.items().zip( self.maps .iter() .flat_map(|(map, count)| iter::repeat(map).take(*count)), ) } } impl Default for StyleVec { fn default() -> Self { Self { items: vec![], maps: vec![] } } } impl FromIterator for StyleVec { fn from_iter>(iter: I) -> Self { let items: Vec<_> = iter.into_iter().collect(); let maps = vec![(StyleMap::new(), items.len())]; Self { items, maps } } } impl Debug for StyleVec { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_list() .entries(self.iter().map(|(item, map)| { crate::util::debug(|f| { map.fmt(f)?; item.fmt(f) }) })) .finish() } } /// Assists in the construction of a [`StyleVec`]. pub struct StyleVecBuilder<'a, T> { items: Vec, chains: Vec<(StyleChain<'a>, usize)>, } impl<'a, T> StyleVecBuilder<'a, T> { /// Create a new style-vec builder. pub fn new() -> Self { Self { items: vec![], chains: vec![] } } /// Whether the builder is empty. pub fn is_empty(&self) -> bool { self.items.is_empty() } /// Push a new item into the style vector. pub fn push(&mut self, item: T, styles: StyleChain<'a>) { self.items.push(item); if let Some((prev, count)) = self.chains.last_mut() { if *prev == styles { *count += 1; return; } } self.chains.push((styles, 1)); } /// Iterate over the contained items. pub fn items(&self) -> std::slice::Iter<'_, T> { self.items.iter() } /// Finish building, returning a pair of two things: /// - a style vector of items with the non-shared styles /// - a shared prefix chain of styles that apply to all items pub fn finish(self) -> (StyleVec, StyleChain<'a>) { let mut iter = self.chains.iter(); let mut trunk = match iter.next() { Some(&(chain, _)) => chain, None => return Default::default(), }; let mut shared = trunk.links().count(); for &(mut chain, _) in iter { let len = chain.links().count(); if len < shared { for _ in 0 .. shared - len { trunk.pop(); } shared = len; } else if len > shared { for _ in 0 .. len - shared { chain.pop(); } } while shared > 0 && chain != trunk { trunk.pop(); chain.pop(); shared -= 1; } } let maps = self .chains .into_iter() .map(|(chain, count)| (chain.suffix(shared), count)) .collect(); (StyleVec { items: self.items, maps }, trunk) } } impl<'a, T> Default for StyleVecBuilder<'a, T> { fn default() -> Self { Self::new() } }