Reorganize content type
This commit is contained in:
parent
b476de87b7
commit
5992f11b4c
@ -4,7 +4,7 @@ use typst::model::{capability, Content, StyleChain, StyleVec, StyleVecBuilder};
|
||||
|
||||
/// How a node interacts with other nodes.
|
||||
#[capability]
|
||||
pub trait Behave: 'static + Send + Sync {
|
||||
pub trait Behave {
|
||||
/// The node's interaction behaviour.
|
||||
fn behaviour(&self) -> Behaviour;
|
||||
|
||||
@ -62,13 +62,13 @@ impl<'a> BehavedBuilder<'a> {
|
||||
/// Push an item into the sequence.
|
||||
pub fn push(&mut self, item: Content, styles: StyleChain<'a>) {
|
||||
let interaction = item
|
||||
.to::<dyn Behave>()
|
||||
.with::<dyn Behave>()
|
||||
.map_or(Behaviour::Supportive, Behave::behaviour);
|
||||
|
||||
match interaction {
|
||||
Behaviour::Weak(level) => {
|
||||
if matches!(self.last, Behaviour::Weak(_)) {
|
||||
let item = item.to::<dyn Behave>().unwrap();
|
||||
let item = item.with::<dyn Behave>().unwrap();
|
||||
let i = self.staged.iter().position(|prev| {
|
||||
let Behaviour::Weak(prev_level) = prev.1 else { return false };
|
||||
level < prev_level
|
||||
|
@ -25,7 +25,7 @@ impl LayoutBlock for FlowNode {
|
||||
|
||||
for (child, map) in self.0.iter() {
|
||||
let styles = map.chain(&styles);
|
||||
if let Some(&node) = child.downcast::<VNode>() {
|
||||
if let Some(&node) = child.to::<VNode>() {
|
||||
layouter.layout_spacing(node.amount, styles);
|
||||
} else if child.has::<dyn LayoutBlock>() {
|
||||
layouter.layout_block(world, child, styles)?;
|
||||
@ -134,7 +134,7 @@ impl FlowLayouter {
|
||||
|
||||
// Placed nodes that are out of flow produce placed items which aren't
|
||||
// aligned later.
|
||||
if let Some(placed) = block.downcast::<PlaceNode>() {
|
||||
if let Some(placed) = block.to::<PlaceNode>() {
|
||||
if placed.out_of_flow() {
|
||||
let frame = block.layout_block(world, &self.regions, styles)?.remove(0);
|
||||
self.items.push(FlowItem::Placed(frame));
|
||||
@ -149,7 +149,7 @@ impl FlowLayouter {
|
||||
styles.get(ParNode::ALIGN),
|
||||
// Vertical align node alignment is respected by the flow.
|
||||
block
|
||||
.downcast::<AlignNode>()
|
||||
.to::<AlignNode>()
|
||||
.and_then(|aligned| aligned.aligns.y)
|
||||
.map(|align| align.resolve(styles))
|
||||
.unwrap_or(Align::Top),
|
||||
|
@ -32,8 +32,7 @@ use typst::diag::SourceResult;
|
||||
use typst::frame::Frame;
|
||||
use typst::geom::*;
|
||||
use typst::model::{
|
||||
capability, Content, Node, SequenceNode, Style, StyleChain, StyleVecBuilder,
|
||||
StyledNode,
|
||||
capability, Content, SequenceNode, Style, StyleChain, StyleVecBuilder, StyledNode,
|
||||
};
|
||||
use typst::World;
|
||||
|
||||
@ -48,7 +47,7 @@ use crate::text::{
|
||||
|
||||
/// Root-level layout.
|
||||
#[capability]
|
||||
pub trait LayoutRoot: 'static + Sync + Send {
|
||||
pub trait LayoutRoot {
|
||||
/// Layout into one frame per page.
|
||||
fn layout_root(&self, world: Tracked<dyn World>) -> SourceResult<Vec<Frame>>;
|
||||
}
|
||||
@ -69,7 +68,7 @@ impl LayoutRoot for Content {
|
||||
|
||||
/// Block-level layout.
|
||||
#[capability]
|
||||
pub trait LayoutBlock: 'static + Sync + Send {
|
||||
pub trait LayoutBlock {
|
||||
/// Layout into one frame per region.
|
||||
fn layout_block(
|
||||
&self,
|
||||
@ -88,7 +87,7 @@ impl LayoutBlock for Content {
|
||||
styles: StyleChain,
|
||||
) -> SourceResult<Vec<Frame>> {
|
||||
if !styles.applicable(self) {
|
||||
if let Some(node) = self.to::<dyn LayoutBlock>() {
|
||||
if let Some(node) = self.with::<dyn LayoutBlock>() {
|
||||
let barrier = Style::Barrier(self.id());
|
||||
let styles = barrier.chain(&styles);
|
||||
return node.layout_block(world, regions, styles);
|
||||
@ -105,7 +104,7 @@ impl LayoutBlock for Content {
|
||||
|
||||
/// Inline-level layout.
|
||||
#[capability]
|
||||
pub trait LayoutInline: 'static + Sync + Send {
|
||||
pub trait LayoutInline {
|
||||
/// Layout into a single frame.
|
||||
fn layout_inline(
|
||||
&self,
|
||||
@ -127,13 +126,13 @@ impl LayoutInline for Content {
|
||||
assert!(regions.last.is_none());
|
||||
|
||||
if !styles.applicable(self) {
|
||||
if let Some(node) = self.to::<dyn LayoutInline>() {
|
||||
if let Some(node) = self.with::<dyn LayoutInline>() {
|
||||
let barrier = Style::Barrier(self.id());
|
||||
let styles = barrier.chain(&styles);
|
||||
return node.layout_inline(world, regions, styles);
|
||||
}
|
||||
|
||||
if let Some(node) = self.to::<dyn LayoutBlock>() {
|
||||
if let Some(node) = self.with::<dyn LayoutBlock>() {
|
||||
let barrier = Style::Barrier(self.id());
|
||||
let styles = barrier.chain(&styles);
|
||||
return Ok(node.layout_block(world, regions, styles)?.remove(0));
|
||||
@ -312,11 +311,11 @@ impl<'a> Builder<'a> {
|
||||
content: &'a Content,
|
||||
styles: StyleChain<'a>,
|
||||
) -> SourceResult<()> {
|
||||
if let Some(styled) = content.downcast::<StyledNode>() {
|
||||
if let Some(styled) = content.to::<StyledNode>() {
|
||||
return self.styled(styled, styles);
|
||||
}
|
||||
|
||||
if let Some(seq) = content.downcast::<SequenceNode>() {
|
||||
if let Some(seq) = content.to::<SequenceNode>() {
|
||||
return self.sequence(seq, styles);
|
||||
}
|
||||
|
||||
@ -347,7 +346,7 @@ impl<'a> Builder<'a> {
|
||||
}
|
||||
|
||||
let keep = content
|
||||
.downcast::<PagebreakNode>()
|
||||
.to::<PagebreakNode>()
|
||||
.map_or(false, |pagebreak| !pagebreak.weak);
|
||||
self.interrupt(Interruption::Page, styles, keep)?;
|
||||
|
||||
@ -457,12 +456,12 @@ struct DocBuilder<'a> {
|
||||
|
||||
impl<'a> DocBuilder<'a> {
|
||||
fn accept(&mut self, content: &Content, styles: StyleChain<'a>) -> bool {
|
||||
if let Some(pagebreak) = content.downcast::<PagebreakNode>() {
|
||||
if let Some(pagebreak) = content.to::<PagebreakNode>() {
|
||||
self.keep_next = !pagebreak.weak;
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(page) = content.downcast::<PageNode>() {
|
||||
if let Some(page) = content.to::<PageNode>() {
|
||||
self.pages.push(page.clone(), styles);
|
||||
self.keep_next = false;
|
||||
return true;
|
||||
@ -498,11 +497,11 @@ impl<'a> FlowBuilder<'a> {
|
||||
}
|
||||
|
||||
if content.has::<dyn LayoutBlock>() {
|
||||
let is_tight_list = if let Some(node) = content.downcast::<ListNode>() {
|
||||
let is_tight_list = if let Some(node) = content.to::<ListNode>() {
|
||||
node.tight
|
||||
} else if let Some(node) = content.downcast::<EnumNode>() {
|
||||
} else if let Some(node) = content.to::<EnumNode>() {
|
||||
node.tight
|
||||
} else if let Some(node) = content.downcast::<DescNode>() {
|
||||
} else if let Some(node) = content.to::<DescNode>() {
|
||||
node.tight
|
||||
} else {
|
||||
false
|
||||
@ -576,7 +575,7 @@ impl<'a> ListBuilder<'a> {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(item) = content.downcast::<ListItem>() {
|
||||
if let Some(item) = content.to::<ListItem>() {
|
||||
if self
|
||||
.items
|
||||
.items()
|
||||
|
@ -49,9 +49,7 @@ impl PlaceNode {
|
||||
/// origin. Instead of relative to the parent's current flow/cursor
|
||||
/// position.
|
||||
pub fn out_of_flow(&self) -> bool {
|
||||
self.0
|
||||
.downcast::<AlignNode>()
|
||||
.map_or(false, |node| node.aligns.y.is_some())
|
||||
self.0.to::<AlignNode>().map_or(false, |node| node.aligns.y.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ impl Behave for HNode {
|
||||
}
|
||||
|
||||
fn larger(&self, prev: &Content) -> bool {
|
||||
let Some(prev) = prev.downcast::<Self>() else { return false };
|
||||
let Some(prev) = prev.to::<Self>() else { return false };
|
||||
self.amount > prev.amount
|
||||
}
|
||||
}
|
||||
@ -110,7 +110,7 @@ impl Behave for VNode {
|
||||
}
|
||||
|
||||
fn larger(&self, prev: &Content) -> bool {
|
||||
let Some(prev) = prev.downcast::<Self>() else { return false };
|
||||
let Some(prev) = prev.to::<Self>() else { return false };
|
||||
self.amount > prev.amount
|
||||
}
|
||||
}
|
||||
|
@ -182,11 +182,11 @@ impl<'a> StackLayouter<'a> {
|
||||
// Block-axis alignment of the `AlignNode` is respected
|
||||
// by the stack node.
|
||||
let align = block
|
||||
.downcast::<AlignNode>()
|
||||
.to::<AlignNode>()
|
||||
.and_then(|node| node.aligns.get(self.axis))
|
||||
.map(|align| align.resolve(styles))
|
||||
.unwrap_or_else(|| {
|
||||
if let Some(styled) = block.downcast::<StyledNode>() {
|
||||
if let Some(styled) = block.to::<StyledNode>() {
|
||||
let map = &styled.map;
|
||||
if map.contains(ParNode::ALIGN) {
|
||||
return StyleChain::with_root(map).get(ParNode::ALIGN);
|
||||
|
@ -161,7 +161,7 @@ pub fn items() -> LangItems {
|
||||
linebreak: |justify| text::LinebreakNode { justify }.pack(),
|
||||
text: |text| text::TextNode(text).pack(),
|
||||
text_id: NodeId::of::<text::TextNode>(),
|
||||
text_str: |content| Some(&content.downcast::<text::TextNode>()?.0),
|
||||
text_str: |content| Some(&content.to::<text::TextNode>()?.0),
|
||||
smart_quote: |double| text::SmartQuoteNode { double }.pack(),
|
||||
parbreak: || text::ParbreakNode.pack(),
|
||||
strong: |body| text::StrongNode(body).pack(),
|
||||
|
@ -35,7 +35,7 @@ impl Show for MathNode {
|
||||
let mut realized = self
|
||||
.clone()
|
||||
.pack()
|
||||
.guard(RecipeId::Base(NodeId::of::<Self>()))
|
||||
.guarded(RecipeId::Base(NodeId::of::<Self>()))
|
||||
.styled_with_map(map);
|
||||
|
||||
if self.display {
|
||||
|
@ -10,7 +10,7 @@ use crate::text::{families, variant, LinebreakNode, SpaceNode, TextNode};
|
||||
|
||||
/// Turn a math node into TeX math code.
|
||||
#[capability]
|
||||
pub trait Texify: 'static + Sync + Send {
|
||||
pub trait Texify {
|
||||
/// Perform the conversion.
|
||||
fn texify(&self) -> EcoString;
|
||||
}
|
||||
@ -25,7 +25,7 @@ impl Texify for Content {
|
||||
return r"\\".into();
|
||||
}
|
||||
|
||||
if let Some(node) = self.to::<dyn Texify>() {
|
||||
if let Some(node) = self.with::<dyn Texify>() {
|
||||
return node.texify();
|
||||
}
|
||||
|
||||
|
@ -420,7 +420,7 @@ fn collect<'a>(
|
||||
let segment = if child.is::<SpaceNode>() {
|
||||
full.push(' ');
|
||||
Segment::Text(1)
|
||||
} else if let Some(node) = child.downcast::<TextNode>() {
|
||||
} else if let Some(node) = child.to::<TextNode>() {
|
||||
let prev = full.len();
|
||||
if let Some(case) = styles.get(TextNode::CASE) {
|
||||
full.push_str(&case.apply(&node.0));
|
||||
@ -428,18 +428,18 @@ fn collect<'a>(
|
||||
full.push_str(&node.0);
|
||||
}
|
||||
Segment::Text(full.len() - prev)
|
||||
} else if let Some(node) = child.downcast::<LinebreakNode>() {
|
||||
} else if let Some(node) = child.to::<LinebreakNode>() {
|
||||
let c = if node.justify { '\u{2028}' } else { '\n' };
|
||||
full.push(c);
|
||||
Segment::Text(c.len_utf8())
|
||||
} else if let Some(node) = child.downcast::<SmartQuoteNode>() {
|
||||
} else if let Some(node) = child.to::<SmartQuoteNode>() {
|
||||
let prev = full.len();
|
||||
if styles.get(TextNode::SMART_QUOTES) {
|
||||
let lang = styles.get(TextNode::LANG);
|
||||
let region = styles.get(TextNode::REGION);
|
||||
let quotes = Quotes::from_lang(lang, region);
|
||||
let peeked = iter.peek().and_then(|(child, _)| {
|
||||
if let Some(node) = child.downcast::<TextNode>() {
|
||||
if let Some(node) = child.to::<TextNode>() {
|
||||
node.0.chars().next()
|
||||
} else if child.is::<SmartQuoteNode>() {
|
||||
Some('"')
|
||||
@ -455,7 +455,7 @@ fn collect<'a>(
|
||||
full.push(if node.double { '"' } else { '\'' });
|
||||
}
|
||||
Segment::Text(full.len() - prev)
|
||||
} else if let Some(&node) = child.downcast::<HNode>() {
|
||||
} else if let Some(&node) = child.to::<HNode>() {
|
||||
full.push(SPACING_REPLACE);
|
||||
Segment::Spacing(node.amount)
|
||||
} else if child.has::<dyn LayoutInline>() {
|
||||
@ -523,7 +523,7 @@ fn prepare<'a>(
|
||||
}
|
||||
},
|
||||
Segment::Inline(inline) => {
|
||||
if let Some(repeat) = inline.downcast::<RepeatNode>() {
|
||||
if let Some(repeat) = inline.to::<RepeatNode>() {
|
||||
items.push(Item::Repeat(repeat, styles));
|
||||
} else {
|
||||
let size = Size::new(regions.first.x, regions.base.y);
|
||||
@ -606,11 +606,11 @@ fn is_compatible(a: Script, b: Script) -> bool {
|
||||
|
||||
/// Get a style property, but only if it is the same for all children of the
|
||||
/// paragraph.
|
||||
fn shared_get<'a, K: Key<'a>>(
|
||||
fn shared_get<'a, K: Key>(
|
||||
styles: StyleChain<'a>,
|
||||
children: &StyleVec<Content>,
|
||||
key: K,
|
||||
) -> Option<K::Output> {
|
||||
) -> Option<K::Output<'a>> {
|
||||
children
|
||||
.styles()
|
||||
.all(|map| !map.contains(key))
|
||||
|
@ -69,13 +69,11 @@ impl<const S: ShiftKind> Show for ShiftNode<S> {
|
||||
/// Find and transform the text contained in `content` to the given script kind
|
||||
/// if and only if it only consists of `Text`, `Space`, and `Empty` leaf nodes.
|
||||
fn search_text(content: &Content, mode: ShiftKind) -> Option<EcoString> {
|
||||
if content.is_empty() {
|
||||
Some(EcoString::new())
|
||||
} else if content.is::<SpaceNode>() {
|
||||
if content.is::<SpaceNode>() {
|
||||
Some(' '.into())
|
||||
} else if let Some(text) = content.downcast::<TextNode>() {
|
||||
} else if let Some(text) = content.to::<TextNode>() {
|
||||
convert_script(&text.0, mode)
|
||||
} else if let Some(seq) = content.downcast::<SequenceNode>() {
|
||||
} else if let Some(seq) = content.to::<SequenceNode>() {
|
||||
let mut full = EcoString::new();
|
||||
for item in seq.0.iter() {
|
||||
match search_text(item, mode) {
|
||||
|
@ -227,6 +227,9 @@ fn create(node: &Node) -> Result<TokenStream> {
|
||||
#construct_func
|
||||
#set_func
|
||||
#field_method
|
||||
}
|
||||
|
||||
unsafe impl<#params> ::typst::model::Capable for #self_ty {
|
||||
#vtable_method
|
||||
}
|
||||
};
|
||||
@ -411,9 +414,9 @@ fn create_property_module(node: &Node, property: &Property) -> (syn::Type, syn::
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
|
||||
impl<'a, #params> ::typst::model::Key<'a> for #key {
|
||||
impl<#params> ::typst::model::Key for #key {
|
||||
type Value = #value_ty;
|
||||
type Output = #output_ty;
|
||||
type Output<'a> = #output_ty;
|
||||
#name_const
|
||||
#node_func
|
||||
#get_method
|
||||
@ -492,10 +495,10 @@ fn create_property_get_method(property: &Property) -> syn::ImplItemMethod {
|
||||
};
|
||||
|
||||
parse_quote! {
|
||||
fn get(
|
||||
fn get<'a>(
|
||||
chain: ::typst::model::StyleChain<'a>,
|
||||
mut values: impl ::std::iter::Iterator<Item = &'a Self::Value>,
|
||||
) -> Self::Output {
|
||||
) -> Self::Output<'a> {
|
||||
#value
|
||||
}
|
||||
}
|
||||
|
@ -9,19 +9,22 @@ use comemo::Tracked;
|
||||
use siphasher::sip128::{Hasher128, SipHasher};
|
||||
use typst_macros::node;
|
||||
|
||||
use super::{Args, Key, Property, Recipe, RecipeId, Style, StyleMap, Value, Vm};
|
||||
use super::{
|
||||
Args, Key, Property, Recipe, RecipeId, Style, StyleMap, Unlabellable, Value, Vm,
|
||||
};
|
||||
use crate::diag::{SourceResult, StrResult};
|
||||
use crate::syntax::Span;
|
||||
use crate::util::{EcoString, ReadableTypeId};
|
||||
use crate::World;
|
||||
|
||||
/// Composable representation of styled content.
|
||||
///
|
||||
/// This results from:
|
||||
/// - anything written between square brackets in Typst
|
||||
/// - any constructor function
|
||||
#[derive(Clone, Hash)]
|
||||
pub struct Content(Arc<dyn Bounds>, Vec<RecipeId>, Option<Span>, Option<EcoString>);
|
||||
pub struct Content {
|
||||
obj: Arc<dyn Bounds>,
|
||||
guards: Vec<RecipeId>,
|
||||
span: Option<Span>,
|
||||
label: Option<EcoString>,
|
||||
}
|
||||
|
||||
impl Content {
|
||||
/// Create empty content.
|
||||
@ -37,80 +40,60 @@ impl Content {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the content is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.downcast::<SequenceNode>().map_or(false, |seq| seq.0.is_empty())
|
||||
}
|
||||
|
||||
/// The node's human-readable name.
|
||||
pub fn name(&self) -> &'static str {
|
||||
(*self.0).name()
|
||||
}
|
||||
|
||||
/// The id of the contained node.
|
||||
pub fn id(&self) -> NodeId {
|
||||
(*self.0).id()
|
||||
}
|
||||
|
||||
/// Whether the contained node is of type `T`.
|
||||
pub fn is<T: 'static>(&self) -> bool {
|
||||
(*self.0).as_any().is::<T>()
|
||||
}
|
||||
|
||||
/// Cast to `T` if the contained node is of type `T`.
|
||||
pub fn downcast<T: 'static>(&self) -> Option<&T> {
|
||||
(*self.0).as_any().downcast_ref::<T>()
|
||||
}
|
||||
|
||||
/// Try to cast to a mutable instance of `T`.
|
||||
fn try_downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||
Arc::get_mut(&mut self.0)?.as_any_mut().downcast_mut::<T>()
|
||||
}
|
||||
|
||||
/// Access a field on this content.
|
||||
pub fn field(&self, name: &str) -> Option<Value> {
|
||||
if name == "label" {
|
||||
return Some(match &self.3 {
|
||||
Some(label) => Value::Str(label.clone().into()),
|
||||
None => Value::None,
|
||||
});
|
||||
/// Attach a span to the content.
|
||||
pub fn spanned(mut self, span: Span) -> Self {
|
||||
if let Some(styled) = self.to_mut::<StyledNode>() {
|
||||
styled.sub.span = Some(span);
|
||||
} else if let Some(styled) = self.to::<StyledNode>() {
|
||||
self = StyledNode {
|
||||
sub: styled.sub.clone().spanned(span),
|
||||
map: styled.map.clone(),
|
||||
}
|
||||
.pack();
|
||||
}
|
||||
|
||||
self.0.field(name)
|
||||
self.span = Some(span);
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether this content has the given capability.
|
||||
pub fn has<C>(&self) -> bool
|
||||
where
|
||||
C: Capability + ?Sized,
|
||||
{
|
||||
self.0.vtable(TypeId::of::<C>()).is_some()
|
||||
}
|
||||
|
||||
/// Cast to a trait object if this content has the given capability.
|
||||
pub fn to<C>(&self) -> Option<&C>
|
||||
where
|
||||
C: Capability + ?Sized,
|
||||
{
|
||||
let node: &dyn Bounds = &*self.0;
|
||||
let vtable = node.vtable(TypeId::of::<C>())?;
|
||||
let data = node as *const dyn Bounds as *const ();
|
||||
Some(unsafe { &*crate::util::fat::from_raw_parts(data, vtable) })
|
||||
}
|
||||
|
||||
/// Repeat this content `n` times.
|
||||
pub fn repeat(&self, n: i64) -> StrResult<Self> {
|
||||
let count = usize::try_from(n)
|
||||
.map_err(|_| format!("cannot repeat this content {} times", n))?;
|
||||
|
||||
Ok(Self::sequence(vec![self.clone(); count]))
|
||||
/// Attach a label to the content.
|
||||
pub fn labelled(mut self, label: EcoString) -> Self {
|
||||
self.label = Some(label);
|
||||
self
|
||||
}
|
||||
|
||||
/// Style this content with a single style property.
|
||||
pub fn styled<'k, K: Key<'k>>(self, key: K, value: K::Value) -> Self {
|
||||
pub fn styled<K: Key>(self, key: K, value: K::Value) -> Self {
|
||||
self.styled_with_entry(Style::Property(Property::new(key, value)))
|
||||
}
|
||||
|
||||
/// Style this content with a style entry.
|
||||
pub fn styled_with_entry(mut self, style: Style) -> Self {
|
||||
if let Some(styled) = self.to_mut::<StyledNode>() {
|
||||
styled.map.apply(style);
|
||||
self
|
||||
} else if let Some(styled) = self.to::<StyledNode>() {
|
||||
let mut map = styled.map.clone();
|
||||
map.apply(style);
|
||||
StyledNode { sub: styled.sub.clone(), map }.pack()
|
||||
} else {
|
||||
StyledNode { sub: self, map: style.into() }.pack()
|
||||
}
|
||||
}
|
||||
|
||||
/// Style this content with a full style map.
|
||||
pub fn styled_with_map(mut self, styles: StyleMap) -> Self {
|
||||
if styles.is_empty() {
|
||||
return self;
|
||||
}
|
||||
|
||||
if let Some(styled) = self.to_mut::<StyledNode>() {
|
||||
styled.map.apply_map(&styles);
|
||||
return self;
|
||||
}
|
||||
|
||||
StyledNode { sub: self, map: styles }.pack()
|
||||
}
|
||||
|
||||
/// Style this content with a recipe, eagerly applying it if possible.
|
||||
pub fn styled_with_recipe(
|
||||
self,
|
||||
@ -124,96 +107,115 @@ impl Content {
|
||||
}
|
||||
}
|
||||
|
||||
/// Style this content with a style entry.
|
||||
pub fn styled_with_entry(mut self, style: Style) -> Self {
|
||||
if let Some(styled) = self.try_downcast_mut::<StyledNode>() {
|
||||
styled.map.apply(style);
|
||||
self
|
||||
} else if let Some(styled) = self.downcast::<StyledNode>() {
|
||||
let mut map = styled.map.clone();
|
||||
map.apply(style);
|
||||
StyledNode { sub: styled.sub.clone(), map }.pack()
|
||||
} else {
|
||||
StyledNode { sub: self, map: style.into() }.pack()
|
||||
}
|
||||
/// Repeat this content `n` times.
|
||||
pub fn repeat(&self, n: i64) -> StrResult<Self> {
|
||||
let count = usize::try_from(n)
|
||||
.map_err(|_| format!("cannot repeat this content {} times", n))?;
|
||||
|
||||
Ok(Self::sequence(vec![self.clone(); count]))
|
||||
}
|
||||
}
|
||||
|
||||
impl Content {
|
||||
/// The id of the contained node.
|
||||
pub fn id(&self) -> NodeId {
|
||||
(*self.obj).id()
|
||||
}
|
||||
|
||||
/// Style this content with a full style map.
|
||||
pub fn styled_with_map(mut self, styles: StyleMap) -> Self {
|
||||
if styles.is_empty() {
|
||||
return self;
|
||||
}
|
||||
|
||||
if let Some(styled) = self.try_downcast_mut::<StyledNode>() {
|
||||
styled.map.apply_map(&styles);
|
||||
return self;
|
||||
}
|
||||
|
||||
StyledNode { sub: self, map: styles }.pack()
|
||||
}
|
||||
|
||||
/// Disable a show rule recipe.
|
||||
pub fn guard(mut self, id: RecipeId) -> Self {
|
||||
self.1.push(id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether no show rule was executed for this node so far.
|
||||
pub fn pristine(&self) -> bool {
|
||||
self.1.is_empty()
|
||||
}
|
||||
|
||||
/// Check whether a show rule recipe is disabled.
|
||||
pub fn guarded(&self, id: RecipeId) -> bool {
|
||||
self.1.contains(&id)
|
||||
/// The node's human-readable name.
|
||||
pub fn name(&self) -> &'static str {
|
||||
(*self.obj).name()
|
||||
}
|
||||
|
||||
/// The node's span.
|
||||
pub fn span(&self) -> Option<Span> {
|
||||
self.2
|
||||
}
|
||||
|
||||
/// Set the content's span.
|
||||
pub fn set_span(&mut self, span: Span) {
|
||||
if let Some(styled) = self.try_downcast_mut::<StyledNode>() {
|
||||
styled.sub.2 = Some(span);
|
||||
} else if let Some(styled) = self.downcast::<StyledNode>() {
|
||||
*self = StyledNode {
|
||||
sub: styled.sub.clone().spanned(span),
|
||||
map: styled.map.clone(),
|
||||
}
|
||||
.pack();
|
||||
}
|
||||
self.2 = Some(span);
|
||||
}
|
||||
|
||||
/// Attach a span to the content.
|
||||
pub fn spanned(mut self, span: Span) -> Self {
|
||||
self.set_span(span);
|
||||
self
|
||||
self.span
|
||||
}
|
||||
|
||||
/// The content's label.
|
||||
pub fn label(&self) -> Option<&EcoString> {
|
||||
self.3.as_ref()
|
||||
self.label.as_ref()
|
||||
}
|
||||
|
||||
/// Set the content's label.
|
||||
pub fn set_label(&mut self, label: EcoString) {
|
||||
self.3 = Some(label);
|
||||
/// Access a field on this content.
|
||||
pub fn field(&self, name: &str) -> Option<Value> {
|
||||
if name == "label" {
|
||||
return Some(match &self.label {
|
||||
Some(label) => Value::Str(label.clone().into()),
|
||||
None => Value::None,
|
||||
});
|
||||
}
|
||||
|
||||
self.obj.field(name)
|
||||
}
|
||||
|
||||
/// Attacha label to the content.
|
||||
pub fn labelled(mut self, label: EcoString) -> Self {
|
||||
self.set_label(label);
|
||||
/// Whether the contained node is of type `T`.
|
||||
pub fn is<T: 'static>(&self) -> bool {
|
||||
(*self.obj).as_any().is::<T>()
|
||||
}
|
||||
|
||||
/// Cast to `T` if the contained node is of type `T`.
|
||||
pub fn to<T: 'static>(&self) -> Option<&T> {
|
||||
(*self.obj).as_any().downcast_ref::<T>()
|
||||
}
|
||||
|
||||
/// Whether this content has the given capability.
|
||||
pub fn has<C>(&self) -> bool
|
||||
where
|
||||
C: Capability + ?Sized,
|
||||
{
|
||||
self.obj.vtable(TypeId::of::<C>()).is_some()
|
||||
}
|
||||
|
||||
/// Cast to a trait object if this content has the given capability.
|
||||
pub fn with<C>(&self) -> Option<&C>
|
||||
where
|
||||
C: Capability + ?Sized,
|
||||
{
|
||||
let node: &dyn Bounds = &*self.obj;
|
||||
let vtable = node.vtable(TypeId::of::<C>())?;
|
||||
let data = node as *const dyn Bounds as *const ();
|
||||
Some(unsafe { &*crate::util::fat::from_raw_parts(data, vtable) })
|
||||
}
|
||||
|
||||
/// Try to cast to a mutable instance of `T`.
|
||||
fn to_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||
Arc::get_mut(&mut self.obj)?.as_any_mut().downcast_mut::<T>()
|
||||
}
|
||||
|
||||
/// Disable a show rule recipe.
|
||||
#[doc(hidden)]
|
||||
pub fn guarded(mut self, id: RecipeId) -> Self {
|
||||
self.guards.push(id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether a label can be attached to the content.
|
||||
pub(super) fn labellable(&self) -> bool {
|
||||
!self.has::<dyn Unlabellable>()
|
||||
}
|
||||
|
||||
/// Whether no show rule was executed for this node so far.
|
||||
pub(super) fn is_pristine(&self) -> bool {
|
||||
self.guards.is_empty()
|
||||
}
|
||||
|
||||
/// Check whether a show rule recipe is disabled.
|
||||
pub(super) fn is_guarded(&self, id: RecipeId) -> bool {
|
||||
self.guards.contains(&id)
|
||||
}
|
||||
|
||||
/// Copy the metadata from other content.
|
||||
pub fn copy_meta(&mut self, from: &Content) {
|
||||
self.1 = from.1.clone();
|
||||
self.2 = from.2;
|
||||
self.3 = from.3.clone();
|
||||
pub(super) fn copy_meta(&mut self, from: &Content) {
|
||||
self.guards = from.guards.clone();
|
||||
self.span = from.span;
|
||||
self.label = from.label.clone();
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Content {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
self.obj.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,15 +225,9 @@ impl Default for Content {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Content {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Content {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
(*self.0).hash128() == (*other.0).hash128()
|
||||
(*self.obj).hash128() == (*other.obj).hash128()
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,10 +236,10 @@ impl Add for Content {
|
||||
|
||||
fn add(self, mut rhs: Self) -> Self::Output {
|
||||
let mut lhs = self;
|
||||
if let Some(lhs_mut) = lhs.try_downcast_mut::<SequenceNode>() {
|
||||
if let Some(rhs_mut) = rhs.try_downcast_mut::<SequenceNode>() {
|
||||
if let Some(lhs_mut) = lhs.to_mut::<SequenceNode>() {
|
||||
if let Some(rhs_mut) = rhs.to_mut::<SequenceNode>() {
|
||||
lhs_mut.0.append(&mut rhs_mut.0);
|
||||
} else if let Some(rhs) = rhs.downcast::<SequenceNode>() {
|
||||
} else if let Some(rhs) = rhs.to::<SequenceNode>() {
|
||||
lhs_mut.0.extend(rhs.0.iter().cloned());
|
||||
} else {
|
||||
lhs_mut.0.push(rhs);
|
||||
@ -251,7 +247,7 @@ impl Add for Content {
|
||||
return lhs;
|
||||
}
|
||||
|
||||
let seq = match (lhs.downcast::<SequenceNode>(), rhs.downcast::<SequenceNode>()) {
|
||||
let seq = match (lhs.to::<SequenceNode>(), rhs.to::<SequenceNode>()) {
|
||||
(Some(lhs), Some(rhs)) => lhs.0.iter().chain(&rhs.0).cloned().collect(),
|
||||
(Some(lhs), None) => lhs.0.iter().cloned().chain(iter::once(rhs)).collect(),
|
||||
(None, Some(rhs)) => iter::once(lhs).chain(rhs.0.iter().cloned()).collect(),
|
||||
@ -306,68 +302,6 @@ impl Hash for dyn Bounds {
|
||||
}
|
||||
}
|
||||
|
||||
/// A constructable, stylable content node.
|
||||
pub trait Node: 'static {
|
||||
/// Pack into type-erased content.
|
||||
fn pack(self) -> Content
|
||||
where
|
||||
Self: Debug + Hash + Sync + Send + Sized + 'static,
|
||||
{
|
||||
Content(Arc::new(self), vec![], None, None)
|
||||
}
|
||||
|
||||
/// A unique identifier of the node type.
|
||||
fn id(&self) -> NodeId;
|
||||
|
||||
/// The node's name.
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
/// Construct a node from the arguments.
|
||||
///
|
||||
/// This is passed only the arguments that remain after execution of the
|
||||
/// node's set rule.
|
||||
fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult<Content>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Parse relevant arguments into style properties for this node.
|
||||
///
|
||||
/// When `constructor` is true, [`construct`](Self::construct) will run
|
||||
/// after this invocation of `set` with the remaining arguments.
|
||||
fn set(args: &mut Args, constructor: bool) -> SourceResult<StyleMap>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Access a field on this node.
|
||||
fn field(&self, name: &str) -> Option<Value>;
|
||||
|
||||
/// Extract the pointer of the vtable of the trait object with the
|
||||
/// given type `id` if this node implements that trait.
|
||||
fn vtable(&self, id: TypeId) -> Option<*const ()>;
|
||||
}
|
||||
|
||||
/// A capability a node can have.
|
||||
///
|
||||
/// This is implemented by trait objects.
|
||||
pub trait Capability: 'static + Send + Sync {}
|
||||
|
||||
/// 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 node with applied styles.
|
||||
#[derive(Clone, Hash)]
|
||||
pub struct StyledNode {
|
||||
@ -402,3 +336,73 @@ impl Debug for SequenceNode {
|
||||
f.debug_list().entries(self.0.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A constructable, stylable content node.
|
||||
pub trait Node: 'static + Capable {
|
||||
/// Pack a node into type-erased content.
|
||||
fn pack(self) -> Content
|
||||
where
|
||||
Self: Node + Debug + Hash + Sync + Send + Sized + 'static,
|
||||
{
|
||||
Content {
|
||||
obj: Arc::new(self),
|
||||
guards: vec![],
|
||||
span: None,
|
||||
label: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// A unique identifier of the node type.
|
||||
fn id(&self) -> NodeId;
|
||||
|
||||
/// The node's name.
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
/// Construct a node from the arguments.
|
||||
///
|
||||
/// This is passed only the arguments that remain after execution of the
|
||||
/// node's set rule.
|
||||
fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult<Content>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Parse relevant arguments into style properties for this node.
|
||||
///
|
||||
/// When `constructor` is true, [`construct`](Self::construct) will run
|
||||
/// after this invocation of `set` with the remaining arguments.
|
||||
fn set(args: &mut Args, constructor: bool) -> SourceResult<StyleMap>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Access a field on this node.
|
||||
fn field(&self, name: &str) -> Option<Value>;
|
||||
}
|
||||
|
||||
/// 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 capability a node can have.
|
||||
///
|
||||
/// This is implemented by trait objects.
|
||||
pub trait Capability: 'static {}
|
||||
|
||||
/// Dynamically access a trait implementation at runtime.
|
||||
pub unsafe trait Capable {
|
||||
/// Return the vtable pointer of the trait object with given type `id`
|
||||
/// if `self` implements the trait.
|
||||
fn vtable(&self, of: TypeId) -> Option<*const ()>;
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
//! Evaluation of markup into modules.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::mem;
|
||||
|
||||
use comemo::{Track, Tracked};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
use super::{
|
||||
methods, ops, Arg, Args, Array, CapturesVisitor, Closure, Content, Dict, Flow, Func,
|
||||
Recipe, Scope, Scopes, Selector, StyleMap, Transform, Unlabellable, Value, Vm,
|
||||
Recipe, Scope, Scopes, Selector, StyleMap, Transform, Value, Vm,
|
||||
};
|
||||
use crate::diag::{bail, error, At, SourceResult, StrResult, Trace, Tracepoint};
|
||||
use crate::geom::{Abs, Angle, Em, Fr, Ratio};
|
||||
@ -137,10 +138,8 @@ fn eval_markup(
|
||||
seq.push(tail.styled_with_recipe(vm.world, recipe)?)
|
||||
}
|
||||
ast::MarkupNode::Label(label) => {
|
||||
if let Some(node) =
|
||||
seq.iter_mut().rev().find(|node| !node.has::<dyn Unlabellable>())
|
||||
{
|
||||
node.set_label(label.get().clone());
|
||||
if let Some(node) = seq.iter_mut().rev().find(|node| node.labellable()) {
|
||||
*node = mem::take(node).labelled(label.get().clone());
|
||||
}
|
||||
}
|
||||
_ => seq.push(node.eval(vm)?),
|
||||
@ -1080,7 +1079,7 @@ impl Eval for ast::FuncReturn {
|
||||
}
|
||||
|
||||
/// Access an expression mutably.
|
||||
pub trait Access {
|
||||
trait Access {
|
||||
/// Access the value.
|
||||
fn access<'a>(&self, vm: &'a mut Vm) -> SourceResult<&'a mut Value>;
|
||||
}
|
||||
|
@ -36,19 +36,19 @@ impl StyleMap {
|
||||
/// If the property needs folding and the value is already contained in the
|
||||
/// style map, `self` contributes the outer values and `value` is the inner
|
||||
/// one.
|
||||
pub fn set<'a, K: Key<'a>>(&mut self, key: K, value: K::Value) {
|
||||
pub fn set<K: Key>(&mut self, key: K, value: K::Value) {
|
||||
self.0.push(Style::Property(Property::new(key, value)));
|
||||
}
|
||||
|
||||
/// Set an inner value for a style property if it is `Some(_)`.
|
||||
pub fn set_opt<'a, K: Key<'a>>(&mut self, key: K, value: Option<K::Value>) {
|
||||
pub fn set_opt<K: Key>(&mut self, key: K, value: Option<K::Value>) {
|
||||
if let Some(value) = value {
|
||||
self.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the map contains a style property for the given key.
|
||||
pub fn contains<'a, K: Key<'a>>(&self, _: K) -> bool {
|
||||
pub fn contains<K: Key>(&self, _: K) -> bool {
|
||||
self.0
|
||||
.iter()
|
||||
.filter_map(|entry| entry.property())
|
||||
@ -188,13 +188,13 @@ impl Debug for Style {
|
||||
///
|
||||
/// This trait is not intended to be implemented manually, but rather through
|
||||
/// the `#[node]` proc-macro.
|
||||
pub trait Key<'a>: Copy + 'static {
|
||||
pub trait Key: Copy + 'static {
|
||||
/// The unfolded type which this property is stored as in a style map.
|
||||
type Value: Debug + Clone + Hash + Sync + Send + 'static;
|
||||
|
||||
/// The folded type of value that is returned when reading this property
|
||||
/// from a style chain.
|
||||
type Output;
|
||||
type Output<'a>;
|
||||
|
||||
/// The name of the property, used for debug printing.
|
||||
const NAME: &'static str;
|
||||
@ -204,10 +204,10 @@ pub trait Key<'a>: Copy + 'static {
|
||||
|
||||
/// Compute an output value from a sequence of values belonging to this key,
|
||||
/// folding if necessary.
|
||||
fn get(
|
||||
fn get<'a>(
|
||||
chain: StyleChain<'a>,
|
||||
values: impl Iterator<Item = &'a Self::Value>,
|
||||
) -> Self::Output;
|
||||
) -> Self::Output<'a>;
|
||||
}
|
||||
|
||||
/// A style property originating from a set rule or constructor.
|
||||
@ -229,7 +229,7 @@ pub struct Property {
|
||||
|
||||
impl Property {
|
||||
/// Create a new property from a key-value pair.
|
||||
pub fn new<'a, K: Key<'a>>(_: K, value: K::Value) -> Self {
|
||||
pub fn new<K: Key>(_: K, value: K::Value) -> Self {
|
||||
Self {
|
||||
key: KeyId::of::<K>(),
|
||||
node: K::node(),
|
||||
@ -241,7 +241,7 @@ impl Property {
|
||||
}
|
||||
|
||||
/// Whether this property has the given key.
|
||||
pub fn is<'a, K: Key<'a>>(&self) -> bool {
|
||||
pub fn is<K: Key>(&self) -> bool {
|
||||
self.key == KeyId::of::<K>()
|
||||
}
|
||||
|
||||
@ -251,7 +251,7 @@ impl Property {
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
pub fn downcast<K: Key>(&self) -> Option<&K::Value> {
|
||||
if self.key == KeyId::of::<K>() {
|
||||
(**self.value).as_any().downcast_ref()
|
||||
} else {
|
||||
@ -314,7 +314,7 @@ struct KeyId(ReadableTypeId);
|
||||
|
||||
impl KeyId {
|
||||
/// The id of the given key.
|
||||
pub fn of<'a, T: Key<'a>>() -> Self {
|
||||
pub fn of<T: Key>() -> Self {
|
||||
Self(ReadableTypeId::of::<T>())
|
||||
}
|
||||
}
|
||||
@ -327,7 +327,7 @@ impl Debug for KeyId {
|
||||
|
||||
/// A built-in show rule for a node.
|
||||
#[capability]
|
||||
pub trait Show: 'static + Sync + Send {
|
||||
pub trait Show {
|
||||
/// Execute the base recipe for this node.
|
||||
fn show(
|
||||
&self,
|
||||
@ -338,7 +338,7 @@ pub trait Show: 'static + Sync + Send {
|
||||
|
||||
/// Post-process a node after it was realized.
|
||||
#[capability]
|
||||
pub trait Finalize: 'static + Sync + Send {
|
||||
pub trait Finalize {
|
||||
/// Finalize the fully realized form of the node. Use this for effects that
|
||||
/// should work even in the face of a user-defined show rule, for example
|
||||
/// the linking behaviour of a link node.
|
||||
@ -352,7 +352,7 @@ pub trait Finalize: 'static + Sync + Send {
|
||||
|
||||
/// Indicates that a node cannot be labelled.
|
||||
#[capability]
|
||||
pub trait Unlabellable: 'static + Sync + Send {}
|
||||
pub trait Unlabellable {}
|
||||
|
||||
/// A show rule recipe.
|
||||
#[derive(Clone, PartialEq, Hash)]
|
||||
@ -386,7 +386,7 @@ impl Recipe {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
self.transform.apply(world, self.span, target.clone().guard(sel))?
|
||||
self.transform.apply(world, self.span, target.clone().guarded(sel))?
|
||||
}
|
||||
|
||||
Some(Selector::Regex(regex)) => {
|
||||
@ -412,7 +412,7 @@ impl Recipe {
|
||||
let transformed = self.transform.apply(
|
||||
world,
|
||||
self.span,
|
||||
make(m.as_str().into()).guard(sel),
|
||||
make(m.as_str().into()).guarded(sel),
|
||||
)?;
|
||||
|
||||
result.push(transformed);
|
||||
@ -559,7 +559,7 @@ impl<'a> StyleChain<'a> {
|
||||
/// Returns the property's default value if no map in the chain contains an
|
||||
/// entry for it. Also takes care of resolving and folding and returns
|
||||
/// references where applicable.
|
||||
pub fn get<K: Key<'a>>(self, key: K) -> K::Output {
|
||||
pub fn get<K: Key>(self, key: K) -> K::Output<'a> {
|
||||
K::get(self, self.values(key))
|
||||
}
|
||||
|
||||
@ -576,7 +576,7 @@ impl<'a> StyleChain<'a> {
|
||||
let mut realized = None;
|
||||
for recipe in self.entries().filter_map(Style::recipe) {
|
||||
let sel = RecipeId::Nth(n);
|
||||
if recipe.applicable(target) && !target.guarded(sel) {
|
||||
if recipe.applicable(target) && !target.is_guarded(sel) {
|
||||
if let Some(content) = recipe.apply(world, sel, target)? {
|
||||
realized = Some(content);
|
||||
break;
|
||||
@ -587,15 +587,15 @@ impl<'a> StyleChain<'a> {
|
||||
|
||||
// Realize if there was no matching recipe.
|
||||
let base = RecipeId::Base(target.id());
|
||||
if realized.is_none() && !target.guarded(base) {
|
||||
if let Some(showable) = target.to::<dyn Show>() {
|
||||
if realized.is_none() && !target.is_guarded(base) {
|
||||
if let Some(showable) = target.with::<dyn Show>() {
|
||||
realized = Some(showable.show(world, self)?);
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize only if this is the first application for this node.
|
||||
if let Some(node) = target.to::<dyn Finalize>() {
|
||||
if target.pristine() {
|
||||
if let Some(node) = target.with::<dyn Finalize>() {
|
||||
if target.is_pristine() {
|
||||
if let Some(content) = realized {
|
||||
realized = Some(node.finalize(world, self, content)?);
|
||||
}
|
||||
@ -612,7 +612,7 @@ impl<'a> StyleChain<'a> {
|
||||
|
||||
// Find out whether any recipe matches and is unguarded.
|
||||
for recipe in self.entries().filter_map(Style::recipe) {
|
||||
if recipe.applicable(target) && !target.guarded(RecipeId::Nth(n)) {
|
||||
if recipe.applicable(target) && !target.is_guarded(RecipeId::Nth(n)) {
|
||||
return true;
|
||||
}
|
||||
n -= 1;
|
||||
@ -638,7 +638,7 @@ impl<'a> StyleChain<'a> {
|
||||
}
|
||||
|
||||
/// Iterate over all values for the given property in the chain.
|
||||
fn values<K: Key<'a>>(self, _: K) -> Values<'a, K> {
|
||||
fn values<K: Key>(self, _: K) -> Values<'a, K> {
|
||||
Values {
|
||||
entries: self.entries(),
|
||||
key: PhantomData,
|
||||
@ -682,7 +682,7 @@ struct Values<'a, K> {
|
||||
barriers: usize,
|
||||
}
|
||||
|
||||
impl<'a, K: Key<'a>> Iterator for Values<'a, K> {
|
||||
impl<'a, K: Key> Iterator for Values<'a, K> {
|
||||
type Item = &'a K::Value;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user