summaryrefslogtreecommitdiff
path: root/src/model/element.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-03-19 22:28:49 +0100
committerLaurenz <laurmaedje@gmail.com>2023-03-19 22:39:19 +0100
commitab43bd802eafe33977a91893907e67553e099569 (patch)
treeaf4dead92b143348f52e2e8f869df3f7dfd7322a /src/model/element.rs
parentd6aaae0cea1e79eecd85dc94ab85b9ad8eff48e8 (diff)
Renaming and refactoring
Diffstat (limited to 'src/model/element.rs')
-rw-r--r--src/model/element.rs145
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 {}