#![allow(dead_code)]
use std::collections::BTreeMap;
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicU32, Ordering};
use std::cell::RefCell;
use sva_ast::{Expr, Graph};
use sva_engine::{
Backend, Change, Changed, EngineError, Handle, Placed, Render, Stream, Tier, change,
};
static RUN: AtomicU32 = AtomicU32::new(0);
pub trait Now: Future + Sized {
fn now(self) -> Self::Output {
let mut future = std::pin::pin!(self);
let waker = std::task::Waker::noop();
match future
.as_mut()
.poll(&mut std::task::Context::from_waker(waker))
{
std::task::Poll::Ready(out) => out,
std::task::Poll::Pending => panic!("a future over memory alone never waits"),
}
}
}
impl<F: Future> Now for F {}
pub async fn added<B: Backend>(
stream: &RefCell<Stream>,
graph: &Graph,
term: &Expr,
tier: &Tier<B>,
) -> Result<Handle, EngineError> {
let build = |_: &Stream| {
Ok::<_, EngineError>(Change::Add(graph.clone(), term.clone(), Placed::Written))
};
match change(stream, build, tier).await? {
Changed::Added(handle) => Ok(handle),
other => panic!("an add answered {other:?}"),
}
}
pub async fn replaced<B: Backend>(
stream: &RefCell<Stream>,
graph: &Graph,
(handle, term): (Handle, &Expr),
tier: &Tier<B>,
) -> Result<bool, EngineError> {
let build = |_: &Stream| {
Ok(Change::Replace(
handle,
graph.clone(),
term.clone(),
Placed::Written,
))
};
Ok(change(stream, build, tier).await? == Changed::Held(true))
}
pub async fn removed<B: Backend>(
stream: &RefCell<Stream>,
handle: Handle,
tier: &Tier<B>,
) -> Result<bool, EngineError> {
let build = |_: &Stream| Ok(Change::Remove(handle));
Ok(change(stream, build, tier).await? == Changed::Held(true))
}
pub async fn edited<B: Backend>(
stream: &RefCell<Stream>,
graph: &Graph,
target: &Expr,
tier: &Tier<B>,
) -> Result<(), EngineError> {
let build = |_: &Stream| Ok(Change::Target(graph.clone(), target.clone()));
change(stream, build, tier).await.map(|_| ())
}
pub fn dir_of(name: &str, files: &[(&str, &str)]) -> PathBuf {
let dir = std::env::temp_dir().join(format!(
"sva-engine-{name}-{:x}-{}",
std::process::id(),
RUN.fetch_add(1, Ordering::Relaxed)
));
let _ = fs::remove_dir_all(&dir);
fs::create_dir_all(&dir).expect("a fresh directory");
for (rel, content) in files {
let full = Path::new(&dir).join(rel);
fs::create_dir_all(full.parent().expect("a parent")).expect("a subdirectory");
fs::write(full, content).expect("a node file");
}
dir
}
pub fn graph_of(name: &str, files: &[(&str, &str)]) -> Graph {
sva_ast::parse_composition(&dir_of(name, files)).expect("a composition that parses")
}
pub fn samples(r: &Render) -> BTreeMap<String, Vec<f64>> {
r.buffers
.iter()
.map(|(id, b)| (r.tys.name(*id).to_string(), b.plane(0).to_vec()))
.collect()
}
pub fn next(stream: &mut Stream) -> Result<Option<sva_samples::Buffer>, EngineError> {
let (at, n) = (stream.position(), stream.config().block);
stream.read(at, n)
}