use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use comemo::{Tracked, TrackedMut};
use typst_syntax::{Span, SyntaxMode};
use typst_utils::LazyHash;
use crate::World;
use crate::diag::SourceResult;
use crate::engine::{Engine, Route, Sink, Traced};
use crate::foundations::{
Args, Closure, Content, Context, Func, Module, NativeRuleMap, Scope, StyleChain,
Styles, Value,
};
use crate::introspection::{Introspector, Locator, SplitLocator};
use crate::layout::{Frame, Region};
use crate::model::DocumentInfo;
use crate::visualize::Color;
macro_rules! routines {
($(
$(#[$attr:meta])*
fn $name:ident $(<$($time:lifetime),*>)? ($($args:tt)*) -> $ret:ty
)*) => {
pub struct Routines {
pub rules: NativeRuleMap,
$(
$(#[$attr])*
pub $name: $(for<$($time),*>)? fn ($($args)*) -> $ret
),*
}
impl Hash for Routines {
fn hash<H: Hasher>(&self, _: &mut H) {}
}
impl Debug for Routines {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad("Routines(..)")
}
}
};
}
routines! {
fn eval_string(
routines: &Routines,
world: Tracked<dyn World + '_>,
sink: TrackedMut<Sink>,
string: &str,
span: Span,
mode: SyntaxMode,
scope: Scope,
) -> SourceResult<Value>
fn eval_closure(
func: &Func,
closure: &LazyHash<Closure>,
routines: &Routines,
world: Tracked<dyn World + '_>,
introspector: Tracked<Introspector>,
traced: Tracked<Traced>,
sink: TrackedMut<Sink>,
route: Tracked<Route>,
context: Tracked<Context>,
args: Args,
) -> SourceResult<Value>
fn realize<'a>(
kind: RealizationKind,
engine: &mut Engine,
locator: &mut SplitLocator,
arenas: &'a Arenas,
content: &'a Content,
styles: StyleChain<'a>,
) -> SourceResult<Vec<Pair<'a>>>
fn layout_frame(
engine: &mut Engine,
content: &Content,
locator: Locator,
styles: StyleChain,
region: Region,
) -> SourceResult<Frame>
fn html_module() -> Module
fn html_span_filled(content: Content, color: Color) -> Content
}
pub enum RealizationKind<'a> {
LayoutDocument { info: &'a mut DocumentInfo },
LayoutFragment { kind: &'a mut FragmentKind },
LayoutPar,
HtmlDocument { info: &'a mut DocumentInfo, is_inline: fn(&Content) -> bool },
HtmlFragment { kind: &'a mut FragmentKind, is_inline: fn(&Content) -> bool },
Math,
}
impl RealizationKind<'_> {
pub fn is_html(&self) -> bool {
matches!(self, Self::HtmlDocument { .. } | Self::HtmlFragment { .. })
}
pub fn is_fragment(&self) -> bool {
matches!(self, Self::LayoutFragment { .. } | Self::HtmlFragment { .. })
}
pub fn is_document(&self) -> bool {
matches!(self, Self::LayoutDocument { .. } | Self::HtmlDocument { .. })
}
pub fn as_document_mut(&mut self) -> Option<&mut DocumentInfo> {
match self {
Self::LayoutDocument { info } | Self::HtmlDocument { info, .. } => {
Some(*info)
}
_ => None,
}
}
pub fn as_fragment_mut(&mut self) -> Option<&mut FragmentKind> {
match self {
Self::LayoutFragment { kind } | Self::HtmlFragment { kind, .. } => {
Some(*kind)
}
_ => None,
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum FragmentKind {
Inline,
Block,
}
#[derive(Default)]
pub struct Arenas {
pub content: typed_arena::Arena<Content>,
pub styles: typed_arena::Arena<Styles>,
pub bump: bumpalo::Bump,
}
pub type Pair<'a> = (&'a Content, StyleChain<'a>);