Public style entry enum

This commit is contained in:
Laurenz 2022-04-25 15:50:13 +02:00
parent 649c101f07
commit 09aabc3a21
4 changed files with 108 additions and 122 deletions

View File

@ -2,8 +2,12 @@ use super::{StyleChain, StyleVec, StyleVecBuilder};
/// A wrapper around a [`StyleVecBuilder`] that allows to collapse items. /// A wrapper around a [`StyleVecBuilder`] that allows to collapse items.
pub struct CollapsingBuilder<'a, T> { pub struct CollapsingBuilder<'a, T> {
/// The internal builder.
builder: StyleVecBuilder<'a, T>, builder: StyleVecBuilder<'a, T>,
/// Staged weak and ignorant items that we can't yet commit to the builder.
/// The option is `Some(_)` for weak items and `None` for ignorant items.
staged: Vec<(T, StyleChain<'a>, Option<u8>)>, staged: Vec<(T, StyleChain<'a>, Option<u8>)>,
/// What the last non-ignorant item was.
last: Last, last: Last,
} }
@ -51,14 +55,14 @@ impl<'a, T> CollapsingBuilder<'a, T> {
/// Forces nearby weak items to collapse. /// Forces nearby weak items to collapse.
pub fn destructive(&mut self, item: T, styles: StyleChain<'a>) { pub fn destructive(&mut self, item: T, styles: StyleChain<'a>) {
self.flush(false); self.flush(false);
self.push(item, styles); self.builder.push(item, styles);
self.last = Last::Destructive; self.last = Last::Destructive;
} }
/// Allows nearby weak items to exist. /// Allows nearby weak items to exist.
pub fn supportive(&mut self, item: T, styles: StyleChain<'a>) { pub fn supportive(&mut self, item: T, styles: StyleChain<'a>) {
self.flush(true); self.flush(true);
self.push(item, styles); self.builder.push(item, styles);
self.last = Last::Supportive; self.last = Last::Supportive;
} }
@ -78,7 +82,8 @@ impl<'a, T> CollapsingBuilder<'a, T> {
self.builder.finish() self.builder.finish()
} }
/// Push the staged items, filtering out weak items if `supportive` is false. /// Push the staged items, filtering out weak items if `supportive` is
/// false.
fn flush(&mut self, supportive: bool) { fn flush(&mut self, supportive: bool) {
for (item, styles, strength) in self.staged.drain(..) { for (item, styles, strength) in self.staged.drain(..) {
if supportive || strength.is_none() { if supportive || strength.is_none() {
@ -86,11 +91,6 @@ impl<'a, T> CollapsingBuilder<'a, T> {
} }
} }
} }
/// Push a new item into the style vector.
fn push(&mut self, item: T, styles: StyleChain<'a>) {
self.builder.push(item, styles);
}
} }
impl<'a, T> Default for CollapsingBuilder<'a, T> { impl<'a, T> Default for CollapsingBuilder<'a, T> {

View File

@ -238,19 +238,11 @@ impl Debug for Content {
Self::Horizontal(kind) => write!(f, "Horizontal({kind:?})"), Self::Horizontal(kind) => write!(f, "Horizontal({kind:?})"),
Self::Text(text) => write!(f, "Text({text:?})"), Self::Text(text) => write!(f, "Text({text:?})"),
Self::Quote(double) => write!(f, "Quote({double})"), Self::Quote(double) => write!(f, "Quote({double})"),
Self::Inline(node) => { Self::Inline(node) => node.fmt(f),
f.write_str("Inline(")?;
node.fmt(f)?;
f.write_str(")")
}
Self::Parbreak => f.pad("Parbreak"), Self::Parbreak => f.pad("Parbreak"),
Self::Colbreak => f.pad("Colbreak"), Self::Colbreak => f.pad("Colbreak"),
Self::Vertical(kind) => write!(f, "Vertical({kind:?})"), Self::Vertical(kind) => write!(f, "Vertical({kind:?})"),
Self::Block(node) => { Self::Block(node) => node.fmt(f),
f.write_str("Block(")?;
node.fmt(f)?;
f.write_str(")")
}
Self::List(item) => { Self::List(item) => {
f.write_str("- ")?; f.write_str("- ")?;
item.body.fmt(f) item.body.fmt(f)
@ -264,11 +256,7 @@ impl Debug for Content {
} }
Self::Pagebreak(soft) => write!(f, "Pagebreak({soft})"), Self::Pagebreak(soft) => write!(f, "Pagebreak({soft})"),
Self::Page(page) => page.fmt(f), Self::Page(page) => page.fmt(f),
Self::Show(node) => { Self::Show(node) => node.fmt(f),
f.write_str("Show(")?;
node.fmt(f)?;
f.write_str(")")
}
Self::Styled(styled) => { Self::Styled(styled) => {
let (sub, map) = styled.as_ref(); let (sub, map) = styled.as_ref();
map.fmt(f)?; map.fmt(f)?;

View File

@ -5,7 +5,7 @@ use std::fmt::{self, Debug, Formatter};
use std::hash::Hash; use std::hash::Hash;
use std::sync::Arc; use std::sync::Arc;
use super::{Barrier, NodeId, Resolve, StyleChain, StyleSlot}; use super::{Barrier, NodeId, Resolve, StyleChain, StyleEntry};
use crate::diag::TypResult; use crate::diag::TypResult;
use crate::eval::{RawAlign, RawLength}; use crate::eval::{RawAlign, RawLength};
use crate::frame::{Element, Frame, Geometry}; use crate::frame::{Element, Frame, Geometry};
@ -220,8 +220,8 @@ impl Layout for LayoutNode {
styles: StyleChain, styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> { ) -> TypResult<Vec<Arc<Frame>>> {
ctx.query((self, regions, styles), |ctx, (node, regions, styles)| { ctx.query((self, regions, styles), |ctx, (node, regions, styles)| {
let slot = StyleSlot::from(Barrier::new(node.id())); let entry = StyleEntry::Barrier(Barrier::new(node.id()));
node.0.layout(ctx, regions, slot.chain(&styles)) node.0.layout(ctx, regions, entry.chain(&styles))
}) })
.clone() .clone()
} }

View File

@ -16,7 +16,7 @@ use crate::Context;
/// A map of style properties. /// A map of style properties.
#[derive(Default, Clone, PartialEq, Hash)] #[derive(Default, Clone, PartialEq, Hash)]
pub struct StyleMap(Vec<Entry>); pub struct StyleMap(Vec<StyleEntry>);
impl StyleMap { impl StyleMap {
/// Create a new, empty style map. /// Create a new, empty style map.
@ -29,6 +29,11 @@ impl StyleMap {
self.0.is_empty() 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. /// Create a style map from a single property-value pair.
pub fn with<'a, K: Key<'a>>(key: K, value: K::Value) -> Self { pub fn with<'a, K: Key<'a>>(key: K, value: K::Value) -> Self {
let mut styles = Self::new(); let mut styles = Self::new();
@ -42,7 +47,7 @@ impl StyleMap {
/// style map, `self` contributes the outer values and `value` is the inner /// style map, `self` contributes the outer values and `value` is the inner
/// one. /// one.
pub fn set<'a, K: Key<'a>>(&mut self, key: K, value: K::Value) { pub fn set<'a, K: Key<'a>>(&mut self, key: K, value: K::Value) {
self.0.push(Entry::Property(Property::new(key, value))); self.push(StyleEntry::Property(Property::new(key, value)));
} }
/// Set an inner value for a style property if it is `Some(_)`. /// Set an inner value for a style property if it is `Some(_)`.
@ -65,7 +70,7 @@ impl StyleMap {
/// Set a show rule recipe for a node. /// Set a show rule recipe for a node.
pub fn set_recipe<T: Node>(&mut self, func: Func, span: Span) { pub fn set_recipe<T: Node>(&mut self, func: Func, span: Span) {
self.0.push(Entry::Recipe(Recipe::new::<T>(func, span))); self.push(StyleEntry::Recipe(Recipe::new::<T>(func, span)));
} }
/// Whether the map contains a style property for the given key. /// Whether the map contains a style property for the given key.
@ -98,7 +103,7 @@ impl StyleMap {
/// Like [`chain`](Self::chain) or [`apply_map`](Self::apply_map), but with /// Like [`chain`](Self::chain) or [`apply_map`](Self::apply_map), but with
/// only a single property. /// only a single property.
pub fn apply<'a, K: Key<'a>>(&mut self, key: K, value: K::Value) { pub fn apply<'a, K: Key<'a>>(&mut self, key: K, value: K::Value) {
self.0.insert(0, Entry::Property(Property::new(key, value))); self.0.insert(0, StyleEntry::Property(Property::new(key, value)));
} }
/// Apply styles from `tail` in-place. The resulting style map is equivalent /// Apply styles from `tail` in-place. The resulting style map is equivalent
@ -115,7 +120,7 @@ impl StyleMap {
/// not its children, too. This is used by [constructors](Node::construct). /// not its children, too. This is used by [constructors](Node::construct).
pub fn scoped(mut self) -> Self { pub fn scoped(mut self) -> Self {
for entry in &mut self.0 { for entry in &mut self.0 {
if let Entry::Property(property) = entry { if let StyleEntry::Property(property) = entry {
property.scoped = true; property.scoped = true;
} }
} }
@ -132,6 +137,12 @@ impl StyleMap {
} }
} }
impl From<StyleEntry> for StyleMap {
fn from(entry: StyleEntry) -> Self {
Self(vec![entry])
}
}
impl Debug for StyleMap { impl Debug for StyleMap {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
for entry in self.0.iter().rev() { for entry in self.0.iter().rev() {
@ -141,76 +152,6 @@ impl Debug for StyleMap {
} }
} }
/// A stack-allocated slot for a single style property or barrier.
pub struct StyleSlot(Entry);
impl StyleSlot {
/// Make this slot the first link of the `tail` chain.
pub fn chain<'a>(&'a self, tail: &'a StyleChain) -> StyleChain<'a> {
if let Entry::Barrier(barrier) = &self.0 {
if !tail
.entries()
.filter_map(Entry::property)
.any(|p| p.scoped && p.node == barrier.0)
{
return *tail;
}
}
StyleChain {
head: std::slice::from_ref(&self.0),
tail: Some(tail),
}
}
}
impl From<Barrier> for StyleSlot {
fn from(barrier: Barrier) -> Self {
Self(Entry::Barrier(barrier))
}
}
/// An entry for a single style property, recipe or barrier.
#[derive(Clone, PartialEq, Hash)]
enum Entry {
/// 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 Entry {
/// If this is a property, return it.
fn property(&self) -> Option<&Property> {
match self {
Self::Property(property) => Some(property),
_ => None,
}
}
/// If this is a recipe, return it.
fn recipe(&self) -> Option<&Recipe> {
match self {
Self::Recipe(recipe) => Some(recipe),
_ => None,
}
}
}
impl Debug for Entry {
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 unique identifier for a node. /// A unique identifier for a node.
#[derive(Copy, Clone, Eq, PartialEq, Hash)] #[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct NodeId(ReadableTypeId); pub struct NodeId(ReadableTypeId);
@ -245,9 +186,68 @@ impl Debug for KeyId {
} }
} }
/// 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. /// A style property originating from a set rule or constructor.
#[derive(Clone, Hash)] #[derive(Clone, Hash)]
struct Property { pub struct Property {
/// The id of the property's [key](Key). /// The id of the property's [key](Key).
key: KeyId, key: KeyId,
/// The id of the node the property belongs to. /// The id of the node the property belongs to.
@ -264,7 +264,7 @@ struct Property {
impl Property { impl Property {
/// Create a new property from a key-value pair. /// Create a new property from a key-value pair.
fn new<'a, K: Key<'a>>(_: K, value: K::Value) -> Self { pub fn new<'a, K: Key<'a>>(_: K, value: K::Value) -> Self {
Self { Self {
key: KeyId::of::<K>(), key: KeyId::of::<K>(),
node: K::node(), node: K::node(),
@ -276,7 +276,7 @@ impl Property {
} }
/// What kind of structure the property interrupts. /// What kind of structure the property interrupts.
fn interruption(&self) -> Option<Interruption> { pub fn interruption(&self) -> Option<Interruption> {
if self.is_of::<PageNode>() { if self.is_of::<PageNode>() {
Some(Interruption::Page) Some(Interruption::Page)
} else if self.is_of::<ParNode>() { } else if self.is_of::<ParNode>() {
@ -287,7 +287,7 @@ impl Property {
} }
/// Access the property's value if it is of the given key. /// Access the property's value if it is of the given key.
fn downcast<'a, K: Key<'a>>(&'a self) -> Option<&'a K::Value> { pub fn downcast<'a, K: Key<'a>>(&'a self) -> Option<&'a K::Value> {
if self.key == KeyId::of::<K>() { if self.key == KeyId::of::<K>() {
(**self.value).as_any().downcast_ref() (**self.value).as_any().downcast_ref()
} else { } else {
@ -296,7 +296,7 @@ impl Property {
} }
/// Whether this property belongs to the node `T`. /// Whether this property belongs to the node `T`.
fn is_of<T: Node>(&self) -> bool { pub fn is_of<T: 'static>(&self) -> bool {
self.node == NodeId::of::<T>() self.node == NodeId::of::<T>()
} }
} }
@ -478,7 +478,7 @@ impl Debug for Barrier {
/// A show rule recipe. /// A show rule recipe.
#[derive(Clone, PartialEq, Hash)] #[derive(Clone, PartialEq, Hash)]
struct Recipe { pub struct Recipe {
/// The affected node. /// The affected node.
node: NodeId, node: NodeId,
/// The function that defines the recipe. /// The function that defines the recipe.
@ -489,7 +489,7 @@ struct Recipe {
impl Recipe { impl Recipe {
/// Create a new recipe for the node `T`. /// Create a new recipe for the node `T`.
fn new<T: Node>(func: Func, span: Span) -> Self { pub fn new<T: Node>(func: Func, span: Span) -> Self {
Self { node: NodeId::of::<T>(), func, span } Self { node: NodeId::of::<T>(), func, span }
} }
} }
@ -519,7 +519,7 @@ pub enum Interruption {
#[derive(Default, Clone, Copy, Hash)] #[derive(Default, Clone, Copy, Hash)]
pub struct StyleChain<'a> { pub struct StyleChain<'a> {
/// The first link of this chain. /// The first link of this chain.
head: &'a [Entry], head: &'a [StyleEntry],
/// The remaining links in the chain. /// The remaining links in the chain.
tail: Option<&'a Self>, tail: Option<&'a Self>,
} }
@ -553,7 +553,7 @@ impl<'a> StyleChain<'a> {
let id = node.id(); let id = node.id();
if let Some(recipe) = self if let Some(recipe) = self
.entries() .entries()
.filter_map(Entry::recipe) .filter_map(StyleEntry::recipe)
.find(|recipe| recipe.node == id) .find(|recipe| recipe.node == id)
{ {
let dict = node.encode(); let dict = node.encode();
@ -563,16 +563,14 @@ impl<'a> StyleChain<'a> {
Ok(None) Ok(None)
} }
} }
}
impl<'a> StyleChain<'a> { /// Return the chain, but without trailing scoped properties for the given
/// Return the chain, but without the trailing scoped property for the given /// `node`.
/// `node`. This is a 90% hack fix for show node constructor scoping. pub fn unscoped(mut self, node: NodeId) -> Self {
pub(super) fn unscoped(mut self, node: NodeId) -> Self {
while self while self
.head .head
.last() .last()
.and_then(Entry::property) .and_then(StyleEntry::property)
.map_or(false, |p| p.scoped && p.node == node) .map_or(false, |p| p.scoped && p.node == node)
{ {
let len = self.head.len(); let len = self.head.len();
@ -651,17 +649,17 @@ impl<'a, K: Key<'a>> Iterator for Values<'a, K> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while let Some(entry) = self.entries.next() { while let Some(entry) = self.entries.next() {
match entry { match entry {
Entry::Property(property) => { StyleEntry::Property(property) => {
if let Some(value) = property.downcast::<K>() { if let Some(value) = property.downcast::<K>() {
if !property.scoped || self.depth <= 1 { if !property.scoped || self.depth <= 1 {
return Some(value); return Some(value);
} }
} }
} }
Entry::Barrier(barrier) => { StyleEntry::Barrier(barrier) => {
self.depth += (barrier.0 == K::node()) as usize; self.depth += (barrier.0 == K::node()) as usize;
} }
Entry::Recipe(_) => {} StyleEntry::Recipe(_) => {}
} }
} }
@ -671,12 +669,12 @@ impl<'a, K: Key<'a>> Iterator for Values<'a, K> {
/// An iterator over the entries in a style chain. /// An iterator over the entries in a style chain.
struct Entries<'a> { struct Entries<'a> {
inner: std::slice::Iter<'a, Entry>, inner: std::slice::Iter<'a, StyleEntry>,
links: Links<'a>, links: Links<'a>,
} }
impl<'a> Iterator for Entries<'a> { impl<'a> Iterator for Entries<'a> {
type Item = &'a Entry; type Item = &'a StyleEntry;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
@ -696,7 +694,7 @@ impl<'a> Iterator for Entries<'a> {
struct Links<'a>(Option<StyleChain<'a>>); struct Links<'a>(Option<StyleChain<'a>>);
impl<'a> Iterator for Links<'a> { impl<'a> Iterator for Links<'a> {
type Item = &'a [Entry]; type Item = &'a [StyleEntry];
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let StyleChain { head, tail } = self.0?; let StyleChain { head, tail } = self.0?;