use askama::Template;
use serde::Serialize;
use std::error::Error;
const EMPTY: &'static [u8] = &[];
#[macro_export]
macro_rules! sort {
($v:expr, $f:ident) => {{
let mut v = $v.clone();
v.sort_by_key(|a| a.$f);
v
}};
}
mod filters {
#[askama::filter_fn]
pub fn reverse<T>(v: Vec<T>, _: &dyn askama::Values) -> askama::Result<Vec<T>>
where
T: Clone,
{
let mut v = v.clone();
v.reverse();
Ok(v)
}
#[askama::filter_fn]
pub fn md_to_html(s: &str, _: &dyn askama::Values) -> askama::Result<String> {
use pulldown_cmark::{Options, Parser};
let options = Options::all();
let parser = Parser::new_ext(s, options);
let mut out = String::new();
pulldown_cmark::html::push_html(&mut out, parser);
Ok(out)
}
#[askama::filter_fn]
pub fn md_to_html_safe(s: &str, _: &dyn askama::Values) -> askama::Result<String> {
Ok(markdown::to_html_with_options(
s,
&markdown::Options {
parse: markdown::ParseOptions {
constructs: markdown::Constructs {
math_flow: true,
math_text: true,
..markdown::Constructs::gfm()
},
..markdown::ParseOptions::gfm()
},
compile: markdown::CompileOptions {
..markdown::CompileOptions::gfm()
},
},
)
.expect("failed to parse markdown"))
}
#[askama::filter_fn]
pub fn timestamp_s_to_rfc_2822(
timestamp_s: &i64,
_: &dyn askama::Values,
) -> askama::Result<String> {
if let Some(date_time) = chrono::DateTime::from_timestamp(*timestamp_s, 0) {
Ok(date_time.to_rfc2822())
} else {
Err(askama::Error::Custom(
"failed to get timestamp".to_string().into(),
))
}
}
fn inner_timestamp_s_to_formatted(timestamp_s: &i64, format: &str) -> askama::Result<String> {
if let Some(date_time) = chrono::DateTime::from_timestamp(*timestamp_s, 0) {
let formatted = date_time.format(format);
let mut string = String::new();
if formatted.write_to(&mut string).is_ok() {
Ok(string)
} else {
Err(askama::Error::Custom(
"failed to write formatted to string".to_string().into(),
))
}
} else {
Err(askama::Error::Custom(
"failed to get timestamp".to_string().into(),
))
}
}
#[askama::filter_fn]
pub fn timestamp_s_to_formatted(
timestamp_s: &i64,
_: &dyn askama::Values,
format: &str,
) -> askama::Result<String> {
inner_timestamp_s_to_formatted(timestamp_s, format)
}
#[askama::filter_fn]
pub fn uuid_str(bytes: &[u8; 16], _: &dyn askama::Values) -> askama::Result<String> {
Ok(uuid::Uuid::from_bytes(*bytes).to_string())
}
#[askama::filter_fn]
pub fn uuid_to_formatted(
bytes: &[u8; 16],
_: &dyn askama::Values,
format: &str,
) -> askama::Result<String> {
let uuid = uuid::Uuid::from_bytes(*bytes);
match uuid.get_timestamp() {
Some(ts) => inner_timestamp_s_to_formatted(&(ts.to_unix().0 as i64), format),
None => Ok(uuid.to_string()),
}
}
}
#[link(wasm_import_module = "env")]
unsafe extern "C" {
fn host_get_input() -> i64;
fn host_set_output(ptr: i32, len: i32) -> i32;
}
#[link(wasm_import_module = "env")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn alloc(len: usize) -> *mut u8 {
let mut buf: Vec<u8> = Vec::with_capacity(len);
let ptr = buf.as_mut_ptr();
std::mem::forget(buf);
ptr
}
pub fn recv_in<'a>() -> Result<Option<&'a [u8]>, Box<dyn Error>> {
let input = unsafe { host_get_input() };
if input == 0 {
return Ok(None);
}
let input_ptr = (input >> 32) as i32;
let input_len = input as i32;
let input = unsafe { core::slice::from_raw_parts(input_ptr as *mut u8, input_len as usize) };
Ok(Some(input))
}
pub fn send_out(output: Option<Vec<u8>>) -> Result<(), Box<dyn Error>> {
let res = match output {
Some(mut output) => {
let output_len = output.len();
let output_ptr = output.as_mut_ptr();
std::mem::forget(output);
unsafe { host_set_output(output_ptr as i32, output_len as i32) }
}
None => unsafe { host_set_output(1, 0) },
};
if res == 1 {
Ok(())
} else {
Err("failed to write to output".into())
}
}