diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-03-19 22:28:49 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-03-19 22:39:19 +0100 |
| commit | ab43bd802eafe33977a91893907e67553e099569 (patch) | |
| tree | af4dead92b143348f52e2e8f869df3f7dfd7322a /src/model/element.rs | |
| parent | d6aaae0cea1e79eecd85dc94ab85b9ad8eff48e8 (diff) | |
Renaming and refactoring
Diffstat (limited to 'src/model/element.rs')
| -rw-r--r-- | src/model/element.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/model/element.rs b/src/model/element.rs new file mode 100644 index 00000000..e25b22b4 --- /dev/null +++ b/src/model/element.rs @@ -0,0 +1,145 @@ +use std::any::TypeId; +use std::fmt::{self, Debug, Formatter}; +use std::hash::{Hash, Hasher}; + +use ecow::EcoString; +use once_cell::sync::Lazy; + +use super::{Content, Selector, Styles}; +use crate::diag::SourceResult; +use crate::eval::{ + cast_from_value, cast_to_value, Args, Dict, Func, FuncInfo, Value, Vm, +}; + +/// A document element. +pub trait Element: Construct + Set + Sized + 'static { + /// Pack the element into type-erased content. + fn pack(self) -> Content; + + /// Extract this element from type-erased content. + fn unpack(content: &Content) -> Option<&Self>; + + /// The element's function. + fn func() -> ElemFunc; +} + +/// An element's constructor function. +pub trait Construct { + /// Construct an element from the arguments. + /// + /// This is passed only the arguments that remain after execution of the + /// element's set rule. + fn construct(vm: &mut Vm, args: &mut Args) -> SourceResult<Content>; +} + +/// An element's set rule. +pub trait Set { + /// Parse relevant arguments into style properties for this element. + fn set(args: &mut Args) -> SourceResult<Styles>; +} + +/// An element's function. +#[derive(Copy, Clone)] +pub struct ElemFunc(pub(super) &'static NativeElemFunc); + +impl ElemFunc { + /// The function's name. + pub fn name(self) -> &'static str { + self.0.name + } + + /// Apply the given arguments to the function. + pub fn with(self, args: Args) -> Func { + Func::from(self).with(args) + } + + /// Extract details about the function. + pub fn info(&self) -> &'static FuncInfo { + &self.0.info + } + + /// Construct an element. + pub fn construct(self, vm: &mut Vm, args: &mut Args) -> SourceResult<Content> { + (self.0.construct)(vm, args) + } + + /// Create a selector for elements of this function. + pub fn select(self) -> Selector { + Selector::Elem(self, None) + } + + /// Create a selector for elements of this function, filtering for those + /// whose [fields](super::Content::field) match the given arguments. + pub fn where_(self, fields: Dict) -> Selector { + Selector::Elem(self, Some(fields)) + } + + /// Execute the set rule for the element and return the resulting style map. + pub fn set(self, mut args: Args) -> SourceResult<Styles> { + let styles = (self.0.set)(&mut args)?; + args.finish()?; + Ok(styles) + } +} + +impl Debug for ElemFunc { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.pad(self.name()) + } +} + +impl Hash for ElemFunc { + fn hash<H: Hasher>(&self, state: &mut H) { + state.write_usize(self.0 as *const _ as usize); + } +} + +impl Eq for ElemFunc {} + +impl PartialEq for ElemFunc { + fn eq(&self, other: &Self) -> bool { + std::ptr::eq(self.0, other.0) + } +} + +cast_from_value! { + ElemFunc, + v: Func => v.element().ok_or("expected element function")?, +} + +cast_to_value! { + v: ElemFunc => Value::Func(v.into()) +} + +impl From<&'static NativeElemFunc> for ElemFunc { + fn from(native: &'static NativeElemFunc) -> Self { + Self(native) + } +} + +/// An element function backed by a Rust type. +pub struct NativeElemFunc { + /// The element's name. + pub name: &'static str, + /// The element's vtable for capability dispatch. + pub vtable: fn(of: TypeId) -> Option<*const ()>, + /// The element's constructor. + pub construct: fn(&mut Vm, &mut Args) -> SourceResult<Content>, + /// The element's set rule. + pub set: fn(&mut Args) -> SourceResult<Styles>, + /// Details about the function. + pub info: Lazy<FuncInfo>, +} + +/// A label for an element. +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Label(pub EcoString); + +impl Debug for Label { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "<{}>", self.0) + } +} + +/// Indicates that an element cannot be labelled. +pub trait Unlabellable {} |
