mirror of
https://github.com/typst/typst
synced 2025-06-28 00:03:17 +08:00
Optimize Content::has
, Introspector::query_label
, and MetaElem
(#2759)
This commit is contained in:
parent
e36a18b991
commit
0fbb1aaaaa
@ -738,6 +738,27 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Fields that can be checked using the `has` method.
|
||||||
|
let field_has_matches = element.visible_fields().map(|field| {
|
||||||
|
let elem = &element.ident;
|
||||||
|
let name = &field.enum_ident;
|
||||||
|
let field_ident = &field.ident;
|
||||||
|
|
||||||
|
if field.ghost {
|
||||||
|
quote! {
|
||||||
|
<#elem as #foundations::ElementFields>::Fields::#name => false,
|
||||||
|
}
|
||||||
|
} else if field.inherent() {
|
||||||
|
quote! {
|
||||||
|
<#elem as #foundations::ElementFields>::Fields::#name => true,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
<#elem as #foundations::ElementFields>::Fields::#name => self.#field_ident.is_some(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Fields that can be set using the `set_field` method.
|
// Fields that can be set using the `set_field` method.
|
||||||
let field_set_matches = element
|
let field_set_matches = element
|
||||||
.visible_fields()
|
.visible_fields()
|
||||||
@ -888,6 +909,10 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream {
|
|||||||
})
|
})
|
||||||
.unwrap_or_else(|| quote! { None });
|
.unwrap_or_else(|| quote! { None });
|
||||||
|
|
||||||
|
let label_has_field = element
|
||||||
|
.unless_capability("Unlabellable", || quote! { self.label().is_some() })
|
||||||
|
.unwrap_or_else(|| quote! { false });
|
||||||
|
|
||||||
let mark_prepared = element
|
let mark_prepared = element
|
||||||
.unless_capability("Unlabellable", || quote! { self.prepared = true; })
|
.unless_capability("Unlabellable", || quote! { self.prepared = true; })
|
||||||
.unwrap_or_else(|| quote! {});
|
.unwrap_or_else(|| quote! {});
|
||||||
@ -1026,6 +1051,18 @@ fn create_native_elem_impl(element: &Elem) -> TokenStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
fn fields(&self) -> #foundations::Dict {
|
||||||
let mut fields = #foundations::Dict::new();
|
let mut fields = #foundations::Dict::new();
|
||||||
#(#field_dict)*
|
#(#field_dict)*
|
||||||
|
@ -535,7 +535,7 @@ impl Content {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.get(id).is_some()
|
self.0.has(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the specified field on the content. Returns the default value if
|
/// Access the specified field on the content. Returns the default value if
|
||||||
|
@ -265,6 +265,9 @@ pub trait NativeElement: Debug + Repr + Construct + Set + Send + Sync + 'static
|
|||||||
/// Get the field with the given field ID.
|
/// Get the field with the given field ID.
|
||||||
fn field(&self, id: u8) -> Option<Value>;
|
fn field(&self, id: u8) -> Option<Value>;
|
||||||
|
|
||||||
|
/// Whether the element has the given field set.
|
||||||
|
fn has(&self, id: u8) -> bool;
|
||||||
|
|
||||||
/// Set the field with the given ID.
|
/// Set the field with the given ID.
|
||||||
fn set_field(&mut self, id: u8, value: Value) -> StrResult<()>;
|
fn set_field(&mut self, id: u8, value: Value) -> StrResult<()>;
|
||||||
|
|
||||||
|
@ -195,13 +195,13 @@ impl Introspector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Query for a unique element with the label.
|
/// Query for a unique element with the label.
|
||||||
pub fn query_label(&self, label: Label) -> StrResult<Prehashed<Content>> {
|
pub fn query_label(&self, label: Label) -> StrResult<&Prehashed<Content>> {
|
||||||
let mut found = None;
|
let mut found = None;
|
||||||
for elem in self.all().filter(|elem| elem.label() == Some(label)) {
|
for elem in self.all().filter(|elem| elem.label() == Some(label)) {
|
||||||
if found.is_some() {
|
if found.is_some() {
|
||||||
bail!("label `{}` occurs multiple times in the document", label.repr());
|
bail!("label `{}` occurs multiple times in the document", label.repr());
|
||||||
}
|
}
|
||||||
found = Some(elem.clone());
|
found = Some(elem);
|
||||||
}
|
}
|
||||||
found.ok_or_else(|| {
|
found.ok_or_else(|| {
|
||||||
eco_format!("label `{}` does not exist in the document", label.repr())
|
eco_format!("label `{}` does not exist in the document", label.repr())
|
||||||
|
@ -27,6 +27,7 @@ use smallvec::SmallVec;
|
|||||||
|
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
cast, category, elem, ty, Behave, Behaviour, Category, Content, Repr, Scope,
|
cast, category, elem, ty, Behave, Behaviour, Category, Content, Repr, Scope,
|
||||||
|
Unlabellable,
|
||||||
};
|
};
|
||||||
use crate::layout::PdfPageLabel;
|
use crate::layout::PdfPageLabel;
|
||||||
use crate::model::{Destination, Numbering};
|
use crate::model::{Destination, Numbering};
|
||||||
@ -53,7 +54,7 @@ pub fn define(global: &mut Scope) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Hosts metadata and ensures metadata is produced even for empty elements.
|
/// Hosts metadata and ensures metadata is produced even for empty elements.
|
||||||
#[elem(Behave)]
|
#[elem(Behave, Unlabellable)]
|
||||||
pub struct MetaElem {
|
pub struct MetaElem {
|
||||||
/// Metadata that should be attached to all elements affected by this style
|
/// Metadata that should be attached to all elements affected by this style
|
||||||
/// property.
|
/// property.
|
||||||
@ -61,6 +62,8 @@ pub struct MetaElem {
|
|||||||
pub data: SmallVec<[Meta; 1]>,
|
pub data: SmallVec<[Meta; 1]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Unlabellable for MetaElem {}
|
||||||
|
|
||||||
impl Behave for MetaElem {
|
impl Behave for MetaElem {
|
||||||
fn behaviour(&self) -> Behaviour {
|
fn behaviour(&self) -> Behaviour {
|
||||||
Behaviour::Invisible
|
Behaviour::Invisible
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use comemo::Prehashed;
|
|
||||||
|
|
||||||
use crate::diag::{bail, At, SourceResult, StrResult};
|
use crate::diag::{bail, At, SourceResult, StrResult};
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
@ -111,8 +109,7 @@ impl FootnoteElem {
|
|||||||
pub fn declaration_location(&self, engine: &Engine) -> StrResult<Location> {
|
pub fn declaration_location(&self, engine: &Engine) -> StrResult<Location> {
|
||||||
match self.body() {
|
match self.body() {
|
||||||
FootnoteBody::Reference(label) => {
|
FootnoteBody::Reference(label) => {
|
||||||
let element: Prehashed<Content> =
|
let element = engine.introspector.query_label(*label)?;
|
||||||
engine.introspector.query_label(*label)?;
|
|
||||||
let footnote = element
|
let footnote = element
|
||||||
.to::<FootnoteElem>()
|
.to::<FootnoteElem>()
|
||||||
.ok_or("referenced element should be a footnote")?;
|
.ok_or("referenced element should be a footnote")?;
|
||||||
|
@ -148,7 +148,7 @@ impl Synthesize for RefElem {
|
|||||||
|
|
||||||
let target = *self.target();
|
let target = *self.target();
|
||||||
if !BibliographyElem::has(engine, target) {
|
if !BibliographyElem::has(engine, target) {
|
||||||
if let Ok(elem) = engine.introspector.query_label(target) {
|
if let Ok(elem) = engine.introspector.query_label(target).cloned() {
|
||||||
self.push_element(Some(elem.into_inner()));
|
self.push_element(Some(elem.into_inner()));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -180,6 +180,7 @@ impl Show for RefElem {
|
|||||||
return Ok(FootnoteElem::with_label(target).spanned(span).pack());
|
return Ok(FootnoteElem::with_label(target).spanned(span).pack());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let elem = elem.clone();
|
||||||
let refable = elem
|
let refable = elem
|
||||||
.with::<dyn Refable>()
|
.with::<dyn Refable>()
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
@ -213,17 +214,16 @@ impl Show for RefElem {
|
|||||||
))
|
))
|
||||||
.at(span)?;
|
.at(span)?;
|
||||||
|
|
||||||
|
let loc = elem.location().unwrap();
|
||||||
let numbers = refable
|
let numbers = refable
|
||||||
.counter()
|
.counter()
|
||||||
.at(engine, elem.location().unwrap())?
|
.at(engine, loc)?
|
||||||
.display(engine, &numbering.trimmed())?;
|
.display(engine, &numbering.trimmed())?;
|
||||||
|
|
||||||
let supplement = match self.supplement(styles).as_ref() {
|
let supplement = match self.supplement(styles).as_ref() {
|
||||||
Smart::Auto => refable.supplement(),
|
Smart::Auto => refable.supplement(),
|
||||||
Smart::Custom(None) => Content::empty(),
|
Smart::Custom(None) => Content::empty(),
|
||||||
Smart::Custom(Some(supplement)) => {
|
Smart::Custom(Some(supplement)) => supplement.resolve(engine, [elem])?,
|
||||||
supplement.resolve(engine, [(*elem).clone()])?
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut content = numbers;
|
let mut content = numbers;
|
||||||
@ -231,7 +231,7 @@ impl Show for RefElem {
|
|||||||
content = supplement + TextElem::packed("\u{a0}") + content;
|
content = supplement + TextElem::packed("\u{a0}") + content;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(content.linked(Destination::Location(elem.location().unwrap())))
|
Ok(content.linked(Destination::Location(loc)))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ pub fn realize(
|
|||||||
let span = elem.span();
|
let span = elem.span();
|
||||||
let meta = Meta::Elem(elem.clone());
|
let meta = Meta::Elem(elem.clone());
|
||||||
return Ok(Some(
|
return Ok(Some(
|
||||||
(elem + MetaElem::new().pack().spanned(span))
|
(elem + MetaElem::new().spanned(span).pack())
|
||||||
.styled(MetaElem::set_data(smallvec![meta])),
|
.styled(MetaElem::set_data(smallvec![meta])),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -758,6 +758,6 @@ impl<'a> CiteGroupBuilder<'a> {
|
|||||||
|
|
||||||
fn finish(self) -> (Content, StyleChain<'a>) {
|
fn finish(self) -> (Content, StyleChain<'a>) {
|
||||||
let span = self.items.first().map(|cite| cite.span()).unwrap_or(Span::detached());
|
let span = self.items.first().map(|cite| cite.span()).unwrap_or(Span::detached());
|
||||||
(CiteGroup::new(self.items).pack().spanned(span), self.styles)
|
(CiteGroup::new(self.items).spanned(span).pack(), self.styles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user