use futures::future::ready;
use futures::Future;
use std::path::PathBuf;
use tokio::fs::File;
use tokio::io::{AsyncWriteExt, Result};
use tokio::{join, spawn};
use crate::Element;
use crate::ElementList;
use crate::Level::*;
use crate::{Any, Input, Tex};
#[derive(Debug, Clone)]
struct TexAsync<'a, T: Tex>(&'a T);
impl<'a, T: Tex> TexAsync<'a, T> {
fn new(t: &'a T) -> Self {
Self(t)
}
fn async_latex_string(self) -> impl Future<Output = String> + Send {
let s = self.0.to_latex_string();
let future = ready(s);
Box::pin(future)
}
}
pub fn async_latex_string<T: Tex>(t: &T) -> impl Future<Output = String> + Send {
let ta = TexAsync::new(t);
ta.async_latex_string()
}
impl Element<Any> {
pub fn async_latex_string(&self) -> impl Future<Output = String> + Send {
let s = self.latex.to_string();
let future = ready(s);
Box::pin(future)
}
}
impl ElementList<Any> {
pub async fn async_latex_string(&self) -> String {
let mut meta = Vec::new();
let mut packages = Vec::new();
let mut document = Vec::new();
let list = self.clone();
spawn(async move {
meta.push(async_latex_string(&list.metadata()).await);
document.push(r"\begin{document}".to_owned());
if list.metadata().maketitle {
document.push(r"\maketitle".to_owned());
}
for i in list.iter() {
iter_push(i, &mut document, &mut packages, &mut meta).await
}
document.push(r"\end{document}".to_owned());
let result = vec![meta.join("\n"), packages.join("\n"), document.join("\n")];
result.join("\n")
})
.await
.unwrap()
}
pub async fn async_latex_split_string(&self, input: Input) -> (String, String) {
let mut meta = Vec::new();
let mut packages = Vec::new();
let mut document = Vec::new();
let list = self.clone();
spawn(async move {
meta.push(async_latex_string(&list.metadata()).await);
meta.push(async_latex_string(&input).await);
document.push(r"\begin{document}".to_owned());
if list.metadata().maketitle {
document.push(r"\maketitle".to_owned());
}
for i in list.iter() {
iter_push(i, &mut document, &mut packages, &mut meta).await
}
document.push(r"\end{document}".to_owned());
let result = vec![meta.join("\n"), document.join("\n")];
(result.join("\n"), packages.join("\n"))
})
.await
.unwrap()
}
pub async fn async_write(&self, main: PathBuf) -> Result<()> {
let s = self.async_latex_string().await;
spawn(async move {
write_file(main, s.as_bytes())
.await
.expect("Couldn't write to file");
})
.await
.unwrap();
Ok(())
}
pub async fn async_write_split(
&self,
main: PathBuf,
structure: PathBuf,
input: Input,
) -> Result<()> {
let (main_data, str_data) = self.async_latex_split_string(input).await;
let task_m = spawn(async move { write_file(main, main_data.as_bytes()).await });
let task_s = spawn(async move { write_file(structure, str_data.as_bytes()).await });
let (r1, r2) = join!(task_m, task_s);
{
r1??;
r2??;
}
Ok(())
}
}
async fn write_file(path: PathBuf, bytes: &[u8]) -> Result<()> {
let mut file = File::create(path).await?;
file.write_all(bytes).await?;
Ok(())
}
async fn iter_push(
i: &Element<Any>,
document: &mut Vec<String>,
packages: &mut Vec<String>,
meta: &mut Vec<String>,
) {
match i.level {
Document => document.push(i.async_latex_string().await),
Packages => packages.push(i.async_latex_string().await),
Meta => meta.push(i.async_latex_string().await),
}
}