StyleSlot, KeyId and NodeId

This commit is contained in:
Laurenz 2022-04-24 16:38:11 +02:00
parent 8fbb11fc05
commit 89927d7de0
5 changed files with 190 additions and 128 deletions

View File

@ -249,12 +249,12 @@ fn process_const(
const NAME: &'static str = #name; const NAME: &'static str = #name;
fn node() -> TypeId { fn node() -> model::NodeId {
TypeId::of::<#self_ty>() model::NodeId::of::<#self_ty>()
} }
fn get( fn get(
chain: StyleChain<'a>, chain: model::StyleChain<'a>,
mut values: impl Iterator<Item = &'a Self::Value>, mut values: impl Iterator<Item = &'a Self::Value>,
) -> Self::Output { ) -> Self::Output {
#get #get

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, Resolve, StyleChain}; use super::{Barrier, NodeId, Resolve, StyleChain, StyleSlot};
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};
@ -148,9 +148,9 @@ impl LayoutNode {
(**self.0).as_any().is::<T>() (**self.0).as_any().is::<T>()
} }
/// A barrier for the node. /// The id of this node.
pub fn barrier(&self) -> Barrier { pub fn id(&self) -> NodeId {
(**self.0).barrier() (**self.0).node_id()
} }
/// Try to downcast to a specific layout node. /// Try to downcast to a specific layout node.
@ -220,7 +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)| {
node.0.layout(ctx, regions, node.barrier().chain(&styles)) let slot = StyleSlot::from(Barrier::new(node.id()));
node.0.layout(ctx, regions, slot.chain(&styles))
}) })
.clone() .clone()
} }
@ -250,7 +251,7 @@ impl PartialEq for LayoutNode {
trait Bounds: Layout + Debug + Sync + Send + 'static { trait Bounds: Layout + Debug + Sync + Send + 'static {
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn barrier(&self) -> Barrier; fn node_id(&self) -> NodeId;
} }
impl<T> Bounds for T impl<T> Bounds for T
@ -261,8 +262,8 @@ where
self self
} }
fn barrier(&self) -> Barrier { fn node_id(&self) -> NodeId {
Barrier::new::<T>() NodeId::of::<Self>()
} }
} }

View File

@ -1,9 +1,8 @@
use std::any::{Any, TypeId};
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::hash::Hash; use std::hash::Hash;
use std::sync::Arc; use std::sync::Arc;
use super::{Content, StyleChain}; use super::{Content, NodeId, StyleChain};
use crate::diag::TypResult; use crate::diag::TypResult;
use crate::eval::Dict; use crate::eval::Dict;
use crate::util::Prehashed; use crate::util::Prehashed;
@ -57,9 +56,9 @@ impl ShowNode {
Self(Arc::new(Prehashed::new(node))) Self(Arc::new(Prehashed::new(node)))
} }
/// The type id of this node. /// The id of this node.
pub fn id(&self) -> TypeId { pub fn id(&self) -> NodeId {
self.0.as_any().type_id() (**self.0).node_id()
} }
} }
@ -99,14 +98,14 @@ impl PartialEq for ShowNode {
} }
trait Bounds: Show + Debug + Sync + Send + 'static { trait Bounds: Show + Debug + Sync + Send + 'static {
fn as_any(&self) -> &dyn Any; fn node_id(&self) -> NodeId;
} }
impl<T> Bounds for T impl<T> Bounds for T
where where
T: Show + Debug + Hash + Sync + Send + 'static, T: Show + Debug + Hash + Sync + Send + 'static,
{ {
fn as_any(&self) -> &dyn Any { fn node_id(&self) -> NodeId {
self NodeId::of::<Self>()
} }
} }

View File

