diff options
69 files changed, 1012 insertions, 1049 deletions
diff --git a/crates/typst-macros/src/elem.rs b/crates/typst-macros/src/elem.rs index 2199ec92..6ab437cd 100644 --- a/crates/typst-macros/src/elem.rs +++ b/crates/typst-macros/src/elem.rs @@ -311,6 +311,8 @@ fn create(element: &Elem) -> Result<TokenStream> { settable.clone().map(|field| create_set_field_method(element, field)); // Trait implementations. + let fields_impl = create_fields_impl(element); + let capable_impl = create_capable_impl(element); let native_element_impl = create_native_elem_impl(element); let construct_impl = element.unless_capability("Construct", || create_construct_impl(element)); @@ -321,23 +323,11 @@ fn create(element: &Elem) -> Result<TokenStream> { element.unless_capability("PartialEq", || create_partial_eq_impl(element)); let repr_impl = element.unless_capability("Repr", || create_repr_impl(element)); - let label_and_location = element.unless_capability("Unlabellable", || { - quote! { - location: Option<::typst::introspection::Location>, - label: Option<#foundations::Label>, - prepared: bool, - } - }); - Ok(quote! { #[doc = #docs] #[derive(Debug, Clone, Hash)] #[allow(clippy::derived_hash_with_manual_eq)] #vis struct #ident { - span: ::typst::syntax::Span, - #label_and_location - guards: ::std::vec::Vec<#foundations::Guard>, - #(#fields,)* } @@ -353,6 +343,8 @@ fn create(element: &Elem) -> Result<TokenStream> { } #native_element_impl + #fields_impl + #capable_impl #construct_impl #set_impl #locatable_impl @@ -406,6 +398,8 @@ fn create_fields_enum(element: &Elem) -> TokenStream { quote! { #enum_ident } }); + let enum_repr = (!fields.is_empty()).then(|| quote! { #[repr(u8)] }); + quote! { // To hide the private type const _: () = { @@ -414,10 +408,9 @@ fn create_fields_enum(element: &Elem) -> TokenStream { } #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] - #[repr(u8)] + #enum_repr pub enum #enum_ident { #(#definitions,)* - Label = 255, } impl #enum_ident { @@ -425,7 +418,6 @@ fn create_fields_enum(element: &Elem) -> TokenStream { pub fn to_str(self) -> &'static str { match self { #(Self::#field_variants => #field_names,)* - Self::Label => "label", } } } @@ -437,7 +429,6 @@ fn create_fields_enum(element: &Elem) -> TokenStream { #(const #field_consts: u8 = #enum_ident::#field_variants as u8;)* match value { #(#field_consts => Ok(Self::#field_variants),)* - 255 => Ok(Self::Label), _ => Err(()), } } @@ -455,7 +446,6 @@ fn create_fields_enum(element: &Elem) -> TokenStream { fn from_str(s: &str) -> Result<Self, Self::Err> { match s { #(#field_names => Ok(Self::#field_variants),)* - "label" => Ok(Self::Label), _ => Err(()), } } @@ -495,21 +485,10 @@ fn create_new_func(element: &Elem) -> TokenStream { } }); - let label_and_location = element.unless_capability("Unlabellable", || { - quote! { - location: None, - label: None, - prepared: false, - } - }); - quote! { /// Create a new element. pub fn new(#(#params),*) -> Self { Self { - span: ::typst::syntax::Span::detached(), - #label_and_location - guards: ::std::vec::Vec::with_capacity(0), #(#required,)* #(#defaults,)* #(#default_synthesized,)* @@ -700,7 +679,6 @@ fn create_style_chain_access( fn create_native_elem_impl(element: &Elem) -> TokenStream { let Elem { name, ident, title, scope, keywords, docs, .. } = element; - let vtable_func = create_vtable_func(element); let params = element .fields .iter() @@ -713,30 +691,48 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { quote! { #foundations::Scope::new() } }; - // Fields that can be accessed using the `field` method. - let field_matches = element.visible_fields().map(|field| { - let elem = &element.ident; - let name = &field.enum_ident; - let field_ident = &field.ident; + let local_name = element + .if_capability( + "LocalName", + || quote! { Some(<#foundations::Packed<#ident> as ::typst::text::LocalName>::local_name) }, + ) + .unwrap_or_else(|| quote! { None }); - if field.ghost { - quote! { - <#elem as #foundations::ElementFields>::Fields::#name => None, - } - } else if field.inherent() || (field.synthesized && field.default.is_some()) { - quote! { - <#elem as #foundations::ElementFields>::Fields::#name => Some( - #foundations::IntoValue::into_value(self.#field_ident.clone()) - ), - } - } else { - quote! { - <#elem as #foundations::ElementFields>::Fields::#name => { - self.#field_ident.clone().map(#foundations::IntoValue::into_value) - } + let data = quote! { + #foundations::NativeElementData { + name: #name, + title: #title, + docs: #docs, + keywords: &[#(#keywords),*], + construct: <#ident as #foundations::Construct>::construct, + set: <#ident as #foundations::Set>::set, + vtable: <#ident as #foundations::Capable>::vtable, + field_id: |name| + < + <#ident as #foundations::ElementFields>::Fields as ::std::str::FromStr + >::from_str(name).ok().map(|id| id as u8), + field_name: |id| + < + <#ident as #foundations::ElementFields>::Fields as ::std::convert::TryFrom<u8> + >::try_from(id).ok().map(<#ident as #foundations::ElementFields>::Fields::to_str), + local_name: #local_name, + scope: #foundations::Lazy::new(|| #scope), + params: #foundations::Lazy::new(|| ::std::vec![#(#params),*]) + } + }; + + quote! { + impl #foundations::NativeElement for #ident { + fn data() -> &'static #foundations::NativeElementData { + static DATA: #foundations::NativeElementData = #data; + &DATA } } - }); + } +} + +fn create_fields_impl(element: &Elem) -> TokenStream { + let Elem { ident, .. } = element; // Fields that can be checked using the `has` method. let field_has_matches = element.visible_fields().map(|field| { @@ -759,80 +755,6 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { } }); - // Fields that can be set using the `set_field` method. - let field_set_matches = element - .visible_fields() - .filter(|field| field.settable() && !field.synthesized && !field.ghost) - .map(|field| { - let elem = &element.ident; - let name = &field.enum_ident; - let field_ident = &field.ident; - - quote! { - <#elem as #foundations::ElementFields>::Fields::#name => { - self.#field_ident = Some(#foundations::FromValue::from_value(value)?); - return Ok(()); - } - } - }); - - // Fields that are inherent. - let field_inherent_matches = element - .visible_fields() - .filter(|field| field.inherent() && !field.ghost) - .map(|field| { - let elem = &element.ident; - let name = &field.enum_ident; - let field_ident = &field.ident; - - quote! { - <#elem as #foundations::ElementFields>::Fields::#name => { - self.#field_ident = #foundations::FromValue::from_value(value)?; - return Ok(()); - } - } - }); - - // Fields that cannot be set or are internal create an error. - let field_not_set_matches = element - .real_fields() - .filter(|field| field.internal || field.synthesized || field.ghost) - .map(|field| { - let elem = &element.ident; - let ident = &field.enum_ident; - let field_name = &field.name; - if field.internal { - // Internal fields create an error that they are unknown. - let unknown_field = format!("unknown field `{field_name}` on `{name}`"); - quote! { - <#elem as #foundations::ElementFields>::Fields::#ident => ::typst::diag::bail!(#unknown_field), - } - } else { - // Fields that cannot be set create an error that they are not settable. - let not_settable = format!("cannot set `{field_name}` on `{name}`"); - quote! { - <#elem as #foundations::ElementFields>::Fields::#ident => ::typst::diag::bail!(#not_settable), - } - } - }); - - // Statistically compute whether we need preparation or not. - let needs_preparation = element - .unless_capability("Unlabellable", || { - element - .capabilities - .iter() - .any(|capability| capability == "Locatable" || capability == "Synthesize") - .then(|| quote! { !self.prepared }) - .unwrap_or_else(|| quote! { self.label().is_some() && !self.prepared }) - }) - .unwrap_or_else(|| { - assert!(element.capabilities.iter().all(|capability| capability - != "Locatable" - && capability != "Synthesize")); - quote! { false } - }); - // Creation of the fields dictionary for inherent fields. let field_dict = element .inherent_fields() @@ -878,226 +800,58 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream { } }); - let location = element - .unless_capability("Unlabellable", || quote! { self.location }) - .unwrap_or_else(|| quote! { None }); + // Fields that can be accessed using the `field` method. + let field_matches = element.visible_fields().map(|field| { + let elem = &element.ident; + let name = &field.enum_ident; + let field_ident = &field.ident; - let set_location = element - .unless_capability("Unlabellable", || { + if field.ghost { quote! { - self.location = Some(location); + <#elem as #foundations::ElementFields>::Fields::#name => None, } - }) - .unwrap_or_else(|| quote! { drop(location) }); - - let label = element - .unless_capability("Unlabellable", || quote! { self.label }) - .unwrap_or_else(|| quote! { None }); - - let set_label = element - .unless_capability("Unlabellable", || { + } else if field.inherent() || (field.synthesized && field.default.is_some()) { quote! { - self.label = Some(label); + <#elem as #foundations::ElementFields>::Fields::#name => Some( + #foundations::IntoValue::into_value(self.#field_ident.clone()) + ), } - }) - .unwrap_or_else(|| quote! { drop(label) }); - - let label_field = element - .unless_capability("Unlabellable", || { + } else { quote! { - self.label().map(#foundations::Value::Label) - } - }) - .unwrap_or_else(|| quote! { None }); - - let label_has_field = element - .unless_capability("Unlabellable", || quote! { self.label().is_some() }) - .unwrap_or_else(|| quote! { false }); - - let label_field_dict = element.unless_capability("Unlabellable", || { - quote! { - if let Some(label) = self.label() { - fields.insert( - "label".into(), - #foundations::IntoValue::into_value(label) - ); + <#elem as #foundations::ElementFields>::Fields::#name => { + self.#field_ident.clone().map(#foundations::IntoValue::into_value) + } } } }); - let mark_prepared = element - .unless_capability("Unlabellable", || quote! { self.prepared = true; }) - .unwrap_or_else(|| quote! {}); - - let prepared = element - .unless_capability("Unlabellable", || quote! { self.prepared }) - .unwrap_or_else(|| quote! { true }); - - let local_name = element - .if_capability( - "LocalName", - || quote! { Some(<#ident as ::typst::text::LocalName>::local_name) }, - ) - .unwrap_or_else(|| quote! { None }); - - let unknown_field = format!("unknown field {{}} on {name}"); - let label_error = format!("cannot set label on {name}"); - let data = quote! { - #foundations::NativeElementData { - name: #name, - title: #title, - docs: #docs, - keywords: &[#(#keywords),*], - construct: <#ident as #foundations::Construct>::construct, - set: <#ident as #foundations::Set>::set, - vtable: #vtable_func, - field_id: |name| - < - <#ident as #foundations::ElementFields>::Fields as ::std::str::FromStr - >::from_str(name).ok().map(|id| id as u8), - field_name: |id| - < - <#ident as #foundations::ElementFields>::Fields as ::std::convert::TryFrom<u8> - >::try_from(id).ok().map(<#ident as #foundations::ElementFields>::Fields::to_str), - local_name: #local_name, - scope: #foundations::Lazy::new(|| #scope), - params: #foundations::Lazy::new(|| ::std::vec![#(#params),*]) - } - }; - quote! { - impl #foundations::NativeElement for #ident { - fn data() -> &'static #foundations::NativeElementData { - static DATA: #foundations::NativeElementData = #data; - &DATA - } - - fn dyn_elem(&self) -> #foundations::Element { - #foundations::Element::of::<Self>() - } - - fn dyn_hash(&self, mut state: &mut dyn ::std::hash::Hasher) { - // Also hash the TypeId since values with different types but - // equal data should be different. - ::std::hash::Hash::hash(&::std::any::TypeId::of::<Self>(), &mut state); - ::std::hash::Hash::hash(self, &mut state); - } - - fn dyn_eq(&self, other: &#foundations::Content) -> bool { - if let Some(other) = other.to::<Self>() { - <Self as ::std::cmp::PartialEq>::eq(self, other) - } else { - false - } - } - - fn dyn_clone(&self) -> ::std::sync::Arc<dyn #foundations::NativeElement> { - ::std::sync::Arc::new(Clone::clone(self)) - } - - fn as_any(&self) -> &dyn ::std::any::Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn ::std::any::Any { - self - } - - fn into_any(self: ::std::sync::Arc<Self>) -> ::std::sync::Arc<dyn ::std::any::Any + Send + Sync> { - self - } - - fn span(&self) -> ::typst::syntax::Span { - self.span - } + impl #foundations::Fields for #ident { + fn has(&self, id: u8) -> bool { + let Ok(id) = <#ident as #foundations::ElementFields>::Fields::try_from(id) else { + return false; + }; - fn set_span(&mut self, span: ::typst::syntax::Span) { - if self.span().is_detached() { - self.span = span; + match id { + #(#field_has_matches)* + _ => false, } } - fn label(&self) -> Option<#foundations::Label> { - #label - } - - fn set_label(&mut self, label: #foundations::Label) { - #set_label - } - - fn location(&self) -> Option<::typst::introspection::Location> { - #location - } - - fn set_location(&mut self, location: ::typst::introspection::Location) { - #set_location - } - - fn push_guard(&mut self, guard: #foundations::Guard) { - self.guards.push(guard); - } - - fn is_guarded(&self, guard: #foundations::Guard) -> bool { - self.guards.contains(&guard) - } - - fn is_pristine(&self) -> bool { - self.guards.is_empty() - } - - fn mark_prepared(&mut self) { - #mark_prepared - } - - fn needs_preparation(&self) -> bool { - #needs_preparation - } - - fn is_prepared(&self) -> bool { - #prepared - } - fn field(&self, id: u8) -> Option<#foundations::Value> { let id = <#ident as #foundations::ElementFields>::Fields::try_from(id).ok()?; match id { - <#ident as #foundations::ElementFields>::Fields::Label => #label_field, #(#field_matches)* _ => None, } } - fn has(&self, id: u8) -> bool { - let Ok(id) = <#ident as #foundations::ElementFields>::Fields::try_from(id) else { - return false; - }; - - match id { - <#ident as #foundations::ElementFields>::Fields::Label => #label_has_field, - #(#field_has_matches)* - _ => false, - } - } - fn fields(&self) -> #foundations::Dict { let mut fields = #foundations::Dict::new(); - #label_field_dict #(#field_dict)* #(#field_opt_dict)* fields } - - fn set_field(&mut self, id: u8, value: #foundations::Value) -> ::typst::diag::StrResult<()> { - let id = <#ident as #foundations::ElementFields>::Fields::try_from(id) - .map_err(|_| ::ecow::eco_format!(#unknown_field, id))?; - match id { - #(#field_set_matches)* - #(#field_inherent_matches)* - #(#field_not_set_matches)* - <#ident as #foundations::ElementFields>::Fields::Label => { - ::typst::diag::bail!(#label_error); - } - } - } } } } @@ -1182,7 +936,7 @@ fn create_set_impl(element: &Elem) -> TokenStream { /// Creates the element's `Locatable` implementation. fn create_locatable_impl(element: &Elem) -> TokenStream { let ident = &element.ident; - quote! { impl ::typst::introspection::Locatable for #ident {} } + quote! { impl ::typst::introspection::Locatable for #foundations::Packed<#ident> {} } } /// Creates the element's `PartialEq` implementation. @@ -1208,7 +962,7 @@ fn create_repr_impl(element: &Elem) -> TokenStream { quote! { impl #foundations::Repr for #ident { fn repr(&self) -> ::ecow::EcoString { - let fields = #foundations::NativeElement::fields(self).into_iter() + let fields = #foundations::Fields::fields(self).into_iter() .map(|(name, value)| ::ecow::eco_format!("{}: {}", name, value.repr())) .collect::<Vec<_>>(); ::ecow::eco_format!(#repr_format, #foundations::repr::pretty_array_like(&fields, false)) @@ -1218,9 +972,9 @@ fn create_repr_impl(element: &Elem) -> TokenStream { } /// Creates the element's casting vtable. -fn create_vtable_func(element: &Elem) -> TokenStream { +fn create_capable_impl(element: &Elem) -> TokenStream { // Forbidden capabilities (i.e capabilities that are not object safe). - const FORBIDDEN: &[&str] = &["Construct", "PartialEq", "Hash", "LocalName"]; + const FORBIDDEN: &[&str] = &["Construct", "PartialEq", "Hash", "LocalName", "Repr"]; let ident = &element.ident; let relevant = element @@ -1229,20 +983,23 @@ fn create_vtable_func(element: &Elem) -> TokenStream { .filter(|&ident| !FORBIDDEN.contains(&(&ident.to_string() as &str))); let checks = relevant.map(|capability| { quote! { - if id == ::std::any::TypeId::of::<dyn #capability>() { - let vtable = unsafe { - let dangling = ::std::ptr::NonNull::<#ident>::dangling().as_ptr() as *const dyn #capability; - ::typst::util::fat::vtable(dangling) - }; - return Some(vtable); + if capability == ::std::any::TypeId::of::<dyn #capability>() { + // Safety: The vtable function doesn't require initialized + // data, so it's fine to use a dangling pointer. + return Some(unsafe { + ::typst::util::fat::vtable(dangling as *const dyn #capability) + }); } } }); quote! { - |id| { - #(#checks)* - None + unsafe impl #foundations::Capable for #ident { + fn vtable(capability: ::std::any::TypeId) -> ::std::option::Option<*const ()> { + let dangling = ::std::ptr::NonNull::<#foundations::Packed<#ident>>::dangling().as_ptr(); + #(#checks)* + None + } } } } diff --git a/crates/typst-pdf/src/outline.rs b/crates/typst-pdf/src/outline.rs index 78698cf8..172f6d3c 100644 --- a/crates/typst-pdf/src/outline.rs +++ b/crates/typst-pdf/src/outline.rs @@ -1,7 +1,7 @@ use std::num::NonZeroUsize; use pdf_writer::{Finish, Ref, TextStr}; -use typst::foundations::{Content, NativeElement, Smart}; +use typst::foundations::{NativeElement, Packed, StyleChain}; use typst::layout::Abs; use typst::model::HeadingElem; @@ -17,8 +17,10 @@ pub(crate) fn write_outline(ctx: &mut PdfContext) -> Option<Ref> { // Therefore, its next descendant must be added at its level, which is // enforced in the manner shown below. let mut last_skipped_level = None; - for heading in ctx.document.introspector.query(&HeadingElem::elem().select()).iter() { - let leaf = HeadingNode::leaf((**heading).clone()); + let elements = ctx.document.introspector.query(&HeadingElem::elem().select()); + for elem in elements.iter() { + let heading = elem.to::<HeadingElem>().unwrap(); + let leaf = HeadingNode::leaf(heading); if leaf.bookmarked { let mut children = &mut tree; @@ -103,21 +105,21 @@ pub(crate) fn write_outline(ctx: &mut PdfContext) -> Option<Ref> { /// A heading in the outline panel. #[derive(Debug, Clone)] -struct HeadingNode { - element: Content, +struct HeadingNode<'a> { + element: &'a Packed<HeadingElem>, level: NonZeroUsize, bookmarked: bool, - children: Vec<HeadingNode>, + children: Vec<HeadingNode<'a>>, } -impl HeadingNode { - fn leaf(element: Content) -> Self { +impl<'a> HeadingNode<'a> { + fn leaf(element: &'a Packed<HeadingElem>) -> Self { HeadingNode { - level: element.expect_field_by_name::<NonZeroUsize>("level"), + level: element.level(StyleChain::default()), // 'bookmarked' set to 'auto' falls back to the value of 'outlined'. bookmarked: element - .expect_field_by_name::<Smart<bool>>("bookmarked") - .unwrap_or_else(|| element.expect_field_by_name::<bool>("outlined")), + .bookmarked(StyleChain::default()) + .unwrap_or_else(|| element.outlined(StyleChain::default())), element, children: Vec::new(), } @@ -157,7 +159,7 @@ fn write_outline_item( outline.count(-(node.children.len() as i32)); } - let body = node.element.expect_field_by_name::<Content>("body"); + let body = node.element.body(); outline.title(TextStr(body.plain_text().trim())); let loc = node.element.location().unwrap(); diff --git a/crates/typst/src/foundations/cast.rs b/crates/typst/src/foundations/cast.rs index e3b7dd01..2f7e1dad 100644 --- a/crates/typst/src/foundations/cast.rs +++ b/crates/typst/src/foundations/cast.rs @@ -9,7 +9,7 @@ use smallvec::SmallVec; use unicode_math_class::MathClass; use crate::diag::{At, SourceResult, StrResult}; -use crate::foundations::{repr, Repr, Type, Value}; +use crate::foundations::{repr, NativeElement, Packed, Repr, Type, Value}; use crate::syntax::{Span, Spanned}; #[rustfmt::skip] @@ -84,6 +84,20 @@ impl<T: Reflect> Reflect for Spanned<T> { } } +impl<T: NativeElement + Reflect> Reflect for Packed<T> { + fn input() -> CastInfo { + T::input() + } + + fn output() -> CastInfo { + T::output() + } + + fn castable(value: &Value) -> bool { + T::castable(value) + } +} + impl<T: Reflect> Reflect for Prehashed<T> { fn input() -> CastInfo { T::input() @@ -174,6 +188,12 @@ impl<T: IntoValue + Clone> IntoValue for Cow<'_, T> { } } +impl<T: NativeElement + IntoValue> IntoValue for Packed<T> { + fn into_value(self) -> Value { + Value::Content(self.pack()) + } +} + impl<T: IntoValue> IntoValue for Spanned<T> { fn into_value(self) -> Value { self.v.into_value() @@ -233,6 +253,19 @@ impl FromValue for Value { } } +impl<T: NativeElement + FromValue> FromValue for Packed<T> { + fn from_value(mut value: Value) -> StrResult<Self> { + if let Value::Content(content) = value { + match content.to_packed::<T>() { + Ok(packed) => return Ok(packed), + Err(content) => value = Value::Content(content), + } + } + let val = T::from_value(value)?; + Ok(Packed::new(val)) + } +} + impl<T: FromValue + Hash + 'static> FromValue for Prehashed<T> { fn from_value(value: Value) -> StrResult<Self> { Ok(Self::new(T::from_value(value)?)) diff --git a/crates/typst/src/foundations/content.rs b/crates/typst/src/foundations/content.rs index a0cb45cf..3ba458af 100644 --- a/crates/typst/src/foundations/content.rs +++ b/crates/typst/src/foundations/content.rs @@ -1,7 +1,9 @@ use std::any::TypeId; use std::fmt::{self, Debug, Formatter}; +use std::hash::{Hash, Hasher}; use std::iter::{self, Sum}; -use std::ops::{Add, AddAssign}; +use std::marker::PhantomData; +use std::ops::{Add, AddAssign, Deref, DerefMut}; use std::sync::Arc; use comemo::Prehashed; @@ -12,10 +14,10 @@ use smallvec::smallvec; use crate::diag::{SourceResult, StrResult}; use crate::engine::Engine; use crate::foundations::{ - elem, func, scope, ty, Dict, Element, FromValue, Guard, IntoValue, Label, - NativeElement, Recipe, Repr, Selector, Str, Style, Styles, Value, + elem, func, scope, ty, Dict, Element, Fields, Guard, IntoValue, Label, NativeElement, + Recipe, Repr, Selector, Str, Style, Styles, Synthesize, Value, }; -use crate::introspection::{Location, Meta, MetaElem}; +use crate::introspection::{Locatable, Location, Meta, MetaElem}; use crate::layout::{AlignElem, Alignment, Axes, Length, MoveElem, PadElem, Rel, Sides}; use crate::model::{Destination, EmphElem, StrongElem}; use crate::syntax::Span; @@ -68,12 +70,34 @@ use crate::util::fat; #[ty(scope, cast)] #[derive(Clone, Hash)] #[allow(clippy::derived_hash_with_manual_eq)] -pub struct Content(Arc<dyn NativeElement>); +pub struct Content { + inner: Arc<Inner<dyn Bounds>>, + span: Span, +} + +/// The inner representation behind the `Arc`. +#[derive(Hash)] +struct Inner<T: ?Sized> { + label: Option<Label>, + location: Option<Location>, + prepared: bool, + guards: Vec<Guard>, + elem: T, +} impl Content { /// Creates a new content from an element. - pub fn new<E: NativeElement>(elem: E) -> Self { - Self(Arc::new(elem)) + pub fn new<T: NativeElement>(elem: T) -> Self { + Self { + inner: Arc::new(Inner { + label: None, + location: None, + prepared: false, + guards: vec![], + elem, + }), + span: Span::detached(), + } } /// Creates a new empty sequence content. @@ -83,65 +107,70 @@ impl Content { /// Get the element of this content. pub fn elem(&self) -> Element { - self.0.dyn_elem() + self.inner.elem.dyn_elem() } /// Get the span of the content. pub fn span(&self) -> Span { - self.0.span() + self.span } /// Set the span of the content. pub fn spanned(mut self, span: Span) -> Self { - self.make_mut().set_span(span); + if self.span.is_detached() { + self.span = span; + } self } /// Get the label of the content. pub fn label(&self) -> Option<Label> { - self.0.label() + self.inner.label } /// Set the label of the content. pub fn labelled(mut self, label: Label) -> Self { - self.make_mut().set_label(label); + self.make_mut().label = Some(label); self } /// Set the location of the content. pub fn set_location(&mut self, location: Location) { - self.make_mut().set_location(location); + self.make_mut().location = Some(location); } /// Disable a show rule recipe. pub fn guarded(mut self, guard: Guard) -> Self { - self.make_mut().push_guard(guard); - self.0.into() + self.make_mut().guards.push(guard); + self } /// Whether the content needs to be realized specially. pub fn needs_preparation(&self) -> bool { - self.0.needs_preparation() + (self.can::<dyn Locatable>() + || self.can::<dyn Synthesize>() + || self.label().is_some()) + && !self.inner.prepared } /// Check whether a show rule recipe is disabled. pub fn is_guarded(&self, guard: Guard) -> bool { - self.0.is_guarded(guard) + self.inner.guards.contains(&guard) } /// Whether no show rule was executed for this content so far. pub fn is_pristine(&self) -> bool { - self.0.is_pristine() + self.inner.guards.is_empty() } /// Whether this content has already been prepared. pub fn is_prepared(&self) -> bool { - self.0.is_prepared() + self.inner.prepared } /// Mark this content as prepared. pub fn mark_prepared(&mut self) { - self.make_mut().mark_prepared(); + self.make_mut().prepared = true; } /// Get a field by ID. @@ -150,7 +179,12 @@ impl Content { /// if you have set the field IDs yourself or are using the field IDs /// generated by the `#[elem]` macro. pub fn get(&self, id: u8) -> Option<Value> { - self.0.field(id) + if id == 255 { + if let Some(label) = self.label() { + return Some(label.into_value()); + } + } + self.inner.elem.field(id) } /// Get a field by name. @@ -158,6 +192,11 @@ impl Content { /// If you have access to the field IDs of the element, use [`Self::get`] /// instead. pub fn get_by_name(&self, name: &str) -> Option<Value> { + if name == "label" { + if let Some(label) = self.label() { + return Some(label.into_value()); + } + } let id = self.elem().field_id(name)?; self.get(id) } @@ -178,26 +217,7 @@ impl Content { /// If you have access to the field IDs of the element, use [`Self::field`] /// instead. pub fn field_by_name(&self, name: &str) -> StrResult<Value> { - let id = self.elem().field_id(name).ok_or_else(|| missing_field(name))?; - self.field(id) - } - - /// Expect a field on the content to exist as a specified type. - #[track_caller] - pub fn expect_field<T: FromValue>(&self, id: u8) -> T { - self.field(id).unwrap().cast().unwrap() - } - - /// Expect a field on the content to exist as a specified type. - #[track_caller] - pub fn expect_field_by_name<T: FromValue>(&self, name: &str) -> T { - self.field_by_name(name).unwrap().cast().unwrap() - } - - /// Set a field to the content. - pub fn with_field(mut self, id: u8, value: impl IntoValue) -> Self { - self.make_mut().set_field(id, value.into_value()).unwrap(); - self + self.get_by_name(name).ok_or_else(|| missing_field(name)) } /// Create a new sequence element from multiples elements. @@ -214,18 +234,34 @@ impl Content { .into() } - /// Access the children if this is a sequence. - pub fn to_sequence(&self) -> Option<impl Iterator<Item = &Prehashed<Content>>> { - let Some(sequence) = self.to::<SequenceElem>() else { - return None; - }; + /// Whether the contained element is of type `T`. + pub fn is<T: NativeElement>(&self) -> bool { + self.inner.elem.dyn_type_id() == TypeId::of::<T>() + } - Some(sequence.children.iter()) + /// Downcasts the element to a packed value. + pub fn to<T: NativeElement>(&self) -> Option<&Packed<T>> { + Packed::from_ref(self) } - /// Whether the contained element is of type `T`. - pub fn is<T: NativeElement>(&self) -> bool { - self.elem() == T::elem() + /// Downcasts the element to a mutable packed value. + pub fn to_mut<T: NativeElement>(&mut self) -> Option<&mut Packed<T>> { + Packed::from_mut(self) + } + + /// Downcasts the element into an owned packed value. + pub fn to_packed<T: NativeElement>(self) -> Result<Packed<T>, Self> { + Packed::from_owned(self) + } + + /// Makes sure the content is not shared and returns a mutable reference to + /// the inner data. + fn make_mut(&mut self) -> &mut Inner<dyn Bounds> { + let arc = &mut self.inner; + if Arc::strong_count(arc) > 1 || Arc::weak_count(arc) > 0 { + *self = arc.elem.dyn_clone(arc, self.span); + } + Arc::get_mut(&mut self.inner).unwrap() } /// Whether the contained element has the given capability. @@ -236,20 +272,18 @@ impl Content { self.elem().can::<C>() } - /// Whether the contained element has the given capability where the - /// capability is given by a `TypeId`. - pub fn can_type_id(&self, type_id: TypeId) -> bool { - self.elem().can_type_id(type_id) - } - /// Cast to a trait object if the contained element has the given /// capability. pub fn with<C>(&self) -> Option<&C> where C: ?Sized + 'static, { + // Safety: The vtable comes from the `Capable` implementation which + // guarantees to return a matching vtable for `Packed<T>` and `C`. + // Since any `Packed<T>` is a repr(transparent) `Content`, we can also + // use a `*const Content` pointer. let vtable = self.elem().vtable()(TypeId::of::<C>())?; - let data = Arc::as_ptr(&self.0) as *const (); + let data = self as *const Content as *const (); Some(unsafe { &*fat::from_raw_parts(data, vtable) }) } @@ -259,17 +293,20 @@ impl Content { where C: ?Sized + 'static, { - // Safety: We ensure the element is not shared. + // Safety: The vtable comes from the `Capable` implementation which + // guarantees to return a matching vtable for `Packed<T>` and `C`. + // Since any `Packed<T>` is a repr(transparent) `Content`, we can also + // use a `*const Content` pointer. + // + // The resulting trait object contains an `&mut Packed<T>`. We do _not_ + // need to ensure that we hold the only reference to the `Arc` here + // because `Packed<T>`'s DerefMut impl will take care of that if + // mutable access is required. let vtable = self.elem().vtable()(TypeId::of::<C>())?; - let data = self.make_mut() as *mut dyn NativeElement as *mut (); + let data = self as *mut Content as *mut (); Some(unsafe { &mut *fat::from_raw_parts_mut(data, vtable) }) } - /// Whether the content is a sequence. - pub fn is_sequence(&self) -> bool { - self.is::<SequenceElem>() - } - /// Whether the content is an empty sequence. pub fn is_empty(&self) -> bool { let Some(sequence) = self.to::<SequenceElem>() else { @@ -279,6 +316,17 @@ impl Content { sequence.children.is_empty() } + /// Whether the content is a sequence. + pub fn is_sequence(&self) -> bool { + self.is::<SequenceElem>() + } + + /// Access the children if this is a sequence. + pub fn to_sequence(&self) -> Option<impl Iterator<Item = &Prehashed<Content>>> { + let sequence = self.to::<SequenceElem>()?; + Some(sequence.children.iter()) + } + /// Also auto expands sequence of sequences into flat sequence pub fn sequence_recursive_for_each(&self, f: &mut impl FnMut(&Self)) { if let Some(children) = self.to_sequence() { @@ -383,7 +431,8 @@ impl Content { { f(self.clone()); - self.0 + self.inner + .elem .fields() .into_iter() .for_each(|(_, value)| walk_value(value, f)); @@ -404,47 +453,6 @@ impl Content { } } } - - /// Downcasts the element to the specified type. - pub fn to<T: NativeElement>(&self) -> Option<&T> { - // Early check for performance. - if !self.is::<T>() { - return None; - } - - self.0.as_any().downcast_ref() - } - - /// Downcasts mutably the element to the specified type. - pub fn to_mut<T: NativeElement>(&mut self) -> Option<&mut T> { - // Early check for performance. - if !self.is::<T>() { - return None; - } - - self.make_mut().as_any_mut().downcast_mut() - } - - /// Downcast the element into an owned value. - pub fn unpack<T: NativeElement>(self) -> Option<Arc<T>> { - // Early check for performance. - if !self.is::<T>() { - return None; - } - - Arc::downcast(self.0.into_any()).ok() - } - - /// Makes sure the content is not shared and returns a mutable reference to - /// the inner element. - fn make_mut(&mut self) -> &mut dyn NativeElement { - let arc = &mut self.0; - if Arc::strong_count(arc) > 1 || Arc::weak_count(arc) > 0 { - *arc = arc.dyn_clone(); - } - - Arc::get_mut(arc).unwrap() - } } impl Content { @@ -517,11 +525,15 @@ impl Content { /// The field to look for. field: Str, ) -> bool { + if field.as_str() == "label" { + return self.label().is_some(); + } + let Some(id) = self.elem().field_id(&field) else { return false; }; - self.0.has(id) + self.inner.elem.has(id) } /// Access the specified field on the content. Returns the default value if @@ -536,11 +548,7 @@ impl Content { #[named] default: Option<Value>, ) -> StrResult<Value> { - let Some(id) = self.elem().field_id(&field) else { - return default.ok_or_else(|| missing_field_no_default(&field)); - }; - - self.get(id) + self.get_by_name(&field) .or(default) .ok_or_else(|| missing_field_no_default(&field)) } @@ -555,7 +563,11 @@ impl Content { /// ``` #[func] pub fn fields(&self) -> Dict { - self.0.fields() + let mut dict = self.inner.elem.fields(); + if let Some(label) = self.label() { + dict.insert("label".into(), label.into_value()); + } + dict } /// The location of the content. This is only available on content returned @@ -565,7 +577,7 @@ impl Content { /// [counters]($counter), [state]($state) and [queries]($query). #[func] pub fn location(&self) -> Option<Location> { - self.0.location() + self.inner.location } } @@ -577,7 +589,7 @@ impl Default for Content { impl Debug for Content { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - self.0.fmt(f) + self.inner.elem.fmt(f) } } @@ -587,22 +599,16 @@ impl<T: NativeElement> From<T> for Content { } } -impl From<Arc<dyn NativeElement>> for Content { - fn from(value: Arc<dyn NativeElement>) -> Self { - Self(value) - } -} - impl PartialEq for Content { fn eq(&self, other: &Self) -> bool { // Additional short circuit for different elements. - self.elem() == other.elem() && self.0.dyn_eq(other) + self.elem() == other.elem() && self.inner.elem.dyn_eq(other) } } impl Repr for Content { fn repr(&self) -> EcoString { - self.0.repr() + self.inner.elem.repr() } } @@ -686,23 +692,199 @@ impl Serialize for Content { } } -/// Defines the `ElemFunc` for sequences. +/// The trait that combines all the other traits into a trait object. +trait Bounds: Debug + Repr + Fields + Send + Sync + 'static { + fn dyn_type_id(&self) -> TypeId; + fn dyn_elem(&self) -> Element; + fn dyn_clone(&self, inner: &Inner<dyn Bounds>, span: Span) -> Content; + fn dyn_hash(&self, hasher: &mut dyn Hasher); + fn dyn_eq(&self, other: &Content) -> bool; +} + +impl<T: NativeElement> Bounds for T { + fn dyn_type_id(&self) -> TypeId { + TypeId::of::<Self>() + } + + fn dyn_elem(&self) -> Element { + Self::elem() + } + + fn dyn_clone(&self, inner: &Inner<dyn Bounds>, span: Span) -> Content { + Content { + inner: Arc::new(Inner { + label: inner.label, + location: inner.location, + prepared: inner.prepared, + guards: inner.guards.clone(), + elem: self.clone(), + }), + span, + } + } + + fn dyn_hash(&self, mut state: &mut dyn Hasher) { + TypeId::of::<Self>().hash(&mut state); + self.hash(&mut state); + } + + fn dyn_eq(&self, other: &Content) -> bool { + let Some(other) = other.to::<Self>() else { + return false; + }; + *self == **other + } +} + +impl Hash for dyn Bounds { + fn hash<H: Hasher>(&self, state: &mut H) { + self.dyn_hash(state); + } +} + +/// A packed element of a static type. +#[derive(Clone, PartialEq, Hash)] +#[repr(transparent)] +pub struct Packed<T: NativeElement>( + /// Invariant: Must be of type `T`. + Content, + PhantomData<T>, +); + +impl<T: NativeElement> Packed<T> { + /// Pack element while retaining its static type. + pub fn new(element: T) -> Self { + // Safety: The element is known to be of type `T`. + Packed(element.pack(), PhantomData) + } + + /// Try to cast type-erased content into a statically known packed element. + pub fn from_ref(content: &Content) -> Option<&Self> { + if content.is::<T>() { + // Safety: + // - We have checked the type. + // - Packed<T> is repr(transparent). + return Some(unsafe { std::mem::transmute(content) }); + } + None + } + + /// Try to cast type-erased content into a statically known packed element. + pub fn from_mut(content: &mut Content) -> Option<&mut Self> { + if content.is::<T>() { + // Safety: + // - We have checked the type. + // - Packed<T> is repr(transparent). + return Some(unsafe { std::mem::transmute(content) }); + } + None + } + + /// Try to cast type-erased content into a statically known packed element. + pub fn from_owned(content: Content) -> Result<Self, Content> { + if content.is::<T>() { + // Safety: + // - We have checked the type. + // - Packed<T> is repr(transparent). + return Ok(unsafe { std::mem::transmute(content) }); + } + Err(content) + } + + /// Pack back into content. + pub fn pack(self) -> Content { + self.0 + } + + /// Extract the raw underlying element. + pub fn unpack(self) -> T { + // This function doesn't yet need owned self, but might in the future. + (*self).clone() + } + + /// The element's span. + pub fn span(&self) -> Span { + self.0.span() + } + + /// Set the span of the element. + pub fn spanned(self, span: Span) -> Self { + Self(self.0.spanned(span), PhantomData) + } + + /// Accesses the label of the element. + pub fn label(&self) -> Option<Label> { + self.0.label() + } + + /// Accesses the location of the element. + pub fn location(&self) -> Option<Location> { + self.0.location() + } + + /// Sets the location of the element. + pub fn set_location(&mut self, location: Location) { + self.0.set_location(location); + } +} + +impl<T: NativeElement> AsRef<T> for Packed<T> { + fn as_ref(&self) -> &T { + self + } +} + +impl<T: NativeElement> AsMut<T> for Packed<T> { + fn as_mut(&mut self) -> &mut T { + self + } +} + +impl<T: NativeElement> Deref for Packed<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + // Safety: + // - Packed<T> guarantees that the content trait object wraps + // an element of type `T`. + // - This downcast works the same way as dyn Any's does. We can't reuse + // that one because we don't want to pay the cost for every deref. + let elem = &self.0.inner.elem; + unsafe { &*(elem as *const dyn Bounds as *const T) } + } +} + +impl<T: NativeElement> DerefMut for Packed<T> { + fn deref_mut(&mut self) -> &mut Self::Target { + // Safety: + // - Packed<T> guarantees that the content trait object wraps + // an element of type `T`. + // - We have guaranteed unique access thanks to `make_mut`. + // - This downcast works the same way as dyn Any's does. We can't reuse + // that one because we don't want to pay the cost for every deref. + let elem = &mut self.0.make_mut().elem; + unsafe { &mut *(elem as *mut dyn Bounds as *mut T) } + } +} + +impl<T: NativeElement + Debug> Debug for Packed<T> { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + self.0.fmt(f) + } +} + +/// Defines the element for sequences. #[elem(Repr, PartialEq)] struct SequenceElem { #[required] children: Vec<Prehashed<Content>>, } +// Derive is currently incompatible with `elem` macro. +#[allow(clippy::derivable_impls)] impl Default for SequenceElem { fn default() -> Self { - Self { - span: Span::detached(), - location: Default::default(), - label: Default::default(), - prepared: Default::default(), - guards: Default::default(), - children: Default::default(), - } + Self { children: Default::default() } } } @@ -723,7 +905,11 @@ impl Repr for SequenceElem { eco_format!( "[{}]", crate::foundations::repr::pretty_array_like( - &self.children.iter().map(|c| c.0.repr()).collect::<Vec<_>>(), + &self + .children + .iter() + .map(|c| c.inner.elem.repr()) + .collect::<Vec<_>>(), false ) ) @@ -748,7 +934,7 @@ impl PartialEq for StyledElem { impl Repr for StyledElem { fn repr(&self) -> EcoString { - eco_format!("styled(child: {}, ..)", self.child.0.repr()) + eco_format!("styled(child: {}, ..)", self.child.repr()) } } diff --git a/crates/typst/src/foundations/element.rs b/crates/typst/src/foundations/element.rs index 301a4003..665aa8ef 100644 --- a/crates/typst/src/foundations/element.rs +++ b/crates/typst/src/foundations/element.rs @@ -1,22 +1,19 @@ -use std::any::{Any, TypeId}; +use std::any::TypeId; use std::borrow::Cow; use std::cmp::Ordering; use std::fmt::{self, Debug}; -use std::hash::{Hash, Hasher}; -use std::sync::Arc; +use std::hash::Hash; use ecow::EcoString; use once_cell::sync::Lazy; use smallvec::SmallVec; -use crate::diag::{SourceResult, StrResult}; +use crate::diag::SourceResult; use crate::engine::Engine; use crate::foundations::{ - cast, Args, Content, Dict, Func, Label, ParamInfo, Repr, Scope, Selector, StyleChain, + cast, Args, Content, Dict, Func, ParamInfo, Repr, Scope, Selector, StyleChain, Styles, Value, }; -use crate::introspection::Location; -use crate::syntax::Span; use crate::text::{Lang, Region}; use crate::util::Static; @@ -35,11 +32,17 @@ impl Element { /// Extract the field ID for the given field name. pub fn field_id(&self, name: &str) -> Option<u8> { + if name == "label" { + return Some(255); + } (self.0.field_id)(name) } /// Extract the field name for the given field ID. pub fn field_name(&self, id: u8) -> Option<&'static str> { + if id == 255 { + return Some("label"); + } (self.0.field_name)(id) } @@ -163,7 +166,20 @@ pub trait ElementFields { } /// A Typst element that is defined by a native Rust type. -pub trait NativeElement: Debug + Repr + Construct + Set + Send + Sync + 'static { +pub trait NativeElement: + Debug + + Clone + + PartialEq + + Hash + + Construct + + Set + + Capable + + Fields + + Repr + + Send + + Sync + + 'static +{ /// Get the element for the native Rust element. fn elem() -> Element where @@ -184,103 +200,31 @@ pub trait NativeElement: Debug + Repr + Construct + Set + Send + Sync + 'static fn data() -> &'static NativeElementData where Self: Sized; +} - /// Get the element data for the native Rust element. - fn dyn_elem(&self) -> Element; - - /// Dynamically hash the element. - fn dyn_hash(&self, hasher: &mut dyn Hasher); - - /// Dynamically compare the element. - fn dyn_eq(&self, other: &Content) -> bool; - - /// Dynamically clone the element. - fn dyn_clone(&self) -> Arc<dyn NativeElement>; - - /// Get the element as a dynamic value. - fn as_any(&self) -> &dyn Any; - - /// Get the element as a mutable dynamic value. - fn as_any_mut(&mut self) -> &mut dyn Any; - - /// Get the element as a dynamic value. - fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>; - - /// Get the element's span. - /// - /// May be detached if it has not been set. - fn span(&self) -> Span; - - /// Sets the span of this element. - fn set_span(&mut self, span: Span); - - /// Set the element's span. - fn spanned(mut self, span: Span) -> Self - where - Self: Sized, - { - self.set_span(span); - self - } - - /// Get the element's label. - fn label(&self) -> Option<Label>; - - /// Sets the label of this element. - fn set_label(&mut self, label: Label); - - /// Set the element's label. - fn labelled(mut self, label: Label) -> Self - where - Self: Sized, - { - self.set_label(label); - self - } - - /// Get the element's location. - fn location(&self) -> Option<Location>; - - /// Sets the location of this element. - fn set_location(&mut self, location: Location); - - /// Checks whether the element is guarded by the given guard. - fn is_guarded(&self, guard: Guard) -> bool; - - /// Pushes a guard onto the element. - fn push_guard(&mut self, guard: Guard); - - /// Whether the element is pristine. - fn is_pristine(&self) -> bool; - - /// Mark the element as having been prepared. - fn mark_prepared(&mut self); - - /// Whether this element needs preparations. - fn needs_preparation(&self) -> bool; - - /// Whether this element has been prepared. - fn is_prepared(&self) -> bool; - - /// Get the field with the given field ID. - fn field(&self, id: u8) -> Option<Value>; +/// Used to cast an element to a trait object for a trait it implements. +/// +/// # Safety +/// If the `vtable` function returns `Some(p)`, then `p` must be a valid pointer +/// to a vtable of `Packed<Self>` w.r.t to the trait `C` where `capability` is +/// `TypeId::of::<dyn C>()`. +pub unsafe trait Capable { + /// Get the pointer to the vtable for the given capability / trait. + fn vtable(capability: TypeId) -> Option<*const ()>; +} +/// Defines how fields of an element are accessed. +pub trait Fields { /// Whether the element has the given field set. fn has(&self, id: u8) -> bool; - /// Set the field with the given ID. - fn set_field(&mut self, id: u8, value: Value) -> StrResult<()>; + /// Get the field with the given field ID. + fn field(&self, id: u8) -> Option<Value>; /// Get the fields of the element. fn fields(&self) -> Dict; } -impl Hash for dyn NativeElement { - fn hash<H: Hasher>(&self, state: &mut H) { - self.dyn_hash(state); - } -} - /// An element's constructor function. pub trait Construct { /// Construct an element from the arguments. @@ -309,7 +253,7 @@ pub struct NativeElementData { pub keywords: &'static [&'static str], pub construct: fn(&mut Engine, &mut Args) -> SourceResult<Content>, pub set: fn(&mut Engine, &mut Args) -> SourceResult<Styles>, - pub vtable: fn(of: TypeId) -> Option<*const ()>, + pub vtable: fn(capability: TypeId) -> Option<*const ()>, pub field_id: fn(name: &str) -> Option<u8>, pub field_name: fn(u8) -> Option<&'static str>, pub local_name: Option<fn(Lang, Option<Region>) -> &'static str>, diff --git a/crates/typst/src/foundations/styles.rs b/crates/typst/src/foundations/styles.rs index 771a3d2c..b2287c2d 100644 --- a/crates/typst/src/foundations/styles.rs +++ b/crates/typst/src/foundations/styles.rs @@ -12,7 +12,8 @@ use smallvec::SmallVec; use crate::diag::{SourceResult, Trace, Tracepoint}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, func, ty, Content, Element, Func, NativeElement, Repr, Selector, Show, + cast, elem, func, ty, Content, Element, Func, NativeElement, Packed, Repr, Selector, + Show, }; use crate::syntax::Span; use crate::text::{FontFamily, FontList, TextElem}; @@ -45,7 +46,7 @@ pub fn style( /// content that depends on the style context it appears in. func: Func, ) -> Content { - StyleElem::new(func).spanned(span).pack() + StyleElem::new(func).pack().spanned(span) } /// Executes a style access. @@ -56,7 +57,7 @@ struct StyleElem { func: Func, } -impl Show for StyleElem { +impl Show for Packed<StyleElem> { #[typst_macros::time(name = "style", span = self.span())] fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self.func().call(engine, [styles.to_map()])?.display()) diff --git a/crates/typst/src/introspection/counter.rs b/crates/typst/src/introspection/counter.rs index 0f319fab..e4bb282f 100644 --- a/crates/typst/src/introspection/counter.rs +++ b/crates/typst/src/introspection/counter.rs @@ -10,8 +10,8 @@ use crate::engine::{Engine, Route}; use crate::eval::Tracer; use crate::foundations::{ cast, elem, func, scope, select_where, ty, Array, Content, Element, Func, IntoValue, - Label, LocatableSelector, NativeElement, Repr, Selector, Show, Str, StyleChain, - Value, + Label, LocatableSelector, NativeElement, Packed, Repr, Selector, Show, Str, + StyleChain, Value, }; use crate::introspection::{Introspector, Locatable, Location, Locator, Meta}; use crate::layout::{Frame, FrameItem, PageElem}; @@ -372,7 +372,7 @@ impl Counter { #[default(false)] both: bool, ) -> Content { - DisplayElem::new(self, numbering, both).spanned(span).pack() + DisplayElem::new(self, numbering, both).pack().spanned(span) } /// Increases the value of the counter by one. @@ -411,7 +411,7 @@ impl Counter { /// return the new value (integer or array). update: CounterUpdate, ) -> Content { - UpdateElem::new(self.0, update).spanned(span).pack() + UpdateElem::new(self.0, update).pack().spanned(span) } /// Gets the value of the counter at the given location. Always returns an @@ -632,7 +632,7 @@ struct DisplayElem { both: bool, } -impl Show for DisplayElem { +impl Show for Packed<DisplayElem> { #[typst_macros::time(name = "counter.display", span = self.span())] fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(engine.delayed(|engine| { @@ -681,13 +681,13 @@ struct UpdateElem { update: CounterUpdate, } -impl Show for UpdateElem { +impl Show for Packed<UpdateElem> { fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(Content::empty()) } } -impl Count for UpdateElem { +impl Count for Packed<UpdateElem> { fn update(&self) -> Option<CounterUpdate> { Some(self.update.clone()) } @@ -726,7 +726,7 @@ impl ManualPageCounter { let Some(elem) = elem.to::<UpdateElem>() else { continue }; if *elem.key() == CounterKey::Page { let mut state = CounterState(smallvec![self.logical]); - state.update(engine, elem.update().clone())?; + state.update(engine, elem.update.clone())?; self.logical = state.first(); } } diff --git a/crates/typst/src/introspection/locate.rs b/crates/typst/src/introspection/locate.rs index 4cec04c9..132714f1 100644 --- a/crates/typst/src/introspection/locate.rs +++ b/crates/typst/src/introspection/locate.rs @@ -1,6 +1,8 @@ use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{elem, func, Content, Func, NativeElement, Show, StyleChain}; +use crate::foundations::{ + elem, func, Content, Func, NativeElement, Packed, Show, StyleChain, +}; use crate::introspection::Locatable; use crate::syntax::Span; @@ -28,7 +30,7 @@ pub fn locate( /// content that depends on its own location in the document. func: Func, ) -> Content { - LocateElem::new(func).spanned(span).pack() + LocateElem::new(func).pack().spanned(span) } /// Executes a `locate` call. @@ -39,7 +41,7 @@ struct LocateElem { func: Func, } -impl Show for LocateElem { +impl Show for Packed<LocateElem> { #[typst_macros::time(name = "locate", span = self.span())] fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(engine.delayed(|engine| { diff --git a/crates/typst/src/introspection/metadata.rs b/crates/typst/src/introspection/metadata.rs index 15d144eb..d66441a2 100644 --- a/crates/typst/src/introspection/metadata.rs +++ b/crates/typst/src/introspection/metadata.rs @@ -1,6 +1,8 @@ use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{elem, Behave, Behaviour, Content, Show, StyleChain, Value}; +use crate::foundations::{ + elem, Behave, Behaviour, Content, Packed, Show, StyleChain, Value, +}; use crate::introspection::Locatable; /// Exposes a value to the query system without producing visible content. @@ -30,13 +32,13 @@ pub struct MetadataElem { pub value: Value, } -impl Show for MetadataElem { +impl Show for Packed<MetadataElem> { fn show(&self, _: &mut Engine, _styles: StyleChain) -> SourceResult<Content> { Ok(Content::empty()) } } -impl Behave for MetadataElem { +impl Behave for Packed<MetadataElem> { fn behaviour(&self) -> Behaviour { Behaviour::Invisible } diff --git a/crates/typst/src/introspection/mod.rs b/crates/typst/src/introspection/mod.rs index 86917891..e9ea0291 100644 --- a/crates/typst/src/introspection/mod.rs +++ b/crates/typst/src/introspection/mod.rs @@ -25,6 +25,7 @@ use std::fmt::{self, Debug, Formatter}; use ecow::{eco_format, EcoString}; use smallvec::SmallVec; +use crate::foundations::Packed; use crate::foundations::{ category, elem, ty, Behave, Behaviour, Category, Content, Repr, Scope, Unlabellable, }; @@ -61,9 +62,9 @@ pub struct MetaElem { pub data: SmallVec<[Meta; 1]>, } -impl Unlabellable for MetaElem {} +impl Unlabellable for Packed<MetaElem> {} -impl Behave for MetaElem { +impl Behave for Packed<MetaElem> { fn behaviour(&self) -> Behaviour { Behaviour::Invisible } diff --git a/crates/typst/src/introspection/state.rs b/crates/typst/src/introspection/state.rs index 3d050fb0..1f593549 100644 --- a/crates/typst/src/introspection/state.rs +++ b/crates/typst/src/introspection/state.rs @@ -5,8 +5,8 @@ use crate::diag::SourceResult; use crate::engine::{Engine, Route}; use crate::eval::Tracer; use crate::foundations::{ - cast, elem, func, scope, select_where, ty, Content, Func, NativeElement, Repr, - Selector, Show, Str, StyleChain, Value, + cast, elem, func, scope, select_where, ty, Content, Func, NativeElement, Packed, + Repr, Selector, Show, Str, StyleChain, Value, }; use crate::introspection::{Introspector, Locatable, Location, Locator}; use crate::syntax::Span; @@ -280,7 +280,7 @@ impl State { #[default] func: Option<Func>, ) -> Content { - DisplayElem::new(self, func).spanned(span).pack() + DisplayElem::new(self, func).pack().spanned(span) } /// Update the value of the state. @@ -301,7 +301,7 @@ impl State { /// to return the new state. update: StateUpdate, ) -> Content { - UpdateElem::new(self.key, update).spanned(span).pack() + UpdateElem::new(self.key, update).pack().spanned(span) } /// Get the value of the state at the given location. @@ -385,7 +385,7 @@ struct DisplayElem { func: Option<Func>, } -impl Show for DisplayElem { +impl Show for Packed<DisplayElem> { #[typst_macros::time(name = "state.display", span = self.span())] fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(engine.delayed(|engine| { @@ -411,7 +411,7 @@ struct UpdateElem { update: StateUpdate, } -impl Show for UpdateElem { +impl Show for Packed<UpdateElem> { fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(Content::empty()) } diff --git a/crates/typst/src/layout/align.rs b/crates/typst/src/layout/align.rs index a1f2a553..3dbba643 100644 --- a/crates/typst/src/layout/align.rs +++ b/crates/typst/src/layout/align.rs @@ -5,7 +5,7 @@ use ecow::{eco_format, EcoString}; use crate::diag::{bail, SourceResult, StrResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, func, scope, ty, Content, Fold, Repr, Resolve, Show, StyleChain, + cast, elem, func, scope, ty, Content, Fold, Packed, Repr, Resolve, Show, StyleChain, }; use crate::layout::{Abs, Axes, Axis, Dir, Side}; use crate::text::TextElem; @@ -45,13 +45,13 @@ pub struct AlignElem { pub body: Content, } -impl Show for AlignElem { +impl Show for Packed<AlignElem> { #[typst_macros::time(name = "align", span = self.span())] fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self .body() .clone() - .styled(Self::set_alignment(self.alignment(styles)))) + .styled(AlignElem::set_alignment(self.alignment(styles)))) } } diff --git a/crates/typst/src/layout/columns.rs b/crates/typst/src/layout/columns.rs index 4ec8e56e..88b459f2 100644 --- a/crates/typst/src/layout/columns.rs +++ b/crates/typst/src/layout/columns.rs @@ -2,7 +2,7 @@ use std::num::NonZeroUsize; use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{elem, Behave, Behaviour, Content, StyleChain}; +use crate::foundations::{elem, Behave, Behaviour, Content, Packed, StyleChain}; use crate::layout::{ Abs, Axes, Dir, Fragment, Frame, Layout, Length, Point, Ratio, Regions, Rel, Size, }; @@ -57,7 +57,7 @@ pub struct ColumnsElem { pub body: Content, } -impl Layout for ColumnsElem { +impl Layout for Packed<ColumnsElem> { #[typst_macros::time(name = "columns", span = self.span())] fn layout( &self, @@ -166,7 +166,7 @@ pub struct ColbreakElem { pub weak: bool, } -impl Behave for ColbreakElem { +impl Behave for Packed<ColbreakElem> { fn behaviour(&self) -> Behaviour { if self.weak(StyleChain::default()) { Behaviour::Weak(1) diff --git a/crates/typst/src/layout/container.rs b/crates/typst/src/layout/container.rs index f2d182ae..3905a37a 100644 --- a/crates/typst/src/layout/container.rs +++ b/crates/typst/src/layout/container.rs @@ -1,7 +1,7 @@ use crate::diag::SourceResult; use crate::engine::Engine; use crate::foundations::{ - cast, elem, AutoValue, Content, NativeElement, Resolve, Smart, StyleChain, Value, + cast, elem, AutoValue, Content, Packed, Resolve, Smart, StyleChain, Value, }; use crate::layout::{ Abs, Axes, Corners, Em, Fr, Fragment, FrameKind, Layout, Length, Ratio, Regions, Rel, @@ -109,7 +109,7 @@ pub struct BoxElem { pub body: Option<Content>, } -impl Layout for BoxElem { +impl Layout for Packed<BoxElem> { #[typst_macros::time(name = "box", span = self.span())] fn layout( &self, @@ -341,7 +341,7 @@ pub struct BlockElem { pub sticky: bool, } -impl Layout for BlockElem { +impl Layout for Packed<BlockElem> { #[typst_macros::time(name = "block", span = self.span())] fn layout( &self, diff --git a/crates/typst/src/layout/flow.rs b/crates/typst/src/layout/flow.rs index fd9350ac..65774c69 100644 --- a/crates/typst/src/layout/flow.rs +++ b/crates/typst/src/layout/flow.rs @@ -2,7 +2,9 @@ use comemo::Prehashed; use crate::diag::{bail, SourceResult}; use crate::engine::Engine; -use crate::foundations::{elem, Content, NativeElement, Resolve, Smart, StyleChain}; +use crate::foundations::{ + elem, Content, NativeElement, Packed, Resolve, Smart, StyleChain, +}; use crate::introspection::{Meta, MetaElem}; use crate::layout::{ Abs, AlignElem, Axes, BlockElem, ColbreakElem, ColumnsElem, FixedAlign, Fr, Fragment, @@ -27,7 +29,7 @@ pub struct FlowElem { pub children: Vec<Prehashed<Content>>, } -impl Layout for FlowElem { +impl Layout for Packed<FlowElem> { #[typst_macros::time(name = "flow", span = self.span())] fn layout( &self, @@ -207,7 +209,7 @@ impl<'a> FlowLayouter<'a> { fn layout_spacing( &mut self, engine: &mut Engine, - v: &VElem, + v: &Packed<VElem>, styles: StyleChain, ) -> SourceResult<()> { self.layout_item( @@ -226,7 +228,7 @@ impl<'a> FlowLayouter<'a> { fn layout_par( &mut self, engine: &mut Engine, - par: &ParElem, + par: &Packed<ParElem>, styles: StyleChain, ) -> SourceResult<()> { let align = AlignElem::alignment_in(styles).resolve(styles); @@ -299,7 +301,7 @@ impl<'a> FlowLayouter<'a> { fn layout_placed( &mut self, engine: &mut Engine, - placed: &PlaceElem, + placed: &Packed<PlaceElem>, styles: StyleChain, ) -> SourceResult<()> { let float = placed.float(styles); @@ -631,7 +633,7 @@ impl FlowLayouter<'_> { fn try_handle_footnotes( &mut self, engine: &mut Engine, - mut notes: Vec<FootnoteElem>, + mut notes: Vec<Packed<FootnoteElem>>, ) -> SourceResult<()> { if self.root && !self.handle_footnotes(engine, &mut notes, false, false)? { self.finish_region(engine, false)?; @@ -644,7 +646,7 @@ impl FlowLayouter<'_> { fn handle_footnotes( &mut self, engine: &mut Engine, - notes: &mut Vec<FootnoteElem>, + notes: &mut Vec<Packed<FootnoteElem>>, movable: bool, force: bool, ) -> SourceResult<bool> { @@ -735,7 +737,7 @@ impl FlowLayouter<'_> { } /// Finds all footnotes in the frame. -fn find_footnotes(notes: &mut Vec<FootnoteElem>, frame: &Frame) { +fn find_footnotes(notes: &mut Vec<Packed<FootnoteElem>>, frame: &Frame) { for (_, item) in frame.items() { match item { FrameItem::Group(group) => find_footnotes(notes, &group.frame), diff --git a/crates/typst/src/layout/grid/mod.rs b/crates/typst/src/layout/grid/mod.rs index 3b7c8553..fb82dbcf 100644 --- a/crates/typst/src/layout/grid/mod.rs +++ b/crates/typst/src/layout/grid/mod.rs @@ -9,8 +9,8 @@ use smallvec::{smallvec, SmallVec}; use crate::diag::{SourceResult, StrResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, scope, Array, Content, Fold, NativeElement, Show, Smart, StyleChain, - Value, + cast, elem, scope, Array, Content, Fold, NativeElement, Packed, Show, Smart, + StyleChain, Value, }; use crate::layout::{ Abs, AlignElem, Alignment, Axes, Fragment, Layout, Length, Regions, Rel, Sides, @@ -222,7 +222,7 @@ impl GridElem { type GridCell; } -impl Layout for GridElem { +impl Layout for Packed<GridElem> { #[typst_macros::time(name = "grid", span = self.span())] fn layout( &self, @@ -346,7 +346,7 @@ impl ResolvableCell for GridCell { } } -impl Show for GridCell { +impl Show for Packed<GridCell> { fn show(&self, _engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { show_grid_cell(self.body().clone(), self.inset(styles), self.align(styles)) } @@ -354,10 +354,10 @@ impl Show for GridCell { impl From<Content> for GridCell { fn from(value: Content) -> Self { - value - .to::<Self>() - .cloned() - .unwrap_or_else(|| Self::new(value.clone())) + match value.to_packed::<Self>() { + Ok(packed) => packed.unpack(), + Err(v) => Self::new(v), + } } } diff --git a/crates/typst/src/layout/hide.rs b/crates/typst/src/layout/hide.rs index 1b8b0efd..7a8618c1 100644 --- a/crates/typst/src/layout/hide.rs +++ b/crates/typst/src/layout/hide.rs @@ -2,7 +2,7 @@ use smallvec::smallvec; use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{elem, Content, Show, StyleChain}; +use crate::foundations::{elem, Content, Packed, Show, StyleChain}; use crate::introspection::{Meta, MetaElem}; /// Hides content without affecting layout. @@ -24,7 +24,7 @@ pub struct HideElem { pub body: Content, } -impl Show for HideElem { +impl Show for Packed<HideElem> { #[typst_macros::time(name = "hide", span = self.span())] fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(MetaElem::set_data(smallvec![Meta::Hide]))) diff --git a/crates/typst/src/layout/inline/mod.rs b/crates/typst/src/layout/inline/mod.rs index 20e6dcbc..7c243da3 100644 --- a/crates/typst/src/layout/inline/mod.rs +++ b/crates/typst/src/layout/inline/mod.rs @@ -13,7 +13,7 @@ use self::shaping::{ use crate::diag::{bail, SourceResult}; use crate::engine::{Engine, Route}; use crate::eval::Tracer; -use crate::foundations::{Content, Resolve, Smart, StyleChain}; +use crate::foundations::{Content, Packed, Resolve, Smart, StyleChain}; use crate::introspection::{Introspector, Locator, MetaElem}; use crate::layout::{ Abs, AlignElem, Axes, BoxElem, Dir, Em, FixedAlign, Fr, Fragment, Frame, HElem, @@ -189,9 +189,9 @@ enum Segment<'a> { /// Horizontal spacing between other segments. Spacing(Spacing), /// A mathematical equation. - Equation(&'a EquationElem, Vec<MathParItem>), + Equation(&'a Packed<EquationElem>, Vec<MathParItem>), /// A box with arbitrary content. - Box(&'a BoxElem, bool), + Box(&'a Packed<BoxElem>, bool), /// Metadata. Meta, } @@ -221,7 +221,7 @@ enum Item<'a> { /// Absolute spacing between other items. Absolute(Abs), /// Fractional spacing between other items. - Fractional(Fr, Option<(&'a BoxElem, StyleChain<'a>)>), + Fractional(Fr, Option<(&'a Packed<BoxElem>, StyleChain<'a>)>), /// Layouted inline-level content. Frame(Frame), /// Metadata. diff --git a/crates/typst/src/layout/layout.rs b/crates/typst/src/layout/layout.rs index 126fe067..6af3ac79 100644 --- a/crates/typst/src/layout/layout.rs +++ b/crates/typst/src/layout/layout.rs @@ -1,6 +1,8 @@ use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{dict, elem, func, Content, Func, NativeElement, StyleChain}; +use crate::foundations::{ + dict, elem, func, Content, Func, NativeElement, Packed, StyleChain, +}; use crate::layout::{Fragment, Layout, Regions, Size}; use crate::syntax::Span; @@ -57,7 +59,7 @@ pub fn layout( /// content that depends on the size of the container it is inside of. func: Func, ) -> Content { - LayoutElem::new(func).spanned(span).pack() + LayoutElem::new(func).pack().spanned(span) } /// Executes a `layout` call. @@ -68,7 +70,7 @@ struct LayoutElem { func: Func, } -impl Layout for LayoutElem { +impl Layout for Packed<LayoutElem> { #[typst_macros::time(name = "layout", span = self.span())] fn layout( &self, diff --git a/crates/typst/src/layout/pad.rs b/crates/typst/src/layout/pad.rs index 0a880b3b..0e44ab67 100644 --- a/crates/typst/src/layout/pad.rs +++ b/crates/typst/src/layout/pad.rs @@ -1,6 +1,6 @@ use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{elem, Content, Resolve, StyleChain}; +use crate::foundations::{elem, Content, Packed, Resolve, StyleChain}; use crate::layout::{Abs, Fragment, Layout, Length, Point, Regions, Rel, Sides, Size}; /// Adds spacing around content. @@ -58,7 +58,7 @@ pub struct PadElem { pub body: Content, } -impl Layout for PadElem { +impl Layout for Packed<PadElem> { #[typst_macros::time(name = "pad", span = self.span())] fn layout( &self, diff --git a/crates/typst/src/layout/page.rs b/crates/typst/src/layout/page.rs index a99920a8..c36be514 100644 --- a/crates/typst/src/layout/page.rs +++ b/crates/typst/src/layout/page.rs @@ -6,8 +6,8 @@ use std::str::FromStr; use crate::diag::{bail, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, AutoValue, Cast, Content, Dict, Fold, Func, NativeElement, Resolve, - Smart, StyleChain, Value, + cast, elem, AutoValue, Cast, Content, Dict, Fold, Func, NativeElement, Packed, + Resolve, Smart, StyleChain, Value, }; use crate::introspection::{Counter, CounterKey, ManualPageCounter, Meta}; use crate::layout::{ @@ -333,7 +333,7 @@ pub struct PageElem { pub clear_to: Option<Parity>, } -impl PageElem { +impl Packed<PageElem> { /// A document can consist of multiple `PageElem`s, one per run of pages /// with equal properties (not one per actual output page!). The `number` is /// the physical page number of the first page of this run. It is mutated @@ -385,9 +385,9 @@ impl PageElem { let columns = self.columns(styles); if columns.get() > 1 { child = ColumnsElem::new(child) - .spanned(self.span()) .with_count(columns) - .pack(); + .pack() + .spanned(self.span()); } let area = size - margin.sum_by_axis(); diff --git a/crates/typst/src/layout/place.rs b/crates/typst/src/layout/place.rs index 87dd2216..bc88550c 100644 --- a/crates/typst/src/layout/place.rs +++ b/crates/typst/src/layout/place.rs @@ -1,8 +1,6 @@ use crate::diag::{bail, At, Hint, SourceResult}; use crate::engine::Engine; -use crate::foundations::{ - elem, Behave, Behaviour, Content, NativeElement, Smart, StyleChain, -}; +use crate::foundations::{elem, Behave, Behaviour, Content, Packed, Smart, StyleChain}; use crate::layout::{ Alignment, Axes, Em, Fragment, Layout, Length, Regions, Rel, VAlignment, }; @@ -88,7 +86,7 @@ pub struct PlaceElem { pub body: Content, } -impl Layout for PlaceElem { +impl Layout for Packed<PlaceElem> { #[typst_macros::time(name = "place", span = self.span())] fn layout( &self, @@ -125,7 +123,7 @@ impl Layout for PlaceElem { } } -impl Behave for PlaceElem { +impl Behave for Packed<PlaceElem> { fn behaviour(&self) -> Behaviour { Behaviour::Ignorant } diff --git a/crates/typst/src/layout/repeat.rs b/crates/typst/src/layout/repeat.rs index f3018573..1fe21618 100644 --- a/crates/typst/src/layout/repeat.rs +++ b/crates/typst/src/layout/repeat.rs @@ -1,6 +1,6 @@ use crate::diag::{bail, SourceResult}; use crate::engine::Engine; -use crate::foundations::{elem, Content, NativeElement, Resolve, StyleChain}; +use crate::foundations::{elem, Content, Packed, Resolve, StyleChain}; use crate::layout::{ Abs, AlignElem, Axes, Fragment, Frame, Layout, Point, Regions, Size, }; @@ -34,7 +34,7 @@ pub struct RepeatElem { pub body: Content, } -impl Layout for RepeatElem { +impl Layout for Packed<RepeatElem> { #[typst_macros::time(name = "repeat", span = self.span())] fn layout( &self, diff --git a/crates/typst/src/layout/spacing.rs b/crates/typst/src/layout/spacing.rs index 1620c139..4e65fff2 100644 --- a/crates/typst/src/layout/spacing.rs +++ b/crates/typst/src/layout/spacing.rs @@ -1,6 +1,8 @@ use std::borrow::Cow; -use crate::foundations::{cast, elem, Behave, Behaviour, Content, Resolve, StyleChain}; +use crate::foundations::{ + cast, elem, Behave, Behaviour, Content, Packed, Resolve, StyleChain, +}; use crate::layout::{Abs, Em, Fr, Length, Ratio, Rel}; use crate::util::Numeric; @@ -62,7 +64,7 @@ impl HElem { } } -impl Behave for HElem { +impl Behave for Packed<HElem> { fn behaviour(&self) -> Behaviour { if self.amount().is_fractional() { Behaviour::Destructive @@ -78,7 +80,7 @@ impl Behave for HElem { prev: &(Cow<Content>, Behaviour, StyleChain), styles: StyleChain, ) -> bool { - let Some(other) = prev.0.to::<Self>() else { return false }; + let Some(other) = prev.0.to::<HElem>() else { return false }; match (self.amount(), other.amount()) { (Spacing::Fr(this), Spacing::Fr(other)) => this > other, (Spacing::Rel(this), Spacing::Rel(other)) => { @@ -164,7 +166,7 @@ impl VElem { } } -impl Behave for VElem { +impl Behave for Packed<VElem> { fn behaviour(&self) -> Behaviour { if self.amount().is_fractional() { Behaviour::Destructive @@ -180,7 +182,7 @@ impl Behave for VElem { prev: &(Cow<Content>, Behaviour, StyleChain), styles: StyleChain, ) -> bool { - let Some(other) = prev.0.to::<Self>() else { return false }; + let Some(other) = prev.0.to::<VElem>() else { return false }; match (self.amount(), other.amount()) { (Spacing::Fr(this), Spacing::Fr(other)) => this > other, (Spacing::Rel(this), Spacing::Rel(other)) => { @@ -193,7 +195,7 @@ impl Behave for VElem { cast! { VElem, - v: Content => v.to::<Self>().cloned().ok_or("expected `v` element")?, + v: Content => v.to_packed::<Self>().map_err(|_| "expected `v` element")?.unpack(), } /// Kinds of spacing. diff --git a/crates/typst/src/layout/stack.rs b/crates/typst/src/layout/stack.rs index be97e667..477105f7 100644 --- a/crates/typst/src/layout/stack.rs +++ b/crates/typst/src/layout/stack.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Debug, Formatter}; use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{cast, elem, Content, Resolve, StyleChain}; +use crate::foundations::{cast, elem, Content, Packed, Resolve, StyleChain}; use crate::layout::{ Abs, AlignElem, Axes, Axis, Dir, FixedAlign, Fr, Fragment, Frame, Layout, Point, Regions, Size, Spacing, @@ -51,7 +51,7 @@ pub struct StackElem { pub children: Vec<StackChild>, } -impl Layout for StackElem { +impl Layout for Packed<StackElem> { #[typst_macros::time(name = "stack", span = self.span())] fn layout( &self, diff --git a/crates/typst/src/layout/transform.rs b/crates/typst/src/layout/transform.rs index e0887193..527bad7c 100644 --- a/crates/typst/src/layout/transform.rs +++ b/crates/typst/src/layout/transform.rs @@ -1,6 +1,6 @@ use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{elem, Content, Resolve, StyleChain}; +use crate::foundations::{elem, Content, Packed, Resolve, StyleChain}; use crate::layout::{ Abs, Alignment, Angle, Axes, FixedAlign, Fragment, Frame, HAlignment, Layout, Length, Point, Ratio, Regions, Rel, Size, VAlignment, @@ -37,7 +37,7 @@ pub struct MoveElem { pub body: Content, } -impl Layout for MoveElem { +impl Layout for Packed<MoveElem> { #[typst_macros::time(name = "move", span = self.span())] fn layout( &self, @@ -115,7 +115,7 @@ pub struct RotateElem { pub body: Content, } -impl Layout for RotateElem { +impl Layout for Packed<RotateElem> { #[typst_macros::time(name = "rotate", span = self.span())] fn layout( &self, @@ -203,7 +203,7 @@ pub struct ScaleElem { pub body: Content, } -impl Layout for ScaleElem { +impl Layout for Packed<ScaleElem> { #[typst_macros::time(name = "scale", span = self.span())] fn layout( &self, diff --git a/crates/typst/src/math/accent.rs b/crates/typst/src/math/accent.rs index 8f88c5b8..f1602f3c 100644 --- a/crates/typst/src/math/accent.rs +++ b/crates/typst/src/math/accent.rs @@ -1,7 +1,7 @@ use unicode_math_class::MathClass; use crate::diag::{bail, SourceResult}; -use crate::foundations::{cast, elem, Content, NativeElement, Resolve, Smart, Value}; +use crate::foundations::{cast, elem, Content, Packed, Resolve, Smart, Value}; use crate::layout::{Em, Frame, Length, Point, Rel, Size}; use crate::math::{ FrameFragment, GlyphFragment, LayoutMath, MathContext, MathFragment, Scaled, @@ -62,7 +62,7 @@ pub struct AccentElem { pub size: Smart<Rel<Length>>, } -impl LayoutMath for AccentElem { +impl LayoutMath for Packed<AccentElem> { #[typst_macros::time(name = "math.accent", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { ctx.style(ctx.style.with_cramped(true)); diff --git a/crates/typst/src/math/align.rs b/crates/typst/src/math/align.rs index 41f043b4..a1d396da 100644 --- a/crates/typst/src/math/align.rs +++ b/crates/typst/src/math/align.rs @@ -1,5 +1,5 @@ use crate::diag::SourceResult; -use crate::foundations::elem; +use crate::foundations::{elem, Packed}; use crate::layout::Abs; use crate::math::{LayoutMath, MathContext, MathFragment, MathRow}; @@ -7,7 +7,7 @@ use crate::math::{LayoutMath, MathContext, MathFragment, MathRow}; #[elem(title = "Alignment Point", LayoutMath)] pub struct AlignPointElem {} -impl LayoutMath for AlignPointElem { +impl LayoutMath for Packed<AlignPointElem> { fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { ctx.push(MathFragment::Align); Ok(()) diff --git a/crates/typst/src/math/attach.rs b/crates/typst/src/math/attach.rs index a6f92afb..ff66a386 100644 --- a/crates/typst/src/math/attach.rs +++ b/crates/typst/src/math/attach.rs @@ -1,7 +1,7 @@ use unicode_math_class::MathClass; use crate::diag::SourceResult; -use crate::foundations::{elem, Content, StyleChain}; +use crate::foundations::{elem, Content, Packed, StyleChain}; use crate::layout::{Abs, Frame, Point, Size}; use crate::math::{ FrameFragment, LayoutMath, MathContext, MathFragment, MathSize, Scaled, @@ -48,7 +48,7 @@ pub struct AttachElem { pub br: Option<Content>, } -impl LayoutMath for AttachElem { +impl LayoutMath for Packed<AttachElem> { #[typst_macros::time(name = "math.attach", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { type GetAttachment = fn(&AttachElem, styles: StyleChain) -> Option<Content>; @@ -61,15 +61,15 @@ impl LayoutMath for AttachElem { let base = ctx.layout_fragment(self.base())?; ctx.style(ctx.style.for_superscript()); - let tl = layout_attachment(ctx, Self::tl)?; - let tr = layout_attachment(ctx, Self::tr)?; - let t = layout_attachment(ctx, Self::t)?; + let tl = layout_attachment(ctx, AttachElem::tl)?; + let tr = layout_attachment(ctx, AttachElem::tr)?; + let t = layout_attachment(ctx, AttachElem::t)?; ctx.unstyle(); ctx.style(ctx.style.for_subscript()); - let bl = layout_attachment(ctx, Self::bl)?; - let br = layout_attachment(ctx, Self::br)?; - let b = layout_attachment(ctx, Self::b)?; + let bl = layout_attachment(ctx, AttachElem::bl)?; + let br = layout_attachment(ctx, AttachElem::br)?; + let b = layout_attachment(ctx, AttachElem::b)?; ctx.unstyle(); let limits = base.limits().active(ctx); @@ -96,7 +96,7 @@ pub struct PrimesElem { pub count: usize, } -impl LayoutMath for PrimesElem { +impl LayoutMath for Packed<PrimesElem> { #[typst_macros::time(name = "math.primes", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { match *self.count() { @@ -142,7 +142,7 @@ pub struct ScriptsElem { pub body: Content, } -impl LayoutMath for ScriptsElem { +impl LayoutMath for Packed<ScriptsElem> { #[typst_macros::time(name = "math.scripts", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let mut fragment = ctx.layout_fragment(self.body())?; @@ -171,7 +171,7 @@ pub struct LimitsElem { pub inline: bool, } -impl LayoutMath for LimitsElem { +impl LayoutMath for Packed<LimitsElem> { #[typst_macros::time(name = "math.limits", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let mut fragment = ctx.layout_fragment(self.body())?; diff --git a/crates/typst/src/math/cancel.rs b/crates/typst/src/math/cancel.rs index 5fa34d7d..e01b98ca 100644 --- a/crates/typst/src/math/cancel.rs +++ b/crates/typst/src/math/cancel.rs @@ -1,7 +1,7 @@ use unicode_math_class::MathClass; use crate::diag::{At, SourceResult}; -use crate::foundations::{cast, elem, Content, Func, NativeElement, Resolve, Smart}; +use crate::foundations::{cast, elem, Content, Func, Packed, Resolve, Smart}; use crate::layout::{ Abs, Angle, Frame, FrameItem, Length, Point, Ratio, Rel, Size, Transform, }; @@ -105,7 +105,7 @@ pub struct CancelElem { pub stroke: Stroke, } -impl LayoutMath for CancelElem { +impl LayoutMath for Packed<CancelElem> { #[typst_macros::time(name = "math.cancel", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let body = ctx.layout_fragment(self.body())?; diff --git a/crates/typst/src/math/class.rs b/crates/typst/src/math/class.rs index 1b229fce..9f430ad7 100644 --- a/crates/typst/src/math/class.rs +++ b/crates/typst/src/math/class.rs @@ -1,7 +1,7 @@ use unicode_math_class::MathClass; use crate::diag::SourceResult; -use crate::foundations::{elem, Content}; +use crate::foundations::{elem, Content, Packed}; use crate::math::{LayoutMath, MathContext}; /// Forced use of a certain math class. @@ -29,7 +29,7 @@ pub struct ClassElem { pub body: Content, } -impl LayoutMath for ClassElem { +impl LayoutMath for Packed<ClassElem> { #[typst_macros::time(name = "math.class", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { ctx.style(ctx.style.with_class(*self.class())); diff --git a/crates/typst/src/math/ctx.rs b/crates/typst/src/math/ctx.rs index 2c88fe3c..0e7cb2e6 100644 --- a/crates/typst/src/math/ctx.rs +++ b/crates/typst/src/math/ctx.rs @@ -12,7 +12,7 @@ use unicode_segmentation::UnicodeSegmentation; use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{Content, NativeElement, Smart, StyleChain, Styles}; +use crate::foundations::{Content, Packed, Smart, StyleChain, Styles}; use crate::layout::{Abs, Axes, BoxElem, Em, Frame, Layout, Regions, Size}; use crate::math::{ FrameFragment, GlyphFragment, LayoutMath, MathFragment, MathRow, MathSize, MathStyle, @@ -173,7 +173,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { Ok(self.layout_fragment(elem)?.into_frame()) } - pub fn layout_box(&mut self, boxed: &BoxElem) -> SourceResult<Frame> { + pub fn layout_box(&mut self, boxed: &Packed<BoxElem>) -> SourceResult<Frame> { Ok(boxed .layout(self.engine, self.outer.chain(&self.local), self.regions)? .into_frame()) @@ -185,7 +185,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { .into_frame()) } - pub fn layout_text(&mut self, elem: &TextElem) -> SourceResult<MathFragment> { + pub fn layout_text(&mut self, elem: &Packed<TextElem>) -> SourceResult<MathFragment> { let text = elem.text(); let span = elem.span(); let mut chars = text.chars(); @@ -276,7 +276,7 @@ impl<'a, 'b, 'v> MathContext<'a, 'b, 'v> { // it will overflow. So emulate an `hbox` instead and allow the paragraph // to extend as far as needed. let span = elem.span(); - let frame = ParElem::new(vec![Prehashed::new(elem)]) + let frame = Packed::new(ParElem::new(vec![Prehashed::new(elem)])) .spanned(span) .layout( self.engine, diff --git a/crates/typst/src/math/equation.rs b/crates/typst/src/math/equation.rs index 07f61bd3..4a0ee9b8 100644 --- a/crates/typst/src/math/equation.rs +++ b/crates/typst/src/math/equation.rs @@ -3,8 +3,8 @@ use std::num::NonZeroUsize; use crate::diag::{bail, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - elem, Content, Finalize, Guard, NativeElement, Resolve, Show, Smart, StyleChain, - Synthesize, + elem, Content, Finalize, Guard, NativeElement, Packed, Resolve, Show, Smart, + StyleChain, Synthesize, }; use crate::introspection::{Count, Counter, CounterUpdate, Locatable}; use crate::layout::{ @@ -89,41 +89,41 @@ pub struct EquationElem { pub body: Content, } -impl Synthesize for EquationElem { +impl Synthesize for Packed<EquationElem> { fn synthesize( &mut self, engine: &mut Engine, styles: StyleChain, ) -> SourceResult<()> { - // Resolve the supplement. - let supplement = match self.supplement(styles) { + let supplement = match self.as_ref().supplement(styles) { Smart::Auto => TextElem::packed(Self::local_name_in(styles)), Smart::Custom(None) => Content::empty(), Smart::Custom(Some(supplement)) => { - supplement.resolve(engine, [self.clone()])? + supplement.resolve(engine, [self.clone().pack()])? } }; - self.push_block(self.block(styles)); - self.push_numbering(self.numbering(styles)); - self.push_supplement(Smart::Custom(Some(Supplement::Content(supplement)))); + let elem = self.as_mut(); + elem.push_block(elem.block(styles)); + elem.push_numbering(elem.numbering(styles)); + elem.push_supplement(Smart::Custom(Some(Supplement::Content(supplement)))); Ok(()) } } -impl Show for EquationElem { +impl Show for Packed<EquationElem> { #[typst_macros::time(name = "math.equation", span = self.span())] fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { - let mut realized = self.clone().pack().guarded(Guard::Base(Self::elem())); + let mut realized = self.clone().pack().guarded(Guard::Base(EquationElem::elem())); if self.block(styles) { - realized = AlignElem::new(realized).spanned(self.span()).pack(); + realized = AlignElem::new(realized).pack().spanned(self.span()); } Ok(realized) } } -impl Finalize for EquationElem { +impl Finalize for Packed<EquationElem> { fn finalize(&self, realized: Content, style: StyleChain) -> Content { let mut realized = realized; if self.block(style) { @@ -154,7 +154,7 @@ impl MathParItem { } } -impl EquationElem { +impl Packed<EquationElem> { pub fn layout_inline( &self, engine: &mut Engine<'_>, @@ -197,7 +197,7 @@ impl EquationElem { } } -impl Layout for EquationElem { +impl Layout for Packed<EquationElem> { #[typst_macros::time(name = "math.equation", span = self.span())] fn layout( &self, @@ -215,9 +215,9 @@ impl Layout for EquationElem { let mut ctx = MathContext::new(engine, styles, regions, &font, true); let mut frame = ctx.layout_frame(self)?; - if let Some(numbering) = self.numbering(styles) { + if let Some(numbering) = (**self).numbering(styles) { let pod = Regions::one(regions.base(), Axes::splat(false)); - let counter = Counter::of(Self::elem()) + let counter = Counter::of(EquationElem::elem()) .display(self.span(), Some(numbering), false) .layout(engine, styles, pod)? .into_frame(); @@ -258,15 +258,14 @@ impl Layout for EquationElem { } } -impl Count for EquationElem { +impl Count for Packed<EquationElem> { fn update(&self) -> Option<CounterUpdate> { - (self.block(StyleChain::default()) - && self.numbering(StyleChain::default()).is_some()) - .then(|| CounterUpdate::Step(NonZeroUsize::ONE)) + (self.block(StyleChain::default()) && self.numbering().is_some()) + .then(|| CounterUpdate::Step(NonZeroUsize::ONE)) } } -impl LocalName for EquationElem { +impl LocalName for Packed<EquationElem> { fn local_name(lang: Lang, region: Option<Region>) -> &'static str { match lang { Lang::ALBANIAN => "Ekuacion", @@ -304,35 +303,35 @@ impl LocalName for EquationElem { } } -impl Refable for EquationElem { +impl Refable for Packed<EquationElem> { fn supplement(&self) -> Content { // After synthesis, this should always be custom content. - match self.supplement(StyleChain::default()) { + match (**self).supplement(StyleChain::default()) { Smart::Custom(Some(Supplement::Content(content))) => content, _ => Content::empty(), } } fn counter(&self) -> Counter { - Counter::of(Self::elem()) + Counter::of(EquationElem::elem()) } fn numbering(&self) -> Option<Numbering> { - self.numbering(StyleChain::default()) + (**self).numbering(StyleChain::default()) } } -impl Outlinable for EquationElem { +impl Outlinable for Packed<EquationElem> { fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>> { if !self.block(StyleChain::default()) { return Ok(None); } - let Some(numbering) = self.numbering(StyleChain::default()) else { + let Some(numbering) = self.numbering() else { return Ok(None); }; // After synthesis, this should always be custom content. - let mut supplement = match self.supplement(StyleChain::default()) { + let mut supplement = match (**self).supplement(StyleChain::default()) { Smart::Custom(Some(Supplement::Content(content))) => content, _ => Content::empty(), }; @@ -350,7 +349,7 @@ impl Outlinable for EquationElem { } } -impl LayoutMath for EquationElem { +impl LayoutMath for Packed<EquationElem> { #[typst_macros::time(name = "math.equation", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { self.body().layout_math(ctx) diff --git a/crates/typst/src/math/frac.rs b/crates/typst/src/math/frac.rs index b5ced71d..50185de2 100644 --- a/crates/typst/src/math/frac.rs +++ b/crates/typst/src/math/frac.rs @@ -1,5 +1,5 @@ use crate::diag::{bail, SourceResult}; -use crate::foundations::{elem, Content, NativeElement, Value}; +use crate::foundations::{elem, Content, Packed, Value}; use crate::layout::{Em, Frame, FrameItem, Point, Size}; use crate::math::{ FrameFragment, GlyphFragment, LayoutMath, MathContext, MathSize, Scaled, @@ -35,7 +35,7 @@ pub struct FracElem { pub denom: Content, } -impl LayoutMath for FracElem { +impl LayoutMath for Packed<FracElem> { #[typst_macros::time(name = "math.frac", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout(ctx, self.num(), std::slice::from_ref(self.denom()), false, self.span()) @@ -69,7 +69,7 @@ pub struct BinomElem { pub lower: Vec<Content>, } -impl LayoutMath for BinomElem { +impl LayoutMath for Packed<BinomElem> { #[typst_macros::time(name = "math.binom", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout(ctx, self.upper(), self.lower(), true, self.span()) diff --git a/crates/typst/src/math/lr.rs b/crates/typst/src/math/lr.rs index 4a1e758b..e2c098e7 100644 --- a/crates/typst/src/math/lr.rs +++ b/crates/typst/src/math/lr.rs @@ -1,7 +1,7 @@ use unicode_math_class::MathClass; use crate::diag::SourceResult; -use crate::foundations::{elem, func, Content, NativeElement, Resolve, Smart}; +use crate::foundations::{elem, func, Content, NativeElement, Packed, Resolve, Smart}; use crate::layout::{Abs, Em, Length, Rel}; use crate::math::{ GlyphFragment, LayoutMath, MathContext, MathFragment, Scaled, SpacingFragment, @@ -35,7 +35,7 @@ pub struct LrElem { pub body: Content, } -impl LayoutMath for LrElem { +impl LayoutMath for Packed<LrElem> { #[typst_macros::time(name = "math.lr", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let mut body = self.body(); @@ -110,7 +110,7 @@ pub struct MidElem { pub body: Content, } -impl LayoutMath for MidElem { +impl LayoutMath for Packed<MidElem> { #[typst_macros::time(name = "math.mid", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let mut fragments = ctx.layout_fragments(self.body())?; @@ -255,11 +255,10 @@ fn delimited( TextElem::packed(left), body, TextElem::packed(right), - ])) - .spanned(span); + ])); // Push size only if size is provided if let Some(size) = size { elem.push_size(size); } - elem.pack() + elem.pack().spanned(span) } diff --git a/crates/typst/src/math/matrix.rs b/crates/typst/src/math/matrix.rs index fe0a188c..0a3d0c2f 100644 --- a/crates/typst/src/math/matrix.rs +++ b/crates/typst/src/math/matrix.rs @@ -2,7 +2,7 @@ use smallvec::{smallvec, SmallVec}; use crate::diag::{bail, At, SourceResult, StrResult}; use crate::foundations::{ - cast, dict, elem, Array, Cast, Content, Dict, Fold, NativeElement, Resolve, Smart, + cast, dict, elem, Array, Cast, Content, Dict, Fold, Packed, Resolve, Smart, StyleChain, Value, }; use crate::layout::{ @@ -57,7 +57,7 @@ pub struct VecElem { pub children: Vec<Content>, } -impl LayoutMath for VecElem { +impl LayoutMath for Packed<VecElem> { #[typst_macros::time(name = "math.vec", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let delim = self.delim(ctx.styles()); @@ -210,11 +210,9 @@ pub struct MatElem { pub rows: Vec<Vec<Content>>, } -impl LayoutMath for MatElem { +impl LayoutMath for Packed<MatElem> { #[typst_macros::time(name = "math.mat", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { - // validate inputs - let augment = self.augment(ctx.styles()); let rows = self.rows(); @@ -311,7 +309,7 @@ pub struct CasesElem { pub children: Vec<Content>, } -impl LayoutMath for CasesElem { +impl LayoutMath for Packed<CasesElem> { #[typst_macros::time(name = "math.cases", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let delim = self.delim(ctx.styles()); diff --git a/crates/typst/src/math/op.rs b/crates/typst/src/math/op.rs index e1ac2b72..1d0645ff 100644 --- a/crates/typst/src/math/op.rs +++ b/crates/typst/src/math/op.rs @@ -2,7 +2,7 @@ use ecow::EcoString; use unicode_math_class::MathClass; use crate::diag::SourceResult; -use crate::foundations::{elem, Content, NativeElement, Scope}; +use crate::foundations::{elem, Content, NativeElement, Packed, Scope}; use crate::layout::HElem; use crate::math::{FrameFragment, LayoutMath, Limits, MathContext, MathStyleElem, THIN}; use crate::text::TextElem; @@ -33,7 +33,7 @@ pub struct OpElem { pub limits: bool, } -impl LayoutMath for OpElem { +impl LayoutMath for Packed<OpElem> { #[typst_macros::time(name = "math.op", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let fragment = ctx.layout_fragment(self.text())?; diff --git a/crates/typst/src/math/root.rs b/crates/typst/src/math/root.rs index badb8e86..db3a7b85 100644 --- a/crates/typst/src/math/root.rs +++ b/crates/typst/src/math/root.rs @@ -1,5 +1,5 @@ use crate::diag::SourceResult; -use crate::foundations::{elem, func, Content, NativeElement}; +use crate::foundations::{elem, func, Content, NativeElement, Packed}; use crate::layout::{Abs, Frame, FrameItem, Point, Size}; use crate::math::{ FrameFragment, GlyphFragment, LayoutMath, MathContext, MathSize, Scaled, @@ -20,7 +20,7 @@ pub fn sqrt( /// The expression to take the square root of. radicand: Content, ) -> Content { - RootElem::new(radicand).spanned(span).pack() + RootElem::new(radicand).pack().spanned(span) } /// A general root. @@ -39,7 +39,7 @@ pub struct RootElem { pub radicand: Content, } -impl LayoutMath for RootElem { +impl LayoutMath for Packed<RootElem> { #[typst_macros::time(name = "math.root", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout(ctx, self.index(ctx.styles()).as_ref(), self.radicand(), self.span()) diff --git a/crates/typst/src/math/style.rs b/crates/typst/src/math/style.rs index 00c7bef0..0d3c06fa 100644 --- a/crates/typst/src/math/style.rs +++ b/crates/typst/src/math/style.rs @@ -1,7 +1,9 @@ use unicode_math_class::MathClass; use crate::diag::SourceResult; -use crate::foundations::{elem, func, Cast, Content, NativeElement, Smart, StyleChain}; +use crate::foundations::{ + elem, func, Cast, Content, NativeElement, Packed, Smart, StyleChain, +}; use crate::math::{LayoutMath, MathContext}; use crate::syntax::Span; @@ -17,7 +19,7 @@ pub fn bold( /// The content to style. body: Content, ) -> Content { - MathStyleElem::new(body).spanned(span).with_bold(Some(true)).pack() + MathStyleElem::new(body).with_bold(Some(true)).pack().spanned(span) } /// Upright (non-italic) font style in math. @@ -32,7 +34,7 @@ pub fn upright( /// The content to style. body: Content, ) -> Content { - MathStyleElem::new(body).spanned(span).with_italic(Some(false)).pack() + MathStyleElem::new(body).with_italic(Some(false)).pack().spanned(span) } /// Italic font style in math. @@ -45,7 +47,7 @@ pub fn italic( /// The content to style. body: Content, ) -> Content { - MathStyleElem::new(body).spanned(span).with_italic(Some(true)).pack() + MathStyleElem::new(body).with_italic(Some(true)).pack().spanned(span) } /// Serif (roman) font style in math. /// @@ -58,9 +60,9 @@ pub fn serif( body: Content, ) -> Content { MathStyleElem::new(body) - .spanned(span) .with_variant(Some(MathVariant::Serif)) .pack() + .spanned(span) } /// Sans-serif font style in math. @@ -76,9 +78,9 @@ pub fn sans( body: Content, ) -> Content { MathStyleElem::new(body) - .spanned(span) .with_variant(Some(MathVariant::Sans)) .pack() + .spanned(span) } /// Calligraphic font style in math. @@ -94,9 +96,9 @@ pub fn cal( body: Content, ) -> Content { MathStyleElem::new(body) - .spanned(span) .with_variant(Some(MathVariant::Cal)) .pack() + .spanned(span) } /// Fraktur font style in math. @@ -112,9 +114,9 @@ pub fn frak( body: Content, ) -> Content { MathStyleElem::new(body) - .spanned(span) .with_variant(Some(MathVariant::Frak)) .pack() + .spanned(span) } /// Monospace font style in math. @@ -130,9 +132,9 @@ pub fn mono( body: Content, ) -> Content { MathStyleElem::new(body) - .spanned(span) .with_variant(Some(MathVariant::Mono)) .pack() + .spanned(span) } /// Blackboard bold (double-struck) font style in math. @@ -153,9 +155,9 @@ pub fn bb( body: Content, ) -> Content { MathStyleElem::new(body) - .spanned(span) .with_variant(Some(MathVariant::Bb)) .pack() + .spanned(span) } /// Forced display style in math. @@ -178,10 +180,10 @@ pub fn display( cramped: bool, ) -> Content { MathStyleElem::new(body) - .spanned(span) .with_size(Some(MathSize::Display)) .with_cramped(Some(cramped)) .pack() + .spanned(span) } /// Forced inline (text) style in math. @@ -205,10 +207,10 @@ pub fn inline( cramped: bool, ) -> Content { MathStyleElem::new(body) - .spanned(span) .with_size(Some(MathSize::Text)) .with_cramped(Some(cramped)) .pack() + .spanned(span) } /// Forced script style in math. @@ -231,10 +233,10 @@ pub fn script( cramped: bool, ) -> Content { MathStyleElem::new(body) - .spanned(span) .with_size(Some(MathSize::Script)) .with_cramped(Some(cramped)) .pack() + .spanned(span) } /// Forced second script style in math. @@ -258,10 +260,10 @@ pub fn sscript( cramped: bool, ) -> Content { MathStyleElem::new(body) - .spanned(span) .with_size(Some(MathSize::ScriptScript)) .with_cramped(Some(cramped)) .pack() + .spanned(span) } /// A font variant in math. @@ -287,7 +289,7 @@ pub struct MathStyleElem { pub cramped: Option<bool>, } -impl LayoutMath for MathStyleElem { +impl LayoutMath for Packed<MathStyleElem> { #[typst_macros::time(name = "math.style", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { let mut style = ctx.style; diff --git a/crates/typst/src/math/underover.rs b/crates/typst/src/math/underover.rs index c3a2a573..593493b8 100644 --- a/crates/typst/src/math/underover.rs +++ b/crates/typst/src/math/underover.rs @@ -1,7 +1,7 @@ use unicode_math_class::MathClass; use crate::diag::SourceResult; -use crate::foundations::{elem, Content, NativeElement}; +use crate::foundations::{elem, Content, Packed}; use crate::layout::{Abs, Em, FixedAlign, Frame, FrameItem, Point, Size}; use crate::math::{ alignments, AlignmentResult, FrameFragment, GlyphFragment, LayoutMath, MathContext, @@ -32,7 +32,7 @@ pub struct UnderlineElem { pub body: Content, } -impl LayoutMath for UnderlineElem { +impl LayoutMath for Packed<UnderlineElem> { #[typst_macros::time(name = "math.underline", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout_underoverline(ctx, self.body(), self.span(), LineKind::Under) @@ -51,7 +51,7 @@ pub struct OverlineElem { pub body: Content, } -impl LayoutMath for OverlineElem { +impl LayoutMath for Packed<OverlineElem> { #[typst_macros::time(name = "math.overline", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout_underoverline(ctx, self.body(), self.span(), LineKind::Over) @@ -136,7 +136,7 @@ pub struct UnderbraceElem { pub annotation: Option<Content>, } -impl LayoutMath for UnderbraceElem { +impl LayoutMath for Packed<UnderbraceElem> { #[typst_macros::time(name = "math.underbrace", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout_underoverspreader( @@ -167,7 +167,7 @@ pub struct OverbraceElem { pub annotation: Option<Content>, } -impl LayoutMath for OverbraceElem { +impl LayoutMath for Packed<OverbraceElem> { #[typst_macros::time(name = "math.overbrace", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout_underoverspreader( @@ -198,7 +198,7 @@ pub struct UnderbracketElem { pub annotation: Option<Content>, } -impl LayoutMath for UnderbracketElem { +impl LayoutMath for Packed<UnderbracketElem> { #[typst_macros::time(name = "math.underbrace", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout_underoverspreader( @@ -229,7 +229,7 @@ pub struct OverbracketElem { pub annotation: Option<Content>, } -impl LayoutMath for OverbracketElem { +impl LayoutMath for Packed<OverbracketElem> { #[typst_macros::time(name = "math.overbracket", span = self.span())] fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { layout_underoverspreader( diff --git a/crates/typst/src/model/bibliography.rs b/crates/typst/src/model/bibliography.rs index ecffcb78..06a80d6b 100644 --- a/crates/typst/src/model/bibliography.rs +++ b/crates/typst/src/model/bibliography.rs @@ -24,8 +24,8 @@ use crate::engine::Engine; use crate::eval::{eval_string, EvalMode}; use crate::foundations::{ cast, elem, ty, Args, Array, Bytes, CastInfo, Content, Finalize, FromValue, - IntoValue, Label, NativeElement, Reflect, Repr, Scope, Show, Smart, Str, StyleChain, - Synthesize, Type, Value, + IntoValue, Label, NativeElement, Packed, Reflect, Repr, Scope, Show, Smart, Str, + StyleChain, Synthesize, Type, Value, }; use crate::introspection::{Introspector, Locatable, Location}; use crate::layout::{ @@ -155,7 +155,7 @@ cast! { impl BibliographyElem { /// Find the document's bibliography. - pub fn find(introspector: Tracked<Introspector>) -> StrResult<Self> { + pub fn find(introspector: Tracked<Introspector>) -> StrResult<Packed<Self>> { let query = introspector.query(&Self::elem().select()); let mut iter = query.iter(); let Some(elem) = iter.next() else { @@ -166,7 +166,7 @@ impl BibliographyElem { bail!("multiple bibliographies are not yet supported"); } - Ok(elem.to::<Self>().cloned().unwrap()) + Ok(elem.to::<Self>().unwrap().clone()) } /// Whether the bibliography contains the given key. @@ -196,17 +196,18 @@ impl BibliographyElem { } } -impl Synthesize for BibliographyElem { +impl Synthesize for Packed<BibliographyElem> { fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { - self.push_full(self.full(styles)); - self.push_style(self.style(styles)); - self.push_lang(TextElem::lang_in(styles)); - self.push_region(TextElem::region_in(styles)); + let elem = self.as_mut(); + elem.push_full(elem.full(styles)); + elem.push_style(elem.style(styles)); + elem.push_lang(TextElem::lang_in(styles)); + elem.push_region(TextElem::region_in(styles)); Ok(()) } } -impl Show for BibliographyElem { +impl Show for Packed<BibliographyElem> { #[typst_macros::time(name = "bibliography", span = self.span())] fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { const COLUMN_GUTTER: Em = Em::new(0.65); @@ -220,9 +221,9 @@ impl Show for BibliographyElem { seq.push( HeadingElem::new(title) - .spanned(self.span()) .with_level(NonZeroUsize::ONE) - .pack(), + .pack() + .spanned(self.span()), ); } @@ -246,11 +247,11 @@ impl Show for BibliographyElem { seq.push(VElem::new(row_gutter).with_weakness(3).pack()); seq.push( GridElem::new(cells) - .spanned(self.span()) .with_columns(TrackSizings(smallvec![Sizing::Auto; 2])) .with_column_gutter(TrackSizings(smallvec![COLUMN_GUTTER.into()])) .with_row_gutter(TrackSizings(smallvec![(row_gutter).into()])) - .pack(), + .pack() + .spanned(self.span()), ); } else { for (_, reference) in references { @@ -269,7 +270,7 @@ impl Show for BibliographyElem { } } -impl Finalize for BibliographyElem { +impl Finalize for Packed<BibliographyElem> { fn finalize(&self, realized: Content, _: StyleChain) -> Content { const INDENT: Em = Em::new(1.0); realized @@ -278,7 +279,7 @@ impl Finalize for BibliographyElem { } } -impl LocalName for BibliographyElem { +impl LocalName for Packed<BibliographyElem> { fn local_name(lang: Lang, region: Option<Region>) -> &'static str { match lang { Lang::ALBANIAN => "Bibliografi", @@ -607,7 +608,7 @@ struct Generator<'a> { /// The world that is used to evaluate mathematical material in citations. world: Tracked<'a, dyn World + 'a>, /// The document's bibliography. - bibliography: BibliographyElem, + bibliography: Packed<BibliographyElem>, /// The document's citation groups. groups: EcoVec<Prehashed<Content>>, /// Details about each group that are accumulated while driving hayagriva's @@ -672,7 +673,7 @@ impl<'a> Generator<'a> { let mut driver = BibliographyDriver::new(); for elem in &self.groups { let group = elem.to::<CiteGroup>().unwrap(); - let location = group.location().unwrap(); + let location = elem.location().unwrap(); let children = group.children(); // Groups should never be empty. @@ -945,19 +946,19 @@ impl ElemRenderer<'_> { if let Some(prefix) = suf_prefix { const COLUMN_GUTTER: Em = Em::new(0.65); content = GridElem::new(vec![GridCell::new(prefix), GridCell::new(content)]) - .spanned(self.span) .with_columns(TrackSizings(smallvec![Sizing::Auto; 2])) .with_column_gutter(TrackSizings(smallvec![COLUMN_GUTTER.into()])) - .pack(); + .pack() + .spanned(self.span); } match elem.display { Some(Display::Block) => { content = - BlockElem::new().spanned(self.span).with_body(Some(content)).pack(); + BlockElem::new().with_body(Some(content)).pack().spanned(self.span); } Some(Display::Indent) => { - content = PadElem::new(content).spanned(self.span).pack(); + content = PadElem::new(content).pack().spanned(self.span); } Some(Display::LeftMargin) => { *prefix.get_or_insert_with(Default::default) += content; @@ -987,8 +988,8 @@ impl ElemRenderer<'_> { fn display_link(&self, text: &hayagriva::Formatted, url: &str) -> Content { let dest = Destination::Url(url.into()); LinkElem::new(dest.into(), self.display_formatted(text)) - .spanned(self.span) .pack() + .spanned(self.span) } /// Display transparent pass-through content. @@ -1043,10 +1044,10 @@ fn apply_formatting(mut content: Content, format: &hayagriva::Formatting) -> Con citationberg::VerticalAlign::Baseline => {} citationberg::VerticalAlign::Sup => { // Add zero-width weak spacing to make the superscript "sticky". - content = HElem::hole().pack() + SuperElem::new(content).spanned(span).pack(); + content = HElem::hole().pack() + SuperElem::new(content).pack().spanned(span); } citationberg::VerticalAlign::Sub => { - content = HElem::hole().pack() + SubElem::new(content).spanned(span).pack(); + content = HElem::hole().pack() + SubElem::new(content).pack().spanned(span); } } diff --git a/crates/typst/src/model/cite.rs b/crates/typst/src/model/cite.rs index d2b50790..2e28a834 100644 --- a/crates/typst/src/model/cite.rs +++ b/crates/typst/src/model/cite.rs @@ -1,7 +1,7 @@ use crate::diag::{bail, At, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, Cast, Content, Label, NativeElement, Show, Smart, StyleChain, Synthesize, + cast, elem, Cast, Content, Label, Packed, Show, Smart, StyleChain, Synthesize, }; use crate::introspection::Locatable; use crate::model::bibliography::Works; @@ -99,20 +99,21 @@ pub struct CiteElem { pub region: Option<Region>, } -impl Synthesize for CiteElem { +impl Synthesize for Packed<CiteElem> { fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { - self.push_supplement(self.supplement(styles)); - self.push_form(self.form(styles)); - self.push_style(self.style(styles)); - self.push_lang(TextElem::lang_in(styles)); - self.push_region(TextElem::region_in(styles)); + let elem = self.as_mut(); + elem.push_supplement(elem.supplement(styles)); + elem.push_form(elem.form(styles)); + elem.push_style(elem.style(styles)); + elem.push_lang(TextElem::lang_in(styles)); + elem.push_region(TextElem::region_in(styles)); Ok(()) } } cast! { CiteElem, - v: Content => v.to::<Self>().cloned().ok_or("expected citation")?, + v: Content => v.to_packed::<Self>().map_err(|_| "expected citation")?.unpack(), } /// The form of the citation. @@ -139,10 +140,10 @@ pub enum CitationForm { pub struct CiteGroup { /// The citations. #[required] - pub children: Vec<CiteElem>, + pub children: Vec<Packed<CiteElem>>, } -impl Show for CiteGroup { +impl Show for Packed<CiteGroup> { #[typst_macros::time(name = "cite", span = self.span())] fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(engine.delayed(|engine| { diff --git a/crates/typst/src/model/document.rs b/crates/typst/src/model/document.rs index 65b4280b..018a8d25 100644 --- a/crates/typst/src/model/document.rs +++ b/crates/typst/src/model/document.rs @@ -3,7 +3,8 @@ use ecow::EcoString; use crate::diag::{bail, SourceResult, StrResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, Args, Array, Construct, Content, Datetime, Smart, StyleChain, Value, + cast, elem, Args, Array, Construct, Content, Datetime, Packed, Smart, StyleChain, + Value, }; use crate::introspection::{Introspector, ManualPageCounter}; use crate::layout::{Frame, LayoutRoot, PageElem}; @@ -65,7 +66,7 @@ impl Construct for DocumentElem { } } -impl LayoutRoot for DocumentElem { +impl LayoutRoot for Packed<DocumentElem> { /// Layout the document into a sequence of frames, one per page. #[typst_macros::time(name = "document", span = self.span())] fn layout_root( diff --git a/crates/typst/src/model/emph.rs b/crates/typst/src/model/emph.rs index 46fa0ca9..b67643de 100644 --- a/crates/typst/src/model/emph.rs +++ b/crates/typst/src/model/emph.rs @@ -1,6 +1,6 @@ use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{elem, Content, Show, StyleChain}; +use crate::foundations::{elem, Content, Packed, Show, StyleChain}; use crate::text::{ItalicToggle, TextElem}; /// Emphasizes content by toggling italics. @@ -33,7 +33,7 @@ pub struct EmphElem { pub body: Content, } -impl Show for EmphElem { +impl Show for Packed<EmphElem> { #[typst_macros::time(name = "emph", span = self.span())] fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_emph(ItalicToggle))) diff --git a/crates/typst/src/model/enum.rs b/crates/typst/src/model/enum.rs index ad0789f0..870ff3b6 100644 --- a/crates/typst/src/model/enum.rs +++ b/crates/typst/src/model/enum.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use crate::diag::{bail, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, scope, Array, Content, Fold, NativeElement, Smart, StyleChain, + cast, elem, scope, Array, Content, Fold, Packed, Smart, StyleChain, }; use crate::layout::{ Alignment, Axes, BlockElem, Cell, CellGrid, Em, Fragment, GridLayouter, HAlignment, @@ -194,7 +194,7 @@ pub struct EnumElem { /// ) [+ #phase] /// ``` #[variadic] - pub children: Vec<EnumItem>, + pub children: Vec<Packed<EnumItem>>, /// The numbers of parent items. #[internal] @@ -208,7 +208,7 @@ impl EnumElem { type EnumItem; } -impl Layout for EnumElem { +impl Layout for Packed<EnumElem> { #[typst_macros::time(name = "enum", span = self.span())] fn layout( &self, @@ -263,7 +263,7 @@ impl Layout for EnumElem { cells.push(Cell::from(resolved)); cells.push(Cell::from(Content::empty())); cells.push(Cell::from( - item.body().clone().styled(Self::set_parents(Parent(number))), + item.body().clone().styled(EnumElem::set_parents(Parent(number))), )); number = number.saturating_add(1); } @@ -308,7 +308,10 @@ cast! { }; Self::new(body).with_number(number) }, - v: Content => v.to::<Self>().cloned().unwrap_or_else(|| Self::new(v.clone())), + v: Content => match v.to_packed::<Self>() { + Ok(packed) => packed.unpack(), + Err(v) => Self::new(v), + }, } #[derive(Debug, Clone, Copy, PartialEq, Hash)] diff --git a/crates/typst/src/model/figure.rs b/crates/typst/src/model/figure.rs index ad77f171..e42bf68a 100644 --- a/crates/typst/src/model/figure.rs +++ b/crates/typst/src/model/figure.rs @@ -7,8 +7,8 @@ use ecow::EcoString; use crate::diag::{bail, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, scope, select_where, Content, Element, Finalize, NativeElement, Selector, - Show, Smart, StyleChain, Synthesize, + cast, elem, scope, select_where, Content, Element, Finalize, NativeElement, Packed, + Selector, Show, Smart, StyleChain, Synthesize, }; use crate::introspection::{ Count, Counter, CounterKey, CounterUpdate, Locatable, Location, @@ -134,7 +134,7 @@ pub struct FigureElem { pub placement: Option<Smart<VAlignment>>, /// The figure's caption. - pub caption: Option<FigureCaption>, + pub caption: Option<Packed<FigureCaption>>, /// The kind of figure this is. /// @@ -222,24 +222,29 @@ impl FigureElem { type FigureCaption; } -impl Synthesize for FigureElem { +impl Synthesize for Packed<FigureElem> { fn synthesize( &mut self, engine: &mut Engine, styles: StyleChain, ) -> SourceResult<()> { - let numbering = self.numbering(styles); + let span = self.span(); + let location = self.location(); + + let elem = self.as_mut(); + let placement = elem.placement(styles); + let numbering = elem.numbering(styles); // Determine the figure's kind. - let kind = self.kind(styles).unwrap_or_else(|| { - self.body() + let kind = elem.kind(styles).unwrap_or_else(|| { + elem.body() .query_first(Selector::can::<dyn Figurable>()) .map(|elem| FigureKind::Elem(elem.func())) .unwrap_or_else(|| FigureKind::Elem(ImageElem::elem())) }); // Resolve the supplement. - let supplement = match self.supplement(styles).as_ref() { + let supplement = match elem.supplement(styles).as_ref() { Smart::Auto => { // Default to the local name for the kind, if available. let name = match &kind { @@ -253,7 +258,7 @@ impl Synthesize for FigureElem { }; if numbering.is_some() && name.is_none() { - bail!(self.span(), "please specify the figure's supplement") + bail!(span, "please specify the figure's supplement") } Some(name.unwrap_or_default()) @@ -263,45 +268,46 @@ impl Synthesize for FigureElem { // Resolve the supplement with the first descendant of the kind or // just the body, if none was found. let descendant = match kind { - FigureKind::Elem(func) => self + FigureKind::Elem(func) => elem .body() .query_first(Selector::Elem(func, None)) .map(Cow::Owned), FigureKind::Name(_) => None, }; - let target = descendant.unwrap_or_else(|| Cow::Borrowed(self.body())); + let target = descendant.unwrap_or_else(|| Cow::Borrowed(elem.body())); Some(supplement.resolve(engine, [target])?) } }; // Construct the figure's counter. - let counter = - Counter::new(CounterKey::Selector(select_where!(Self, Kind => kind.clone()))); + let counter = Counter::new(CounterKey::Selector( + select_where!(FigureElem, Kind => kind.clone()), + )); // Fill the figure's caption. - let mut caption = self.caption(styles); + let mut caption = elem.caption(styles); if let Some(caption) = &mut caption { caption.push_kind(kind.clone()); caption.push_supplement(supplement.clone()); caption.push_numbering(numbering.clone()); caption.push_counter(Some(counter.clone())); - caption.push_figure_location(self.location()); + caption.push_figure_location(location); } - self.push_placement(self.placement(styles)); - self.push_caption(caption); - self.push_kind(Smart::Custom(kind)); - self.push_supplement(Smart::Custom(supplement.map(Supplement::Content))); - self.push_numbering(numbering); - self.push_outlined(self.outlined(styles)); - self.push_counter(Some(counter)); + elem.push_placement(placement); + elem.push_caption(caption); + elem.push_kind(Smart::Custom(kind)); + elem.push_supplement(Smart::Custom(supplement.map(Supplement::Content))); + elem.push_numbering(numbering); + elem.push_outlined(elem.outlined(styles)); + elem.push_counter(Some(counter)); Ok(()) } } -impl Show for FigureElem { +impl Show for Packed<FigureElem> { #[typst_macros::time(name = "figure", span = self.span())] fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body().clone(); @@ -319,60 +325,62 @@ impl Show for FigureElem { // Wrap the contents in a block. realized = BlockElem::new() .with_body(Some(realized)) - .spanned(self.span()) .pack() + .spanned(self.span()) .aligned(Alignment::CENTER); // Wrap in a float. if let Some(align) = self.placement(styles) { realized = PlaceElem::new(realized) - .spanned(self.span()) .with_float(true) .with_alignment(align.map(|align| HAlignment::Center + align)) - .pack(); + .pack() + .spanned(self.span()); } Ok(realized) } } -impl Finalize for FigureElem { +impl Finalize for Packed<FigureElem> { fn finalize(&self, realized: Content, _: StyleChain) -> Content { // Allow breakable figures with `show figure: set block(breakable: true)`. realized.styled(BlockElem::set_breakable(false)) } } -impl Count for FigureElem { +impl Count for Packed<FigureElem> { fn update(&self) -> Option<CounterUpdate> { // If the figure is numbered, step the counter by one. // This steps the `counter(figure)` which is global to all numbered figures. - self.numbering(StyleChain::default()) + self.numbering() .is_some() .then(|| CounterUpdate::Step(NonZeroUsize::ONE)) } } -impl Refable for FigureElem { +impl Refable for Packed<FigureElem> { fn supplement(&self) -> Content { // After synthesis, this should always be custom content. - let default = StyleChain::default(); - match self.supplement(default).as_ref() { + match (**self).supplement(StyleChain::default()).as_ref() { Smart::Custom(Some(Supplement::Content(content))) => content.clone(), _ => Content::empty(), } } fn counter(&self) -> Counter { - self.counter().clone().unwrap_or_else(|| Counter::of(Self::elem())) + (**self) + .counter() + .clone() + .unwrap_or_else(|| Counter::of(FigureElem::elem())) } fn numbering(&self) -> Option<Numbering> { - self.numbering(StyleChain::default()) + (**self).numbering(StyleChain::default()) } } -impl Outlinable for FigureElem { +impl Outlinable for Packed<FigureElem> { fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>> { if !self.outlined(StyleChain::default()) { return Ok(None); @@ -388,9 +396,9 @@ impl Outlinable for FigureElem { Some(counter), Some(numbering), ) = ( - self.supplement(StyleChain::default()).clone(), - self.counter(), - self.numbering(StyleChain::default()), + (**self).supplement(StyleChain::default()).clone(), + (**self).counter(), + self.numbering(), ) { let location = self.location().unwrap(); let numbers = counter.at(engine, location)?.display(engine, &numbering)?; @@ -546,15 +554,16 @@ impl FigureCaption { } } -impl Synthesize for FigureCaption { +impl Synthesize for Packed<FigureCaption> { fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { - self.push_position(self.position(styles)); - self.push_separator(Smart::Custom(self.get_separator(styles))); + let elem = self.as_mut(); + elem.push_position(elem.position(styles)); + elem.push_separator(Smart::Custom(elem.get_separator(styles))); Ok(()) } } -impl Show for FigureCaption { +impl Show for Packed<FigureCaption> { #[typst_macros::time(name = "figure.caption", span = self.span())] fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body().clone(); @@ -578,7 +587,10 @@ impl Show for FigureCaption { cast! { FigureCaption, - v: Content => v.to::<Self>().cloned().unwrap_or_else(|| Self::new(v.clone())), + v: Content => match v.to_packed::<Self>() { + Ok(packed) => packed.unpack(), + Err(v) => Self::new(v), + }, } /// The `kind` parameter of a [`FigureElem`]. diff --git a/crates/typst/src/model/footnote.rs b/crates/typst/src/model/footnote.rs index 1f9ce704..241f8db5 100644 --- a/crates/typst/src/model/footnote.rs +++ b/crates/typst/src/model/footnote.rs @@ -4,8 +4,8 @@ use std::str::FromStr; use crate::diag::{bail, At, SourceResult, StrResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, scope, Content, Finalize, Label, NativeElement, Show, Smart, StyleChain, - Synthesize, + cast, elem, scope, Content, Finalize, Label, NativeElement, Packed, Show, Smart, + StyleChain, Synthesize, }; use crate::introspection::{Count, Counter, CounterUpdate, Locatable, Location}; use crate::layout::{Abs, Em, HElem, Length, Ratio}; @@ -104,7 +104,9 @@ impl FootnoteElem { _ => None, } } +} +impl Packed<FootnoteElem> { /// Returns the location of the definition of this footnote. pub fn declaration_location(&self, engine: &Engine) -> StrResult<Location> { match self.body() { @@ -120,22 +122,23 @@ impl FootnoteElem { } } -impl Synthesize for FootnoteElem { +impl Synthesize for Packed<FootnoteElem> { fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { - self.push_numbering(self.numbering(styles).clone()); + let elem = self.as_mut(); + elem.push_numbering(elem.numbering(styles).clone()); Ok(()) } } -impl Show for FootnoteElem { +impl Show for Packed<FootnoteElem> { #[typst_macros::time(name = "footnote", span = self.span())] fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(engine.delayed(|engine| { let loc = self.declaration_location(engine).at(self.span())?; let numbering = self.numbering(styles); - let counter = Counter::of(Self::elem()); + let counter = Counter::of(FootnoteElem::elem()); let num = counter.at(engine, loc)?.display(engine, numbering)?; - let sup = SuperElem::new(num).spanned(self.span()).pack(); + let sup = SuperElem::new(num).pack().spanned(self.span()); let loc = loc.variant(1); // Add zero-width weak spacing to make the footnote "sticky". Ok(HElem::hole().pack() + sup.linked(Destination::Location(loc))) @@ -143,7 +146,7 @@ impl Show for FootnoteElem { } } -impl Count for FootnoteElem { +impl Count for Packed<FootnoteElem> { fn update(&self) -> Option<CounterUpdate> { (!self.is_ref()).then(|| CounterUpdate::Step(NonZeroUsize::ONE)) } @@ -203,7 +206,7 @@ pub struct FootnoteEntry { /// listing #footnote[World! 🌏] /// ``` #[required] - pub note: FootnoteElem, + pub note: Packed<FootnoteElem>, /// The separator between the document body and the footnote listing. /// @@ -269,7 +272,7 @@ pub struct FootnoteEntry { pub indent: Length, } -impl Show for FootnoteEntry { +impl Show for Packed<FootnoteEntry> { #[typst_macros::time(name = "footnote.entry", span = self.span())] fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let note = self.note(); @@ -286,8 +289,8 @@ impl Show for FootnoteEntry { let num = counter.at(engine, loc)?.display(engine, numbering)?; let sup = SuperElem::new(num) - .spanned(self.span()) .pack() + .spanned(self.span()) .linked(Destination::Location(loc)) .backlinked(loc.variant(1)); Ok(Content::sequence([ @@ -299,7 +302,7 @@ impl Show for FootnoteEntry { } } -impl Finalize for FootnoteEntry { +impl Finalize for Packed<FootnoteEntry> { fn finalize(&self, realized: Content, _: StyleChain) -> Content { let text_size = Em::new(0.85); let leading = Em::new(0.5); @@ -311,5 +314,8 @@ impl Finalize for FootnoteEntry { cast! { FootnoteElem, - v: Content => v.to::<Self>().cloned().unwrap_or_else(|| Self::with_content(v.clone())), + v: Content => match v.to_packed::<Self>() { + Ok(packed) => packed.unpack(), + Err(v) => Self::with_content(v), + } } diff --git a/crates/typst/src/model/heading.rs b/crates/typst/src/model/heading.rs index bbddcb04..ef5e4007 100644 --- a/crates/typst/src/model/heading.rs +++ b/crates/typst/src/model/heading.rs @@ -3,7 +3,7 @@ use std::num::NonZeroUsize; use crate::diag::SourceResult; use crate::engine::Engine; use crate::foundations::{ - cast, elem, Content, Finalize, NativeElement, Show, Smart, StyleChain, Styles, + elem, Content, Finalize, NativeElement, Packed, Show, Smart, StyleChain, Styles, Synthesize, }; use crate::introspection::{Count, Counter, CounterUpdate, Locatable}; @@ -126,53 +126,49 @@ pub struct HeadingElem { pub body: Content, } -impl Synthesize for HeadingElem { +impl Synthesize for Packed<HeadingElem> { fn synthesize( &mut self, engine: &mut Engine, styles: StyleChain, ) -> SourceResult<()> { - // Resolve the supplement. - let supplement = match self.supplement(styles) { + let supplement = match (**self).supplement(styles) { Smart::Auto => TextElem::packed(Self::local_name_in(styles)), Smart::Custom(None) => Content::empty(), Smart::Custom(Some(supplement)) => { - supplement.resolve(engine, [self.clone()])? + supplement.resolve(engine, [self.clone().pack()])? } }; - self.push_level(self.level(styles)); - self.push_numbering(self.numbering(styles).clone()); - self.push_supplement(Smart::Custom(Some(Supplement::Content(supplement)))); - self.push_outlined(self.outlined(styles)); - self.push_bookmarked(self.bookmarked(styles)); + let elem = self.as_mut(); + elem.push_level(elem.level(styles)); + elem.push_numbering(elem.numbering(styles).clone()); + elem.push_supplement(Smart::Custom(Some(Supplement::Content(supplement)))); + elem.push_outlined(elem.outlined(styles)); + elem.push_bookmarked(elem.bookmarked(styles)); Ok(()) } } -impl Show for HeadingElem { +impl Show for Packed<HeadingElem> { #[typst_macros::time(name = "heading", span = self.span())] fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body().clone(); - if let Some(numbering) = self.numbering(styles).as_ref() { - realized = Counter::of(Self::elem()) + if let Some(numbering) = (**self).numbering(styles).as_ref() { + realized = Counter::of(HeadingElem::elem()) .display(self.span(), Some(numbering.clone()), false) .spanned(self.span()) + HElem::new(Em::new(0.3).into()).with_weak(true).pack() + realized; } - Ok(BlockElem::new() - .spanned(self.span()) - .spanned(self.span()) - .with_body(Some(realized)) - .pack()) + Ok(BlockElem::new().with_body(Some(realized)).pack().spanned(self.span())) } } -impl Finalize for HeadingElem { +impl Finalize for Packed<HeadingElem> { fn finalize(&self, realized: Content, styles: StyleChain) -> Content { - let level = self.level(styles).get(); + let level = (**self).level(styles).get(); let scale = match level { 1 => 1.4, 2 => 1.2, @@ -193,47 +189,42 @@ impl Finalize for HeadingElem { } } -impl Count for HeadingElem { +impl Count for Packed<HeadingElem> { fn update(&self) -> Option<CounterUpdate> { - self.numbering(StyleChain::default()) + (**self) + .numbering(StyleChain::default()) .is_some() - .then(|| CounterUpdate::Step(self.level(StyleChain::default()))) + .then(|| CounterUpdate::Step((**self).level(StyleChain::default()))) } } -cast! { - HeadingElem, - v: Content => v.to::<Self>().ok_or("expected heading")?.clone(), -} - -impl Refable for HeadingElem { +impl Refable for Packed<HeadingElem> { fn supplement(&self) -> Content { // After synthesis, this should always be custom content. - match self.supplement(StyleChain::default()) { + match (**self).supplement(StyleChain::default()) { Smart::Custom(Some(Supplement::Content(content))) => content, _ => Content::empty(), } } fn counter(&self) -> Counter { - Counter::of(Self::elem()) + Counter::of(HeadingElem::elem()) } fn numbering(&self) -> Option<Numbering> { - self.numbering(StyleChain::default()).clone() + (**self).numbering(StyleChain::default()).clone() } } -impl Outlinable for HeadingElem { +impl Outlinable for Packed<HeadingElem> { fn outline(&self, engine: &mut Engine) -> SourceResult<Option<Content>> { if !self.outlined(StyleChain::default()) { return Ok(None); } let mut content = self.body().clone(); - let default = StyleChain::default(); - if let Some(numbering) = self.numbering(default).as_ref() { - let numbers = Counter::of(Self::elem()) + if let Some(numbering) = (**self).numbering(StyleChain::default()).as_ref() { + let numbers = Counter::of(HeadingElem::elem()) .at(engine, self.location().unwrap())? .display(engine, numbering)?; content = numbers + SpaceElem::new().pack() + content; @@ -243,11 +234,11 @@ impl Outlinable for HeadingElem { } fn level(&self) -> NonZeroUsize { - self.level(StyleChain::default()) + (**self).level(StyleChain::default()) } } -impl LocalName for HeadingElem { +impl LocalName for Packed<HeadingElem> { fn local_name(lang: Lang, region: Option<Region>) -> &'static str { match lang { Lang::ALBANIAN => "Kapitull", diff --git a/crates/typst/src/model/link.rs b/crates/typst/src/model/link.rs index 7c68b711..7b39e90b 100644 --- a/crates/typst/src/model/link.rs +++ b/crates/typst/src/model/link.rs @@ -3,7 +3,7 @@ use ecow::{eco_format, EcoString}; use crate::diag::{At, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, Content, Label, NativeElement, Repr, Show, Smart, StyleChain, + cast, elem, Content, Label, Packed, Repr, Show, Smart, StyleChain, }; use crate::introspection::Location; use crate::layout::Position; @@ -89,7 +89,7 @@ impl LinkElem { } } -impl Show for LinkElem { +impl Show for Packed<LinkElem> { #[typst_macros::time(name = "link", span = self.span())] fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> { let body = self.body().clone(); diff --git a/crates/typst/src/model/list.rs b/crates/typst/src/model/list.rs index 4e02f60b..dc0312d2 100644 --- a/crates/typst/src/model/list.rs +++ b/crates/typst/src/model/list.rs @@ -1,8 +1,7 @@ use crate::diag::{bail, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, scope, Array, Content, Fold, Func, NativeElement, Smart, StyleChain, - Value, + cast, elem, scope, Array, Content, Fold, Func, Packed, Smart, StyleChain, Value, }; use crate::layout::{ Axes, BlockElem, Cell, CellGrid, Em, Fragment, GridLayouter, HAlignment, Layout, @@ -120,7 +119,7 @@ pub struct ListElem { /// ] /// ``` #[variadic] - pub children: Vec<ListItem>, + pub children: Vec<Packed<ListItem>>, /// The nesting depth. #[internal] @@ -134,7 +133,7 @@ impl ListElem { type ListItem; } -impl Layout for ListElem { +impl Layout for Packed<ListElem> { #[typst_macros::time(name = "list", span = self.span())] fn layout( &self, @@ -163,7 +162,8 @@ impl Layout for ListElem { cells.push(Cell::from(Content::empty())); cells.push(Cell::from(marker.clone())); cells.push(Cell::from(Content::empty())); - cells.push(Cell::from(item.body().clone().styled(Self::set_depth(Depth)))); + cells + .push(Cell::from(item.body().clone().styled(ListElem::set_depth(Depth)))); } let stroke = None; @@ -194,7 +194,10 @@ pub struct ListItem { cast! { ListItem, - v: Content => v.to::<Self>().cloned().unwrap_or_else(|| Self::new(v.clone())), + v: Content => match v.to_packed::<Self>() { + Ok(packed) => packed.unpack(), + Err(v) => Self::new(v), + } } /// A list's marker. diff --git a/crates/typst/src/model/outline.rs b/crates/typst/src/model/outline.rs index c77a9a98..833b035c 100644 --- a/crates/typst/src/model/outline.rs +++ b/crates/typst/src/model/outline.rs @@ -5,7 +5,7 @@ use crate::diag::{bail, At, SourceResult}; use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, select_where, Content, Finalize, Func, LocatableSelector, - NativeElement, Show, Smart, StyleChain, + NativeElement, Packed, Show, Smart, StyleChain, }; use crate::introspection::{Counter, CounterKey, Locatable}; use crate::layout::{BoxElem, Fr, HElem, HideElem, Length, Rel, RepeatElem, Spacing}; @@ -185,7 +185,7 @@ impl OutlineElem { type OutlineEntry; } -impl Show for OutlineElem { +impl Show for Packed<OutlineElem> { #[typst_macros::time(name = "outline", span = self.span())] fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut seq = vec![ParbreakElem::new().pack()]; @@ -197,9 +197,9 @@ impl Show for OutlineElem { seq.push( HeadingElem::new(title) - .spanned(self.span()) .with_level(NonZeroUsize::ONE) - .pack(), + .pack() + .spanned(self.span()), ); } @@ -250,7 +250,7 @@ impl Show for OutlineElem { } } -impl Finalize for OutlineElem { +impl Finalize for Packed<OutlineElem> { fn finalize(&self, realized: Content, _: StyleChain) -> Content { realized .styled(HeadingElem::set_outlined(false)) @@ -258,7 +258,7 @@ impl Finalize for OutlineElem { } } -impl LocalName for OutlineElem { +impl LocalName for Packed<OutlineElem> { fn local_name(lang: Lang, region: Option<Region>) -> &'static str { match lang { Lang::ALBANIAN => "Përmbajtja", @@ -492,7 +492,7 @@ impl OutlineEntry { } } -impl Show for OutlineEntry { +impl Show for Packed<OutlineEntry> { #[typst_macros::time(name = "outline.entry", span = self.span())] fn show(&self, _: &mut Engine, _: StyleChain) -> SourceResult<Content> { let mut seq = vec![]; @@ -518,10 +518,10 @@ impl Show for OutlineEntry { seq.push(SpaceElem::new().pack()); seq.push( BoxElem::new() - .spanned(self.span()) .with_body(Some(filler.clone())) .with_width(Fr::one().into()) - .pack(), + .pack() + .spanned(self.span()), ); seq.push(SpaceElem::new().pack()); } else { diff --git a/crates/typst/src/model/par.rs b/crates/typst/src/model/par.rs index f00c39f0..690b7276 100644 --- a/crates/typst/src/model/par.rs +++ b/crates/typst/src/model/par.rs @@ -3,7 +3,7 @@ use comemo::Prehashed; use crate::diag::SourceResult; use crate::engine::Engine; use crate::foundations::{ - elem, Args, Cast, Construct, Content, NativeElement, Set, Smart, StyleChain, + elem, Args, Cast, Construct, Content, NativeElement, Packed, Set, Smart, StyleChain, Unlabellable, }; use crate::layout::{Em, Fragment, Length, Size}; @@ -122,7 +122,7 @@ impl Construct for ParElem { } } -impl ParElem { +impl Packed<ParElem> { /// Layout the paragraph into a collection of lines. #[typst_macros::time(name = "par", span = self.span())] pub fn layout( @@ -177,4 +177,4 @@ pub enum Linebreaks { #[elem(title = "Paragraph Break", Unlabellable)] pub struct ParbreakElem {} -impl Unlabellable for ParbreakElem {} +impl Unlabellable for Packed<ParbreakElem> {} diff --git a/crates/typst/src/model/quote.rs b/crates/typst/src/model/quote.rs index 920a2a97..311fd464 100644 --- a/crates/typst/src/model/quote.rs +++ b/crates/typst/src/model/quote.rs @@ -1,7 +1,7 @@ use crate::diag::SourceResult; use crate::engine::Engine; use crate::foundations::{ - cast, elem, Content, Finalize, Label, NativeElement, Show, Smart, StyleChain, + cast, elem, Content, Finalize, Label, NativeElement, Packed, Show, Smart, StyleChain, Synthesize, }; use crate::layout::{Alignment, BlockElem, Em, HElem, PadElem, Spacing, VElem}; @@ -145,15 +145,16 @@ cast! { label: Label => Self::Label(label), } -impl Synthesize for QuoteElem { +impl Synthesize for Packed<QuoteElem> { fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { - self.push_block(self.block(styles)); - self.push_quotes(self.quotes(styles)); + let elem = self.as_mut(); + elem.push_block(elem.block(styles)); + elem.push_quotes(elem.quotes(styles)); Ok(()) } } -impl Show for QuoteElem { +impl Show for Packed<QuoteElem> { #[typst_macros::time(name = "quote", span = self.span())] fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut realized = self.body().clone(); @@ -169,7 +170,7 @@ impl Show for QuoteElem { if block { realized = - BlockElem::new().spanned(self.span()).with_body(Some(realized)).pack(); + BlockElem::new().with_body(Some(realized)).pack().spanned(self.span()); if let Some(attribution) = self.attribution(styles).as_ref() { let mut seq = vec![TextElem::packed('—'), SpaceElem::new().pack()]; @@ -181,9 +182,9 @@ impl Show for QuoteElem { Attribution::Label(label) => { seq.push( CiteElem::new(*label) - .spanned(self.span()) .with_form(Some(CitationForm::Prose)) - .pack(), + .pack() + .spanned(self.span()), ); } } @@ -197,14 +198,14 @@ impl Show for QuoteElem { realized = PadElem::new(realized).pack(); } else if let Some(Attribution::Label(label)) = self.attribution(styles) { realized += SpaceElem::new().pack() - + CiteElem::new(*label).spanned(self.span()).pack(); + + CiteElem::new(*label).pack().spanned(self.span()); } Ok(realized) } } -impl Finalize for QuoteElem { +impl Finalize for Packed<QuoteElem> { fn finalize(&self, realized: Content, _: StyleChain) -> Content { let x = Em::new(1.0).into(); let above = Em::new(2.4).into(); diff --git a/crates/typst/src/model/reference.rs b/crates/typst/src/model/reference.rs index 756c83fa..b96d0a53 100644 --- a/crates/typst/src/model/reference.rs +++ b/crates/typst/src/model/reference.rs @@ -3,8 +3,8 @@ use ecow::eco_format; use crate::diag::{bail, At, Hint, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, Content, Func, IntoValue, Label, NativeElement, Show, Smart, StyleChain, - Synthesize, + cast, elem, Content, Func, IntoValue, Label, NativeElement, Packed, Show, Smart, + StyleChain, Synthesize, }; use crate::introspection::{Counter, Locatable}; use crate::math::EquationElem; @@ -129,27 +129,29 @@ pub struct RefElem { /// A synthesized citation. #[synthesized] - pub citation: Option<CiteElem>, + pub citation: Option<Packed<CiteElem>>, /// The referenced element. #[synthesized] pub element: Option<Content>, } -impl Synthesize for RefElem { +impl Synthesize for Packed<RefElem> { fn synthesize( &mut self, engine: &mut Engine, styles: StyleChain, ) -> SourceResult<()> { - let citation = self.to_citation(engine, styles)?; - self.push_citation(Some(citation)); - self.push_element(None); + let citation = to_citation(self, engine, styles)?; - let target = *self.target(); + let elem = self.as_mut(); + elem.push_citation(Some(citation)); + elem.push_element(None); + + let target = *elem.target(); if !BibliographyElem::has(engine, target) { - if let Ok(elem) = engine.introspector.query_label(target).cloned() { - self.push_element(Some(elem.into_inner())); + if let Ok(found) = engine.introspector.query_label(target).cloned() { + elem.push_element(Some(found.into_inner())); return Ok(()); } } @@ -158,7 +160,7 @@ impl Synthesize for RefElem { } } -impl Show for RefElem { +impl Show for Packed<RefElem> { #[typst_macros::time(name = "ref", span = self.span())] fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(engine.delayed(|engine| { @@ -171,13 +173,13 @@ impl Show for RefElem { bail!(span, "label occurs in the document and its bibliography"); } - return Ok(self.to_citation(engine, styles)?.spanned(span).pack()); + return Ok(to_citation(self, engine, styles)?.pack().spanned(span)); } let elem = elem.at(span)?; if elem.func() == FootnoteElem::elem() { - return Ok(FootnoteElem::with_label(target).spanned(span).pack()); + return Ok(FootnoteElem::with_label(target).pack().spanned(span)); } let elem = elem.clone(); @@ -236,23 +238,23 @@ impl Show for RefElem { } } -impl RefElem { - /// Turn the reference into a citation. - pub fn to_citation( - &self, - engine: &mut Engine, - styles: StyleChain, - ) -> SourceResult<CiteElem> { - let mut elem = CiteElem::new(*self.target()).spanned(self.span()); - elem.set_location(self.location().unwrap()); - elem.synthesize(engine, styles)?; - elem.push_supplement(match self.supplement(styles).clone() { +/// Turn a reference into a citation. +fn to_citation( + reference: &Packed<RefElem>, + engine: &mut Engine, + styles: StyleChain, +) -> SourceResult<Packed<CiteElem>> { + let mut elem = Packed::new(CiteElem::new(*reference.target()).with_supplement( + match reference.supplement(styles).clone() { Smart::Custom(Some(Supplement::Content(content))) => Some(content), _ => None, - }); + }, + )); - Ok(elem) - } + elem.synthesize(engine, styles)?; + elem.set_location(reference.location().unwrap()); + + Ok(elem) } /// Additional content for a reference. diff --git a/crates/typst/src/model/strong.rs b/crates/typst/src/model/strong.rs index f6d75fb5..95d1575a 100644 --- a/crates/typst/src/model/strong.rs +++ b/crates/typst/src/model/strong.rs @@ -1,6 +1,6 @@ use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{elem, Content, Show, StyleChain}; +use crate::foundations::{elem, Content, Packed, Show, StyleChain}; use crate::text::{TextElem, WeightDelta}; /// Strongly emphasizes content by increasing the font weight. @@ -37,7 +37,7 @@ pub struct StrongElem { pub body: Content, } -impl Show for StrongElem { +impl Show for Packed<StrongElem> { #[typst_macros::time(name = "strong", span = self.span())] fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self diff --git a/crates/typst/src/model/table.rs b/crates/typst/src/model/table.rs index 3055100f..b405bd9f 100644 --- a/crates/typst/src/model/table.rs +++ b/crates/typst/src/model/table.rs @@ -1,7 +1,7 @@ use crate::diag::SourceResult; use crate::engine::Engine; use crate::foundations::{ - cast, elem, scope, Content, Fold, NativeElement, Show, Smart, StyleChain, + cast, elem, scope, Content, Fold, NativeElement, Packed, Show, Smart, StyleChain, }; use crate::layout::{ show_grid_cell, Abs, Alignment, Axes, Cell, CellGrid, Celled, Fragment, GridLayouter, @@ -166,7 +166,7 @@ impl TableElem { type TableCell; } -impl Layout for TableElem { +impl Layout for Packed<TableElem> { #[typst_macros::time(name = "table", span = self.span())] fn layout( &self, @@ -202,7 +202,7 @@ impl Layout for TableElem { } } -impl LocalName for TableElem { +impl LocalName for Packed<TableElem> { fn local_name(lang: Lang, _: Option<Region>) -> &'static str { match lang { Lang::ALBANIAN => "Tabel", @@ -239,7 +239,7 @@ impl LocalName for TableElem { } } -impl Figurable for TableElem {} +impl Figurable for Packed<TableElem> {} /// A cell in the table. Use this to either override table properties for a /// particular cell, or in show rules to apply certain styles to multiple cells @@ -315,7 +315,7 @@ impl ResolvableCell for TableCell { } } -impl Show for TableCell { +impl Show for Packed<TableCell> { fn show(&self, _engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { show_grid_cell(self.body().clone(), self.inset(styles), self.align(styles)) } @@ -323,9 +323,9 @@ impl Show for TableCell { impl From<Content> for TableCell { fn from(value: Content) -> Self { - value - .to::<Self>() - .cloned() - .unwrap_or_else(|| Self::new(value.clone())) + match value.to_packed::<Self>() { + Ok(packed) => packed.unpack(), + Err(v) => Self::new(v), + } } } diff --git a/crates/typst/src/model/terms.rs b/crates/typst/src/model/terms.rs index 53310f07..9fa7365b 100644 --- a/crates/typst/src/model/terms.rs +++ b/crates/typst/src/model/terms.rs @@ -1,7 +1,7 @@ use crate::diag::{bail, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, scope, Array, Content, NativeElement, Smart, StyleChain, + cast, elem, scope, Array, Content, NativeElement, Packed, Smart, StyleChain, }; use crate::layout::{ BlockElem, Em, Fragment, HElem, Layout, Length, Regions, Spacing, VElem, @@ -98,7 +98,7 @@ pub struct TermsElem { /// ) [/ #product: Born in #year.] /// ``` #[variadic] - pub children: Vec<TermItem>, + pub children: Vec<Packed<TermItem>>, } #[scope] @@ -107,7 +107,7 @@ impl TermsElem { type TermItem; } -impl Layout for TermsElem { +impl Layout for Packed<TermsElem> { #[typst_macros::time(name = "terms", span = self.span())] fn layout( &self, @@ -166,5 +166,5 @@ cast! { }; Self::new(term, description) }, - v: Content => v.to::<Self>().cloned().ok_or("expected term item or array")?, + v: Content => v.to_packed::<Self>().map_err(|_| "expected term item or array")?.unpack(), } diff --git a/crates/typst/src/realize/mod.rs b/crates/typst/src/realize/mod.rs index a17f82bb..080b854f 100644 --- a/crates/typst/src/realize/mod.rs +++ b/crates/typst/src/realize/mod.rs @@ -13,8 +13,8 @@ use typed_arena::Arena; use crate::diag::{bail, SourceResult}; use crate::engine::{Engine, Route}; use crate::foundations::{ - Behave, Behaviour, Content, Finalize, Guard, NativeElement, Recipe, Selector, Show, - StyleChain, StyleVec, StyleVecBuilder, Styles, Synthesize, + Behave, Behaviour, Content, Finalize, Guard, NativeElement, Packed, Recipe, Selector, + Show, StyleChain, StyleVec, StyleVecBuilder, Styles, Synthesize, }; use crate::introspection::{Locatable, Meta, MetaElem}; use crate::layout::{ @@ -51,7 +51,7 @@ pub fn realize_root<'a>( builder.interrupt_page(Some(styles), true)?; let (pages, shared) = builder.doc.unwrap().pages.finish(); let span = first_span(&pages); - Ok((Cow::Owned(DocumentElem::new(pages.to_vec()).spanned(span).pack()), shared)) + Ok((Cow::Owned(DocumentElem::new(pages.to_vec()).pack().spanned(span)), shared)) } /// Realize into an element that is capable of block-level layout. @@ -86,7 +86,7 @@ pub fn realize_block<'a>( let (children, shared) = builder.flow.0.finish(); let span = first_span(&children); - Ok((Cow::Owned(FlowElem::new(children.to_vec()).spanned(span).pack()), shared)) + Ok((Cow::Owned(FlowElem::new(children.to_vec()).pack().spanned(span)), shared)) } /// Whether the target is affected by show rules in the given style chain. @@ -137,7 +137,7 @@ pub fn realize( let span = elem.span(); let meta = Meta::Elem(elem.clone()); return Ok(Some( - (elem + MetaElem::new().spanned(span).pack()) + (elem + MetaElem::new().pack().spanned(span)) .styled(MetaElem::set_data(smallvec![meta])), )); } @@ -307,7 +307,7 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> { content = self .scratch .content - .alloc(EquationElem::new(content.clone()).spanned(content.span()).pack()); + .alloc(EquationElem::new(content.clone()).pack().spanned(content.span())); } if let Some(realized) = realize(self.engine, content, styles)? { @@ -482,9 +482,9 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> { shared }; let span = first_span(&children); - let flow = FlowElem::new(children.to_vec()).spanned(span); - let page = PageElem::new(flow.pack()).spanned(span); - let stored = self.scratch.content.alloc(page.pack()); + let flow = FlowElem::new(children.to_vec()); + let page = PageElem::new(flow.pack().spanned(span)); + let stored = self.scratch.content.alloc(page.pack().spanned(span)); self.accept(stored, styles)?; } Ok(()) @@ -622,7 +622,7 @@ impl<'a> ParBuilder<'a> { fn finish(self) -> (Content, StyleChain<'a>) { let (children, shared) = self.0.finish(); let span = first_span(&children); - (ParElem::new(children.to_vec()).spanned(span).pack(), shared) + (ParElem::new(children.to_vec()).pack().spanned(span), shared) } } @@ -671,46 +671,49 @@ impl<'a> ListBuilder<'a> { items .iter() .map(|(item, local)| { - let item = item.to::<ListItem>().unwrap(); - item.clone() - .with_body(item.body().clone().styled_with_map(local.clone())) + let mut item = item.to::<ListItem>().unwrap().clone(); + let body = item.body().clone().styled_with_map(local.clone()); + item.push_body(body); + item }) .collect::<Vec<_>>(), ) .with_tight(self.tight) - .spanned(span) .pack() + .spanned(span) } else if item.is::<EnumItem>() { EnumElem::new( items .iter() .map(|(item, local)| { - let item = item.to::<EnumItem>().unwrap(); - item.clone() - .with_body(item.body().clone().styled_with_map(local.clone())) + let mut item = item.to::<EnumItem>().unwrap().clone(); + let body = item.body().clone().styled_with_map(local.clone()); + item.push_body(body); + item }) .collect::<Vec<_>>(), ) .with_tight(self.tight) - .spanned(span) .pack() + .spanned(span) } else if item.is::<TermItem>() { TermsElem::new( items .iter() .map(|(item, local)| { - let item = item.to::<TermItem>().unwrap(); - item.clone() - .with_term(item.term().clone().styled_with_map(local.clone())) - .with_description( - item.description().clone().styled_with_map(local.clone()), - ) + let mut item = item.to::<TermItem>().unwrap().clone(); + let term = item.term().clone().styled_with_map(local.clone()); + let description = + item.description().clone().styled_with_map(local.clone()); + item.push_term(term); + item.push_description(description); + item }) .collect::<Vec<_>>(), ) .with_tight(self.tight) - .spanned(span) .pack() + .spanned(span) } else { unreachable!() }; @@ -734,7 +737,7 @@ struct CiteGroupBuilder<'a> { /// The styles. styles: StyleChain<'a>, /// The citations. - items: Vec<CiteElem>, + items: Vec<Packed<CiteElem>>, /// Trailing content for which it is unclear whether it is part of the list. staged: Vec<(&'a Content, StyleChain<'a>)>, } @@ -762,7 +765,7 @@ impl<'a> CiteGroupBuilder<'a> { fn finish(self) -> (Content, StyleChain<'a>) { let span = self.items.first().map(|cite| cite.span()).unwrap_or(Span::detached()); - (CiteGroup::new(self.items).spanned(span).pack(), self.styles) + (CiteGroup::new(self.items).pack().spanned(span), self.styles) } } diff --git a/crates/typst/src/text/deco.rs b/crates/typst/src/text/deco.rs index 0968782e..3872334d 100644 --- a/crates/typst/src/text/deco.rs +++ b/crates/typst/src/text/deco.rs @@ -5,7 +5,9 @@ use ecow::{eco_format, EcoString}; use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{elem, ty, Content, Fold, Repr, Show, Smart, StyleChain}; +use crate::foundations::{ + elem, ty, Content, Fold, Packed, Repr, Show, Smart, StyleChain, +}; use crate::layout::{Abs, Em, Frame, FrameItem, Length, Point, Size}; use crate::syntax::Span; use crate::text::{ @@ -84,7 +86,7 @@ pub struct UnderlineElem { pub body: Content, } -impl Show for UnderlineElem { +impl Show for Packed<UnderlineElem> { #[typst_macros::time(name = "underline", span = self.span())] fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_deco(Decoration { @@ -176,7 +178,7 @@ pub struct OverlineElem { pub body: Content, } -impl Show for OverlineElem { +impl Show for Packed<OverlineElem> { #[typst_macros::time(name = "overline", span = self.span())] fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_deco(Decoration { @@ -253,7 +255,7 @@ pub struct StrikeElem { pub body: Content, } -impl Show for StrikeElem { +impl Show for Packed<StrikeElem> { #[typst_macros::time(name = "strike", span = self.span())] fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_deco(Decoration { @@ -323,7 +325,7 @@ pub struct HighlightElem { pub body: Content, } -impl Show for HighlightElem { +impl Show for Packed<HighlightElem> { #[typst_macros::time(name = "highlight", span = self.span())] fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone().styled(TextElem::set_deco(Decoration { diff --git a/crates/typst/src/text/linebreak.rs b/crates/typst/src/text/linebreak.rs index d9802942..2bc315a3 100644 --- a/crates/typst/src/text/linebreak.rs +++ b/crates/typst/src/text/linebreak.rs @@ -1,4 +1,4 @@ -use crate::foundations::{elem, Behave, Behaviour}; +use crate::foundations::{elem, Behave, Behaviour, Packed}; /// Inserts a line break. /// @@ -36,7 +36,7 @@ pub struct LinebreakElem { pub justify: bool, } -impl Behave for LinebreakElem { +impl Behave for Packed<LinebreakElem> { fn behaviour(&self) -> Behaviour { Behaviour::Destructive } diff --git a/crates/typst/src/text/mod.rs b/crates/typst/src/text/mod.rs index 06e347a3..01d93feb 100644 --- a/crates/typst/src/text/mod.rs +++ b/crates/typst/src/text/mod.rs @@ -36,6 +36,7 @@ use ttf_parser::Rect; use crate::diag::{bail, SourceResult, StrResult}; use crate::engine::Engine; +use crate::foundations::Packed; use crate::foundations::{ cast, category, elem, Args, Array, Cast, Category, Construct, Content, Dict, Fold, NativeElement, Never, PlainText, Repr, Resolve, Scope, Set, Smart, StyleChain, Value, @@ -673,7 +674,7 @@ impl Construct for TextElem { } } -impl PlainText for TextElem { +impl PlainText for Packed<TextElem> { fn plain_text(&self, text: &mut EcoString) { text.push_str(self.text()); } diff --git a/crates/typst/src/text/raw.rs b/crates/typst/src/text/raw.rs index fc5d8129..b032f666 100644 --- a/crates/typst/src/text/raw.rs +++ b/crates/typst/src/text/raw.rs @@ -13,7 +13,7 @@ use crate::diag::{At, FileError, SourceResult, StrResult}; use crate::engine::Engine; use crate::foundations::{ cast, elem, scope, Args, Array, Bytes, Content, Finalize, Fold, NativeElement, - PlainText, Show, Smart, StyleChain, Styles, Synthesize, Value, + Packed, PlainText, Show, Smart, StyleChain, Styles, Synthesize, Value, }; use crate::layout::{BlockElem, Em, HAlignment}; use crate::model::Figurable; @@ -261,7 +261,7 @@ pub struct RawElem { /// Made accessible for the [`raw.line` element]($raw.line). /// Allows more styling control in `show` rules. #[synthesized] - pub lines: Vec<RawLine>, + pub lines: Vec<Packed<RawLine>>, } #[scope] @@ -287,11 +287,15 @@ impl RawElem { } } -impl Synthesize for RawElem { +impl Synthesize for Packed<RawElem> { fn synthesize(&mut self, _: &mut Engine, styles: StyleChain) -> SourceResult<()> { - self.push_lang(self.lang(styles).clone()); + let span = self.span(); + let elem = self.as_mut(); - let mut text = self.text().clone(); + let lang = elem.lang(styles).clone(); + elem.push_lang(lang); + + let mut text = elem.text().clone(); if text.contains('\t') { let tab_size = RawElem::tab_size_in(styles); text = align_tabs(&text, tab_size); @@ -300,7 +304,7 @@ impl Synthesize for RawElem { let lines = split_newlines(&text); let count = lines.len() as i64; - let lang = self + let lang = elem .lang(styles) .as_ref() .as_ref() @@ -308,11 +312,11 @@ impl Synthesize for RawElem { .or(Some("txt".into())); let extra_syntaxes = UnsyncLazy::new(|| { - load_syntaxes(&self.syntaxes(styles), &self.syntaxes_data(styles)).unwrap() + load_syntaxes(&elem.syntaxes(styles), &elem.syntaxes_data(styles)).unwrap() }); - let theme = self.theme(styles).as_ref().as_ref().map(|theme_path| { - load_theme(theme_path, self.theme_data(styles).as_ref().as_ref().unwrap()) + let theme = elem.theme(styles).as_ref().as_ref().map(|theme_path| { + load_theme(theme_path, elem.theme_data(styles).as_ref().as_ref().unwrap()) .unwrap() }); @@ -333,13 +337,13 @@ impl Synthesize for RawElem { &mut |_, range, style| styled(&text[range], foreground, style), &mut |i, range, line| { seq.push( - RawLine::new( + Packed::new(RawLine::new( i + 1, count, EcoString::from(&text[range]), Content::sequence(line.drain(..)), - ) - .spanned(self.span()), + )) + .spanned(span), ); }, ) @@ -364,34 +368,34 @@ impl Synthesize for RawElem { } seq.push( - RawLine::new( + Packed::new(RawLine::new( i as i64 + 1, count, EcoString::from(line), Content::sequence(line_content), - ) - .spanned(self.span()), + )) + .spanned(span), ); } } else { seq.extend(lines.into_iter().enumerate().map(|(i, line)| { - RawLine::new( + Packed::new(RawLine::new( i as i64 + 1, count, EcoString::from(line), TextElem::packed(line), - ) - .spanned(self.span()) + )) + .spanned(span) })); }; - self.push_lines(seq); + elem.push_lines(seq); Ok(()) } } -impl Show for RawElem { +impl Show for Packed<RawElem> { #[typst_macros::time(name = "raw", span = self.span())] fn show(&self, _: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let mut lines = EcoVec::with_capacity((2 * self.lines().len()).saturating_sub(1)); @@ -408,14 +412,14 @@ impl Show for RawElem { // Align the text before inserting it into the block. realized = realized.aligned(self.align(styles).into()); realized = - BlockElem::new().spanned(self.span()).with_body(Some(realized)).pack(); + BlockElem::new().with_body(Some(realized)).pack().spanned(self.span()); } Ok(realized) } } -impl Finalize for RawElem { +impl Finalize for Packed<RawElem> { fn finalize(&self, realized: Content, _: StyleChain) -> Content { let mut styles = Styles::new(); styles.set(TextElem::set_overhang(false)); @@ -428,7 +432,7 @@ impl Finalize for RawElem { } } -impl LocalName for RawElem { +impl LocalName for Packed<RawElem> { fn local_name(lang: Lang, region: Option<Region>) -> &'static str { match lang { Lang::ALBANIAN => "List", @@ -464,9 +468,9 @@ impl LocalName for RawElem { } } -impl Figurable for RawElem {} +impl Figurable for Packed<RawElem> {} -impl PlainText for RawElem { +impl PlainText for Packed<RawElem> { fn plain_text(&self, text: &mut EcoString) { text.push_str(self.text()); } @@ -498,14 +502,14 @@ pub struct RawLine { pub body: Content, } -impl Show for RawLine { +impl Show for Packed<RawLine> { #[typst_macros::time(name = "raw.line", span = self.span())] fn show(&self, _: &mut Engine, _styles: StyleChain) -> SourceResult<Content> { Ok(self.body().clone()) } } -impl PlainText for RawLine { +impl PlainText for Packed<RawLine> { fn plain_text(&self, text: &mut EcoString) { text.push_str(self.text()); } diff --git a/crates/typst/src/text/shift.rs b/crates/typst/src/text/shift.rs index 47a186fe..46ef703e 100644 --- a/crates/typst/src/text/shift.rs +++ b/crates/typst/src/text/shift.rs @@ -2,7 +2,7 @@ use ecow::EcoString; use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{elem, Content, Show, StyleChain}; +use crate::foundations::{elem, Content, Packed, Show, StyleChain}; use crate::layout::{Em, Length}; use crate::text::{variant, SpaceElem, TextElem, TextSize}; use crate::World; @@ -47,7 +47,7 @@ pub struct SubElem { pub body: Content, } -impl Show for SubElem { +impl Show for Packed<SubElem> { #[typst_macros::time(name = "sub", span = self.span())] fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let body = self.body().clone(); @@ -107,7 +107,7 @@ pub struct SuperElem { pub body: Content, } -impl Show for SuperElem { +impl Show for Packed<SuperElem> { #[typst_macros::time(name = "super", span = self.span())] fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { let body = self.body().clone(); diff --git a/crates/typst/src/text/space.rs b/crates/typst/src/text/space.rs index f790ee61..e584d948 100644 --- a/crates/typst/src/text/space.rs +++ b/crates/typst/src/text/space.rs @@ -1,4 +1,6 @@ -use crate::foundations::{elem, Behave, Behaviour, PlainText, Repr, Unlabellable}; +use crate::foundations::{ + elem, Behave, Behaviour, Packed, PlainText, Repr, Unlabellable, +}; use ecow::EcoString; /// A text space. @@ -11,15 +13,15 @@ impl Repr for SpaceElem { } } -impl Behave for SpaceElem { +impl Behave for Packed<SpaceElem> { fn behaviour(&self) -> Behaviour { Behaviour::Weak(2) } } -impl Unlabellable for SpaceElem {} +impl Unlabellable for Packed<SpaceElem> {} -impl PlainText for SpaceElem { +impl PlainText for Packed<SpaceElem> { fn plain_text(&self, text: &mut EcoString) { text.push(' '); } diff --git a/crates/typst/src/visualize/image/mod.rs b/crates/typst/src/visualize/image/mod.rs index 0f4d59cc..15f9276f 100644 --- a/crates/typst/src/visualize/image/mod.rs +++ b/crates/typst/src/visualize/image/mod.rs @@ -16,7 +16,7 @@ use ecow::EcoString; use crate::diag::{bail, At, SourceResult, StrResult}; use crate::engine::Engine; use crate::foundations::{ - cast, elem, func, scope, Bytes, Cast, Content, NativeElement, Resolve, Smart, + cast, elem, func, scope, Bytes, Cast, Content, NativeElement, Packed, Resolve, Smart, StyleChain, }; use crate::layout::{ @@ -124,7 +124,7 @@ impl ImageElem { #[named] fit: Option<ImageFit>, ) -> StrResult<Content> { - let mut elem = ImageElem::new(EcoString::new(), data).spanned(span); + let mut elem = ImageElem::new(EcoString::new(), data); if let Some(format) = format { elem.push_format(format); } @@ -140,11 +140,11 @@ impl ImageElem { if let Some(fit) = fit { elem.push_fit(fit); } - Ok(elem.pack()) + Ok(elem.pack().spanned(span)) } } -impl Layout for ImageElem { +impl Layout for Packed<ImageElem> { #[typst_macros::time(name = "image", span = self.span())] fn layout( &self, @@ -247,7 +247,7 @@ impl Layout for ImageElem { } } -impl LocalName for ImageElem { +impl LocalName for Packed<ImageElem> { fn local_name(lang: Lang, region: Option<Region>) -> &'static str { match lang { Lang::ALBANIAN => "Figurë", @@ -285,7 +285,7 @@ impl LocalName for ImageElem { } } -impl Figurable for ImageElem {} +impl Figurable for Packed<ImageElem> {} /// How an image should adjust itself to a given area. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)] diff --git a/crates/typst/src/visualize/line.rs b/crates/typst/src/visualize/line.rs index 94841d39..0c883500 100644 --- a/crates/typst/src/visualize/line.rs +++ b/crates/typst/src/visualize/line.rs @@ -1,6 +1,6 @@ use crate::diag::{bail, SourceResult}; use crate::engine::Engine; -use crate::foundations::{elem, NativeElement, StyleChain}; +use crate::foundations::{elem, Packed, StyleChain}; use crate::layout::{ Abs, Angle, Axes, Fragment, Frame, FrameItem, Layout, Length, Regions, Rel, Size, }; @@ -58,7 +58,7 @@ pub struct LineElem { pub stroke: Stroke, } -impl Layout for LineElem { +impl Layout for Packed<LineElem> { #[typst_macros::time(name = "line", span = self.span())] fn layout( &self, diff --git a/crates/typst/src/visualize/path.rs b/crates/typst/src/visualize/path.rs index 8b80f870..23be1d27 100644 --- a/crates/typst/src/visualize/path.rs +++ b/crates/typst/src/visualize/path.rs @@ -3,7 +3,7 @@ use kurbo::{CubicBez, ParamCurveExtrema}; use crate::diag::{bail, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - array, cast, elem, Array, NativeElement, Reflect, Resolve, Smart, StyleChain, + array, cast, elem, Array, Packed, Reflect, Resolve, Smart, StyleChain, }; use crate::layout::{ Abs, Axes, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel, Size, @@ -70,7 +70,7 @@ pub struct PathElem { pub vertices: Vec<PathVertex>, } -impl Layout for PathElem { +impl Layout for Packed<PathElem> { #[typst_macros::time(name = "path", span = self.span())] fn layout( &self, diff --git a/crates/typst/src/visualize/polygon.rs b/crates/typst/src/visualize/polygon.rs index 3b686f79..1f6dce44 100644 --- a/crates/typst/src/visualize/polygon.rs +++ b/crates/typst/src/visualize/polygon.rs @@ -3,7 +3,7 @@ use std::f64::consts::PI; use crate::diag::{bail, SourceResult}; use crate::engine::Engine; use crate::foundations::{ - elem, func, scope, Content, NativeElement, Resolve, Smart, StyleChain, + elem, func, scope, Content, NativeElement, Packed, Resolve, Smart, StyleChain, }; use crate::layout::{ Axes, Em, Fragment, Frame, FrameItem, Layout, Length, Point, Regions, Rel, @@ -114,18 +114,18 @@ impl PolygonElem { }) .collect(); - let mut elem = PolygonElem::new(vertices).spanned(span); + let mut elem = PolygonElem::new(vertices); if let Some(fill) = fill { elem.push_fill(fill); } if let Some(stroke) = stroke { elem.push_stroke(stroke); } - elem.pack() + elem.pack().spanned(span) } } -impl Layout for PolygonElem { +impl Layout for Packed<PolygonElem> { #[typst_macros::time(name = "polygon", span = self.span())] fn layout( &self, diff --git a/crates/typst/src/visualize/shape.rs b/crates/typst/src/visualize/shape.rs index f378d363..b8938d3b 100644 --- a/crates/typst/src/visualize/shape.rs +++ b/crates/typst/src/visualize/shape.rs @@ -2,7 +2,7 @@ use std::f64::consts::SQRT_2; use crate::diag::SourceResult; use crate::engine::Engine; -use crate::foundations::{elem, Content, NativeElement, Resolve, Smart, StyleChain}; +use crate::foundations::{elem, Content, Packed, Resolve, Smart, StyleChain}; use crate::layout::{ Abs, Axes, Corner, Corners, Fragment, Frame, FrameItem, Layout, Length, Point, Ratio, Regions, Rel, Sides, Size, @@ -131,7 +131,7 @@ pub struct RectElem { pub body: Option<Content>, } -impl Layout for RectElem { +impl Layout for Packed<RectElem> { #[typst_macros::time(name = "rect", span = self.span())] fn layout( &self, @@ -237,7 +237,7 @@ pub struct SquareElem { pub body: Option<Content>, } -impl Layout for SquareElem { +impl Layout for Packed<SquareElem> { #[typst_macros::time(name = "square", span = self.span())] fn layout( &self, @@ -315,7 +315,7 @@ pub struct EllipseElem { pub body: Option<Content>, } -impl Layout for EllipseElem { +impl Layout for Packed<EllipseElem> { #[typst_macros::time(name = "ellipse", span = self.span())] fn layout( &self, @@ -418,7 +418,7 @@ pub struct CircleElem { pub body: Option<Content>, } -impl Layout for CircleElem { +impl Layout for Packed<CircleElem> { #[typst_macros::time(name = "circle", span = self.span())] fn layout( &self, |
