typst_library/foundations/
content.rs

1use std::any::TypeId;
2use std::fmt::{self, Debug, Formatter};
3use std::hash::{Hash, Hasher};
4use std::iter::{self, Sum};
5use std::marker::PhantomData;
6use std::ops::{Add, AddAssign, Deref, DerefMut};
7use std::sync::Arc;
8
9use comemo::Tracked;
10use ecow::{eco_format, EcoString};
11use serde::{Serialize, Serializer};
12use typst_syntax::Span;
13use typst_utils::{fat, singleton, LazyHash, SmallBitSet};
14
15use crate::diag::{SourceResult, StrResult};
16use crate::engine::Engine;
17use crate::foundations::{
18    elem, func, scope, ty, Context, Dict, Element, Fields, IntoValue, Label,
19    NativeElement, Recipe, RecipeIndex, Repr, Selector, Str, Style, StyleChain, Styles,
20    Value,
21};
22use crate::introspection::Location;
23use crate::layout::{AlignElem, Alignment, Axes, Length, MoveElem, PadElem, Rel, Sides};
24use crate::model::{Destination, EmphElem, LinkElem, StrongElem};
25use crate::text::UnderlineElem;
26
27/// A piece of document content.
28///
29/// This type is at the heart of Typst. All markup you write and most
30/// [functions]($function) you call produce content values. You can create a
31/// content value by enclosing markup in square brackets. This is also how you
32/// pass content to functions.
33///
34/// # Example
35/// ```example
36/// Type of *Hello!* is
37/// #type([*Hello!*])
38/// ```
39///
40/// Content can be added with the `+` operator,
41/// [joined together]($scripting/#blocks) and multiplied with integers. Wherever
42/// content is expected, you can also pass a [string]($str) or `{none}`.
43///
44/// # Representation
45/// Content consists of elements with fields. When constructing an element with
46/// its _element function,_ you provide these fields as arguments and when you
47/// have a content value, you can access its fields with [field access
48/// syntax]($scripting/#field-access).
49///
50/// Some fields are required: These must be provided when constructing an
51/// element and as a consequence, they are always available through field access
52/// on content of that type. Required fields are marked as such in the
53/// documentation.
54///
55/// Most fields are optional: Like required fields, they can be passed to the
56/// element function to configure them for a single element. However, these can
57/// also be configured with [set rules]($styling/#set-rules) to apply them to
58/// all elements within a scope. Optional fields are only available with field
59/// access syntax when they were explicitly passed to the element function, not
60/// when they result from a set rule.
61///
62/// Each element has a default appearance. However, you can also completely
63/// customize its appearance with a [show rule]($styling/#show-rules). The show
64/// rule is passed the element. It can access the element's field and produce
65/// arbitrary content from it.
66///
67/// In the web app, you can hover over a content variable to see exactly which
68/// elements the content is composed of and what fields they have.
69/// Alternatively, you can inspect the output of the [`repr`] function.
70#[ty(scope, cast)]
71#[derive(Clone, Hash)]
72#[allow(clippy::derived_hash_with_manual_eq)]
73pub struct Content {
74    /// The partially element-dependent inner data.
75    inner: Arc<Inner<dyn Bounds>>,
76    /// The element's source code location.
77    span: Span,
78}
79
80/// The inner representation behind the `Arc`.
81#[derive(Hash)]
82struct Inner<T: ?Sized + 'static> {
83    /// An optional label attached to the element.
84    label: Option<Label>,
85    /// The element's location which identifies it in the layouted output.
86    location: Option<Location>,
87    /// Manages the element during realization.
88    /// - If bit 0 is set, the element is prepared.
89    /// - If bit n is set, the element is guarded against the n-th show rule
90    ///   recipe from the top of the style chain (counting from 1).
91    lifecycle: SmallBitSet,
92    /// The element's raw data.
93    elem: LazyHash<T>,
94}
95
96impl Content {
97    /// Creates a new content from an element.
98    pub fn new<T: NativeElement>(elem: T) -> Self {
99        Self {
100            inner: Arc::new(Inner {
101                label: None,
102                location: None,
103                lifecycle: SmallBitSet::new(),
104                elem: elem.into(),
105            }),
106            span: Span::detached(),
107        }
108    }
109
110    /// Creates a empty sequence content.
111    pub fn empty() -> Self {
112        singleton!(Content, SequenceElem::default().pack()).clone()
113    }
114
115    /// Get the element of this content.
116    pub fn elem(&self) -> Element {
117        self.inner.elem.dyn_elem()
118    }
119
120    /// Get the span of the content.
121    pub fn span(&self) -> Span {
122        self.span
123    }
124
125    /// Set the span of the content.
126    pub fn spanned(mut self, span: Span) -> Self {
127        if self.span.is_detached() {
128            self.span = span;
129        }
130        self
131    }
132
133    /// Get the label of the content.
134    pub fn label(&self) -> Option<Label> {
135        self.inner.label
136    }
137
138    /// Attach a label to the content.
139    pub fn labelled(mut self, label: Label) -> Self {
140        self.set_label(label);
141        self
142    }
143
144    /// Set the label of the content.
145    pub fn set_label(&mut self, label: Label) {
146        self.make_mut().label = Some(label);
147    }
148
149    /// Assigns a location to the content.
150    ///
151    /// This identifies the content and e.g. makes it linkable by
152    /// `.linked(Destination::Location(loc))`.
153    ///
154    /// Useful in combination with [`Location::variant`].
155    pub fn located(mut self, loc: Location) -> Self {
156        self.set_location(loc);
157        self
158    }
159
160    /// Set the location of the content.
161    pub fn set_location(&mut self, location: Location) {
162        self.make_mut().location = Some(location);
163    }
164
165    /// Check whether a show rule recipe is disabled.
166    pub fn is_guarded(&self, index: RecipeIndex) -> bool {
167        self.inner.lifecycle.contains(index.0)
168    }
169
170    /// Disable a show rule recipe.
171    pub fn guarded(mut self, index: RecipeIndex) -> Self {
172        self.make_mut().lifecycle.insert(index.0);
173        self
174    }
175
176    /// Whether this content has already been prepared.
177    pub fn is_prepared(&self) -> bool {
178        self.inner.lifecycle.contains(0)
179    }
180
181    /// Mark this content as prepared.
182    pub fn mark_prepared(&mut self) {
183        self.make_mut().lifecycle.insert(0);
184    }
185
186    /// Get a field by ID.
187    ///
188    /// This is the preferred way to access fields. However, you can only use it
189    /// if you have set the field IDs yourself or are using the field IDs
190    /// generated by the `#[elem]` macro.
191    pub fn get(
192        &self,
193        id: u8,
194        styles: Option<StyleChain>,
195    ) -> Result<Value, FieldAccessError> {
196        if id == 255 {
197            if let Some(label) = self.label() {
198                return Ok(label.into_value());
199            }
200        }
201        match styles {
202            Some(styles) => self.inner.elem.field_with_styles(id, styles),
203            None => self.inner.elem.field(id),
204        }
205    }
206
207    /// Get a field by name.
208    ///
209    /// If you have access to the field IDs of the element, use [`Self::get`]
210    /// instead.
211    pub fn get_by_name(&self, name: &str) -> Result<Value, FieldAccessError> {
212        if name == "label" {
213            return self
214                .label()
215                .map(|label| label.into_value())
216                .ok_or(FieldAccessError::Unknown);
217        }
218        let id = self.elem().field_id(name).ok_or(FieldAccessError::Unknown)?;
219        self.get(id, None)
220    }
221
222    /// Get a field by ID, returning a missing field error if it does not exist.
223    ///
224    /// This is the preferred way to access fields. However, you can only use it
225    /// if you have set the field IDs yourself or are using the field IDs
226    /// generated by the `#[elem]` macro.
227    pub fn field(&self, id: u8) -> StrResult<Value> {
228        self.get(id, None)
229            .map_err(|e| e.message(self, self.elem().field_name(id).unwrap()))
230    }
231
232    /// Get a field by name, returning a missing field error if it does not
233    /// exist.
234    ///
235    /// If you have access to the field IDs of the element, use [`Self::field`]
236    /// instead.
237    pub fn field_by_name(&self, name: &str) -> StrResult<Value> {
238        self.get_by_name(name).map_err(|e| e.message(self, name))
239    }
240
241    /// Resolve all fields with the styles and save them in-place.
242    pub fn materialize(&mut self, styles: StyleChain) {
243        self.make_mut().elem.materialize(styles);
244    }
245
246    /// Create a new sequence element from multiples elements.
247    pub fn sequence(iter: impl IntoIterator<Item = Self>) -> Self {
248        let vec: Vec<_> = iter.into_iter().collect();
249        if vec.is_empty() {
250            Self::empty()
251        } else if vec.len() == 1 {
252            vec.into_iter().next().unwrap()
253        } else {
254            SequenceElem::new(vec).into()
255        }
256    }
257
258    /// Whether the contained element is of type `T`.
259    pub fn is<T: NativeElement>(&self) -> bool {
260        self.inner.elem.dyn_type_id() == TypeId::of::<T>()
261    }
262
263    /// Downcasts the element to a packed value.
264    pub fn to_packed<T: NativeElement>(&self) -> Option<&Packed<T>> {
265        Packed::from_ref(self)
266    }
267
268    /// Downcasts the element to a mutable packed value.
269    pub fn to_packed_mut<T: NativeElement>(&mut self) -> Option<&mut Packed<T>> {
270        Packed::from_mut(self)
271    }
272
273    /// Downcasts the element into an owned packed value.
274    pub fn into_packed<T: NativeElement>(self) -> Result<Packed<T>, Self> {
275        Packed::from_owned(self)
276    }
277
278    /// Extract the raw underlying element.
279    pub fn unpack<T: NativeElement>(self) -> Result<T, Self> {
280        self.into_packed::<T>().map(Packed::unpack)
281    }
282
283    /// Makes sure the content is not shared and returns a mutable reference to
284    /// the inner data.
285    fn make_mut(&mut self) -> &mut Inner<dyn Bounds> {
286        let arc = &mut self.inner;
287        if Arc::strong_count(arc) > 1 || Arc::weak_count(arc) > 0 {
288            *self = arc.elem.dyn_clone(arc, self.span);
289        }
290        Arc::get_mut(&mut self.inner).unwrap()
291    }
292
293    /// Whether the contained element has the given capability.
294    pub fn can<C>(&self) -> bool
295    where
296        C: ?Sized + 'static,
297    {
298        self.elem().can::<C>()
299    }
300
301    /// Cast to a trait object if the contained element has the given
302    /// capability.
303    pub fn with<C>(&self) -> Option<&C>
304    where
305        C: ?Sized + 'static,
306    {
307        // Safety: The vtable comes from the `Capable` implementation which
308        // guarantees to return a matching vtable for `Packed<T>` and `C`.
309        // Since any `Packed<T>` is a repr(transparent) `Content`, we can also
310        // use a `*const Content` pointer.
311        let vtable = self.elem().vtable()(TypeId::of::<C>())?;
312        let data = self as *const Content as *const ();
313        Some(unsafe { &*fat::from_raw_parts(data, vtable.as_ptr()) })
314    }
315
316    /// Cast to a mutable trait object if the contained element has the given
317    /// capability.
318    pub fn with_mut<C>(&mut self) -> Option<&mut C>
319    where
320        C: ?Sized + 'static,
321    {
322        // Safety: The vtable comes from the `Capable` implementation which
323        // guarantees to return a matching vtable for `Packed<T>` and `C`.
324        // Since any `Packed<T>` is a repr(transparent) `Content`, we can also
325        // use a `*const Content` pointer.
326        //
327        // The resulting trait object contains an `&mut Packed<T>`. We do _not_
328        // need to ensure that we hold the only reference to the `Arc` here
329        // because `Packed<T>`'s DerefMut impl will take care of that if
330        // mutable access is required.
331        let vtable = self.elem().vtable()(TypeId::of::<C>())?;
332        let data = self as *mut Content as *mut ();
333        Some(unsafe { &mut *fat::from_raw_parts_mut(data, vtable.as_ptr()) })
334    }
335
336    /// Whether the content is an empty sequence.
337    pub fn is_empty(&self) -> bool {
338        let Some(sequence) = self.to_packed::<SequenceElem>() else {
339            return false;
340        };
341
342        sequence.children.is_empty()
343    }
344
345    /// Also auto expands sequence of sequences into flat sequence
346    pub fn sequence_recursive_for_each<'a>(&'a self, f: &mut impl FnMut(&'a Self)) {
347        if let Some(sequence) = self.to_packed::<SequenceElem>() {
348            for child in &sequence.children {
349                child.sequence_recursive_for_each(f);
350            }
351        } else {
352            f(self);
353        }
354    }
355
356    /// Style this content with a recipe, eagerly applying it if possible.
357    pub fn styled_with_recipe(
358        self,
359        engine: &mut Engine,
360        context: Tracked<Context>,
361        recipe: Recipe,
362    ) -> SourceResult<Self> {
363        if recipe.selector().is_none() {
364            recipe.apply(engine, context, self)
365        } else {
366            Ok(self.styled(recipe))
367        }
368    }
369
370    /// Repeat this content `count` times.
371    pub fn repeat(&self, count: usize) -> Self {
372        Self::sequence(std::iter::repeat_with(|| self.clone()).take(count))
373    }
374
375    /// Style this content with a style entry.
376    pub fn styled(mut self, style: impl Into<Style>) -> Self {
377        if let Some(style_elem) = self.to_packed_mut::<StyledElem>() {
378            style_elem.styles.apply_one(style.into());
379            self
380        } else {
381            self.styled_with_map(style.into().into())
382        }
383    }
384
385    /// Style this content with a full style map.
386    pub fn styled_with_map(mut self, styles: Styles) -> Self {
387        if styles.is_empty() {
388            return self;
389        }
390
391        if let Some(style_elem) = self.to_packed_mut::<StyledElem>() {
392            style_elem.styles.apply(styles);
393            self
394        } else {
395            StyledElem::new(self, styles).into()
396        }
397    }
398
399    /// Style this content with a full style map in-place.
400    pub fn style_in_place(&mut self, styles: Styles) {
401        if styles.is_empty() {
402            return;
403        }
404
405        if let Some(style_elem) = self.to_packed_mut::<StyledElem>() {
406            style_elem.styles.apply(styles);
407        } else {
408            *self = StyledElem::new(std::mem::take(self), styles).into();
409        }
410    }
411
412    /// Queries the content tree for all elements that match the given selector.
413    ///
414    /// Elements produced in `show` rules will not be included in the results.
415    pub fn query(&self, selector: Selector) -> Vec<Content> {
416        let mut results = Vec::new();
417        self.traverse(&mut |element| {
418            if selector.matches(&element, None) {
419                results.push(element);
420            }
421        });
422        results
423    }
424
425    /// Queries the content tree for the first element that match the given
426    /// selector.
427    ///
428    /// Elements produced in `show` rules will not be included in the results.
429    pub fn query_first(&self, selector: &Selector) -> Option<Content> {
430        let mut result = None;
431        self.traverse(&mut |element| {
432            if result.is_none() && selector.matches(&element, None) {
433                result = Some(element);
434            }
435        });
436        result
437    }
438
439    /// Extracts the plain text of this content.
440    pub fn plain_text(&self) -> EcoString {
441        let mut text = EcoString::new();
442        self.traverse(&mut |element| {
443            if let Some(textable) = element.with::<dyn PlainText>() {
444                textable.plain_text(&mut text);
445            }
446        });
447        text
448    }
449
450    /// Traverse this content.
451    fn traverse<F>(&self, f: &mut F)
452    where
453        F: FnMut(Content),
454    {
455        f(self.clone());
456
457        self.inner
458            .elem
459            .fields()
460            .into_iter()
461            .for_each(|(_, value)| walk_value(value, f));
462
463        /// Walks a given value to find any content that matches the selector.
464        fn walk_value<F>(value: Value, f: &mut F)
465        where
466            F: FnMut(Content),
467        {
468            match value {
469                Value::Content(content) => content.traverse(f),
470                Value::Array(array) => {
471                    for value in array {
472                        walk_value(value, f);
473                    }
474                }
475                _ => {}
476            }
477        }
478    }
479}
480
481impl Content {
482    /// Strongly emphasize this content.
483    pub fn strong(self) -> Self {
484        let span = self.span();
485        StrongElem::new(self).pack().spanned(span)
486    }
487
488    /// Emphasize this content.
489    pub fn emph(self) -> Self {
490        let span = self.span();
491        EmphElem::new(self).pack().spanned(span)
492    }
493
494    /// Underline this content.
495    pub fn underlined(self) -> Self {
496        let span = self.span();
497        UnderlineElem::new(self).pack().spanned(span)
498    }
499
500    /// Link the content somewhere.
501    pub fn linked(self, dest: Destination) -> Self {
502        self.styled(LinkElem::set_current(Some(dest)))
503    }
504
505    /// Set alignments for this content.
506    pub fn aligned(self, align: Alignment) -> Self {
507        self.styled(AlignElem::set_alignment(align))
508    }
509
510    /// Pad this content at the sides.
511    pub fn padded(self, padding: Sides<Rel<Length>>) -> Self {
512        let span = self.span();
513        PadElem::new(self)
514            .with_left(padding.left)
515            .with_top(padding.top)
516            .with_right(padding.right)
517            .with_bottom(padding.bottom)
518            .pack()
519            .spanned(span)
520    }
521
522    /// Transform this content's contents without affecting layout.
523    pub fn moved(self, delta: Axes<Rel<Length>>) -> Self {
524        let span = self.span();
525        MoveElem::new(self)
526            .with_dx(delta.x)
527            .with_dy(delta.y)
528            .pack()
529            .spanned(span)
530    }
531}
532
533#[scope]
534impl Content {
535    /// The content's element function. This function can be used to create the element
536    /// contained in this content. It can be used in set and show rules for the
537    /// element. Can be compared with global functions to check whether you have
538    /// a specific
539    /// kind of element.
540    #[func]
541    pub fn func(&self) -> Element {
542        self.elem()
543    }
544
545    /// Whether the content has the specified field.
546    #[func]
547    pub fn has(
548        &self,
549        /// The field to look for.
550        field: Str,
551    ) -> bool {
552        if field.as_str() == "label" {
553            return self.label().is_some();
554        }
555
556        let Some(id) = self.elem().field_id(&field) else {
557            return false;
558        };
559
560        self.inner.elem.has(id)
561    }
562
563    /// Access the specified field on the content. Returns the default value if
564    /// the field does not exist or fails with an error if no default value was
565    /// specified.
566    #[func]
567    pub fn at(
568        &self,
569        /// The field to access.
570        field: Str,
571        /// A default value to return if the field does not exist.
572        #[named]
573        default: Option<Value>,
574    ) -> StrResult<Value> {
575        self.get_by_name(&field)
576            .or_else(|e| default.ok_or(e))
577            .map_err(|e| e.message_no_default(self, &field))
578    }
579
580    /// Returns the fields of this content.
581    ///
582    /// ```example
583    /// #rect(
584    ///   width: 10cm,
585    ///   height: 10cm,
586    /// ).fields()
587    /// ```
588    #[func]
589    pub fn fields(&self) -> Dict {
590        let mut dict = self.inner.elem.fields();
591        if let Some(label) = self.label() {
592            dict.insert("label".into(), label.into_value());
593        }
594        dict
595    }
596
597    /// The location of the content. This is only available on content returned
598    /// by [query] or provided by a [show rule]($reference/styling/#show-rules),
599    /// for other content it will be `{none}`. The resulting location can be
600    /// used with [counters]($counter), [state] and [queries]($query).
601    #[func]
602    pub fn location(&self) -> Option<Location> {
603        self.inner.location
604    }
605}
606
607impl Default for Content {
608    fn default() -> Self {
609        Self::empty()
610    }
611}
612
613impl Debug for Content {
614    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
615        self.inner.elem.fmt(f)
616    }
617}
618
619impl<T: NativeElement> From<T> for Content {
620    fn from(value: T) -> Self {
621        Self::new(value)
622    }
623}
624
625impl PartialEq for Content {
626    fn eq(&self, other: &Self) -> bool {
627        // Additional short circuit for different elements.
628        self.elem() == other.elem() && self.inner.elem.dyn_eq(other)
629    }
630}
631
632impl Repr for Content {
633    fn repr(&self) -> EcoString {
634        self.inner.elem.repr()
635    }
636}
637
638impl Add for Content {
639    type Output = Self;
640
641    fn add(self, mut rhs: Self) -> Self::Output {
642        let mut lhs = self;
643        match (lhs.to_packed_mut::<SequenceElem>(), rhs.to_packed_mut::<SequenceElem>()) {
644            (Some(seq_lhs), Some(rhs)) => {
645                seq_lhs.children.extend(rhs.children.iter().cloned());
646                lhs
647            }
648            (Some(seq_lhs), None) => {
649                seq_lhs.children.push(rhs);
650                lhs
651            }
652            (None, Some(rhs_seq)) => {
653                rhs_seq.children.insert(0, lhs);
654                rhs
655            }
656            (None, None) => Self::sequence([lhs, rhs]),
657        }
658    }
659}
660
661impl<'a> Add<&'a Self> for Content {
662    type Output = Self;
663
664    fn add(self, rhs: &'a Self) -> Self::Output {
665        let mut lhs = self;
666        match (lhs.to_packed_mut::<SequenceElem>(), rhs.to_packed::<SequenceElem>()) {
667            (Some(seq_lhs), Some(rhs)) => {
668                seq_lhs.children.extend(rhs.children.iter().cloned());
669                lhs
670            }
671            (Some(seq_lhs), None) => {
672                seq_lhs.children.push(rhs.clone());
673                lhs
674            }
675            (None, Some(_)) => {
676                let mut rhs = rhs.clone();
677                rhs.to_packed_mut::<SequenceElem>().unwrap().children.insert(0, lhs);
678                rhs
679            }
680            (None, None) => Self::sequence([lhs, rhs.clone()]),
681        }
682    }
683}
684
685impl AddAssign for Content {
686    fn add_assign(&mut self, rhs: Self) {
687        *self = std::mem::take(self) + rhs;
688    }
689}
690
691impl AddAssign<&Self> for Content {
692    fn add_assign(&mut self, rhs: &Self) {
693        *self = std::mem::take(self) + rhs;
694    }
695}
696
697impl Sum for Content {
698    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
699        Self::sequence(iter)
700    }
701}
702
703impl Serialize for Content {
704    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
705    where
706        S: Serializer,
707    {
708        serializer.collect_map(
709            iter::once(("func".into(), self.func().name().into_value()))
710                .chain(self.fields()),
711        )
712    }
713}
714
715/// The trait that combines all the other traits into a trait object.
716trait Bounds: Debug + Repr + Fields + Send + Sync + 'static {
717    fn dyn_type_id(&self) -> TypeId;
718    fn dyn_elem(&self) -> Element;
719    fn dyn_clone(&self, inner: &Inner<dyn Bounds>, span: Span) -> Content;
720    fn dyn_hash(&self, hasher: &mut dyn Hasher);
721    fn dyn_eq(&self, other: &Content) -> bool;
722}
723
724impl<T: NativeElement> Bounds for T {
725    fn dyn_type_id(&self) -> TypeId {
726        TypeId::of::<Self>()
727    }
728
729    fn dyn_elem(&self) -> Element {
730        Self::elem()
731    }
732
733    fn dyn_clone(&self, inner: &Inner<dyn Bounds>, span: Span) -> Content {
734        Content {
735            inner: Arc::new(Inner {
736                label: inner.label,
737                location: inner.location,
738                lifecycle: inner.lifecycle.clone(),
739                elem: LazyHash::reuse(self.clone(), &inner.elem),
740            }),
741            span,
742        }
743    }
744
745    fn dyn_hash(&self, mut state: &mut dyn Hasher) {
746        TypeId::of::<Self>().hash(&mut state);
747        self.hash(&mut state);
748    }
749
750    fn dyn_eq(&self, other: &Content) -> bool {
751        let Some(other) = other.to_packed::<Self>() else {
752            return false;
753        };
754        *self == **other
755    }
756}
757
758impl Hash for dyn Bounds {
759    fn hash<H: Hasher>(&self, state: &mut H) {
760        self.dyn_hash(state);
761    }
762}
763
764/// A packed element of a static type.
765#[derive(Clone, PartialEq, Hash)]
766#[repr(transparent)]
767pub struct Packed<T: NativeElement>(
768    /// Invariant: Must be of type `T`.
769    Content,
770    PhantomData<T>,
771);
772
773impl<T: NativeElement> Packed<T> {
774    /// Pack element while retaining its static type.
775    pub fn new(element: T) -> Self {
776        // Safety: The element is known to be of type `T`.
777        Packed(element.pack(), PhantomData)
778    }
779
780    /// Try to cast type-erased content into a statically known packed element.
781    pub fn from_ref(content: &Content) -> Option<&Self> {
782        if content.is::<T>() {
783            // Safety:
784            // - We have checked the type.
785            // - Packed<T> is repr(transparent).
786            return Some(unsafe { std::mem::transmute::<&Content, &Packed<T>>(content) });
787        }
788        None
789    }
790
791    /// Try to cast type-erased content into a statically known packed element.
792    pub fn from_mut(content: &mut Content) -> Option<&mut Self> {
793        if content.is::<T>() {
794            // Safety:
795            // - We have checked the type.
796            // - Packed<T> is repr(transparent).
797            return Some(unsafe {
798                std::mem::transmute::<&mut Content, &mut Packed<T>>(content)
799            });
800        }
801        None
802    }
803
804    /// Try to cast type-erased content into a statically known packed element.
805    pub fn from_owned(content: Content) -> Result<Self, Content> {
806        if content.is::<T>() {
807            // Safety:
808            // - We have checked the type.
809            // - Packed<T> is repr(transparent).
810            return Ok(unsafe { std::mem::transmute::<Content, Packed<T>>(content) });
811        }
812        Err(content)
813    }
814
815    /// Pack back into content.
816    pub fn pack(self) -> Content {
817        self.0
818    }
819
820    /// Extract the raw underlying element.
821    pub fn unpack(self) -> T {
822        // This function doesn't yet need owned self, but might in the future.
823        (*self).clone()
824    }
825
826    /// The element's span.
827    pub fn span(&self) -> Span {
828        self.0.span()
829    }
830
831    /// Set the span of the element.
832    pub fn spanned(self, span: Span) -> Self {
833        Self(self.0.spanned(span), PhantomData)
834    }
835
836    /// Accesses the label of the element.
837    pub fn label(&self) -> Option<Label> {
838        self.0.label()
839    }
840
841    /// Accesses the location of the element.
842    pub fn location(&self) -> Option<Location> {
843        self.0.location()
844    }
845
846    /// Sets the location of the element.
847    pub fn set_location(&mut self, location: Location) {
848        self.0.set_location(location);
849    }
850}
851
852impl<T: NativeElement> AsRef<T> for Packed<T> {
853    fn as_ref(&self) -> &T {
854        self
855    }
856}
857
858impl<T: NativeElement> AsMut<T> for Packed<T> {
859    fn as_mut(&mut self) -> &mut T {
860        self
861    }
862}
863
864impl<T: NativeElement> Deref for Packed<T> {
865    type Target = T;
866
867    fn deref(&self) -> &Self::Target {
868        // Safety:
869        // - Packed<T> guarantees that the content trait object wraps
870        //   an element of type `T`.
871        // - This downcast works the same way as dyn Any's does. We can't reuse
872        //   that one because we don't want to pay the cost for every deref.
873        let elem = &*self.0.inner.elem;
874        unsafe { &*(elem as *const dyn Bounds as *const T) }
875    }
876}
877
878impl<T: NativeElement> DerefMut for Packed<T> {
879    fn deref_mut(&mut self) -> &mut Self::Target {
880        // Safety:
881        // - Packed<T> guarantees that the content trait object wraps
882        //   an element of type `T`.
883        // - We have guaranteed unique access thanks to `make_mut`.
884        // - This downcast works the same way as dyn Any's does. We can't reuse
885        //   that one because we don't want to pay the cost for every deref.
886        let elem = &mut *self.0.make_mut().elem;
887        unsafe { &mut *(elem as *mut dyn Bounds as *mut T) }
888    }
889}
890
891impl<T: NativeElement + Debug> Debug for Packed<T> {
892    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
893        self.0.fmt(f)
894    }
895}
896
897/// A sequence of content.
898#[elem(Debug, Repr, PartialEq)]
899pub struct SequenceElem {
900    /// The elements.
901    #[required]
902    pub children: Vec<Content>,
903}
904
905impl Debug for SequenceElem {
906    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
907        write!(f, "Sequence ")?;
908        f.debug_list().entries(&self.children).finish()
909    }
910}
911
912// Derive is currently incompatible with `elem` macro.
913#[allow(clippy::derivable_impls)]
914impl Default for SequenceElem {
915    fn default() -> Self {
916        Self { children: Default::default() }
917    }
918}
919
920impl PartialEq for SequenceElem {
921    fn eq(&self, other: &Self) -> bool {
922        self.children.iter().eq(other.children.iter())
923    }
924}
925
926impl Repr for SequenceElem {
927    fn repr(&self) -> EcoString {
928        if self.children.is_empty() {
929            "[]".into()
930        } else {
931            let elements = crate::foundations::repr::pretty_array_like(
932                &self.children.iter().map(|c| c.inner.elem.repr()).collect::<Vec<_>>(),
933                false,
934            );
935            eco_format!("sequence{}", elements)
936        }
937    }
938}
939
940/// Content alongside styles.
941#[elem(Debug, Repr, PartialEq)]
942pub struct StyledElem {
943    /// The content.
944    #[required]
945    pub child: Content,
946    /// The styles.
947    #[required]
948    pub styles: Styles,
949}
950
951impl Debug for StyledElem {
952    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
953        for style in self.styles.iter() {
954            writeln!(f, "#{style:?}")?;
955        }
956        self.child.fmt(f)
957    }
958}
959
960impl PartialEq for StyledElem {
961    fn eq(&self, other: &Self) -> bool {
962        self.child == other.child
963    }
964}
965
966impl Repr for StyledElem {
967    fn repr(&self) -> EcoString {
968        eco_format!("styled(child: {}, ..)", self.child.repr())
969    }
970}
971
972/// Tries to extract the plain-text representation of the element.
973pub trait PlainText {
974    /// Write this element's plain text into the given buffer.
975    fn plain_text(&self, text: &mut EcoString);
976}
977
978/// An error arising when trying to access a field of content.
979#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
980pub enum FieldAccessError {
981    Unknown,
982    Unset,
983    Internal,
984}
985
986impl FieldAccessError {
987    /// Formats the error message given the content and the field name.
988    #[cold]
989    pub fn message(self, content: &Content, field: &str) -> EcoString {
990        let elem_name = content.elem().name();
991        match self {
992            FieldAccessError::Unknown => {
993                eco_format!("{elem_name} does not have field {}", field.repr())
994            }
995            FieldAccessError::Unset => {
996                eco_format!(
997                    "field {} in {elem_name} is not known at this point",
998                    field.repr()
999                )
1000            }
1001            FieldAccessError::Internal => {
1002                eco_format!(
1003                    "internal error when accessing field {} in {elem_name} – this is a bug",
1004                    field.repr()
1005                )
1006            }
1007        }
1008    }
1009
1010    /// Formats the error message for an `at` calls without a default value.
1011    #[cold]
1012    pub fn message_no_default(self, content: &Content, field: &str) -> EcoString {
1013        let mut msg = self.message(content, field);
1014        msg.push_str(" and no default was specified");
1015        msg
1016    }
1017}