Split up style module
This commit is contained in:
parent
aa10ea8470
commit
f77f1f61bf
@ -5,10 +5,14 @@ mod styles;
|
||||
mod collapse;
|
||||
mod content;
|
||||
mod layout;
|
||||
mod property;
|
||||
mod recipe;
|
||||
mod show;
|
||||
|
||||
pub use collapse::*;
|
||||
pub use content::*;
|
||||
pub use layout::*;
|
||||
pub use property::*;
|
||||
pub use recipe::*;
|
||||
pub use show::*;
|
||||
pub use styles::*;
|
||||
|
299
src/model/property.rs
Normal file
299
src/model/property.rs
Normal file
@ -0,0 +1,299 @@
|
||||
use std::any::Any;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::hash::Hash;
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::{Interruption, NodeId, StyleChain};
|
||||
use crate::eval::{RawLength, Smart};
|
||||
use crate::geom::{Length, Numeric, Relative, Sides, Spec};
|
||||
use crate::library::layout::PageNode;
|
||||
use crate::library::structure::{EnumNode, ListNode};
|
||||
use crate::library::text::ParNode;
|
||||
use crate::util::{Prehashed, ReadableTypeId};
|
||||
|
||||
/// A style property originating from a set rule or constructor.
|
||||
#[derive(Clone, Hash)]
|
||||
pub struct Property {
|
||||
/// The id of the property's [key](Key).
|
||||
pub key: KeyId,
|
||||
/// The id of the node the property belongs to.
|
||||
pub node: NodeId,
|
||||
/// Whether the property should only affects the first node down the
|
||||
/// hierarchy. Used by constructors.
|
||||
pub scoped: bool,
|
||||
/// The property's value.
|
||||
value: Arc<Prehashed<dyn Bounds>>,
|
||||
/// The name of the property.
|
||||
#[cfg(debug_assertions)]
|
||||
name: &'static str,
|
||||
}
|
||||
|
||||
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(),
|
||||
value: Arc::new(Prehashed::new(value)),
|
||||
scoped: false,
|
||||
#[cfg(debug_assertions)]
|
||||
name: K::NAME,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this property has the given key.
|
||||
pub fn is<'a, K: Key<'a>>(&self) -> bool {
|
||||
self.key == KeyId::of::<K>()
|
||||
}
|
||||
|
||||
/// Whether this property belongs to the node `T`.
|
||||
pub fn is_of<T: 'static>(&self) -> bool {
|
||||
self.node == NodeId::of::<T>()
|
||||
}
|
||||
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
|
||||
/// Whether this barrier is for the node `T`.
|
||||
pub fn is_for(&self, node: NodeId) -> bool {
|
||||
self.0 == node
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Barrier {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "Barrier for {:?}", self.0)
|
||||
}
|
||||
}
|
29
src/model/recipe.rs
Normal file
29
src/model/recipe.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
use super::NodeId;
|
||||
use crate::eval::{Func, Node};
|
||||
use crate::syntax::Span;
|
||||
|
||||
/// A show rule recipe.
|
||||
#[derive(Clone, PartialEq, Hash)]
|
||||
pub struct Recipe {
|
||||
/// The affected node.
|
||||
pub node: NodeId,
|
||||
/// The function that defines the recipe.
|
||||
pub func: Func,
|
||||
/// The span to report all erros with.
|
||||
pub 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)
|
||||
}
|
||||
}
|
@ -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(_) => {}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user