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 indexmap::IndexMap;
9use rustc_hash::FxBuildHasher;
10use smallvec::SmallVec;
11use typst_syntax::Span;
12use typst_utils::LazyHash;
13
14use crate::diag::{SourceResult, Trace, Tracepoint};
15use crate::engine::Engine;
16use crate::foundations::{
17 Content, Context, Element, Field, Func, NativeElement, OneOrMultiple, Packed,
18 RefableProperty, Repr, Selector, SettableProperty, Target, cast, ty,
19};
20use crate::introspection::TagElem;
21
22#[ty(cast)]
24#[derive(Default, Clone, PartialEq, Hash)]
25pub struct Styles(EcoVec<LazyHash<Style>>);
26
27impl Styles {
28 pub const fn new() -> Self {
30 Self(EcoVec::new())
31 }
32
33 pub fn is_empty(&self) -> bool {
35 self.0.is_empty()
36 }
37
38 pub fn iter(&self) -> impl Iterator<Item = &Style> {
40 self.0.iter().map(|style| &**style)
41 }
42
43 pub fn as_slice(&self) -> &[LazyHash<Style>] {
45 self.0.as_slice()
46 }
47
48 pub fn set<E, const I: u8>(&mut self, field: Field<E, I>, value: E::Type)
54 where
55 E: SettableProperty<I>,
56 E::Type: Debug + Clone + Hash + Send + Sync + 'static,
57 {
58 self.push(Property::new(field, value));
59 }
60
61 pub fn push(&mut self, style: impl Into<Style>) {
63 self.0.push(LazyHash::new(style.into()));
64 }
65
66 pub fn unset(&mut self) {
68 self.0.pop();
69 }
70
71 pub fn apply(&mut self, mut outer: Self) {
73 outer.0.extend(mem::take(self).0);
74 *self = outer;
75 }
76
77 pub fn apply_one(&mut self, outer: Style) {
79 self.0.insert(0, LazyHash::new(outer));
80 }
81
82 pub fn spanned(mut self, span: Span) -> Self {
84 for entry in self.0.make_mut() {
85 if let Style::Property(property) = &mut **entry {
86 property.span = span;
87 }
88 }
89 self
90 }
91
92 pub fn outside(mut self) -> Self {
94 for entry in self.0.make_mut() {
95 match &mut **entry {
96 Style::Property(property) => property.outside = true,
97 Style::Recipe(recipe) => recipe.outside = true,
98 _ => {}
99 }
100 }
101 self
102 }
103
104 pub fn liftable(mut self) -> Self {
106 for entry in self.0.make_mut() {
107 if let Style::Property(property) = &mut **entry {
108 property.liftable = true;
109 }
110 }
111 self
112 }
113
114 pub fn root(children: &[(&Content, StyleChain)], initial: StyleChain) -> Styles {
142 let base = StyleChain::trunk_from_pairs(children).unwrap_or(initial).to_map();
144
145 let trunk_len = initial
149 .to_map()
150 .as_slice()
151 .iter()
152 .zip(base.as_slice())
153 .take_while(|&(a, b)| a == b)
154 .count();
155
156 base.into_iter()
158 .enumerate()
159 .filter(|(i, style)| {
160 let initial = *i < trunk_len;
161 style.outside() && (initial || style.liftable())
162 })
163 .map(|(_, style)| style)
164 .collect()
165 }
166}
167
168impl From<LazyHash<Style>> for Styles {
169 fn from(style: LazyHash<Style>) -> Self {
170 Self(eco_vec![style])
171 }
172}
173
174impl<const N: usize> From<[LazyHash<Style>; N]> for Styles {
175 fn from(arr: [LazyHash<Style>; N]) -> Self {
176 Self(arr.into())
177 }
178}
179
180impl From<Style> for Styles {
181 fn from(style: Style) -> Self {
182 Self(eco_vec![LazyHash::new(style)])
183 }
184}
185
186impl IntoIterator for Styles {
187 type Item = LazyHash<Style>;
188 type IntoIter = ecow::vec::IntoIter<Self::Item>;
189
190 fn into_iter(self) -> Self::IntoIter {
191 self.0.into_iter()
192 }
193}
194
195impl FromIterator<LazyHash<Style>> for Styles {
196 fn from_iter<T: IntoIterator<Item = LazyHash<Style>>>(iter: T) -> Self {
197 Self(iter.into_iter().collect())
198 }
199}
200
201impl Debug for Styles {
202 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
203 f.write_str("Styles ")?;
204 f.debug_list().entries(&self.0).finish()
205 }
206}
207
208impl Repr for Styles {
209 fn repr(&self) -> EcoString {
210 "styles(..)".into()
211 }
212}
213
214#[derive(Clone, Hash)]
216pub enum Style {
217 Property(Property),
219 Recipe(Recipe),
221 Revocation(RecipeIndex),
227}
228
229impl Style {
230 pub fn property(&self) -> Option<&Property> {
232 match self {
233 Self::Property(property) => Some(property),
234 _ => None,
235 }
236 }
237
238 pub fn recipe(&self) -> Option<&Recipe> {
240 match self {
241 Self::Recipe(recipe) => Some(recipe),
242 _ => None,
243 }
244 }
245
246 pub fn span(&self) -> Span {
248 match self {
249 Self::Property(property) => property.span,
250 Self::Recipe(recipe) => recipe.span,
251 Self::Revocation(_) => Span::detached(),
252 }
253 }
254
255 pub fn element(&self) -> Option<Element> {
258 match self {
259 Style::Property(property) => Some(property.elem),
260 Style::Recipe(recipe) => match recipe.selector {
261 Some(Selector::Elem(elem, _)) => Some(elem),
262 _ => None,
263 },
264 Style::Revocation(_) => None,
265 }
266 }
267
268 pub fn liftable(&self) -> bool {
271 match self {
272 Self::Property(property) => property.liftable,
273 Self::Recipe(_) => true,
274 Self::Revocation(_) => false,
275 }
276 }
277
278 pub fn outside(&self) -> bool {
281 match self {
282 Self::Property(property) => property.outside,
283 Self::Recipe(recipe) => recipe.outside,
284 Self::Revocation(_) => false,
285 }
286 }
287
288 pub fn wrap(self) -> LazyHash<Style> {
290 LazyHash::new(self)
291 }
292}
293
294impl Debug for Style {
295 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
296 match self {
297 Self::Property(property) => property.fmt(f),
298 Self::Recipe(recipe) => recipe.fmt(f),
299 Self::Revocation(guard) => guard.fmt(f),
300 }
301 }
302}
303
304impl From<Property> for Style {
305 fn from(property: Property) -> Self {
306 Self::Property(property)
307 }
308}
309
310impl From<Recipe> for Style {
311 fn from(recipe: Recipe) -> Self {
312 Self::Recipe(recipe)
313 }
314}
315
316#[derive(Clone, Hash)]
318pub struct Property {
319 elem: Element,
321 id: u8,
323 value: Block,
325 span: Span,
327 liftable: bool,
329 outside: bool,
331}
332
333impl Property {
334 pub fn new<E, const I: u8>(_: Field<E, I>, value: E::Type) -> Self
336 where
337 E: SettableProperty<I>,
338 E::Type: Debug + Clone + Hash + Send + Sync + 'static,
339 {
340 Self {
341 elem: E::ELEM,
342 id: I,
343 value: Block::new(value),
344 span: Span::detached(),
345 liftable: false,
346 outside: false,
347 }
348 }
349
350 pub fn is(&self, elem: Element, id: u8) -> bool {
352 self.elem == elem && self.id == id
353 }
354
355 pub fn is_of(&self, elem: Element) -> bool {
357 self.elem == elem
358 }
359
360 pub fn wrap(self) -> LazyHash<Style> {
362 Style::Property(self).wrap()
363 }
364}
365
366impl Debug for Property {
367 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
368 write!(
369 f,
370 "Set({}.{}: ",
371 self.elem.name(),
372 self.elem.field_name(self.id).unwrap_or("internal")
373 )?;
374 self.value.fmt(f)?;
375 write!(f, ")")
376 }
377}
378
379#[derive(Hash)]
385struct Block(Box<dyn Blockable>);
386
387impl Block {
388 fn new<T: Blockable>(value: T) -> Self {
390 Self(Box::new(value))
391 }
392
393 fn downcast<T: 'static>(&self, func: Element, id: u8) -> &T {
395 let inner: &dyn Blockable = &*self.0;
396 (inner as &dyn Any)
397 .downcast_ref()
398 .unwrap_or_else(|| block_wrong_type(func, id, self))
399 }
400}
401
402impl Debug for Block {
403 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
404 self.0.fmt(f)
405 }
406}
407
408impl Clone for Block {
409 fn clone(&self) -> Self {
410 self.0.dyn_clone()
411 }
412}
413
414trait Blockable: Debug + Any + Send + Sync + 'static {
419 fn dyn_hash(&self, state: &mut dyn Hasher);
421
422 fn dyn_clone(&self) -> Block;
424}
425
426impl<T: Debug + Clone + Hash + Send + Sync + 'static> Blockable for T {
427 fn dyn_hash(&self, mut state: &mut dyn Hasher) {
428 TypeId::of::<Self>().hash(&mut state);
431 self.hash(&mut state);
432 }
433
434 fn dyn_clone(&self) -> Block {
435 Block(Box::new(self.clone()))
436 }
437}
438
439impl Hash for dyn Blockable {
440 fn hash<H: Hasher>(&self, state: &mut H) {
441 self.dyn_hash(state);
442 }
443}
444
445#[derive(Clone, PartialEq, Hash)]
447pub struct Recipe {
448 selector: Option<Selector>,
454 transform: Transformation,
456 span: Span,
458 outside: bool,
461}
462
463impl Recipe {
464 pub fn new(
466 selector: Option<Selector>,
467 transform: Transformation,
468 span: Span,
469 ) -> Self {
470 Self { selector, transform, span, outside: false }
471 }
472
473 pub fn selector(&self) -> Option<&Selector> {
475 self.selector.as_ref()
476 }
477
478 pub fn transform(&self) -> &Transformation {
480 &self.transform
481 }
482
483 pub fn span(&self) -> Span {
485 self.span
486 }
487
488 pub fn apply(
490 &self,
491 engine: &mut Engine,
492 context: Tracked<Context>,
493 content: Content,
494 ) -> SourceResult<Content> {
495 let mut content = match &self.transform {
496 Transformation::Content(content) => content.clone(),
497 Transformation::Func(func) => {
498 let mut result = func.call(engine, context, [content.clone()]);
499 if self.selector.is_some() {
500 let point = || Tracepoint::Show(content.func().name().into());
501 result = result.trace(engine.world, point, content.span());
502 }
503 result?.display()
504 }
505 Transformation::Style(styles) => content.styled_with_map(styles.clone()),
506 };
507 if content.span().is_detached() {
508 content = content.spanned(self.span);
509 }
510 Ok(content)
511 }
512}
513
514impl Debug for Recipe {
515 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
516 f.write_str("Show(")?;
517 if let Some(selector) = &self.selector {
518 selector.fmt(f)?;
519 f.write_str(", ")?;
520 }
521 self.transform.fmt(f)?;
522 f.write_str(")")
523 }
524}
525
526#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
528pub struct RecipeIndex(pub usize);
529
530#[derive(Clone, PartialEq, Hash)]
532pub enum Transformation {
533 Content(Content),
535 Func(Func),
537 Style(Styles),
539}
540
541impl Debug for Transformation {
542 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
543 match self {
544 Self::Content(content) => content.fmt(f),
545 Self::Func(func) => func.fmt(f),
546 Self::Style(styles) => styles.fmt(f),
547 }
548 }
549}
550
551cast! {
552 Transformation,
553 content: Content => Self::Content(content),
554 func: Func => Self::Func(func),
555}
556
557#[derive(Default, Copy, Clone, Hash)]
565pub struct StyleChain<'a> {
566 head: &'a [LazyHash<Style>],
568 tail: Option<&'a Self>,
570}
571
572impl<'a> StyleChain<'a> {
573 pub fn new(root: &'a Styles) -> Self {
575 Self { head: &root.0, tail: None }
576 }
577
578 pub fn get<E, const I: u8>(self, field: Field<E, I>) -> E::Type
589 where
590 E: SettableProperty<I>,
591 E::Type: Copy,
592 {
593 self.get_cloned(field)
594 }
595
596 pub fn get_cloned<E, const I: u8>(self, _: Field<E, I>) -> E::Type
601 where
602 E: SettableProperty<I>,
603 {
604 if let Some(fold) = E::FOLD {
605 self.get_folded::<E::Type>(E::ELEM, I, fold, E::default())
606 } else {
607 self.get_unfolded::<E::Type>(E::ELEM, I)
608 .cloned()
609 .unwrap_or_else(E::default)
610 }
611 }
612
613 pub fn get_ref<E, const I: u8>(self, _: Field<E, I>) -> &'a E::Type
618 where
619 E: RefableProperty<I>,
620 {
621 self.get_unfolded(E::ELEM, I).unwrap_or_else(|| E::default_ref())
622 }
623
624 pub fn resolve<E, const I: u8>(
626 self,
627 field: Field<E, I>,
628 ) -> <E::Type as Resolve>::Output
629 where
630 E: SettableProperty<I>,
631 E::Type: Resolve,
632 {
633 self.get_cloned(field).resolve(self)
634 }
635
636 pub fn has<E: NativeElement, const I: u8>(&self, _: Field<E, I>) -> bool {
638 let elem = E::ELEM;
639 self.entries()
640 .filter_map(|style| style.property())
641 .any(|property| property.is_of(elem) && property.id == I)
642 }
643
644 fn get_unfolded<T: 'static>(self, func: Element, id: u8) -> Option<&'a T> {
647 self.find(func, id).map(|block| block.downcast(func, id))
648 }
649
650 fn get_folded<T: 'static + Clone>(
653 self,
654 func: Element,
655 id: u8,
656 fold: fn(T, T) -> T,
657 default: T,
658 ) -> T {
659 let iter = self
660 .properties(func, id)
661 .map(|block| block.downcast::<T>(func, id).clone());
662
663 if let Some(folded) = iter.reduce(fold) { fold(folded, default) } else { default }
664 }
665
666 fn find(self, func: Element, id: u8) -> Option<&'a Block> {
668 self.properties(func, id).next()
669 }
670
671 fn properties(self, func: Element, id: u8) -> impl Iterator<Item = &'a Block> {
673 self.entries()
674 .filter_map(|style| style.property())
675 .filter(move |property| property.is(func, id))
676 .map(|property| &property.value)
677 }
678
679 pub fn chain<'b, C>(&'b self, local: &'b C) -> StyleChain<'b>
685 where
686 C: Chainable + ?Sized,
687 {
688 Chainable::chain(local, self)
689 }
690
691 pub fn entries(self) -> Entries<'a> {
693 Entries { inner: [].as_slice().iter(), links: self.links() }
694 }
695
696 pub fn recipes(self) -> impl Iterator<Item = &'a Recipe> {
698 self.entries().filter_map(|style| style.recipe())
699 }
700
701 pub fn links(self) -> Links<'a> {
703 Links(Some(self))
704 }
705
706 pub fn to_map(self) -> Styles {
708 let mut styles: EcoVec<_> = self.entries().cloned().collect();
709 styles.make_mut().reverse();
710 Styles(styles)
711 }
712
713 pub fn suffix(self, len: usize) -> Styles {
716 let mut styles = EcoVec::new();
717 let take = self.links().count().saturating_sub(len);
718 for link in self.links().take(take) {
719 styles.extend(link.iter().cloned().rev());
720 }
721 styles.make_mut().reverse();
722 Styles(styles)
723 }
724
725 pub fn pop(&mut self) {
727 *self = self.tail.copied().unwrap_or_default();
728 }
729
730 pub fn trunk(iter: impl IntoIterator<Item = Self>) -> Option<Self> {
732 let mut iter = iter.into_iter();
734 let mut trunk = iter.next()?;
735 let mut depth = trunk.links().count();
736
737 for mut chain in iter {
738 let len = chain.links().count();
739 if len < depth {
740 for _ in 0..depth - len {
741 trunk.pop();
742 }
743 depth = len;
744 } else if len > depth {
745 for _ in 0..len - depth {
746 chain.pop();
747 }
748 }
749
750 while depth > 0 && chain != trunk {
751 trunk.pop();
752 chain.pop();
753 depth -= 1;
754 }
755 }
756
757 Some(trunk)
758 }
759
760 pub fn trunk_from_pairs(iter: &[(&Content, Self)]) -> Option<Self> {
764 Self::trunk(iter.iter().filter(|(c, _)| !c.is::<TagElem>()).map(|&(_, s)| s))
765 }
766}
767
768impl Debug for StyleChain<'_> {
769 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
770 f.write_str("StyleChain ")?;
771 f.debug_list()
772 .entries(self.entries().collect::<Vec<_>>().into_iter().rev())
773 .finish()
774 }
775}
776
777impl PartialEq for StyleChain<'_> {
778 fn eq(&self, other: &Self) -> bool {
779 ptr::eq(self.head, other.head)
780 && match (self.tail, other.tail) {
781 (Some(a), Some(b)) => ptr::eq(a, b),
782 (None, None) => true,
783 _ => false,
784 }
785 }
786}
787
788pub trait Chainable {
790 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a>;
792}
793
794impl Chainable for LazyHash<Style> {
795 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
796 StyleChain {
797 head: std::slice::from_ref(self),
798 tail: Some(outer),
799 }
800 }
801}
802
803impl Chainable for [LazyHash<Style>] {
804 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
805 if self.is_empty() {
806 *outer
807 } else {
808 StyleChain { head: self, tail: Some(outer) }
809 }
810 }
811}
812
813impl<const N: usize> Chainable for [LazyHash<Style>; N] {
814 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
815 Chainable::chain(self.as_slice(), outer)
816 }
817}
818
819impl Chainable for Styles {
820 fn chain<'a>(&'a self, outer: &'a StyleChain<'_>) -> StyleChain<'a> {
821 Chainable::chain(self.0.as_slice(), outer)
822 }
823}
824
825pub struct Entries<'a> {
827 inner: std::slice::Iter<'a, LazyHash<Style>>,
828 links: Links<'a>,
829}
830
831impl<'a> Iterator for Entries<'a> {
832 type Item = &'a LazyHash<Style>;
833
834 fn next(&mut self) -> Option<Self::Item> {
835 loop {
836 if let Some(entry) = self.inner.next_back() {
837 return Some(entry);
838 }
839
840 match self.links.next() {
841 Some(next) => self.inner = next.iter(),
842 None => return None,
843 }
844 }
845 }
846}
847
848pub struct Links<'a>(Option<StyleChain<'a>>);
850
851impl<'a> Iterator for Links<'a> {
852 type Item = &'a [LazyHash<Style>];
853
854 fn next(&mut self) -> Option<Self::Item> {
855 let StyleChain { head, tail } = self.0?;
856 self.0 = tail.copied();
857 Some(head)
858 }
859}
860
861pub trait Resolve {
863 type Output;
865
866 fn resolve(self, styles: StyleChain) -> Self::Output;
868}
869
870impl<T: Resolve> Resolve for Option<T> {
871 type Output = Option<T::Output>;
872
873 fn resolve(self, styles: StyleChain) -> Self::Output {
874 self.map(|v| v.resolve(styles))
875 }
876}
877
878pub trait Fold {
892 fn fold(self, outer: Self) -> Self;
894}
895
896impl Fold for bool {
897 fn fold(self, _: Self) -> Self {
898 self
899 }
900}
901
902impl<T: Fold> Fold for Option<T> {
903 fn fold(self, outer: Self) -> Self {
904 match (self, outer) {
905 (Some(inner), Some(outer)) => Some(inner.fold(outer)),
906 (inner, _) => inner,
909 }
910 }
911}
912
913impl<T> Fold for Vec<T> {
914 fn fold(self, mut outer: Self) -> Self {
915 outer.extend(self);
916 outer
917 }
918}
919
920impl<T, const N: usize> Fold for SmallVec<[T; N]> {
921 fn fold(self, mut outer: Self) -> Self {
922 outer.extend(self);
923 outer
924 }
925}
926
927impl<T> Fold for OneOrMultiple<T> {
928 fn fold(self, mut outer: Self) -> Self {
929 outer.0.extend(self.0);
930 outer
931 }
932}
933
934pub type FoldFn<T> = fn(T, T) -> T;
936
937pub trait AlternativeFold {
949 fn fold_or(self, outer: Self) -> Self;
952}
953
954impl<T: Fold> AlternativeFold for Option<T> {
955 fn fold_or(self, outer: Self) -> Self {
956 match (self, outer) {
957 (Some(inner), Some(outer)) => Some(inner.fold(outer)),
958 (inner, outer) => inner.or(outer),
961 }
962 }
963}
964
965#[derive(Debug, Default, Copy, Clone, PartialEq, Hash)]
967pub struct Depth(pub usize);
968
969impl Fold for Depth {
970 fn fold(self, outer: Self) -> Self {
971 Self(outer.0 + self.0)
972 }
973}
974
975#[cold]
976fn block_wrong_type(func: Element, id: u8, value: &Block) -> ! {
977 panic!(
978 "attempted to read a value of a different type than was written {}.{}: {:?}",
979 func.name(),
980 func.field_name(id).unwrap(),
981 value
982 )
983}
984
985#[derive(Debug, Clone)]
987pub struct NativeRuleMap {
988 rules: IndexMap<(Element, Target), NativeShowRule, FxBuildHasher>,
989}
990
991pub type ShowFn<T> = fn(
993 elem: &Packed<T>,
994 engine: &mut Engine,
995 styles: StyleChain,
996) -> SourceResult<Content>;
997
998impl NativeRuleMap {
999 pub fn new() -> Self {
1006 fn empty<T: NativeElement>() -> ShowFn<T> {
1007 |_, _, _| Ok(Content::empty())
1008 }
1009
1010 let mut rules = Self { rules: IndexMap::default() };
1011
1012 for target in [Target::Paged, Target::Html, Target::Bundle] {
1013 rules.register(target, crate::foundations::CONTEXT_RULE);
1016
1017 rules.register(target, crate::introspection::COUNTER_DISPLAY_RULE);
1021
1022 rules.register(target, empty::<crate::introspection::CounterUpdateElem>());
1024 rules.register(target, empty::<crate::introspection::StateUpdateElem>());
1025 rules.register(target, empty::<crate::introspection::MetadataElem>());
1026 rules.register(target, empty::<crate::model::PrefixInfo>());
1027 }
1028
1029 for target in [Target::Paged, Target::Html] {
1030 rules.register(target, crate::model::ASSET_UNSUPPORTED_RULE);
1031 rules.register(target, crate::model::DOCUMENT_UNSUPPORTED_RULE);
1032 }
1033
1034 rules
1035 }
1036
1037 #[track_caller]
1041 pub fn register<T: NativeElement>(&mut self, target: Target, f: ShowFn<T>) {
1042 let res = self.rules.insert((T::ELEM, target), NativeShowRule::new(f));
1043 if res.is_some() {
1044 panic!(
1045 "duplicate native show rule for `{}` on {target:?} target",
1046 T::ELEM.name()
1047 )
1048 }
1049 }
1050
1051 #[track_caller]
1055 pub fn replace<T: NativeElement>(&mut self, target: Target, f: ShowFn<T>) {
1056 let res = self.rules.insert((T::ELEM, target), NativeShowRule::new(f));
1057 if res.is_none() {
1058 panic!(
1059 "no existing native show rule for `{}` on {target:?} target",
1060 T::ELEM.name()
1061 )
1062 }
1063 }
1064
1065 pub fn get(&self, target: Target, content: &Content) -> Option<NativeShowRule> {
1068 self.rules.get(&(content.func(), target)).copied()
1069 }
1070}
1071
1072impl Default for NativeRuleMap {
1073 fn default() -> Self {
1074 Self::new()
1075 }
1076}
1077
1078impl Hash for NativeRuleMap {
1079 fn hash<H: Hasher>(&self, state: &mut H) {
1080 state.write_usize(self.rules.len());
1081 for item in &self.rules {
1082 item.hash(state);
1083 }
1084 }
1085}
1086
1087pub use rule::NativeShowRule;
1088
1089mod rule {
1090 use super::*;
1091
1092 #[derive(Copy, Clone, Hash)]
1094 pub struct NativeShowRule {
1095 elem: Element,
1097 f: unsafe fn(
1099 elem: &Content,
1100 engine: &mut Engine,
1101 styles: StyleChain,
1102 ) -> SourceResult<Content>,
1103 }
1104
1105 impl NativeShowRule {
1106 pub fn new<T: NativeElement>(f: ShowFn<T>) -> Self {
1108 Self {
1109 elem: T::ELEM,
1110 #[allow(clippy::missing_transmute_annotations)]
1116 f: unsafe { std::mem::transmute(f) },
1117 }
1118 }
1119
1120 pub fn apply(
1123 &self,
1124 content: &Content,
1125 engine: &mut Engine,
1126 styles: StyleChain,
1127 ) -> SourceResult<Content> {
1128 assert_eq!(content.elem(), self.elem);
1129
1130 unsafe { (self.f)(content, engine, styles) }
1132 }
1133 }
1134
1135 impl Debug for NativeShowRule {
1136 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
1137 f.pad("NativeShowRule(..)")
1138 }
1139 }
1140}