use std::path::PathBuf;
use std::sync::Arc;
use ezu::graph::build_graph;
use ezu::paint::nodes::default_registry;
use ezu::renderer::Renderer;
use ezu::style::Document;
use serde::Serialize;
use tokio::sync::{broadcast, RwLock};
use crate::render::{Open, TileRenderer};
use crate::source::{FeatureSources, TileByteCache};
#[derive(Clone)]
pub struct AppState {
pub feature_sources: Arc<FeatureSources>,
pub style: Arc<RwLock<StyleSnapshot>>,
pub sources: Arc<Sources>,
pub schema: Arc<serde_json::Value>,
pub events: broadcast::Sender<StyleReload>,
}
pub struct Sources {
pub assets_dir: PathBuf,
pub feature_sources: Arc<FeatureSources>,
pub overzoom_levels: u8,
pub byte_cache: Arc<TileByteCache>,
pub tile_size: Option<u32>,
pub pixel_ratio: f32,
pub pad: Option<u32>,
pub png_compression: ezu::paint::host::PngCompression,
}
#[derive(Debug, Clone, Serialize)]
pub struct StyleReload {
pub version: u64,
pub text: String,
pub mtime_ms: i64,
}
pub struct StyleSnapshot {
pub doc: Document,
pub pad: u32,
pub tiles: Arc<TileRenderer>,
pub text: String,
pub version: u64,
}
impl StyleSnapshot {
pub async fn build(
text: String,
version: u64,
sources: &Sources,
) -> Result<Self, BuildSnapshotError> {
let doc = Document::from_json(&text).map_err(BuildSnapshotError::Parse)?;
let renderer =
Renderer::new(&text).map_err(|e| BuildSnapshotError::Graph(e.to_string()))?;
let pad = sources
.pad
.unwrap_or_else(|| crate::canvas_pad(renderer.graph(), &doc));
let tiles = TileRenderer::open(Open {
renderer,
doc: &doc,
pad,
tile_size: sources.tile_size,
pixel_ratio: sources.pixel_ratio,
assets_dir: &sources.assets_dir,
vector: Arc::clone(&sources.feature_sources),
overzoom_levels: sources.overzoom_levels,
params: Vec::new(),
byte_cache: Some((&sources.byte_cache, true)),
decoded_budget: crate::DECODED_CACHE_BUDGET,
cache_budget: None,
})
.await
.map_err(|e| BuildSnapshotError::Assets(e.to_string()))?;
Ok(Self {
doc,
pad,
tiles: Arc::new(tiles),
text,
version,
})
}
}
#[derive(Debug, thiserror::Error)]
pub enum BuildSnapshotError {
#[error("parse: {0}")]
Parse(#[from] ezu::style::StyleError),
#[error("build graph: {0}")]
Graph(String),
#[error("prefetch assets: {0}")]
Assets(String),
}
pub fn validate_text(text: &str) -> Result<(), BuildSnapshotError> {
let doc = Document::from_json(text).map_err(BuildSnapshotError::Parse)?;
let registry = default_registry();
build_graph(&doc, ®istry).map_err(|e| BuildSnapshotError::Graph(e.to_string()))?;
Ok(())
}
impl AppState {
pub fn new(sources: Sources, snapshot: StyleSnapshot) -> Self {
let schema = default_registry().document_schema();
let (events, _) = broadcast::channel(8);
Self {
feature_sources: Arc::clone(&sources.feature_sources),
style: Arc::new(RwLock::new(snapshot)),
sources: Arc::new(sources),
schema: Arc::new(schema),
events,
}
}
}