@ -1,17 +1,17 @@
use std::any::{Any, TypeId}; use std::any::Any;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::hash::Hash; use std::hash::Hash;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::sync::Arc; use std::sync::Arc;
use super::{Content, Layout, Show, ShowNode}; use super::{Content, Show, ShowNode};
use crate::diag::{At, TypResult}; use crate::diag::{At, TypResult};
use crate::eval::{Args, Func, Node, Smart, Value}; use crate::eval::{Args, Func, Node, Smart, Value};
use crate::geom::{Numeric, Relative, Sides, Spec}; use crate::geom::{Numeric, Relative, Sides, Spec};
use crate::library::layout::PageNode; use crate::library::layout::PageNode;
use crate::library::text::{FontFamily, ParNode, TextNode}; use crate::library::text::{FontFamily, ParNode, TextNode};
use crate::syntax::Span; use crate::syntax::Span;
use crate::util::Prehashed; use crate::util::{Prehashed, ReadableTypeId};
use crate::Context; use crate::Context;
/// A map of style properties. /// A map of style properties.
@ -73,7 +73,7 @@ impl StyleMap {
self.0 self.0
.iter() .iter()
.filter_map(|entry| entry.property()) .filter_map(|entry| entry.property())
.any(|property| property.key == TypeId::of::<K>()) .any(|property| property.key == KeyId::of::<K>())
} }
/// Make `self` the first link of the `tail` chain. /// Make `self` the first link of the `tail` chain.
@ -141,13 +141,42 @@ 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. /// An entry for a single style property, recipe or barrier.
#[derive(Clone, PartialEq, Hash)] #[derive(Clone, PartialEq, Hash)]
enum Entry { enum Entry {
/// A style property originating from a set rule or constructor. /// A style property originating from a set rule or constructor.
Property(Property), Property(Property),
/// A barrier for scoped styles. /// A barrier for scoped styles.
Barrier(TypeId, &'static str), Barrier(Barrier),
/// A show rule recipe. /// A show rule recipe.
Recipe(Recipe), Recipe(Recipe),
} }
@ -176,20 +205,55 @@ impl Debug for Entry {
match self { match self {
Self::Property(property) => property.fmt(f)?, Self::Property(property) => property.fmt(f)?,
Self::Recipe(recipe) => recipe.fmt(f)?, Self::Recipe(recipe) => recipe.fmt(f)?,
Self::Barrier(_, name) => write!(f, "Barrier for {name}")?, Self::Barrier(barrier) => barrier.fmt(f)?,
} }
f.write_str("]") f.write_str("]")
} }
} }
/// 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<T: 'static>() -> Self {
Self(ReadableTypeId::of::<T>())
}
}
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::<T>())
}
}
impl Debug for KeyId {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
/// 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 { struct Property {
/// The type id of the property's [key](Key). /// The id of the property's [key](Key).
key: TypeId, key: KeyId,
/// The type id of the node the property belongs to. /// The id of the node the property belongs to.
node: TypeId, node: NodeId,
/// The name of the property. /// The name of the property.
#[cfg(debug_assertions)]
name: &'static str, name: &'static str,
/// The property's value. /// The property's value.
value: Arc<Prehashed<dyn Bounds>>, value: Arc<Prehashed<dyn Bounds>>,
@ -202,8 +266,9 @@ 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 { fn new<'a, K: Key<'a>>(_: K, value: K::Value) -> Self {
Self { Self {
key: TypeId::of::<K>(), key: KeyId::of::<K>(),
node: K::node(), node: K::node(),
#[cfg(debug_assertions)]
name: K::NAME, name: K::NAME,
value: Arc::new(Prehashed::new(value)), value: Arc::new(Prehashed::new(value)),
scoped: false, scoped: false,
@ -223,7 +288,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> { fn downcast<'a, K: Key<'a>>(&'a self) -> Option<&'a K::Value> {
if self.key == TypeId::of::<K>() { if self.key == KeyId::of::<K>() {
(**self.value).as_any().downcast_ref() (**self.value).as_any().downcast_ref()
} else { } else {
None None
@ -232,13 +297,15 @@ 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 { fn is_of<T: Node>(&self) -> bool {
self.node == TypeId::of::<T>() self.node == NodeId::of::<T>()
} }
} }
impl Debug for Property { impl Debug for Property {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{} = {:?}", self.name, self.value)?; #[cfg(debug_assertions)]
write!(f, "{} = ", self.name)?;
write!(f, "{:?}", self.value)?;
if self.scoped { if self.scoped {
write!(f, " [scoped]")?; write!(f, " [scoped]")?;
} }
@ -286,8 +353,8 @@ pub trait Key<'a>: Copy + 'static {
/// The name of the property, used for debug printing. /// The name of the property, used for debug printing.
const NAME: &'static str; const NAME: &'static str;
/// The type id of the node this property belongs to. /// The ids of the key and of the node the key belongs to.
fn node() -> TypeId; fn node() -> NodeId;
/// Compute an output value from a sequence of values belong to this key, /// Compute an output value from a sequence of values belong to this key,
/// folding if necessary. /// folding if necessary.
@ -388,13 +455,32 @@ where
} }
} }
/// 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. /// A show rule recipe.
#[derive(Clone, PartialEq, Hash)] #[derive(Clone, PartialEq, Hash)]
struct Recipe { struct Recipe {
/// The affected node. /// The affected node.
node: TypeId, node: NodeId,
/// The name of the affected node.
name: &'static str,
/// The function that defines the recipe. /// The function that defines the recipe.
func: Func, func: Func,
/// The span to report all erros with. /// The span to report all erros with.
@ -404,67 +490,13 @@ 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 { fn new<T: Node>(func: Func, span: Span) -> Self {
Self { Self { node: NodeId::of::<T>(), func, span }
node: TypeId::of::<T>(),
name: std::any::type_name::<T>(),
func,
span,
}
} }
} }
impl Debug for Recipe { impl Debug for Recipe {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Recipe for {} from {:?}", self.name, self.span) write!(f, "Recipe for {:?} from {:?}", self.node, self.span)
}
}
/// A style chain 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(Clone, PartialEq, Hash)]
pub struct Barrier(Entry);
impl Barrier {
/// Create a new barrier for the layout node `T`.
pub fn new<T: Layout>() -> Self {
Self(Entry::Barrier(
TypeId::of::<T>(),
std::any::type_name::<T>(),
))
}
/// Make this barrier the first link of the `tail` chain.
pub fn chain<'a>(&'a self, tail: &'a StyleChain) -> StyleChain<'a> {
// We have to store a full `Entry` enum inside the barrier because
// otherwise the `slice::from_ref` trick below won't work.
// Unfortunately, that also means we have to somehow extract the id
// here.
let id = match self.0 {
Entry::Barrier(id, _) => id,
_ => unreachable!(),
};
if tail
.entries()
.filter_map(Entry::property)
.any(|p| p.scoped && p.node == id)
{
StyleChain {
head: std::slice::from_ref(&self.0),
tail: Some(tail),
}
} else {
*tail
}
}
}
impl Debug for Barrier {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.0.fmt(f)
} }
} }
@ -536,7 +568,7 @@ impl<'a> StyleChain<'a> {
impl<'a> StyleChain<'a> { impl<'a> StyleChain<'a> {
/// Return the chain, but without the trailing scoped property for the given /// Return the chain, but without the trailing scoped property for the given
/// `node`. This is a 90% hack fix for show node constructor scoping. /// `node`. This is a 90% hack fix for show node constructor scoping.
pub(super) fn unscoped(mut self, node: TypeId) -> Self { pub(super) fn unscoped(mut self, node: NodeId) -> Self {
while self while self
.head .head
.last() .last()
@ -626,8 +658,8 @@ impl<'a, K: Key<'a>> Iterator for Values<'a, K> {
} }
} }
} }
Entry::Barrier(id, _) => { Entry::Barrier(barrier) => {
self.depth += (*id == K::node()) as usize; self.depth += (barrier.0 == K::node()) as usize;
} }
Entry::Recipe(_) => {} Entry::Recipe(_) => {}
} }

View File

@ -9,6 +9,7 @@ pub use eco_string::EcoString;
pub use mac_roman::decode_mac_roman; pub use mac_roman::decode_mac_roman;
pub use prehashed::Prehashed; pub use prehashed::Prehashed;
use std::any::TypeId;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::ops::{Deref, Range}; use std::ops::{Deref, Range};
@ -34,7 +35,61 @@ where
Wrapper(f) Wrapper(f)
} }
/// Additional methods for strings. /// An alternative type id that prints as something readable in debug mode.
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct ReadableTypeId {
id: TypeId,
#[cfg(debug_assertions)]
name: &'static str,
}
impl ReadableTypeId {
/// The type id of the given type.
pub fn of<T: 'static>() -> Self {
Self {
id: TypeId::of::<T>(),
#[cfg(debug_assertions)]
name: std::any::type_name::<T>(),
}
}
}
impl Debug for ReadableTypeId {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
#[cfg(debug_assertions)]
f.pad(self.name)?;
#[cfg(not(debug_assertions))]
f.pad("ReadableTypeId")?;
Ok(())
}
}
/// Either owned or shared.
pub enum MaybeShared<T> {
/// Owned data.
Owned(T),
/// Shared data.
Shared(Arc<T>),
}
impl<T> AsRef<T> for MaybeShared<T> {
fn as_ref(&self) -> &T {
self
}
}
impl<T> Deref for MaybeShared<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
Self::Owned(owned) => owned,
Self::Shared(shared) => shared,
}
}
}
/// Extra methods for [`str`].
pub trait StrExt { pub trait StrExt {
/// The number of code units this string would use if it was encoded in /// The number of code units this string would use if it was encoded in
/// UTF16. This runs in linear time. /// UTF16. This runs in linear time.
@ -47,7 +102,7 @@ impl StrExt for str {
} }
} }
/// Additional methods for options. /// Extra methods for [`Option<T>`].
pub trait OptionExt<T> { pub trait OptionExt<T> {
/// Sets `other` as the value if `self` is `None` or if it contains a value /// Sets `other` as the value if `self` is `None` or if it contains a value
/// larger than `other`. /// larger than `other`.
@ -82,7 +137,7 @@ impl<T> OptionExt<T> for Option<T> {
} }
} }
/// Additional methods for reference-counted pointers. /// Extra methods for [`Arc`].
pub trait ArcExt<T> { pub trait ArcExt<T> {
/// Takes the inner value if there is exactly one strong reference and /// Takes the inner value if there is exactly one strong reference and
/// clones it otherwise. /// clones it otherwise.
@ -101,32 +156,7 @@ where
} }
} }
/// Either owned or shared. /// Extra methods for `[T]`.
pub enum MaybeShared<T> {
/// Owned data.
Owned(T),
/// Shared data.
Shared(Arc<T>),
}
impl<T> AsRef<T> for MaybeShared<T> {
fn as_ref(&self) -> &T {
self
}
}
impl<T> Deref for MaybeShared<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
Self::Owned(owned) => owned,
Self::Shared(shared) => shared,
}
}
}
/// Additional methods for slices.
pub trait SliceExt<T> { pub trait SliceExt<T> {
/// Split a slice into consecutive runs with the same key and yield for /// Split a slice into consecutive runs with the same key and yield for
/// each such run the key and the slice of elements with that key. /// each such run the key and the slice of elements with that key.
@ -165,7 +195,7 @@ where
} }
} }
/// Additional methods for [`Range<usize>`]. /// Extra methods for [`Range<usize>`].
pub trait RangeExt { pub trait RangeExt {
/// Locate a position relative to a range. /// Locate a position relative to a range.
/// ///
@ -193,7 +223,7 @@ impl RangeExt for Range<usize> {
} }
} }
/// Additional methods for [`Path`]. /// Extra methods for [`Path`].
pub trait PathExt { pub trait PathExt {
/// Lexically normalize a path. /// Lexically normalize a path.
fn normalize(&self) -> PathBuf; fn normalize(&self) -> PathBuf;