summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-04-24 16:38:11 +0200
committerLaurenz <laurmaedje@gmail.com>2022-04-24 16:42:19 +0200
commit89927d7de069169eeecfa091d6b77408b69fe188 (patch)
treebd9172a9935f2e15214d82c36d2e411c3623b7f5
parent8fbb11fc05b3313bf102c1f23693290661d00863 (diff)
`StyleSlot`, `KeyId` and `NodeId`
-rw-r--r--macros/src/lib.rs6
-rw-r--r--src/model/layout.rs17
-rw-r--r--src/model/show.rs15
-rw-r--r--src/model/styles.rs188
-rw-r--r--src/util/mod.rs92
5 files changed, 190 insertions, 128 deletions
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index 8614a26f..15925df7 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -249,12 +249,12 @@ fn process_const(
const NAME: &'static str = #name;
- fn node() -> TypeId {
- TypeId::of::<#self_ty>()
+ fn node() -> model::NodeId {
+ model::NodeId::of::<#self_ty>()
}
fn get(
- chain: StyleChain<'a>,
+ chain: model::StyleChain<'a>,
mut values: impl Iterator<Item = &'a Self::Value>,
) -> Self::Output {
#get
diff --git a/src/model/layout.rs b/src/model/layout.rs
index da6290ae..9a4d5df3 100644
--- a/src/model/layout.rs
+++ b/src/model/layout.rs
@@ -5,7 +5,7 @@ use std::fmt::{self, Debug, Formatter};
use std::hash::Hash;
use std::sync::Arc;
-use super::{Barrier, Resolve, StyleChain};
+use super::{Barrier, NodeId, Resolve, StyleChain, StyleSlot};
use crate::diag::TypResult;
use crate::eval::{RawAlign, RawLength};
use crate::frame::{Element, Frame, Geometry};
@@ -148,9 +148,9 @@ impl LayoutNode {
(**self.0).as_any().is::<T>()
}
- /// A barrier for the node.
- pub fn barrier(&self) -> Barrier {
- (**self.0).barrier()
+ /// The id of this node.
+ pub fn id(&self) -> NodeId {
+ (**self.0).node_id()
}
/// Try to downcast to a specific layout node.
@@ -220,7 +220,8 @@ impl Layout for LayoutNode {
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
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()
}
@@ -250,7 +251,7 @@ impl PartialEq for LayoutNode {
trait Bounds: Layout + Debug + Sync + Send + 'static {
fn as_any(&self) -> &dyn Any;
- fn barrier(&self) -> Barrier;
+ fn node_id(&self) -> NodeId;
}
impl<T> Bounds for T
@@ -261,8 +262,8 @@ where
self
}
- fn barrier(&self) -> Barrier {
- Barrier::new::<T>()
+ fn node_id(&self) -> NodeId {
+ NodeId::of::<Self>()
}
}
diff --git a/src/model/show.rs b/src/model/show.rs
index 5f76ba19..d1365eb2 100644
--- a/src/model/show.rs
+++ b/src/model/show.rs
@@ -1,9 +1,8 @@
-use std::any::{Any, TypeId};
use std::fmt::{self, Debug, Formatter};
use std::hash::Hash;
use std::sync::Arc;
-use super::{Content, StyleChain};
+use super::{Content, NodeId, StyleChain};
use crate::diag::TypResult;
use crate::eval::Dict;
use crate::util::Prehashed;
@@ -57,9 +56,9 @@ impl ShowNode {
Self(Arc::new(Prehashed::new(node)))
}
- /// The type id of this node.
- pub fn id(&self) -> TypeId {
- self.0.as_any().type_id()
+ /// The id of this node.
+ pub fn id(&self) -> NodeId {
+ (**self.0).node_id()
}
}
@@ -99,14 +98,14 @@ impl PartialEq for ShowNode {
}
trait Bounds: Show + Debug + Sync + Send + 'static {
- fn as_any(&self) -> &dyn Any;
+ fn node_id(&self) -> NodeId;
}
impl<T> Bounds for T
where
T: Show + Debug + Hash + Sync + Send + 'static,
{
- fn as_any(&self) -> &dyn Any {
- self
+ fn node_id(&self) -> NodeId {
+ NodeId::of::<Self>()
}
}
diff --git a/src/model/styles.rs b/src/model/styles.rs
index 2195568d..8c9092a4 100644
--- a/src/model/styles.rs
+++ b/src/model/styles.rs
@@ -1,17 +1,17 @@
-use std::any::{Any, TypeId};
+use std::any::Any;
use std::fmt::{self, Debug, Formatter};
use std::hash::Hash;
use std::marker::PhantomData;
use std::sync::Arc;
-use super::{Content, Layout, Show, ShowNode};
+use super::{Content, Show, ShowNode};
use crate::diag::{At, TypResult};
use crate::eval::{Args, Func, Node, Smart, Value};
use crate::geom::{Numeric, Relative, Sides, Spec};
use crate::library::layout::PageNode;
use crate::library::text::{FontFamily, ParNode, TextNode};
use crate::syntax::Span;
-use crate::util::Prehashed;
+use crate::util::{Prehashed, ReadableTypeId};
use crate::Context;
/// A map of style properties.
@@ -73,7 +73,7 @@ impl StyleMap {
self.0
.iter()
.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.
@@ -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.
#[derive(Clone, PartialEq, Hash)]
enum Entry {
/// A style property originating from a set rule or constructor.
Property(Property),
/// A barrier for scoped styles.
- Barrier(TypeId, &'static str),
+ Barrier(Barrier),
/// A show rule recipe.
Recipe(Recipe),
}
@@ -176,20 +205,55 @@ impl Debug for Entry {
match self {
Self::Property(property) => property.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("]")
}
}
+/// 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.
#[derive(Clone, Hash)]
struct Property {
- /// The type id of the property's [key](Key).
- key: TypeId,
- /// The type id of the node the property belongs to.
- node: TypeId,
+ /// 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>>,
@@ -202,8 +266,9 @@ impl Property {
/// Create a new property from a key-value pair.
fn new<'a, K: Key<'a>>(_: K, value: K::Value) -> Self {
Self {
- key: TypeId::of::<K>(),
+ key: KeyId::of::<K>(),
node: K::node(),
+ #[cfg(debug_assertions)]
name: K::NAME,
value: Arc::new(Prehashed::new(value)),
scoped: false,
@@ -223,7 +288,7 @@ impl Property {
/// Access the property's value if it is of the given key.
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()
} else {
None
@@ -232,13 +297,15 @@ impl Property {
/// Whether this property belongs to the node `T`.
fn is_of<T: Node>(&self) -> bool {
- self.node == TypeId::of::<T>()
+ self.node == NodeId::of::<T>()
}
}
impl Debug for Property {
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 {
write!(f, " [scoped]")?;
}
@@ -286,8 +353,8 @@ pub trait Key<'a>: Copy + 'static {
/// The name of the property, used for debug printing.
const NAME: &'static str;
- /// The type id of the node this property belongs to.
- fn node() -> TypeId;
+ /// 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.
@@ -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.
#[derive(Clone, PartialEq, Hash)]
struct Recipe {
/// The affected node.
- node: TypeId,
- /// The name of the affected node.
- name: &'static str,
+ node: NodeId,
/// The function that defines the recipe.
func: Func,
/// The span to report all erros with.
@@ -404,67 +490,13 @@ struct Recipe {
impl Recipe {
/// Create a new recipe for the node `T`.
fn new<T: Node>(func: Func, span: Span) -> Self {
- Self {
- node: TypeId::of::<T>(),
- name: std::any::type_name::<T>(),
- func,
- span,
- }
+ 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.name, 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)
+ write!(f, "Recipe for {:?} from {:?}", self.node, self.span)
}
}
@@ -536,7 +568,7 @@ impl<'a> StyleChain<'a> {
impl<'a> StyleChain<'a> {
/// Return the chain, but without the trailing scoped property for the given
/// `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
.head
.last()
@@ -626,8 +658,8 @@ impl<'a, K: Key<'a>> Iterator for Values<'a, K> {
}
}
}
- Entry::Barrier(id, _) => {
- self.depth += (*id == K::node()) as usize;
+ Entry::Barrier(barrier) => {
+ self.depth += (barrier.0 == K::node()) as usize;
}
Entry::Recipe(_) => {}
}
diff --git a/src/util/mod.rs b/src/util/mod.rs
index 3bc13bac..f762d88d 100644
--- a/src/util/mod.rs
+++ b/src/util/mod.rs
@@ -9,6 +9,7 @@ pub use eco_string::EcoString;
pub use mac_roman::decode_mac_roman;
pub use prehashed::Prehashed;
+use std::any::TypeId;
use std::cmp::Ordering;
use std::fmt::{self, Debug, Formatter};
use std::ops::{Deref, Range};
@@ -34,7 +35,61 @@ where
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 {
/// The number of code units this string would use if it was encoded in
/// 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> {
/// Sets `other` as the value if `self` is `None` or if it contains a value
/// 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> {
/// Takes the inner value if there is exactly one strong reference and
/// clones it otherwise.
@@ -101,32 +156,7 @@ where
}
}
-/// 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,
- }
- }
-}
-
-/// Additional methods for slices.
+/// Extra methods for `[T]`.
pub trait SliceExt<T> {
/// 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.
@@ -165,7 +195,7 @@ where
}
}
-/// Additional methods for [`Range<usize>`].
+/// Extra methods for [`Range<usize>`].
pub trait RangeExt {
/// 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 {
/// Lexically normalize a path.
fn normalize(&self) -> PathBuf;