use crate::model::VisualizationDocument;
use std::cell::RefCell;
mod preflight;
pub const MAX_DOCUMENT_BYTES: usize = 16 * 1024 * 1024;
pub const MAX_UNITARY_VALIDATION_WORK: usize = 16_777_216;
pub type IoResult<T> = Result<T, Box<dyn std::error::Error>>;
pub fn parse_document(text: &str) -> IoResult<VisualizationDocument> {
if text.len() > MAX_DOCUMENT_BYTES {
return Err("experiment JSON exceeds the 16 MiB input budget".into());
}
let value: serde_json::Value = serde_json::from_str(text)?;
preflight::check(&value)?;
let document: VisualizationDocument = serde_json::from_value(value)?;
document.validate()?;
Ok(document)
}
pub fn document_json(document: &VisualizationDocument) -> IoResult<String> {
document.validate()?;
let value = serde_json::to_value(document)?;
preflight::check(&value)?;
let text = serde_json::to_string_pretty(&value)?;
if text.len() > MAX_DOCUMENT_BYTES {
return Err("experiment JSON exceeds the 16 MiB export budget".into());
}
Ok(text)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn read_input(path: impl AsRef<std::path::Path>) -> IoResult<VisualizationDocument> {
use std::io::Read;
let file = std::fs::File::open(path)?;
let mut bytes = Vec::new();
file.take(MAX_DOCUMENT_BYTES as u64 + 1)
.read_to_end(&mut bytes)?;
parse_document(std::str::from_utf8(&bytes)?)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn write_export(
path: impl AsRef<std::path::Path>,
document: &VisualizationDocument,
) -> IoResult<()> {
std::fs::write(path, document_json(document)?)?;
Ok(())
}
thread_local! {
static PENDING: RefCell<Option<VisualizationDocument>> = const { RefCell::new(None) };
static CURRENT: RefCell<Option<VisualizationDocument>> = const { RefCell::new(None) };
}
pub fn queue_document(document: VisualizationDocument) -> IoResult<()> {
document.validate()?;
PENDING.with(|slot| *slot.borrow_mut() = Some(document));
Ok(())
}
pub fn take_pending_document() -> Option<VisualizationDocument> {
PENDING.with(|slot| slot.borrow_mut().take())
}
pub fn set_current_document(document: &VisualizationDocument) {
CURRENT.with(|slot| *slot.borrow_mut() = Some(document.clone()));
}
#[cfg(all(feature = "viewer", target_arch = "wasm32"))]
#[wasm_bindgen::prelude::wasm_bindgen]
pub fn load_document_json(text: &str) -> Result<(), wasm_bindgen::JsValue> {
let document =
parse_document(text).map_err(|e| wasm_bindgen::JsValue::from_str(&e.to_string()))?;
queue_document(document).map_err(|e| wasm_bindgen::JsValue::from_str(&e.to_string()))
}
#[cfg(all(feature = "viewer", target_arch = "wasm32"))]
#[wasm_bindgen::prelude::wasm_bindgen]
pub fn export_document_json() -> Result<String, wasm_bindgen::JsValue> {
CURRENT.with(|slot| match slot.borrow().as_ref() {
Some(document) => {
document_json(document).map_err(|e| wasm_bindgen::JsValue::from_str(&e.to_string()))
}
None => Err(wasm_bindgen::JsValue::from_str(
"No experiment is loaded yet",
)),
})
}