diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-04-30 16:47:43 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-04-30 16:47:43 +0200 |
| commit | f77f1f61bf05ae506689be3c40252c5807276280 (patch) | |
| tree | 1d6d6ff64f9747ed422dbabb2de58b4267b0e6f2 /src/model/styles.rs | |
| parent | aa10ea8470763afe98d5ff558381f0a0beb0c017 (diff) | |
Split up style module
Diffstat (limited to 'src/model/styles.rs')
| -rw-r--r-- | src/model/styles.rs | 338 |
1 files changed, 16 insertions, 322 deletions
diff --git a/src/model/styles.rs b/src/model/styles.rs index ae4c1586..b3020c88 100644 --- a/src/model/styles.rs +++ b/src/model/styles.rs @@ -1,19 +1,14 @@ -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 super::{Barrier, Content, Key, Property, Recipe, Show, ShowNode}; use crate::diag::{At, TypResult}; -use crate::eval::{Args, Func, Node, RawLength, 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::eval::{Args, Func, Node, Value}; +use crate::library::text::{FontFamily, TextNode}; use crate::syntax::Span; -use crate::util::{Prehashed, ReadableTypeId}; +use crate::util::ReadableTypeId; use crate::Context; /// A map of style properties. @@ -80,7 +75,7 @@ impl StyleMap { self.0 .iter() .filter_map(|entry| entry.property()) - .any(|property| property.key == KeyId::of::<K>()) + .any(|property| property.is::<K>()) } /// Make `self` the first link of the `tail` chain. @@ -171,21 +166,15 @@ impl Debug for NodeId { } } -/// 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::<T>()) - } -} - -impl Debug for KeyId { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - self.0.fmt(f) - } +/// 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, } /// An entry for a single style property, recipe or barrier. @@ -222,7 +211,7 @@ impl StyleEntry { if !tail .entries() .filter_map(StyleEntry::property) - .any(|p| p.scoped && p.node == barrier.0) + .any(|p| p.scoped && barrier.is_for(p.node)) { return *tail; } @@ -247,301 +236,6 @@ impl Debug for StyleEntry { } } -/// 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<Prehashed<dyn Bounds>>, - /// 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::<K>(), - 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<Interruption> { - if self.is_of::<PageNode>() { - Some(Interruption::Page) - } else if self.is_of::<ParNode>() { - Some(Interruption::Par) - } else if self.is_of::<ListNode>() || self.is_of::<EnumNode>() { - 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::<K>() { - (**self.value).as_any().downcast_ref() - } else { - None - } - } - - /// Whether this property belongs to the node `T`. - pub fn is_of<T: 'static>(&self) -> bool { - self.node == NodeId::of::<T>() - } -} - -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<T> 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<Item = &'a Self::Value>, - ) -> 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<T: Resolve> Resolve for Option<T> { - type Output = Option<T::Output>; - - fn resolve(self, styles: StyleChain) -> Self::Output { - self.map(|v| v.resolve(styles)) - } -} - -impl<T: Resolve> Resolve for Smart<T> { - type Output = Smart<T::Output>; - - fn resolve(self, styles: StyleChain) -> Self::Output { - self.map(|v| v.resolve(styles)) - } -} - -impl<T: Resolve> Resolve for Spec<T> { - type Output = Spec<T::Output>; - - fn resolve(self, styles: StyleChain) -> Self::Output { - self.map(|v| v.resolve(styles)) - } -} - -impl<T: Resolve> Resolve for Sides<T> { - type Output = Sides<T::Output>; - - 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<T> Resolve for Relative<T> -where - T: Resolve + Numeric, - <T as Resolve>::Output: Numeric, -{ - type Output = Relative<<T as Resolve>::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<T> Fold for Option<T> -where - T: Fold, - T::Output: Default, -{ - type Output = Option<T::Output>; - - fn fold(self, outer: Self::Output) -> Self::Output { - self.map(|inner| inner.fold(outer.unwrap_or_default())) - } -} - -impl<T> Fold for Smart<T> -where - T: Fold, - T::Output: Default, -{ - type Output = Smart<T::Output>; - - fn fold(self, outer: Self::Output) -> Self::Output { - self.map(|inner| inner.fold(outer.unwrap_or_default())) - } -} - -impl<T> Fold for Sides<T> -where - T: Fold, -{ - type Output = Sides<T::Output>; - - fn fold(self, outer: Self::Output) -> Self::Output { - self.zip(outer, |inner, outer, _| inner.fold(outer)) - } -} - -impl Fold for Sides<Option<Relative<Length>>> { - type Output = Sides<Relative<Length>>; - - fn fold(self, outer: Self::Output) -> Self::Output { - self.zip(outer, |inner, outer, _| inner.unwrap_or(outer)) - } -} - -impl Fold for Sides<Option<Smart<Relative<RawLength>>>> { - type Output = Sides<Smart<Relative<RawLength>>>; - - fn fold(self, outer: Self::Output) -> Self::Output { - self.zip(outer, |inner, outer, _| inner.unwrap_or(outer)) - } -} - -/// 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<T: Node>(func: Func, span: Span) -> Self { - Self { node: NodeId::of::<T>(), 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 @@ -690,7 +384,7 @@ impl<'a, K: Key<'a>> Iterator for Values<'a, K> { } } StyleEntry::Barrier(barrier) => { - self.depth += (barrier.0 == K::node()) as usize; + self.depth += barrier.is_for(K::node()) as usize; } StyleEntry::Recipe(_) => {} } |
