1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
use crate::*;
use std::sync::Arc;
/// Compiler function
///
/// compiler function takes [`Context`] as parameter,
/// and returns [`CompilerReturn`] which is boxed future.
pub trait CompileFunction: Fn(Context) -> CompilerReturn + Send + Sync {}
impl<F> CompileFunction for F where F: Fn(Context) -> CompilerReturn + Send + Sync {}
/// Generic compiler
/// You can create new compiler using this.
pub struct GenericCompiler {
compile_method: Box<dyn CompileFunction>,
}
impl GenericCompiler {
pub fn empty() -> Self {
Self::from(|ctx| compile!(Ok(ctx)))
}
/// Create compiler from closure which implements [`CompileFunction`].
///
/// # Example
/// ```
/// use polysite::{compiler::utils::GenericCompiler, *};
/// GenericCompiler::from(|ctx| compile!({ Ok(ctx) }));
/// ```
pub fn from<F: CompileFunction + 'static>(f: F) -> Self {
Self {
compile_method: Box::new(f),
}
}
}
impl Compiler for GenericCompiler {
fn compile(&self, ctx: Context) -> CompilerReturn {
(self.compile_method)(ctx)
}
}
/// Pipe compiler
/// Create large compiler from piping small ones
pub struct PipeCompiler {
compilers: Vec<Arc<dyn Compiler>>,
}
impl PipeCompiler {
pub fn new(compilers: Vec<Arc<dyn Compiler>>) -> Self {
Self { compilers }
}
}
impl Compiler for PipeCompiler {
fn compile(&self, ctx: Context) -> CompilerReturn {
let compilers = self.compilers.clone();
compile!({
let mut ctx = ctx;
for c in compilers {
ctx = c.compile(ctx).await?;
}
Ok(ctx)
})
}
}
/// [`pipe!`] macro may used to make large compiler from
/// piping multiple compilers
///
/// # Example
/// This example will read source as Markdown and write HTML to target.
///
/// ```
/// use polysite::{compiler::*, *};
/// pipe!(
/// path::SetExtension::new("html"),
/// file::FileReader::new(),
/// markdown::MarkdownRenderer::new(None),
/// file::FileWriter::new(),
/// );
/// ```
#[macro_export]
macro_rules! pipe {
($f:expr, $($n:expr),+ $(,)?) => {{
$crate::compiler::utils::PipeCompiler::new(vec![
$f.get(),
$(
$n.get(),
)+
])
}}
}
pub use pipe;