typst_library/foundations/
styles.rs

1use std::any::{Any, TypeId};
2use std::fmt::{self, Debug, Formatter};
3use std::hash::{Hash, Hasher};
4use std::{mem, ptr};
5
6use comemo::Tracked;
7use ecow::{EcoString, EcoVec, eco_vec};
8use rustc_hash::FxHashMap;
9use smallvec::SmallVec;
10use typst_syntax::Span;
11use typst_utils::LazyHash;
12
13use crate::diag::{SourceResult, Trace, Tracepoint};
14use crate::engine::Engine;
15use crate::foundations::{
16    Content, Context, Element, Field, Func, NativeElement, OneOrMultiple, Packed,
17    RefableProperty, Repr, Selector, SettableProperty, Target, cast, ty,
18};
19use crate::introspection::TagElem;
20
21/// A list of style properties.
22#[ty(cast)]
23#[derive(Default, Clone, PartialEq, Hash)]
24pub struct Styles(EcoVec<LazyHash<Style>>);
25
26impl Styles {
27    /// Create a new, empty style list.
28    pub const fn new() -> Self {
29        Self(EcoVec::new())
30    }
31
32    /// Whether this contains no styles.
33    pub fn is_empty(&self) -> bool {
34        self.0.is_empty()
35    }
36
37    /// Iterate over the contained styles.
38    pub fn iter(&self) -> impl Iterator<Item = &Style> {
39        self.0.iter().map(|style| &**style)
40    }
41
42    /// Iterate over the contained styles.
43    pub fn as_slice(&self) -> &[LazyHash<Style>] {
44        self.0.as_slice()
45    }
46
47    /// Set an inner value for a style property.
48    ///
49    /// If the property needs folding and the value is already contained in the
50    /// style map, `self` contributes the outer values and `value` is the inner
51    /// one.
52    pub fn set<E, const I: u8>(&mut self, field: Field<E, I>, value: E::Type)
53    where
54        E: SettableProperty<I>,
55        E::Type: Debug + Clone + Hash + Send + Sync + 'static,
56    {
57        self.push(Property::new(field, value));
58    }
59
60    /// Add a new style to the list.
61    pub fn push(&mut self, style: impl Into<Style>) {
62        self.0.push(LazyHash::new(style.into()));
63    }
64
65    /// Remove the style that was last set.
66    pub fn unset(&mut self) {
67        self.0.pop();
68    }
69
70    /// Apply outer styles. Like [`chain`](StyleChain::chain), but in-place.
71    pub fn apply(&mut self, mut outer: Self) {
72        outer.0.extend(mem::take(self).0);
73        *self = outer;
74    }
75
76    /// Apply one outer styles.
77    pub fn apply_one(&mut self, outer: Style) {
78        self.0.insert(0, LazyHash::new(outer));
79    }
80
81    /// Add an origin span to all contained properties.
82    pub fn spanned(mut self, span: Span) -> Self {
83        for entry in self.0.make_mut() {
84            if let Style::Property(property) = &mut **entry {
85                property.span = span;
86            }
87        }
88        self
89    }
90
91    /// Marks the styles as having been applied outside of any show rule.
92    pub fn outside(mut self) -> Self {
93        for entry in self.0.make_mut() {
94            match &mut **entry {
95                Style::Property(property) => property.outside = true,
96                Style::Recipe(recipe) => recipe.outside = true,
97                _ => {}
98            }
99        }
100        self
101    }
102
103    /// Marks the styles as being allowed to be lifted up to the page level.
104    pub fn liftable(mut self) -> Self {
105        for entry in self.0.make_mut() {
106            if let Style::Property(property) = &mut **entry {
107                property.liftable = true;
108            }
109        }
110        self
111    }
112
113    /// Whether there is a style for the given field of the given element.
114    pub fn has<E: NativeElement, const I: u8>(&self, _: Field<E, I>) -> bool {
115        let elem = E::ELEM;
116        self.0
117            .iter()
118            .filter_map(|style| style.property())
119            .any(|property| property.is_of(elem) && property.id == I)
120    }
121
122    /// Determines the styles used for content that it at the root, outside of
123    /// the user-controlled content (e.g. page marginals and footnotes). This
124    /// applies to both paged and HTML export.
125    ///
126    /// As a base, we collect the styles that are shared by all elements in the
127    /// children (this can be a whole document in HTML or a page run in paged
128    /// export). As a fallback if there are no elements, we use the styles
129    /// active at the very start or, for page runs, at the pagebreak that
130    /// introduced the page. Then, to produce our trunk styles, we filter this
131    /// list of styles according to a few rules:
132    ///
133    /// - Other styles are only kept if they are `outside && (initial ||
134    ///   liftable)`.
135    /// - "Outside" means they were not produced within a show rule or, for page
136    ///   runs, that the show rule "broke free" to the root level by emitting
137    ///   page styles.
138    /// - "Initial" means they were active where the children start (efor pages,
139    ///   at the pagebreak that introduced the page). Since these are
140    ///   intuitively already active, they should be kept even if not liftable.
141    ///   (E.g. `text(red, page(..)`) makes the footer red.)
142    /// - "Liftable" means they can be lifted to the root  level even though
143    ///   they weren't yet active at the very beginning. Set rule styles are
144    ///   liftable as opposed to direct constructor calls:
145    ///   - For `set page(..); set text(red)` the red text is kept even though
146    ///     it comes after the weak pagebreak from set page.
147    ///   - For `set page(..); text(red)[..]` the red isn't kept because the
148    ///     constructor styles are not liftable.
149    pub fn root(children: &[(&Content, StyleChain)], initial: StyleChain) -> Styles {
150        // Determine the shared styles (excluding tags).
151        let base = StyleChain::trunk_from_pairs(children).unwrap_or(initial).to_map();
152
153        // Determine the initial styles that are also shared by everything. We can't
154        // use `StyleChain::trunk` because it currently doesn't deal with partially
155        // shared links (where a subslice matches).
156        let trunk_len = initial
157            .to_map()
158            .as_slice()
159            .iter()
160            .zip(base.as_slice())
161            .take_while(|&(a, b)| a == b)
162            .count();
163
164        // Filter the base styles according to our rules.
165        base.into_iter()
166            .enumerate()
167            .filter(|(i, style)| {
168                let initial = *i < trunk_len;
169                style.outside() && (initial || style.liftable())
170            })
171            .map(|(_, style)| style)
172            .collect()
173    }
174}
175
176impl From<LazyHash<Style>> for Styles {
177    fn from(style: LazyHash<Style>) -> Self {
178        Self(eco_vec![style])
179    }
180}
181
182impl From<Style> for Styles {
183    fn from(style: Style) -> Self {
184        Self(eco_vec![LazyHash::new(style)])
185    }
186}
187
188impl IntoIterator for Styles {
189    type Item = LazyHash<Style>;
190    type IntoIter = ecow::vec::IntoIter<Self::Item>;
191
192    fn into_iter(self) -> Self::IntoIter {
193        self.0.into_iter()
194    }
195}
196
197impl FromIterator<LazyHash<Style>> for Styles {
198    fn from_iter<T: IntoIterator<Item = LazyHash<Style>>>(iter: T) -> Self {
199        Self(iter.into_iter().collect())
200    }
201}
202
203impl Debug for Styles {
204    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
205        f.write_str("Styles ")?;
206        f.debug_list().entries(&self.0).finish()
207    }
208}
209
210impl Repr for Styles {
211    fn repr(&self) -> EcoString {
212        "..".into()
213    }
214}
215
216/// A single style property or recipe.
217#[derive(Clone, Hash)]
218pub enum Style {
219    /// A style property originating from a set rule or constructor.
220    Property(Property),
221    /// A show rule recipe.
222    Recipe(Recipe),
223    /// Disables a specific show rule recipe.
224    ///
225    /// Note: This currently only works for regex recipes since it's the only
226    /// place we need it for the moment. Normal show rules use guards directly
227    /// on elements instead.
228    Revocation(RecipeIndex),
229}
230
231impl Style {
232    /// If this is a property, return it.
233    pub fn property(&self) -> Option<&Property> {
234        match self {
235            Self::Property(property) => Some(property),
236            _ => None,
237        }
238    }
239
240    /// If this is a recipe, return it.
241    pub fn recipe(&self) -> Option<&Recipe> {
242        match self {
243            Self::Recipe(recipe) => Some(recipe),
244            _ => None,
245        }
246    }
247
248    /// The style's span, if any.
249    pub fn span(&self) -> Span {
250        match self {
251            Self::Property(property) => property.span,
252            Self::Recipe(recipe) => recipe.span,
253            Self::Revocation(_) => Span::detached(),
254        }
255    }
256
257    /// Returns `Some(_)` with an optional span if this style is for
258    /// the given element.
259    pub fn element(&self) -> Option<Element> {
260        match self {
261            Style::Property(property) => Some(property.elem),
262            Style::Recipe(recipe) => match recipe.selector {
263                Some(Selector::Elem(elem, _)) => Some(elem),
264                _ => None,
265            },
266            Style::Revocation(_) => None,
267        }
268    }
269
270    /// Whether the style is allowed to be lifted up to the page level. Only
271    /// true for styles originating from set rules.
272    pub fn liftable(&self) -> bool {
273        match self {
274            Self::Property(property) => property.liftable,
275            Self::Recipe(_) => true,
276            Self::Revocation(_) => false,
277        }
278    }
279
280    /// Whether the style was applied outside of any show rule. This is set
281    /// during realization.
282    pub fn outside(&self) -> bool {
283        match self {
284            Self::Property(property) => property.outside,
285            Self::Recipe(recipe) => recipe.outside,
286            Self::Revocation(_) => false,
287        }
288    }
289
290    /// Turn this style into prehashed style.
291    pub fn wrap(self) -> LazyHash<Style> {
292        LazyHash::new(self)
293    }
294}
295
296impl Debug for Style {
297    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
298        match self {
299            Self::Property(property) => property.fmt(f),
300            Self::Recipe(recipe) => recipe.fmt(f),
301            Self::Revocation(guard) => guard.fmt(f),
302        }
303    }
304}
305
306impl From<Property> for Style {
307    fn from(property: Property) -> Self {
308        Self::Property(property)
309    }
310}
311
312impl From<Recipe> for Style {
313    fn from(recipe: Recipe) -> Self {
314        Self::Recipe(recipe)
315    }
316}
317
318/// A style property originating from a set rule or constructor.
319#[derive(Clone, Hash)]
320pub struct Property {
321    /// The element the property belongs to.
322    elem: Element,
323    /// The property's ID.
324    id: u8,
325    /// The property's value.
326    value: Block,
327    /// The span of the set rule the property stems from.
328    span: Span,
329    /// Whether the property is allowed to be lifted up to the page level.
330    liftable: bool,
331    /// Whether the property was applied outside of any show rule.
332    outside: bool,
333}
334
335impl Property {
336    /// Create a new property from a key-value pair.
337    pub fn new<E, const I: u8>(_: Field<E, I>, value: E::Type) -> Self
338    where
339        E: SettableProperty<I>,
340        E::Type: Debug + Clone + Hash + Send + Sync + 'static,
341    {
342        Self {
343            elem: E::ELEM,
344            id: I,
345            value: Block::new(value),
346            span: Span::detached(),
347            liftable: false,
348            outside: false,
349        }
350    }
351
352    /// Whether this property is the given one.
353    pub fn is(&self, elem: Element, id: u8) -> bool {
354        self.elem == elem && self.id == id
355    }
356
357    /// Whether this property belongs to the given element.
358    pub fn is_of(&self, elem: Element) -> bool {
359        self.elem == elem
360    }
361
362    /// Turn this property into prehashed style.
363    pub fn wrap(self) -> LazyHash<Style> {
364        Style::Property(self).wrap()
365    }
366}
367
368impl Debug for Property {
369    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
370        write!(
371            f,
372            "Set({}.{}: ",
373            self.elem.name(),
374            self.elem.field_name(self.id).unwrap_or("internal")
375        )?;
376        self.value.fmt(f)?;
377        write!(f, ")")
378    }
379}
380
381/// A block storage for storing style values.
382///
383/// We're using a `Box` since values will either be contained in an `Arc` and
384/// therefore already on the heap or they will be small enough that we can just
385/// clone them.
386#[derive(Hash)]
387struct Block(Box<dyn Blockable>);
388
389impl Block {
390    /// Creates a new block.
391    fn new<T: Blockable>(value: T) -> Self {
392        Self(Box::new(value))
393    }
394
395    /// Downcasts the block to the specified type.
396    fn downcast<T: 'static>(&self, func: Element, id: u8) -> &T {
397        self.0
398            .as_any()
399            .downcast_ref()
400            .unwrap_or_else(|| block_wrong_type(func, id, self))
401    }
402}
403
404impl Debug for Block {
405    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
406        self.0.fmt(f)
407    }
408}
409
410impl Clone for Block {
411    fn clone(&self) -> Self {
412        self.0.dyn_clone()
413    }
414}
415
416/// A value that can be stored in a block.
417///
418/// Auto derived for all types that implement [`Any`], [`Clone`], [`Hash`],
419/// [`Debug`], [`Send`] and [`Sync`].
420trait Blockable: Debug + Send + Sync + 'static {
421    /// Equivalent to `downcast_ref` for the block.
422    fn as_any(&self) -> &dyn Any;
423
424    /// Equivalent to [`Hash`] for the block.
425    fn dyn_hash(&self, state: &mut dyn Hasher);
426
427    /// Equivalent to [`Clone`] for the block.
428    fn dyn_clone(&self) -> Block;
429}
430
431impl<T: Debug + Clone + Hash + Send + Sync + 'static> Blockable for T {
432    fn as_any(&self) -> &dyn Any {
433        self
434    }
435
436    fn dyn_hash(&self, mut state: &mut dyn Hasher) {
437        // Also hash the TypeId since values with different types but
438        // equal data should be different.
439        TypeId::of::<Self>().hash(&mut state);
440        self.hash(&mut state);
441    }
442
443    fn dyn_clone(&self) -> Block {
444        Block(Box::new(self.clone()))
445    }
446}
447
448impl Hash for dyn Blockable {
449    fn hash<H: Hasher>(&self, state: &mut H) {
450        self.dyn_hash(state);
451    }
452}
453
454/// A show rule recipe.
455#[derive(Clone, PartialEq, Hash)]
456pub struct Recipe {
457    /// Determines whether the recipe applies to an element.
458    ///
459    /// If this is `None`, then this recipe is from a show rule with
460    /// no selector (`show: rest => ...`), which is [eagerly applied][Content::styled_with_recipe]
461    /// to the rest of the content in the scope.
462    selector: Option<Selector>,
463    /// The transformation to perform on the match.
464    transform: Transformation,
465    /// The span that errors are reported with.
466    span: Span,
467    /// Relevant properties of the kind of construct the style originated from
468    /// and where it was applied.
469    outside: bool,
470}
471
472impl Recipe {
473    /// Create a new recipe from a key-value pair.
474    pub fn new(
475        selector: Option<Selector>,
476        transform: Transformation,
477        span: Span,
478    ) -> Self {
479        Self { selector, transform, span, outside: false }
480    }
481
482    /// The recipe's selector.
483    pub fn selector(&self) -> Option<&Selector> {
484        self.selector.as_ref()
485    }
486
487    /// The recipe's transformation.
488    pub fn transform(&self) -> &Transformation {
489        &self.transform
490    }
491
492    /// The recipe's span.
493    pub fn span(&self) -> Span {
494        self.span
495    }
496
497    /// Apply the recipe to the given content.
498    pub fn apply(
499        &self,
500        engine: &mut Engine,
501        context: Tracked<Context>,
502        content: Content,
503    ) -> SourceResult<Content> {
504        let mut content = match &self.transform {
505            Transformation::Content(content) => content.clone(),
506            Transformation::Func(func) => {
507                let mut result = func.call(engine, context, [content.clone()]);
508                if self.selector.is_some() {
509                    let point = || Tracepoint::Show(content.func().name().into());
510                    result = result.trace(engine.world, point, content.span());
511                }
512                result?.display()
513            }
514            Transformation::Style(styles) => content.styled_with_map(styles.clone()),
515        };
516        if content.span().is_detached() {
517            content = content.spanned(self.span);
518        }
519        Ok(content)
520    }
521}
522
523impl Debug for Recipe {
524    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
525        f.write_str("Show(")?;
526        if let Some(selector) = &self.selector {
527            selector.fmt(f)?;
528            f.write_str(", ")?;
529        }
530        self.transform.fmt(f)?;
531        f.write_str(")")
532    }
533}
534
535/// Identifies a show rule recipe from the top of the chain.
536#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
537pub struct RecipeIndex(pub usize);
538
539/// A show rule transformation that can be applied to a match.
540#[derive(Clone, PartialEq, Hash)]
541pub enum Transformation {
542    /// Replacement content.
543    Content(Content),
544    /// A function to apply to the match.
545    Func(Func),
546    /// Apply styles to the content.
547    Style(Styles),
548}
549
550impl Debug for Transformation {
551    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
552        match self {
553            Self::Content(content) => content.fmt(f),
554            Self::Func(func) => func.fmt(f),
555            Self::Style(styles) => styles.fmt(f),
556        }
557    }
558}
559
560cast! {
561    Transformation,
562    content: Content => Self::Content(content),
563    func: Func => Self::Func(func),
564}
565
566/// A chain of styles, similar to a linked list.
567///
568/// A style chain allows to combine properties from multiple style lists in a
569/// element hierarchy in a non-allocating way. Rather than eagerly merging the
570/// lists, each access walks the hierarchy from the innermost to the outermost
571/// map, trying to find a match and then folding it with matches further up the
572/// chain.
573#[derive(Default, Copy, Clone, Hash)]
574pub struct StyleChain<'a> {
575    /// The first link of this chain.
576    head: &'a [LazyHash<Style>],
577    /// The remaining links in the chain.
578    tail: Option<&'a Self>,
579}
580
581impl<'a> StyleChain<'a> {
582    /// Start a new style chain with root styles.
583    pub fn new(root: &'a Styles) -> Self {
584        Self { head: &root.0, tail: None }
585    }
586
587    /// Retrieves the value of the given field from the style chain.
588    ///
589    /// A `Field` value is a zero-sized value that specifies which field of an
590    /// element you want to retrieve on the type-system level. It also ensures
591    /// that Rust can infer the correct return type.
592    ///
593    /// Should be preferred over [`get_cloned`](Self::get_cloned) or
594    /// [`get_ref`](Self::get_ref), but is only available for [`Copy`] types.
595    /// For other types an explicit decision needs to be made whether cloning is
596    /// necessary.
597    pub fn get<E, const I: u8>(self, field: Field<E, I>) -> E::Type
598    where
599        E: SettableProperty<I>,
600        E::Type: Copy,
601    {
602        self.get_cloned(field)
603    }
604
605    /// Retrieves and clones the value from the style chain.
606    ///
607    /// Prefer [`get`](Self::get) if the type is `Copy` and
608    /// [`get_ref`](Self::get_ref) if a reference suffices.
609    pub fn get_cloned<E, const I: u8>(self, _: Field<E, I>) -> E::Type
610    where
611        E: SettableProperty<I>,
612    {
613        if let Some(fold) = E::FOLD {
614            self.get_folded::<E::Type>(E::ELEM, I, fold, E::default())
615        } else {
616            self.get_unfolded::<E::Type>(E::ELEM, I)
617                .cloned()
618                .unwrap_or_else(E::default)
619        }
620    }
621
622    /// Retrieves a reference to the value of the given field from the style
623    /// chain.
624    ///
625    /// Not possible if the value needs folding.
626    pub fn get_ref<E, const I: u8>(self, _: Field<E, I>) -> &'a E::Type
627    where
628        E: RefableProperty<I>,
629    {
630        self.get_unfolded(E::ELEM, I).unwrap_or_else(|| E::default_ref())
631    }
632
633    /// Retrieves the value and then immediately [resolves](Resolve) it.
634    pub fn resolve<E, const I: u8>(
635        self,
636        field: Field<E, I>,
637    ) -> <E::Type as Resolve>::Output
638    where
639        E: SettableProperty<I>,
640        E::Type: Resolve,
641    {
642        self.get_cloned(field).resolve(self)
643    }
644
645    /// Retrieves a reference to a field, also taking into account the
646    /// instance's value if any.
647    fn get_unfolded<T: 'static>(self, func: Element, id: u8) -> Option<&'a T> {
648        self.find(func, id).map(|block| block.downcast(func, id))
649    }
650
651    /// Retrieves a reference to a field, also taking into account the
652    /// instance's value if any.
653    fn get_folded<T: 'static + Clone>(
654        self,
655        func: Element,
656        id: u8,
657        fold: fn(T, T) -> T,
658        default: T,
659    ) -> T {
660        let iter = self
661            .properties(func, id)
662            .map(|block| block.downcast::<T>(func, id).clone());
663
664        if let Some(folded) = iter.reduce(fold) { fold(folded, default) } else { default }
665    }
666
667    /// Iterate over all values for the given property in the chain.
668    fn find(self, func: Element, id: u8) -> Option<&'a Block> {
669        self.properties(func, id).next()
670    }
671
672    /// Iterate over all values for the given property in the chain.
673    fn properties(self, func: Element, id: u8) -> impl Iterator<Item = &'a Block> {
674        self.entries()
675            .filter_map(|style| style.property())
676            .filter(move |property| property.is(func, id))
677            .map(|property| &property.value)
678    }
679
680    /// Make the given chainable the first link of this chain.
681    ///
682    /// The resulting style chain contains styles from `local` as well as
683    /// `self`. The ones from `local` take precedence over the ones from
684    /// `self`. For folded properties `local` contributes the inner value.
685    pub fn chain<'b, C>(&'b self, local: &'b C) -> StyleChain<'b>
686    where
687        C: Chainable + ?Sized,
688    {
689        Chainable::chain(local, self)
690    }
691
692    /// Iterate over the entries of the chain.
693    pub fn entries(self) -> Entries<'a> {
694        Entries { inner: [].as_slice().iter(), links: self.links() }
695    }
696
697    /// Iterate over the recipes in the chain.
698    pub fn recipes(self) -> impl Iterator<Item = &'a Recipe> {
699        self.entries().filter_map(|style| style.recipe())
700    }
701
702    /// Iterate over the links of the chain.
703    pub fn links(self) -> Links<'a> {
704        Links(Some(self))
705    }
706
707    /// Convert to a style map.
708    pub fn to_map(self) -> Styles {
709        let mut styles: EcoVec<_> = self.entries().cloned().collect();
710        styles.make_mut().reverse();
711        Styles(styles)
712    }
713
714    /// Build owned styles from the suffix (all links beyond the `len`) of the
715    /// chain.
716    pub fn suffix(self, len: usize) -> Styles {
717        let mut styles = EcoVec::new();
718        let take = self.links().count().saturating_sub(len);
719        for link in self.links().take(take) {
720            styles.extend(link.iter().cloned().rev());
721        }
722        styles.make_mut().reverse();
723        Styles(styles)
724    }
725
726    /// Remove the last link from the chain.
727    pub fn pop(&mut self) {
728        *self = self.tail.copied().unwrap_or_default();
729    }
730
731    /// Determine the shared trunk of a collection of style chains.
732    pub fn trunk(iter: impl IntoIterator<Item = Self>) -> Option<Self> {
733        // Determine shared style depth and first span.
734        let mut iter = iter.into_iter();
735        let mut trunk = iter.next()?;
736        let mut depth = trunk.links().count();
737
738        for mut chain in iter {
739            let len = chain.links().count();
740            if len < depth {
741                for _ in 0..depth - len {
742                    trunk.pop();
743                }
744                depth = len;
745            } else if len > depth {
746                for _ in 0..len - depth {
747                    chain.pop();
748                }
749            }
750
751            while depth > 0 && chain != trunk {
752                trunk.pop();
753                chain.pop();
754                depth -= 1;
755            }
756        }
757
758        Some(trunk)
759    }
760
761    /// Determines the shared trunk of a list of elements.
762    ///
763    /// This will ignore styles for tags (conceptually, they just don't exist).
764    pub fn trunk_from_pairs(iter: &[(&Content, Self)]) -> Option<Self> {
765        Self::trunk(iter.iter().filter(|(c, _)| !c.is::<TagElem>()).map(|&(_, s)| s))
766    }
767}
768
769impl Debug for StyleChain<'_> {
770    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
771        f.write_str("StyleChain ")?;
772        f.debug_list()
773            .entries(self.entries().collect::<Vec<_>>().into_iter().rev())
774            .finish()
775    }
776}
777
778impl PartialEq for StyleChain<'_> {
779    fn eq(&self, other: &Self) -> bool {
780        ptr::eq(self.head, other.head)
781            && match (self.tail, other.tail) {
782                (Some(a), Some(b)) => ptr::eq(a, b),
783                (None, None) => true,
784                _ => false,
785            }
786    }
787}
788
789/// Things that can be attached to a style chain.
790pub trait Chainable {
791    /// Attach `self` as the first link of the chain.
792    fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a>;
793}
794
795impl Chainable for LazyHash<Style> {
796    fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
797        StyleChain {
798            head: std::slice::from_ref(self),
799            tail: Some(outer),
800        }
801    }
802}
803
804impl Chainable for [LazyHash<Style>] {
805    fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
806        if self.is_empty() {
807            *outer
808        } else {
809            StyleChain { head: self, tail: Some(outer) }
810        }
811    }
812}
813
814impl<const N: usize> Chainable for [LazyHash<Style>; N] {
815    fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
816        Chainable::chain(self.as_slice(), outer)
817    }
818}
819
820impl Chainable for Styles {
821    fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
822        Chainable::chain(self.0.as_slice(), outer)
823    }
824}
825
826/// An iterator over the entries in a style chain.
827pub struct Entries<'a> {
828    inner: std::slice::Iter<'a, LazyHash<Style>>,
829    links: Links<'a>,
830}
831
832impl<'a> Iterator for Entries<'a> {
833    type Item = &'a LazyHash<Style>;
834
835    fn next(&mut self) -> Option<Self::Item> {
836        loop {
837            if let Some(entry) = self.inner.next_back() {
838                return Some(entry);
839            }
840
841            match self.links.next() {
842                Some(next) => self.inner = next.iter(),
843                None => return None,
844            }
845        }
846    }
847}
848
849/// An iterator over the links of a style chain.
850pub struct Links<'a>(Option<StyleChain<'a>>);
851
852impl<'a> Iterator for Links<'a> {
853    type Item = &'a [LazyHash<Style>];
854
855    fn next(&mut self) -> Option<Self::Item> {
856        let StyleChain { head, tail } = self.0?;
857        self.0 = tail.copied();
858        Some(head)
859    }
860}
861
862/// A property that is resolved with other properties from the style chain.
863pub trait Resolve {
864    /// The type of the resolved output.
865    type Output;
866
867    /// Resolve the value using the style chain.
868    fn resolve(self, styles: StyleChain) -> Self::Output;
869}
870
871impl<T: Resolve> Resolve for Option<T> {
872    type Output = Option<T::Output>;
873
874    fn resolve(self, styles: StyleChain) -> Self::Output {
875        self.map(|v| v.resolve(styles))
876    }
877}
878
879/// A property that is folded to determine its final value.
880///
881/// In the example below, the chain of stroke values is folded into a single
882/// value: `4pt + red`.
883///
884/// ```example
885/// #set rect(stroke: red)
886/// #set rect(stroke: 4pt)
887/// #rect()
888/// ```
889///
890/// Note: Folding must be associative, i.e. any implementation must satisfy
891/// `fold(fold(a, b), c) == fold(a, fold(b, c))`.
892pub trait Fold {
893    /// Fold this inner value with an outer folded value.
894    fn fold(self, outer: Self) -> Self;
895}
896
897impl Fold for bool {
898    fn fold(self, _: Self) -> Self {
899        self
900    }
901}
902
903impl<T: Fold> Fold for Option<T> {
904    fn fold(self, outer: Self) -> Self {
905        match (self, outer) {
906            (Some(inner), Some(outer)) => Some(inner.fold(outer)),
907            // An explicit `None` should be respected, thus we don't do
908            // `inner.or(outer)`.
909            (inner, _) => inner,
910        }
911    }
912}
913
914impl<T> Fold for Vec<T> {
915    fn fold(self, mut outer: Self) -> Self {
916        outer.extend(self);
917        outer
918    }
919}
920
921impl<T, const N: usize> Fold for SmallVec<[T; N]> {
922    fn fold(self, mut outer: Self) -> Self {
923        outer.extend(self);
924        outer
925    }
926}
927
928impl<T> Fold for OneOrMultiple<T> {
929    fn fold(self, mut outer: Self) -> Self {
930        outer.0.extend(self.0);
931        outer
932    }
933}
934
935/// A [folding](Fold) function.
936pub type FoldFn<T> = fn(T, T) -> T;
937
938/// A variant of fold for foldable optional (`Option<T>`) values where an inner
939/// `None` value isn't respected (contrary to `Option`'s usual `Fold`
940/// implementation, with which folding with an inner `None` always returns
941/// `None`). Instead, when either of the `Option` objects is `None`, the other
942/// one is necessarily returned by `fold_or`. Normal folding still occurs when
943/// both values are `Some`, using `T`'s `Fold` implementation.
944///
945/// This is useful when `None` in a particular context means "unspecified"
946/// rather than "absent", in which case a specified value (`Some`) is chosen
947/// over an unspecified one (`None`), while two specified values are folded
948/// together.
949pub trait AlternativeFold {
950    /// Attempts to fold this inner value with an outer value. However, if
951    /// either value is `None`, returns the other one instead of folding.
952    fn fold_or(self, outer: Self) -> Self;
953}
954
955impl<T: Fold> AlternativeFold for Option<T> {
956    fn fold_or(self, outer: Self) -> Self {
957        match (self, outer) {
958            (Some(inner), Some(outer)) => Some(inner.fold(outer)),
959            // If one of values is `None`, return the other one instead of
960            // folding.
961            (inner, outer) => inner.or(outer),
962        }
963    }
964}
965
966/// A type that accumulates depth when folded.
967#[derive(Debug, Default, Copy, Clone, PartialEq, Hash)]
968pub struct Depth(pub usize);
969
970impl Fold for Depth {
971    fn fold(self, outer: Self) -> Self {
972        Self(outer.0 + self.0)
973    }
974}
975
976#[cold]
977fn block_wrong_type(func: Element, id: u8, value: &Block) -> ! {
978    panic!(
979        "attempted to read a value of a different type than was written {}.{}: {:?}",
980        func.name(),
981        func.field_name(id).unwrap(),
982        value
983    )
984}
985
986/// Holds native show rules.
987pub struct NativeRuleMap {
988    rules: FxHashMap<(Element, Target), NativeShowRule>,
989}
990
991/// The signature of a native show rule.
992pub type ShowFn<T> = fn(
993    elem: &Packed<T>,
994    engine: &mut Engine,
995    styles: StyleChain,
996) -> SourceResult<Content>;
997
998impl NativeRuleMap {
999    /// Creates a new rule map.
1000    ///
1001    /// Should be populated with rules for all target-element combinations that
1002    /// are supported.
1003    ///
1004    /// Contains built-in rules for a few special elements.
1005    pub fn new() -> Self {
1006        let mut rules = Self { rules: FxHashMap::default() };
1007
1008        // ContextElem is as special as SequenceElem and StyledElem and could,
1009        // in theory, also be special cased in realization.
1010        rules.register_builtin(crate::foundations::CONTEXT_RULE);
1011
1012        // CounterDisplayElem only exists because the compiler can't currently
1013        // express the equivalent of `context counter(..).display(..)` in native
1014        // code (no native closures).
1015        rules.register_builtin(crate::introspection::COUNTER_DISPLAY_RULE);
1016
1017        // These are all only for introspection and empty on all targets.
1018        rules.register_empty::<crate::introspection::CounterUpdateElem>();
1019        rules.register_empty::<crate::introspection::StateUpdateElem>();
1020        rules.register_empty::<crate::introspection::MetadataElem>();
1021        rules.register_empty::<crate::model::PrefixInfo>();
1022
1023        rules
1024    }
1025
1026    /// Registers a rule for all targets.
1027    fn register_empty<T: NativeElement>(&mut self) {
1028        self.register_builtin::<T>(|_, _, _| Ok(Content::empty()));
1029    }
1030
1031    /// Registers a rule for all targets.
1032    fn register_builtin<T: NativeElement>(&mut self, f: ShowFn<T>) {
1033        self.register(Target::Paged, f);
1034        self.register(Target::Html, f);
1035    }
1036
1037    /// Registers a rule for a target.
1038    ///
1039    /// Panics if a rule already exists for this target-element combination.
1040    pub fn register<T: NativeElement>(&mut self, target: Target, f: ShowFn<T>) {
1041        let res = self.rules.insert((T::ELEM, target), NativeShowRule::new(f));
1042        if res.is_some() {
1043            panic!(
1044                "duplicate native show rule for `{}` on {target:?} target",
1045                T::ELEM.name()
1046            )
1047        }
1048    }
1049
1050    /// Retrieves the rule that applies to the `content` on the current
1051    /// `target`.
1052    pub fn get(&self, target: Target, content: &Content) -> Option<NativeShowRule> {
1053        self.rules.get(&(content.func(), target)).copied()
1054    }
1055}
1056
1057impl Default for NativeRuleMap {
1058    fn default() -> Self {
1059        Self::new()
1060    }
1061}
1062
1063pub use rule::NativeShowRule;
1064
1065mod rule {
1066    use super::*;
1067
1068    /// The show rule for a native element.
1069    #[derive(Copy, Clone)]
1070    pub struct NativeShowRule {
1071        /// The element to which this rule applies.
1072        elem: Element,
1073        /// Must only be called with content of the appropriate type.
1074        f: unsafe fn(
1075            elem: &Content,
1076            engine: &mut Engine,
1077            styles: StyleChain,
1078        ) -> SourceResult<Content>,
1079    }
1080
1081    impl NativeShowRule {
1082        /// Create a new type-erased show rule.
1083        pub fn new<T: NativeElement>(f: ShowFn<T>) -> Self {
1084            Self {
1085                elem: T::ELEM,
1086                // Safety: The two function pointer types only differ in the
1087                // first argument, which changes from `&Packed<T>` to
1088                // `&Content`. `Packed<T>` is a transparent wrapper around
1089                // `Content`. The resulting function is unsafe to call because
1090                // content of the correct type must be passed to it.
1091                #[allow(clippy::missing_transmute_annotations)]
1092                f: unsafe { std::mem::transmute(f) },
1093            }
1094        }
1095
1096        /// Applies the rule to content. Panics if the content is of the wrong
1097        /// type.
1098        pub fn apply(
1099            &self,
1100            content: &Content,
1101            engine: &mut Engine,
1102            styles: StyleChain,
1103        ) -> SourceResult<Content> {
1104            assert_eq!(content.elem(), self.elem);
1105
1106            // Safety: We just checked that the element is of the correct type.
1107            unsafe { (self.f)(content, engine, styles) }
1108        }
1109    }
1110}