mirror of
https://github.com/maplibre/maplibre-rs.git
synced 2025-12-08 19:05:57 +00:00
Improve error handling (#222)
* Introduce proper error types for a lot of functions, remove main catch-all type * Fix compilation and clippy issues * Map, unmap and drop always * Remove not required parentheses * Fix running on non-vulkan platforms * Add and use thiserror crate
This commit is contained in:
parent
5b084f033e
commit
c12f3f1127
@ -4,7 +4,6 @@ use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use maplibre::{
|
||||
benchmarking::io::static_tile_fetcher::StaticTileFetcher,
|
||||
coords::{TileCoords, ZoomLevel},
|
||||
error::Error,
|
||||
io::{
|
||||
pipeline::{PipelineContext, PipelineProcessor, Processable},
|
||||
tile_pipelines::{ParseTile, TessellateLayer},
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use maplibre::{
|
||||
coords::{WorldTileCoords, ZoomLevel},
|
||||
error::Error,
|
||||
headless::{create_headless_renderer, map::HeadlessMap},
|
||||
platform::run_multithreaded,
|
||||
style::Style,
|
||||
@ -15,32 +14,20 @@ fn headless_render(c: &mut Criterion) {
|
||||
let map = HeadlessMap::new(style, renderer, kernel, false).unwrap();
|
||||
|
||||
let tile = map
|
||||
.fetch_tile(
|
||||
WorldTileCoords::from((0, 0, ZoomLevel::default())),
|
||||
&["water"],
|
||||
)
|
||||
.fetch_tile(WorldTileCoords::from((0, 0, ZoomLevel::default())))
|
||||
.await
|
||||
.expect("Failed to fetch and process!");
|
||||
.expect("Failed to fetch!");
|
||||
|
||||
let tile = map
|
||||
.process_tile(tile, &["water"])
|
||||
.await
|
||||
.expect("Failed to process!");
|
||||
|
||||
(map, tile)
|
||||
});
|
||||
|
||||
b.to_async(
|
||||
tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap(),
|
||||
)
|
||||
.iter(|| {
|
||||
match map.render_tile(tile.clone()) {
|
||||
Ok(_) => {}
|
||||
Err(Error::Render(e)) => {
|
||||
eprintln!("{}", e);
|
||||
if e.should_exit() {}
|
||||
}
|
||||
e => eprintln!("{:?}", e),
|
||||
};
|
||||
async {}
|
||||
b.iter(|| {
|
||||
map.render_tile(tile.clone());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@ -32,17 +32,20 @@ pub async fn run_headless(tile_size: u32, min: LatLon, max: LatLon) {
|
||||
for (z, x, y) in GridIterator::new(10, 10, tile_limits) {
|
||||
let coords = WorldTileCoords::from((x as i32, y as i32, z.into()));
|
||||
println!("Rendering {}", &coords);
|
||||
|
||||
let tile = map.fetch_tile(coords).await.expect("Failed to fetch!");
|
||||
|
||||
let tile = map
|
||||
.fetch_tile(
|
||||
coords,
|
||||
.process_tile(
|
||||
tile,
|
||||
&requested_layers
|
||||
.iter()
|
||||
.map(|layer| layer.as_str())
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.await
|
||||
.expect("Failed to fetch and process");
|
||||
.expect("Failed to process!");
|
||||
|
||||
map.render_tile(tile).expect("Rendering failed");
|
||||
map.render_tile(tile);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,8 +5,7 @@ use std::{fmt::Debug, marker::PhantomData};
|
||||
use instant::Instant;
|
||||
use maplibre::{
|
||||
environment::Environment,
|
||||
error::Error,
|
||||
event_loop::{EventLoop, EventLoopProxy},
|
||||
event_loop::{EventLoop, EventLoopProxy, SendEventError},
|
||||
io::{apc::AsyncProcedureCall, scheduler::Scheduler, source_client::HttpClient},
|
||||
map::Map,
|
||||
window::{HeadedMapWindow, MapWindowConfig},
|
||||
@ -84,16 +83,10 @@ impl<ET: 'static + PartialEq + Debug> EventLoop<ET> for WinitEventLoop<ET> {
|
||||
#[cfg(target_os = "android")]
|
||||
if !map.has_renderer() && event == Event::Resumed {
|
||||
use tokio::{runtime::Handle, task};
|
||||
use maplibre::render::settings::WgpuSettings;
|
||||
use maplibre::render::builder::RendererBuilder;
|
||||
|
||||
task::block_in_place(|| {
|
||||
Handle::current().block_on(async {
|
||||
map.initialize_renderer(RendererBuilder::new()
|
||||
.with_wgpu_settings(WgpuSettings {
|
||||
backends: Some(maplibre::render::settings::Backends::VULKAN), // FIXME: Change
|
||||
..WgpuSettings::default()
|
||||
})).await.unwrap();
|
||||
map.initialize_renderer().await.unwrap();
|
||||
})
|
||||
});
|
||||
return;
|
||||
@ -146,16 +139,8 @@ impl<ET: 'static + PartialEq + Debug> EventLoop<ET> for WinitEventLoop<ET> {
|
||||
input_controller.update_state(map_context, dt);
|
||||
}
|
||||
|
||||
match map.run_schedule() {
|
||||
Ok(_) => {}
|
||||
Err(Error::Render(e)) => {
|
||||
eprintln!("{}", e);
|
||||
if e.should_exit() {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
}
|
||||
}
|
||||
e => eprintln!("{:?}", e)
|
||||
};
|
||||
// TODO: Maybe handle gracefully
|
||||
map.run_schedule().expect("Failed to run schedule!");
|
||||
|
||||
if let Some(max_frames) = max_frames {
|
||||
if current_frame >= max_frames {
|
||||
@ -193,8 +178,10 @@ pub struct WinitEventLoopProxy<ET: 'static> {
|
||||
}
|
||||
|
||||
impl<ET: 'static> EventLoopProxy<ET> for WinitEventLoopProxy<ET> {
|
||||
fn send_event(&self, event: ET) -> Result<(), Error> {
|
||||
self.proxy.send_event(event).map_err(|e| Error::EventLoop)
|
||||
fn send_event(&self, event: ET) -> Result<(), SendEventError> {
|
||||
self.proxy
|
||||
.send_event(event)
|
||||
.map_err(|_e| SendEventError::Closed)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ use maplibre::{
|
||||
kernel::{Kernel, KernelBuilder},
|
||||
map::Map,
|
||||
platform::{http_client::ReqwestHttpClient, run_multithreaded, scheduler::TokioScheduler},
|
||||
render::{builder::RendererBuilder, settings::WgpuSettings},
|
||||
style::Style,
|
||||
window::{MapWindow, MapWindowConfig, WindowSize},
|
||||
};
|
||||
@ -82,18 +83,16 @@ pub fn run_headed_map(cache_path: Option<String>) {
|
||||
.with_scheduler(TokioScheduler::new())
|
||||
.build();
|
||||
|
||||
let mut map = Map::new(Style::default(), kernel).unwrap();
|
||||
let renderer_builder = RendererBuilder::new().with_wgpu_settings(WgpuSettings {
|
||||
backends: Some(maplibre::render::settings::Backends::all()),
|
||||
..WgpuSettings::default()
|
||||
});
|
||||
|
||||
let mut map = Map::new(Style::default(), kernel, renderer_builder).unwrap();
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
{
|
||||
use maplibre::render::{builder::RendererBuilder, settings::WgpuSettings};
|
||||
|
||||
map.initialize_renderer(RendererBuilder::new().with_wgpu_settings(WgpuSettings {
|
||||
backends: Some(maplibre::render::settings::Backends::VULKAN), // FIXME: Change
|
||||
..WgpuSettings::default()
|
||||
}))
|
||||
.await
|
||||
.unwrap();
|
||||
map.initialize_renderer().await.unwrap();
|
||||
}
|
||||
|
||||
map.window_mut()
|
||||
|
||||
@ -66,6 +66,7 @@ log = "0.4.17"
|
||||
# Utils
|
||||
bytemuck = "1.12.1"
|
||||
bytemuck_derive = "1.2.1"
|
||||
thiserror = "1.0"
|
||||
|
||||
# Static tiles inclusion
|
||||
include_dir = "0.7.2"
|
||||
@ -79,7 +80,6 @@ csscolorparser = { version = "0.6.2", features = ["serde", "cint"] }
|
||||
cint = "0.3.1"
|
||||
|
||||
# Required by bevy renderer
|
||||
thiserror = "1.0.32"
|
||||
downcast-rs = "1.2.0"
|
||||
smallvec = "1.9.0"
|
||||
|
||||
|
||||
@ -127,9 +127,9 @@ impl From<u8> for ZoomLevel {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for ZoomLevel {
|
||||
fn into(self) -> u8 {
|
||||
self.0
|
||||
impl From<ZoomLevel> for u8 {
|
||||
fn from(val: ZoomLevel) -> Self {
|
||||
val.0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
//! Errors which can happen in various parts of the library.
|
||||
|
||||
use std::{borrow::Cow, sync::mpsc::SendError};
|
||||
|
||||
use lyon::tessellation::TessellationError;
|
||||
|
||||
use crate::render::error::RenderError;
|
||||
|
||||
/// Enumeration of errors which can happen during the operation of the library.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
APC,
|
||||
Scheduler,
|
||||
EventLoop,
|
||||
Network(String),
|
||||
Tesselation(TessellationError),
|
||||
Render(RenderError),
|
||||
Generic(Cow<'static, str>),
|
||||
}
|
||||
|
||||
impl<E> From<E> for Error
|
||||
where
|
||||
E: Into<RenderError>,
|
||||
{
|
||||
fn from(e: E) -> Self {
|
||||
Error::Render(e.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TessellationError> for Error {
|
||||
fn from(e: TessellationError) -> Self {
|
||||
Error::Tesselation(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<SendError<T>> for Error {
|
||||
fn from(_e: SendError<T>) -> Self {
|
||||
Error::Scheduler
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
environment::Environment,
|
||||
error::Error,
|
||||
map::Map,
|
||||
window::{HeadedMapWindow, MapWindowConfig},
|
||||
};
|
||||
@ -12,8 +13,16 @@ pub trait EventLoopConfig {
|
||||
fn create_proxy() -> Self::EventLoopProxy;
|
||||
}
|
||||
|
||||
/// When sending events to an event loop errors can occur.
|
||||
#[derive(Error, Debug)]
|
||||
pub enum SendEventError {
|
||||
/// The event loop was already closed
|
||||
#[error("event loop is closed")]
|
||||
Closed,
|
||||
}
|
||||
|
||||
pub trait EventLoopProxy<T: 'static> {
|
||||
fn send_event(&self, event: T) -> Result<(), Error>;
|
||||
fn send_event(&self, event: T) -> Result<(), SendEventError>;
|
||||
}
|
||||
|
||||
pub trait EventLoop<ET: 'static + PartialEq> {
|
||||
|
||||
@ -3,18 +3,19 @@ use std::collections::HashSet;
|
||||
use crate::{
|
||||
context::MapContext,
|
||||
coords::{WorldCoords, WorldTileCoords, Zoom, TILE_SIZE},
|
||||
error::Error,
|
||||
headless::{
|
||||
environment::HeadlessEnvironment, graph_node::CopySurfaceBufferNode,
|
||||
stage::WriteSurfaceBufferStage,
|
||||
},
|
||||
io::{
|
||||
pipeline::{PipelineContext, PipelineProcessor, Processable},
|
||||
pipeline::{PipelineContext, PipelineError, PipelineProcessor, Processable},
|
||||
source_client::SourceFetchError,
|
||||
tile_pipelines::build_vector_tile_pipeline,
|
||||
tile_repository::{StoredLayer, StoredTile},
|
||||
RawLayer, TileRequest,
|
||||
},
|
||||
kernel::Kernel,
|
||||
map::MapError,
|
||||
render::{
|
||||
create_default_render_graph, draw_graph, eventually::Eventually,
|
||||
register_default_render_stages, stages::RenderStageLabel, Renderer, ShaderVertex,
|
||||
@ -37,7 +38,7 @@ impl HeadlessMap {
|
||||
renderer: Renderer,
|
||||
kernel: Kernel<HeadlessEnvironment>,
|
||||
write_to_disk: bool,
|
||||
) -> Result<Self, Error> {
|
||||
) -> Result<Self, MapError> {
|
||||
let window_size = renderer.state().surface().size();
|
||||
|
||||
let world = World::new(
|
||||
@ -47,7 +48,7 @@ impl HeadlessMap {
|
||||
cgmath::Deg(0.0),
|
||||
);
|
||||
|
||||
let mut graph = create_default_render_graph()?;
|
||||
let mut graph = create_default_render_graph().map_err(|e| MapError::RenderGraphInit(e))?;
|
||||
let draw_graph = graph
|
||||
.get_sub_graph_mut(draw_graph::NAME)
|
||||
.expect("Subgraph does not exist");
|
||||
@ -74,7 +75,7 @@ impl HeadlessMap {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn render_tile(&mut self, tile: StoredTile) -> Result<(), Error> {
|
||||
pub fn render_tile(&mut self, tile: StoredTile) {
|
||||
let context = &mut self.map_context;
|
||||
|
||||
if let Eventually::Initialized(pool) = context.renderer.state.buffer_pool_mut() {
|
||||
@ -88,18 +89,19 @@ impl HeadlessMap {
|
||||
context.world.tile_repository.put_tile(tile);
|
||||
|
||||
self.schedule.run(&mut self.map_context);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn fetch_tile(
|
||||
&self,
|
||||
coords: WorldTileCoords,
|
||||
source_layers: &[&str],
|
||||
) -> Result<StoredTile, Error> {
|
||||
pub async fn fetch_tile(&self, coords: WorldTileCoords) -> Result<Box<[u8]>, SourceFetchError> {
|
||||
let source_client = self.kernel.source_client();
|
||||
|
||||
let data = source_client.fetch(&coords).await?.into_boxed_slice();
|
||||
Ok(source_client.fetch(&coords).await?.into_boxed_slice())
|
||||
}
|
||||
|
||||
pub async fn process_tile(
|
||||
&self,
|
||||
tile_data: Box<[u8]>,
|
||||
source_layers: &[&str],
|
||||
) -> Result<StoredTile, PipelineError> {
|
||||
let mut pipeline_context = PipelineContext::new(HeadlessPipelineProcessor::default());
|
||||
let pipeline = build_vector_tile_pipeline();
|
||||
|
||||
@ -113,7 +115,7 @@ impl HeadlessMap {
|
||||
.map(|layer| layer.to_string())
|
||||
.collect::<HashSet<String>>(),
|
||||
},
|
||||
data,
|
||||
tile_data,
|
||||
),
|
||||
&mut pipeline_context,
|
||||
)?;
|
||||
@ -138,7 +140,7 @@ impl PipelineProcessor for HeadlessPipelineProcessor {
|
||||
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
|
||||
feature_indices: Vec<u32>,
|
||||
layer_data: RawLayer,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), PipelineError> {
|
||||
self.layers.push(StoredLayer::TessellatedLayer {
|
||||
coords: *coords,
|
||||
layer_name: layer_data.name,
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokio::{runtime::Handle, task};
|
||||
|
||||
use crate::{
|
||||
context::MapContext,
|
||||
render::{
|
||||
@ -44,19 +42,21 @@ impl Stage for WriteSurfaceBufferStage {
|
||||
let device = device.clone();
|
||||
let current_frame = self.frame;
|
||||
|
||||
let buffer_slice = buffered_texture.map_async(&device);
|
||||
let padded_buffer = buffer_slice.get_mapped_range();
|
||||
|
||||
if self.write_to_disk {
|
||||
task::block_in_place(|| {
|
||||
Handle::current().block_on(async {
|
||||
buffered_texture
|
||||
.create_png(
|
||||
&device,
|
||||
format!("frame_{}.png", current_frame).as_str(),
|
||||
)
|
||||
.await;
|
||||
})
|
||||
});
|
||||
buffered_texture.write_png(
|
||||
&padded_buffer,
|
||||
format!("frame_{}.png", current_frame).as_str(),
|
||||
);
|
||||
}
|
||||
|
||||
// With the current interface, we have to make sure all mapped views are
|
||||
// dropped before we unmap the buffer.
|
||||
drop(padded_buffer);
|
||||
buffered_texture.unmap();
|
||||
|
||||
self.frame += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,15 +8,13 @@ use std::{
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
io::{
|
||||
scheduler::Scheduler,
|
||||
source_client::{HttpClient, HttpSourceClient, SourceClient},
|
||||
transferables::{DefaultTransferables, Transferables},
|
||||
TileRequest,
|
||||
},
|
||||
use crate::io::{
|
||||
scheduler::Scheduler,
|
||||
source_client::{HttpClient, HttpSourceClient, SourceClient},
|
||||
transferables::{DefaultTransferables, Transferables},
|
||||
TileRequest,
|
||||
};
|
||||
|
||||
/// The result of the tessellation of a tile. This is sent as a message from a worker to the caller
|
||||
@ -41,18 +39,47 @@ pub enum Input {
|
||||
NotYetImplemented, // TODO: Placeholder, should be removed when second input is added
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum SendError {
|
||||
#[error("could not transmit data")]
|
||||
Transmission,
|
||||
}
|
||||
|
||||
/// Allows sending messages from workers to back to the caller.
|
||||
pub trait Context<T: Transferables, HC: HttpClient>: Send + 'static {
|
||||
/// Send a message back to the caller.
|
||||
fn send(&self, data: Message<T>) -> Result<(), Error>;
|
||||
fn send(&self, data: Message<T>) -> Result<(), SendError>;
|
||||
|
||||
fn source_client(&self) -> &SourceClient<HC>;
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ProcedureError {
|
||||
/// The [`Input`] is not compatible with the procedure
|
||||
#[error("provided input is not compatible with procedure")]
|
||||
IncompatibleInput,
|
||||
#[error("execution of procedure failed")]
|
||||
Execution(Box<dyn std::error::Error>),
|
||||
#[error("sending data failed")]
|
||||
Send(SendError),
|
||||
}
|
||||
|
||||
#[cfg(feature = "thread-safe-futures")]
|
||||
pub type AsyncProcedureFuture = Pin<Box<(dyn Future<Output = Result<(), Error>> + Send + 'static)>>;
|
||||
pub type AsyncProcedureFuture =
|
||||
Pin<Box<(dyn Future<Output = Result<(), ProcedureError>> + Send + 'static)>>;
|
||||
#[cfg(not(feature = "thread-safe-futures"))]
|
||||
pub type AsyncProcedureFuture = Pin<Box<(dyn Future<Output = Result<(), Error>> + 'static)>>;
|
||||
pub type AsyncProcedureFuture =
|
||||
Pin<Box<(dyn Future<Output = Result<(), ProcedureError>> + 'static)>>;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum CallError {
|
||||
#[error("scheduling work failed")]
|
||||
Schedule,
|
||||
#[error("serializing data failed")]
|
||||
Serialize(Box<dyn std::error::Error>),
|
||||
#[error("deserializing failed")]
|
||||
Deserialize(Box<dyn std::error::Error>),
|
||||
}
|
||||
|
||||
/// Type definitions for asynchronous procedure calls. These functions can be called in an
|
||||
/// [`AsyncProcedureCall`]. Functions of this type are required to be statically available at
|
||||
@ -109,7 +136,8 @@ pub trait AsyncProcedureCall<HC: HttpClient>: 'static {
|
||||
|
||||
/// Call an [`AsyncProcedure`] using some [`Input`]. This function is non-blocking and
|
||||
/// returns immediately.
|
||||
fn call(&self, input: Input, procedure: AsyncProcedure<Self::Context>);
|
||||
fn call(&self, input: Input, procedure: AsyncProcedure<Self::Context>)
|
||||
-> Result<(), CallError>;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -119,8 +147,8 @@ pub struct SchedulerContext<T: Transferables, HC: HttpClient> {
|
||||
}
|
||||
|
||||
impl<T: Transferables, HC: HttpClient> Context<T, HC> for SchedulerContext<T, HC> {
|
||||
fn send(&self, data: Message<T>) -> Result<(), Error> {
|
||||
self.sender.send(data).map_err(|_e| Error::APC)
|
||||
fn send(&self, data: Message<T>) -> Result<(), SendError> {
|
||||
self.sender.send(data).map_err(|_e| SendError::Transmission)
|
||||
}
|
||||
|
||||
fn source_client(&self) -> &SourceClient<HC> {
|
||||
@ -156,13 +184,17 @@ impl<HC: HttpClient, S: Scheduler> AsyncProcedureCall<HC> for SchedulerAsyncProc
|
||||
Some(transferred)
|
||||
}
|
||||
|
||||
fn call(&self, input: Input, procedure: AsyncProcedure<Self::Context>) {
|
||||
fn call(
|
||||
&self,
|
||||
input: Input,
|
||||
procedure: AsyncProcedure<Self::Context>,
|
||||
) -> Result<(), CallError> {
|
||||
let sender = self.channel.0.clone();
|
||||
let client = self.http_client.clone(); // TODO (perf): do not clone each time
|
||||
|
||||
self.scheduler
|
||||
.schedule(move || async move {
|
||||
(procedure)(
|
||||
procedure(
|
||||
input,
|
||||
SchedulerContext {
|
||||
sender,
|
||||
@ -172,6 +204,6 @@ impl<HC: HttpClient, S: Scheduler> AsyncProcedureCall<HC> for SchedulerAsyncProc
|
||||
.await
|
||||
.unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
.map_err(|_e| CallError::Schedule)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,25 +2,35 @@ use std::marker::PhantomData;
|
||||
|
||||
use downcast_rs::Downcast;
|
||||
use geozero::mvt::tile;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
coords::WorldTileCoords,
|
||||
error::Error,
|
||||
io::geometry_index::IndexedGeometry,
|
||||
io::{apc::SendError, geometry_index::IndexedGeometry},
|
||||
render::ShaderVertex,
|
||||
tessellation::{IndexDataType, OverAlignedVertexBuffer},
|
||||
};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum PipelineError {
|
||||
/// Sending of results failed
|
||||
#[error("sending data back from pipeline failed")]
|
||||
SendError(SendError),
|
||||
/// Error during processing of the pipeline
|
||||
#[error("processing data in pipeline failed")]
|
||||
Processing(Box<dyn std::error::Error>),
|
||||
}
|
||||
|
||||
/// Processes events which happen during the pipeline execution
|
||||
pub trait PipelineProcessor: Downcast {
|
||||
fn tile_finished(&mut self, _coords: &WorldTileCoords) -> Result<(), Error> {
|
||||
fn tile_finished(&mut self, _coords: &WorldTileCoords) -> Result<(), PipelineError> {
|
||||
Ok(())
|
||||
}
|
||||
fn layer_unavailable(
|
||||
&mut self,
|
||||
_coords: &WorldTileCoords,
|
||||
_layer_name: &str,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), PipelineError> {
|
||||
Ok(())
|
||||
}
|
||||
fn layer_tesselation_finished(
|
||||
@ -29,14 +39,14 @@ pub trait PipelineProcessor: Downcast {
|
||||
_buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
|
||||
_feature_indices: Vec<u32>,
|
||||
_layer_data: tile::Layer,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), PipelineError> {
|
||||
Ok(())
|
||||
}
|
||||
fn layer_indexing_finished(
|
||||
&mut self,
|
||||
_coords: &WorldTileCoords,
|
||||
_geometries: Vec<IndexedGeometry<f64>>,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), PipelineError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -76,7 +86,7 @@ pub trait Processable {
|
||||
&self,
|
||||
input: Self::Input,
|
||||
context: &mut PipelineContext,
|
||||
) -> Result<Self::Output, Error>;
|
||||
) -> Result<Self::Output, PipelineError>;
|
||||
}
|
||||
|
||||
/// A pipeline which consists of multiple steps. Steps are [`Processable`] workloads. Later steps
|
||||
@ -112,7 +122,7 @@ where
|
||||
&self,
|
||||
input: Self::Input,
|
||||
context: &mut PipelineContext,
|
||||
) -> Result<Self::Output, Error> {
|
||||
) -> Result<Self::Output, PipelineError> {
|
||||
let output = self.step.process(input, context)?;
|
||||
self.next_step.process(output, context)
|
||||
}
|
||||
@ -139,7 +149,7 @@ impl<I> Processable for PipelineEnd<I> {
|
||||
&self,
|
||||
input: Self::Input,
|
||||
_context: &mut PipelineContext,
|
||||
) -> Result<Self::Output, Error> {
|
||||
) -> Result<Self::Output, PipelineError> {
|
||||
Ok(input)
|
||||
}
|
||||
}
|
||||
@ -152,7 +162,7 @@ impl<I, O> Processable for &fn(input: I, context: &mut PipelineContext) -> O {
|
||||
&self,
|
||||
input: Self::Input,
|
||||
context: &mut PipelineContext,
|
||||
) -> Result<Self::Output, Error> {
|
||||
) -> Result<Self::Output, PipelineError> {
|
||||
Ok((self)(input, context))
|
||||
}
|
||||
}
|
||||
@ -165,7 +175,7 @@ impl<I, O> Processable for fn(input: I, context: &mut PipelineContext) -> O {
|
||||
&self,
|
||||
input: Self::Input,
|
||||
context: &mut PipelineContext,
|
||||
) -> Result<Self::Output, Error> {
|
||||
) -> Result<Self::Output, PipelineError> {
|
||||
Ok((self)(input, context))
|
||||
}
|
||||
}
|
||||
@ -203,7 +213,7 @@ where
|
||||
&self,
|
||||
input: Self::Input,
|
||||
context: &mut PipelineContext,
|
||||
) -> Result<Self::Output, Error> {
|
||||
) -> Result<Self::Output, PipelineError> {
|
||||
Ok((self.func)(input, context))
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,15 @@
|
||||
|
||||
use std::future::Future;
|
||||
|
||||
use crate::error::Error;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ScheduleError {
|
||||
#[error("scheduling work failed")]
|
||||
Scheduling(Box<dyn std::error::Error>),
|
||||
#[error("scheduler is not implemented on this platform")]
|
||||
NotImplemented,
|
||||
}
|
||||
|
||||
/// Async/await scheduler.
|
||||
/// Can schedule a task from a future factory and a shared state.
|
||||
@ -11,7 +19,7 @@ pub trait Scheduler: 'static {
|
||||
fn schedule<T>(
|
||||
&self,
|
||||
future_factory: impl (FnOnce() -> T) + Send + 'static,
|
||||
) -> Result<(), Error>
|
||||
) -> Result<(), ScheduleError>
|
||||
where
|
||||
T: Future<Output = ()> + Send + 'static;
|
||||
|
||||
@ -19,7 +27,7 @@ pub trait Scheduler: 'static {
|
||||
fn schedule<T>(
|
||||
&self,
|
||||
future_factory: impl (FnOnce() -> T) + Send + 'static,
|
||||
) -> Result<(), Error>
|
||||
) -> Result<(), ScheduleError>
|
||||
where
|
||||
T: Future<Output = ()> + 'static;
|
||||
}
|
||||
@ -27,10 +35,13 @@ pub trait Scheduler: 'static {
|
||||
pub struct NopScheduler;
|
||||
|
||||
impl Scheduler for NopScheduler {
|
||||
fn schedule<T>(&self, _future_factory: impl FnOnce() -> T + Send + 'static) -> Result<(), Error>
|
||||
fn schedule<T>(
|
||||
&self,
|
||||
_future_factory: impl FnOnce() -> T + Send + 'static,
|
||||
) -> Result<(), ScheduleError>
|
||||
where
|
||||
T: Future<Output = ()> + 'static,
|
||||
{
|
||||
Err(Error::Scheduler)
|
||||
Err(ScheduleError::NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
//! HTTP client.
|
||||
|
||||
use async_trait::async_trait;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{coords::WorldTileCoords, error::Error, style::source::TileAddressingScheme};
|
||||
use crate::{coords::WorldTileCoords, style::source::TileAddressingScheme};
|
||||
|
||||
/// A closure that returns a HTTP client.
|
||||
pub type HTTPClientFactory<HC> = dyn Fn() -> HC;
|
||||
@ -16,7 +17,7 @@ pub type HTTPClientFactory<HC> = dyn Fn() -> HC;
|
||||
#[cfg_attr(not(feature = "thread-safe-futures"), async_trait(?Send))]
|
||||
#[cfg_attr(feature = "thread-safe-futures", async_trait)]
|
||||
pub trait HttpClient: Clone + Sync + Send + 'static {
|
||||
async fn fetch(&self, url: &str) -> Result<Vec<u8>, Error>;
|
||||
async fn fetch(&self, url: &str) -> Result<Vec<u8>, SourceFetchError>;
|
||||
}
|
||||
|
||||
/// Gives access to the HTTP client which can be of multiple types,
|
||||
@ -29,6 +30,10 @@ where
|
||||
inner_client: HC,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("failed to fetch from source")]
|
||||
pub struct SourceFetchError(#[source] pub Box<dyn std::error::Error>);
|
||||
|
||||
/// Defines the different types of HTTP clients such as basic HTTP and Mbtiles.
|
||||
/// More types might be coming such as S3 and other cloud http clients.
|
||||
#[derive(Clone)]
|
||||
@ -47,7 +52,7 @@ where
|
||||
Self { http }
|
||||
}
|
||||
|
||||
pub async fn fetch(&self, coords: &WorldTileCoords) -> Result<Vec<u8>, Error> {
|
||||
pub async fn fetch(&self, coords: &WorldTileCoords) -> Result<Vec<u8>, SourceFetchError> {
|
||||
self.http.fetch(coords).await
|
||||
}
|
||||
}
|
||||
@ -62,7 +67,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn fetch(&self, coords: &WorldTileCoords) -> Result<Vec<u8>, Error> {
|
||||
pub async fn fetch(&self, coords: &WorldTileCoords) -> Result<Vec<u8>, SourceFetchError> {
|
||||
let tile_coords = coords.into_tile(TileAddressingScheme::TMS).unwrap();
|
||||
self.inner_client
|
||||
.fetch(
|
||||
|
||||
@ -1,17 +1,32 @@
|
||||
//! Static tile fetcher
|
||||
|
||||
use std::{concat, env};
|
||||
use std::{
|
||||
concat, env,
|
||||
fmt::{Display, Formatter},
|
||||
};
|
||||
|
||||
#[cfg(static_tiles_found)]
|
||||
use include_dir::include_dir;
|
||||
use include_dir::Dir;
|
||||
|
||||
use crate::{coords::TileCoords, error::Error};
|
||||
use crate::coords::TileCoords;
|
||||
#[cfg(static_tiles_found)]
|
||||
static TILES: Dir = include_dir!("$OUT_DIR/extracted-tiles");
|
||||
#[cfg(not(static_tiles_found))]
|
||||
static TILES: Dir = Dir::new("/path", &[]);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum StaticFetchError {
|
||||
/// Tile was not found in the static content
|
||||
NotFound,
|
||||
}
|
||||
|
||||
impl Display for StaticFetchError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Load PBF files which were statically embedded in the `build.rs`
|
||||
#[derive(Default)]
|
||||
pub struct StaticTileFetcher;
|
||||
@ -25,15 +40,15 @@ impl StaticTileFetcher {
|
||||
Self {}
|
||||
}
|
||||
|
||||
/// Fetch the tile static file asynchrounously and returns a vector of bytes or a network error if the file
|
||||
/// Fetch the tile static file asynchronously and returns a vector of bytes or a network error if the file
|
||||
/// could not be fetched.
|
||||
pub async fn fetch_tile(&self, coords: &TileCoords) -> Result<Vec<u8>, Error> {
|
||||
pub async fn fetch_tile(&self, coords: &TileCoords) -> Result<Vec<u8>, StaticFetchError> {
|
||||
self.sync_fetch_tile(coords)
|
||||
}
|
||||
|
||||
/// Fetch the tile static file and returns a vector of bytes or a network error if the file
|
||||
/// could not be fetched.
|
||||
pub fn sync_fetch_tile(&self, coords: &TileCoords) -> Result<Vec<u8>, Error> {
|
||||
pub fn sync_fetch_tile(&self, coords: &TileCoords) -> Result<Vec<u8>, StaticFetchError> {
|
||||
if TILES.entries().is_empty() {
|
||||
panic!(
|
||||
"There are not tiles statically embedded in this binary! StaticTileFetcher will \
|
||||
@ -43,9 +58,7 @@ impl StaticTileFetcher {
|
||||
|
||||
let tile = TILES
|
||||
.get_file(format!("{}/{}/{}.{}", coords.z, coords.x, coords.y, "pbf"))
|
||||
.ok_or_else(|| {
|
||||
Error::Network("Failed to load tile from within the binary".to_string())
|
||||
})?;
|
||||
.ok_or_else(|| StaticFetchError::NotFound)?;
|
||||
Ok(Vec::from(tile.contents()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,10 +4,9 @@ use geozero::GeozeroDatasource;
|
||||
use prost::Message;
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
io::{
|
||||
geometry_index::IndexProcessor,
|
||||
pipeline::{DataPipeline, PipelineContext, PipelineEnd, Processable},
|
||||
pipeline::{DataPipeline, PipelineContext, PipelineEnd, PipelineError, Processable},
|
||||
TileRequest,
|
||||
},
|
||||
tessellation::{zero_tessellator::ZeroTessellator, IndexDataType},
|
||||
@ -24,7 +23,7 @@ impl Processable for ParseTile {
|
||||
&self,
|
||||
(tile_request, data): Self::Input,
|
||||
_context: &mut PipelineContext,
|
||||
) -> Result<Self::Output, Error> {
|
||||
) -> Result<Self::Output, PipelineError> {
|
||||
let tile = geozero::mvt::Tile::decode(data.as_ref()).expect("failed to load tile");
|
||||
Ok((tile_request, tile))
|
||||
}
|
||||
@ -41,7 +40,7 @@ impl Processable for IndexLayer {
|
||||
&self,
|
||||
(tile_request, mut tile): Self::Input,
|
||||
context: &mut PipelineContext,
|
||||
) -> Result<Self::Output, Error> {
|
||||
) -> Result<Self::Output, PipelineError> {
|
||||
let mut index = IndexProcessor::new();
|
||||
|
||||
for layer in &mut tile.layers {
|
||||
@ -70,7 +69,7 @@ impl Processable for TessellateLayer {
|
||||
&self,
|
||||
(tile_request, mut tile): Self::Input,
|
||||
context: &mut PipelineContext,
|
||||
) -> Result<Self::Output, Error> {
|
||||
) -> Result<Self::Output, PipelineError> {
|
||||
let coords = &tile_request.coords;
|
||||
|
||||
for layer in &mut tile.layers {
|
||||
|
||||
@ -23,7 +23,6 @@ pub(crate) mod tessellation;
|
||||
|
||||
pub mod context;
|
||||
pub mod coords;
|
||||
pub mod error;
|
||||
#[cfg(feature = "headless")]
|
||||
pub mod headless;
|
||||
pub mod io;
|
||||
|
||||
@ -1,16 +1,19 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{
|
||||
context::MapContext,
|
||||
coords::{LatLon, Zoom},
|
||||
environment::Environment,
|
||||
error::Error,
|
||||
kernel::Kernel,
|
||||
render::{
|
||||
builder::{
|
||||
InitializationResult, InitializedRenderer, RendererBuilder, UninitializedRenderer,
|
||||
},
|
||||
create_default_render_graph, register_default_render_stages,
|
||||
create_default_render_graph,
|
||||
graph::RenderGraphError,
|
||||
register_default_render_stages,
|
||||
},
|
||||
schedule::{Schedule, Stage},
|
||||
stages::register_stages,
|
||||
@ -19,9 +22,23 @@ use crate::{
|
||||
world::World,
|
||||
};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum MapError {
|
||||
/// No need to set renderer again
|
||||
#[error("renderer was already set for this map")]
|
||||
RendererAlreadySet,
|
||||
#[error("initializing render graph failed")]
|
||||
RenderGraphInit(RenderGraphError),
|
||||
#[error("initializing device failed")]
|
||||
DeviceInit,
|
||||
}
|
||||
|
||||
pub enum MapContextState {
|
||||
Ready(MapContext),
|
||||
Pending { style: Style },
|
||||
Pending {
|
||||
style: Style,
|
||||
renderer_builder: RendererBuilder,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct Map<E: Environment> {
|
||||
@ -35,7 +52,11 @@ impl<E: Environment> Map<E>
|
||||
where
|
||||
<<E as Environment>::MapWindowConfig as MapWindowConfig>::MapWindow: HeadedMapWindow,
|
||||
{
|
||||
pub fn new(style: Style, kernel: Kernel<E>) -> Result<Self, Error> {
|
||||
pub fn new(
|
||||
style: Style,
|
||||
kernel: Kernel<E>,
|
||||
renderer_builder: RendererBuilder,
|
||||
) -> Result<Self, MapError> {
|
||||
let mut schedule = Schedule::default();
|
||||
|
||||
let graph = create_default_render_graph().unwrap(); // TODO: Remove unwrap
|
||||
@ -49,26 +70,30 @@ where
|
||||
|
||||
let map = Self {
|
||||
kernel,
|
||||
map_context: MapContextState::Pending { style },
|
||||
map_context: MapContextState::Pending {
|
||||
style,
|
||||
renderer_builder,
|
||||
},
|
||||
schedule,
|
||||
window,
|
||||
};
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
pub async fn initialize_renderer(
|
||||
&mut self,
|
||||
render_builder: RendererBuilder,
|
||||
) -> Result<(), Error> {
|
||||
let result = render_builder
|
||||
.build()
|
||||
.initialize_renderer::<E::MapWindowConfig>(&self.window)
|
||||
.await
|
||||
.expect("Failed to initialize renderer");
|
||||
|
||||
pub async fn initialize_renderer(&mut self) -> Result<(), MapError> {
|
||||
match &mut self.map_context {
|
||||
MapContextState::Ready(_) => Err(Error::Generic("Renderer is already set".into())),
|
||||
MapContextState::Pending { style } => {
|
||||
MapContextState::Ready(_) => Err(MapError::RendererAlreadySet),
|
||||
MapContextState::Pending {
|
||||
style,
|
||||
renderer_builder,
|
||||
} => {
|
||||
let init_result = renderer_builder
|
||||
.clone() // Cloning because we want to be able to build multiple times maybe
|
||||
.build()
|
||||
.initialize_renderer::<E::MapWindowConfig>(&self.window)
|
||||
.await
|
||||
.map_err(|e| MapError::DeviceInit)?;
|
||||
|
||||
let window_size = self.window.size();
|
||||
|
||||
let center = style.center.unwrap_or_default();
|
||||
@ -80,7 +105,7 @@ where
|
||||
cgmath::Deg::<f64>(style.pitch.unwrap_or_default()),
|
||||
);
|
||||
|
||||
match result {
|
||||
match init_result {
|
||||
InitializationResult::Initialized(InitializedRenderer { renderer, .. }) => {
|
||||
self.map_context = MapContextState::Ready(MapContext {
|
||||
world,
|
||||
@ -111,33 +136,27 @@ where
|
||||
}
|
||||
|
||||
#[tracing::instrument(name = "update_and_redraw", skip_all)]
|
||||
pub fn run_schedule(&mut self) -> Result<(), Error> {
|
||||
pub fn run_schedule(&mut self) -> Result<(), MapError> {
|
||||
match &mut self.map_context {
|
||||
MapContextState::Ready(map_context) => {
|
||||
self.schedule.run(map_context);
|
||||
Ok(())
|
||||
}
|
||||
MapContextState::Pending { .. } => {
|
||||
Err(Error::Generic("Renderer is already set".into()))
|
||||
}
|
||||
MapContextState::Pending { .. } => Err(MapError::RendererAlreadySet),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn context(&self) -> Result<&MapContext, Error> {
|
||||
pub fn context(&self) -> Result<&MapContext, MapError> {
|
||||
match &self.map_context {
|
||||
MapContextState::Ready(map_context) => Ok(map_context),
|
||||
MapContextState::Pending { .. } => {
|
||||
Err(Error::Generic("Renderer is already set".into()))
|
||||
}
|
||||
MapContextState::Pending { .. } => Err(MapError::RendererAlreadySet),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn context_mut(&mut self) -> Result<&mut MapContext, Error> {
|
||||
pub fn context_mut(&mut self) -> Result<&mut MapContext, MapError> {
|
||||
match &mut self.map_context {
|
||||
MapContextState::Ready(map_context) => Ok(map_context),
|
||||
MapContextState::Pending { .. } => {
|
||||
Err(Error::Generic("Renderer is already set".into()))
|
||||
}
|
||||
MapContextState::Pending { .. } => Err(MapError::RendererAlreadySet),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,21 +3,22 @@ use reqwest::{Client, StatusCode};
|
||||
use reqwest_middleware::ClientWithMiddleware;
|
||||
use reqwest_middleware_cache::{managers::CACacheManager, Cache, CacheMode};
|
||||
|
||||
use crate::{error::Error, io::source_client::HttpClient};
|
||||
use crate::io::source_client::{HttpClient, SourceFetchError};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ReqwestHttpClient {
|
||||
client: ClientWithMiddleware,
|
||||
}
|
||||
impl From<reqwest::Error> for Error {
|
||||
|
||||
impl From<reqwest::Error> for SourceFetchError {
|
||||
fn from(err: reqwest::Error) -> Self {
|
||||
Error::Network(err.to_string())
|
||||
SourceFetchError(Box::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<reqwest_middleware::Error> for Error {
|
||||
impl From<reqwest_middleware::Error> for SourceFetchError {
|
||||
fn from(err: reqwest_middleware::Error) -> Self {
|
||||
Error::Network(err.to_string())
|
||||
SourceFetchError(Box::new(err))
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,7 +44,7 @@ impl ReqwestHttpClient {
|
||||
#[cfg_attr(not(feature = "thread-safe-futures"), async_trait(?Send))]
|
||||
#[cfg_attr(feature = "thread-safe-futures", async_trait)]
|
||||
impl HttpClient for ReqwestHttpClient {
|
||||
async fn fetch(&self, url: &str) -> Result<Vec<u8>, Error> {
|
||||
async fn fetch(&self, url: &str) -> Result<Vec<u8>, SourceFetchError> {
|
||||
let response = self.client.get(url).send().await?;
|
||||
match response.error_for_status() {
|
||||
Ok(response) => {
|
||||
@ -54,7 +55,7 @@ impl HttpClient for ReqwestHttpClient {
|
||||
let body = response.bytes().await?;
|
||||
Ok(Vec::from(body.as_ref()))
|
||||
}
|
||||
Err(e) => Err(Error::Network(e.to_string())),
|
||||
Err(e) => Err(SourceFetchError(Box::new(e))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::future::Future;
|
||||
|
||||
use crate::{error::Error, io::scheduler::Scheduler};
|
||||
use crate::io::scheduler::{ScheduleError, Scheduler};
|
||||
|
||||
/// Multi-threading with Tokio.
|
||||
pub struct TokioScheduler;
|
||||
@ -13,7 +13,10 @@ impl TokioScheduler {
|
||||
|
||||
impl Scheduler for TokioScheduler {
|
||||
#[cfg(feature = "thread-safe-futures")]
|
||||
fn schedule<T>(&self, future_factory: impl FnOnce() -> T + Send + 'static) -> Result<(), Error>
|
||||
fn schedule<T>(
|
||||
&self,
|
||||
future_factory: impl FnOnce() -> T + Send + 'static,
|
||||
) -> Result<(), ScheduleError>
|
||||
where
|
||||
T: Future<Output = ()> + Send + 'static,
|
||||
{
|
||||
@ -23,7 +26,10 @@ impl Scheduler for TokioScheduler {
|
||||
|
||||
// FIXME: Provide a working implementation
|
||||
#[cfg(not(feature = "thread-safe-futures"))]
|
||||
fn schedule<T>(&self, _future_factory: impl FnOnce() -> T + 'static) -> Result<(), Error>
|
||||
fn schedule<T>(
|
||||
&self,
|
||||
_future_factory: impl FnOnce() -> T + 'static,
|
||||
) -> Result<(), ScheduleError>
|
||||
where
|
||||
T: Future<Output = ()> + 'static,
|
||||
{
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
use crate::{
|
||||
error::Error,
|
||||
render::{
|
||||
error::RenderError,
|
||||
settings::{RendererSettings, WgpuSettings},
|
||||
Renderer,
|
||||
},
|
||||
window::{HeadedMapWindow, MapWindowConfig},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RendererBuilder {
|
||||
wgpu_settings: Option<WgpuSettings>,
|
||||
renderer_settings: Option<RendererSettings>,
|
||||
@ -87,7 +88,7 @@ impl UninitializedRenderer {
|
||||
pub async fn initialize_renderer<MWC>(
|
||||
self,
|
||||
existing_window: &MWC::MapWindow,
|
||||
) -> Result<InitializationResult, Error>
|
||||
) -> Result<InitializationResult, RenderError>
|
||||
where
|
||||
MWC: MapWindowConfig,
|
||||
<MWC as MapWindowConfig>::MapWindow: HeadedMapWindow,
|
||||
@ -109,7 +110,7 @@ impl UninitializedRenderer {
|
||||
pub(crate) async fn initialize_headless<MWC>(
|
||||
self,
|
||||
existing_window: &MWC::MapWindow,
|
||||
) -> Result<Renderer, Error>
|
||||
) -> Result<Renderer, RenderError>
|
||||
where
|
||||
MWC: MapWindowConfig,
|
||||
{
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::fmt;
|
||||
|
||||
use crate::{error::Error, render::graph::RenderGraphError};
|
||||
use crate::render::graph::RenderGraphError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RenderError {
|
||||
@ -37,14 +37,14 @@ impl From<RenderGraphError> for RenderError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<wgpu::SurfaceError> for Error {
|
||||
impl From<wgpu::SurfaceError> for RenderError {
|
||||
fn from(e: wgpu::SurfaceError) -> Self {
|
||||
Error::Render(RenderError::Surface(e))
|
||||
RenderError::Surface(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<wgpu::RequestDeviceError> for Error {
|
||||
impl From<wgpu::RequestDeviceError> for RenderError {
|
||||
fn from(e: wgpu::RequestDeviceError) -> Self {
|
||||
Error::Render(RenderError::Device(e))
|
||||
RenderError::Device(e)
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,14 +159,14 @@ impl SlotInfos {
|
||||
/// Retrieves the [`SlotInfo`] for the provided label.
|
||||
pub fn get_slot(&self, label: impl Into<SlotLabel>) -> Option<&SlotInfo> {
|
||||
let label = label.into();
|
||||
let index = self.get_slot_index(&label)?;
|
||||
let index = self.get_slot_index(label)?;
|
||||
self.slots.get(index)
|
||||
}
|
||||
|
||||
/// Retrieves the [`SlotInfo`] for the provided label mutably.
|
||||
pub fn get_slot_mut(&mut self, label: impl Into<SlotLabel>) -> Option<&mut SlotInfo> {
|
||||
let label = label.into();
|
||||
let index = self.get_slot_index(&label)?;
|
||||
let index = self.get_slot_index(label)?;
|
||||
self.slots.get_mut(index)
|
||||
}
|
||||
|
||||
|
||||
@ -20,8 +20,6 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use log::info;
|
||||
|
||||
use crate::{
|
||||
render::{
|
||||
eventually::Eventually,
|
||||
@ -246,10 +244,9 @@ impl Renderer {
|
||||
let adapter = instance
|
||||
.request_adapter(request_adapter_options)
|
||||
.await
|
||||
.expect("Unable to find a GPU! Make sure you have installed required drivers!");
|
||||
.ok_or_else(|| wgpu::RequestDeviceError)?;
|
||||
|
||||
let adapter_info = adapter.get_info();
|
||||
info!("{:?}", adapter_info);
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let trace_path = if settings.record_trace {
|
||||
|
||||
@ -67,13 +67,7 @@ pub struct BufferedTextureHead {
|
||||
|
||||
#[cfg(feature = "headless")]
|
||||
impl BufferedTextureHead {
|
||||
pub async fn create_png<'a>(
|
||||
&self,
|
||||
device: &wgpu::Device,
|
||||
png_output_path: &str,
|
||||
// device: &wgpu::Device,
|
||||
) {
|
||||
use std::{fs::File, io::Write};
|
||||
pub fn map_async<'a>(&self, device: &wgpu::Device) -> wgpu::BufferSlice {
|
||||
// Note that we're not calling `.await` here.
|
||||
let buffer_slice = self.output_buffer.slice(..);
|
||||
buffer_slice.map_async(wgpu::MapMode::Read, |_| ());
|
||||
@ -82,8 +76,15 @@ impl BufferedTextureHead {
|
||||
// In an actual application, `device.poll(...)` should
|
||||
// be called in an event loop or on another thread.
|
||||
device.poll(wgpu::Maintain::Wait);
|
||||
let padded_buffer = buffer_slice.get_mapped_range();
|
||||
buffer_slice
|
||||
}
|
||||
|
||||
pub fn unmap(&self) {
|
||||
self.output_buffer.unmap();
|
||||
}
|
||||
|
||||
pub fn write_png<'a>(&self, padded_buffer: &wgpu::BufferView<'a>, png_output_path: &str) {
|
||||
use std::{fs::File, io::Write};
|
||||
let mut png_encoder = png::Encoder::new(
|
||||
File::create(png_output_path).unwrap(), // TODO: Remove unwrap
|
||||
self.buffer_dimensions.width as u32,
|
||||
@ -104,12 +105,6 @@ impl BufferedTextureHead {
|
||||
.unwrap(); // TODO: Remove unwrap
|
||||
}
|
||||
png_writer.finish().unwrap(); // TODO: Remove unwrap
|
||||
|
||||
// With the current interface, we have to make sure all mapped views are
|
||||
// dropped before we unmap the buffer.
|
||||
drop(padded_buffer);
|
||||
|
||||
self.output_buffer.unmap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -51,6 +51,8 @@ impl Stage for GraphRunnerStage {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Replace panic with a graceful exit in the event loop
|
||||
// if e.should_exit() { *control_flow = ControlFlow::Exit; }
|
||||
panic!("Error running render graph: {:?}", e);
|
||||
}
|
||||
|
||||
|
||||
@ -8,11 +8,10 @@ use request_stage::RequestStage;
|
||||
use crate::{
|
||||
coords::WorldTileCoords,
|
||||
environment::Environment,
|
||||
error::Error,
|
||||
io::{
|
||||
apc::{Context, Message},
|
||||
geometry_index::{IndexedGeometry, TileIndex},
|
||||
pipeline::PipelineProcessor,
|
||||
pipeline::{PipelineError, PipelineProcessor},
|
||||
source_client::HttpClient,
|
||||
transferables::{
|
||||
LayerIndexed, LayerTessellated, LayerUnavailable, TileTessellated, Transferables,
|
||||
@ -43,23 +42,25 @@ pub struct HeadedPipelineProcessor<T: Transferables, HC: HttpClient, C: Context<
|
||||
impl<'c, T: Transferables, HC: HttpClient, C: Context<T, HC>> PipelineProcessor
|
||||
for HeadedPipelineProcessor<T, HC, C>
|
||||
{
|
||||
fn tile_finished(&mut self, coords: &WorldTileCoords) -> Result<(), Error> {
|
||||
fn tile_finished(&mut self, coords: &WorldTileCoords) -> Result<(), PipelineError> {
|
||||
self.context
|
||||
.send(Message::TileTessellated(T::TileTessellated::build_from(
|
||||
*coords,
|
||||
)))
|
||||
.map_err(|e| PipelineError::Processing(Box::new(e)))
|
||||
}
|
||||
|
||||
fn layer_unavailable(
|
||||
&mut self,
|
||||
coords: &WorldTileCoords,
|
||||
layer_name: &str,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), PipelineError> {
|
||||
self.context
|
||||
.send(Message::LayerUnavailable(T::LayerUnavailable::build_from(
|
||||
*coords,
|
||||
layer_name.to_owned(),
|
||||
)))
|
||||
.map_err(|e| PipelineError::Processing(Box::new(e)))
|
||||
}
|
||||
|
||||
fn layer_tesselation_finished(
|
||||
@ -68,7 +69,7 @@ impl<'c, T: Transferables, HC: HttpClient, C: Context<T, HC>> PipelineProcessor
|
||||
buffer: OverAlignedVertexBuffer<ShaderVertex, IndexDataType>,
|
||||
feature_indices: Vec<u32>,
|
||||
layer_data: tile::Layer,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), PipelineError> {
|
||||
self.context
|
||||
.send(Message::LayerTessellated(T::LayerTessellated::build_from(
|
||||
*coords,
|
||||
@ -76,17 +77,19 @@ impl<'c, T: Transferables, HC: HttpClient, C: Context<T, HC>> PipelineProcessor
|
||||
feature_indices,
|
||||
layer_data,
|
||||
)))
|
||||
.map_err(|e| PipelineError::Processing(Box::new(e)))
|
||||
}
|
||||
|
||||
fn layer_indexing_finished(
|
||||
&mut self,
|
||||
coords: &WorldTileCoords,
|
||||
geometries: Vec<IndexedGeometry<f64>>,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), PipelineError> {
|
||||
self.context
|
||||
.send(Message::LayerIndexed(T::LayerIndexed::build_from(
|
||||
*coords,
|
||||
TileIndex::Linear { list: geometries },
|
||||
)))
|
||||
.map_err(|e| PipelineError::Processing(Box::new(e)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,9 +6,8 @@ use crate::{
|
||||
context::MapContext,
|
||||
coords::{ViewRegion, WorldTileCoords},
|
||||
environment::Environment,
|
||||
error::Error,
|
||||
io::{
|
||||
apc::{AsyncProcedureCall, AsyncProcedureFuture, Context, Input, Message},
|
||||
apc::{AsyncProcedureCall, AsyncProcedureFuture, Context, Input, Message, ProcedureError},
|
||||
pipeline::{PipelineContext, Processable},
|
||||
tile_pipelines::build_vector_tile_pipeline,
|
||||
tile_repository::TileRepository,
|
||||
@ -71,7 +70,7 @@ pub fn schedule<
|
||||
) -> AsyncProcedureFuture {
|
||||
Box::pin(async move {
|
||||
let Input::TileRequest(input) = input else {
|
||||
return Err(Error::APC)
|
||||
return Err(ProcedureError::IncompatibleInput)
|
||||
};
|
||||
|
||||
let coords = input.coords;
|
||||
@ -87,7 +86,9 @@ pub fn schedule<
|
||||
phantom_hc: Default::default(),
|
||||
});
|
||||
let pipeline = build_vector_tile_pipeline();
|
||||
pipeline.process((input, data), &mut pipeline_context)?;
|
||||
pipeline
|
||||
.process((input, data), &mut pipeline_context)
|
||||
.map_err(|e| ProcedureError::Execution(Box::new(e)))?;
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{:?}", &e);
|
||||
@ -100,7 +101,7 @@ pub fn schedule<
|
||||
input.coords,
|
||||
to_load.to_string(),
|
||||
)),
|
||||
)?;
|
||||
).map_err(ProcedureError::Send)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -126,8 +127,7 @@ impl<E: Environment> RequestStage<E> {
|
||||
for coords in view_region.iter() {
|
||||
if coords.build_quad_key().is_some() {
|
||||
// TODO: Make tesselation depend on style?
|
||||
self.request_tile(tile_repository, coords, &source_layers)
|
||||
.unwrap(); // TODO: Remove unwrap
|
||||
self.request_tile(tile_repository, coords, &source_layers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -137,7 +137,7 @@ impl<E: Environment> RequestStage<E> {
|
||||
tile_repository: &mut TileRepository,
|
||||
coords: WorldTileCoords,
|
||||
layers: &HashSet<String>,
|
||||
) -> Result<(), Error> {
|
||||
) {
|
||||
/* TODO: is this still required?
|
||||
if !tile_repository.is_layers_missing(coords, layers) {
|
||||
return Ok(false);
|
||||
@ -147,20 +147,19 @@ impl<E: Environment> RequestStage<E> {
|
||||
tile_repository.create_tile(coords);
|
||||
|
||||
tracing::info!("new tile request: {}", &coords);
|
||||
self.kernel.apc().call(
|
||||
Input::TileRequest(TileRequest {
|
||||
coords,
|
||||
layers: layers.clone(),
|
||||
}),
|
||||
schedule::<
|
||||
E,
|
||||
<E::AsyncProcedureCall as AsyncProcedureCall<
|
||||
E::HttpClient,
|
||||
>>::Context,
|
||||
>,
|
||||
);
|
||||
self.kernel
|
||||
.apc()
|
||||
.call(
|
||||
Input::TileRequest(TileRequest {
|
||||
coords,
|
||||
layers: layers.clone(),
|
||||
}),
|
||||
schedule::<
|
||||
E,
|
||||
<E::AsyncProcedureCall as AsyncProcedureCall<E::HttpClient>>::Context,
|
||||
>,
|
||||
)
|
||||
.unwrap(); // TODO: Remove unwrap
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,11 @@
|
||||
//! Tessellation for lines and polygons is implemented here.
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
use bytemuck::Pod;
|
||||
use lyon::tessellation::{
|
||||
FillVertex, FillVertexConstructor, StrokeVertex, StrokeVertexConstructor, VertexBuffers,
|
||||
};
|
||||
|
||||
use crate::{error::Error, render::ShaderVertex};
|
||||
use crate::render::ShaderVertex;
|
||||
|
||||
pub mod zero_tessellator;
|
||||
|
||||
@ -16,14 +14,6 @@ const DEFAULT_TOLERANCE: f32 = 0.02;
|
||||
/// Vertex buffers index data type.
|
||||
pub type IndexDataType = u32; // Must match INDEX_FORMAT
|
||||
|
||||
/// An element that can be tessellated into vertex buffers.
|
||||
pub trait Tessellated<I: Add> {
|
||||
/// Returns a vertex buffer which represents some object like a layer. Each object can contain
|
||||
/// multiple features. For each feature also the amount of indices is returned.
|
||||
///
|
||||
fn tessellate(&self) -> Result<(VertexBuffers<ShaderVertex, I>, Vec<u32>), Error>;
|
||||
}
|
||||
|
||||
/// Constructor for Fill and Stroke vertices.
|
||||
pub struct VertexConstructor {}
|
||||
|
||||
|
||||
@ -30,6 +30,8 @@ maplibre-winit = { path = "../maplibre-winit", version = "0.1.0" }
|
||||
log = "0.4.17"
|
||||
rand = { version = "0.7", features = ["wasm-bindgen"] }
|
||||
|
||||
thiserror = "1.0"
|
||||
|
||||
console_error_panic_hook = "0.1.7"
|
||||
# Exact version requirement can be removed as soon as https://github.com/gfx-rs/wgpu/pull/2954 is merged
|
||||
web-sys = { version = "0.3.58", features = [
|
||||
@ -42,7 +44,7 @@ js-sys = "0.3.58"
|
||||
wasm-bindgen = "0.2.81"
|
||||
wasm-bindgen-futures = "0.4.31"
|
||||
console_log = { version = "0.2.0", features = ["color"] }
|
||||
tracing-wasm = { version = "0.2.1", optional = true } # TODO: Low quality dependency
|
||||
tracing-wasm = { version = "0.2.1", optional = true } # TODO: Low quality dependency (remove in a separate PR!)
|
||||
# For passing Inputs in AsyncProcedureCalls
|
||||
serde_json = "1.0.85"
|
||||
flatbuffers = "22.10.26"
|
||||
|
||||
388
web/lib/package-lock.json
generated
388
web/lib/package-lock.json
generated
@ -71,9 +71,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.13.tgz",
|
||||
"integrity": "sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
|
||||
"integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@ -87,9 +87,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz",
|
||||
"integrity": "sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz",
|
||||
"integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@ -139,9 +139,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
@ -265,9 +265,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.13.tgz",
|
||||
"integrity": "sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz",
|
||||
"integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
@ -277,34 +277,34 @@
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/android-arm": "0.15.13",
|
||||
"@esbuild/linux-loong64": "0.15.13",
|
||||
"esbuild-android-64": "0.15.13",
|
||||
"esbuild-android-arm64": "0.15.13",
|
||||
"esbuild-darwin-64": "0.15.13",
|
||||
"esbuild-darwin-arm64": "0.15.13",
|
||||
"esbuild-freebsd-64": "0.15.13",
|
||||
"esbuild-freebsd-arm64": "0.15.13",
|
||||
"esbuild-linux-32": "0.15.13",
|
||||
"esbuild-linux-64": "0.15.13",
|
||||
"esbuild-linux-arm": "0.15.13",
|
||||
"esbuild-linux-arm64": "0.15.13",
|
||||
"esbuild-linux-mips64le": "0.15.13",
|
||||
"esbuild-linux-ppc64le": "0.15.13",
|
||||
"esbuild-linux-riscv64": "0.15.13",
|
||||
"esbuild-linux-s390x": "0.15.13",
|
||||
"esbuild-netbsd-64": "0.15.13",
|
||||
"esbuild-openbsd-64": "0.15.13",
|
||||
"esbuild-sunos-64": "0.15.13",
|
||||
"esbuild-windows-32": "0.15.13",
|
||||
"esbuild-windows-64": "0.15.13",
|
||||
"esbuild-windows-arm64": "0.15.13"
|
||||
"@esbuild/android-arm": "0.15.18",
|
||||
"@esbuild/linux-loong64": "0.15.18",
|
||||
"esbuild-android-64": "0.15.18",
|
||||
"esbuild-android-arm64": "0.15.18",
|
||||
"esbuild-darwin-64": "0.15.18",
|
||||
"esbuild-darwin-arm64": "0.15.18",
|
||||
"esbuild-freebsd-64": "0.15.18",
|
||||
"esbuild-freebsd-arm64": "0.15.18",
|
||||
"esbuild-linux-32": "0.15.18",
|
||||
"esbuild-linux-64": "0.15.18",
|
||||
"esbuild-linux-arm": "0.15.18",
|
||||
"esbuild-linux-arm64": "0.15.18",
|
||||
"esbuild-linux-mips64le": "0.15.18",
|
||||
"esbuild-linux-ppc64le": "0.15.18",
|
||||
"esbuild-linux-riscv64": "0.15.18",
|
||||
"esbuild-linux-s390x": "0.15.18",
|
||||
"esbuild-netbsd-64": "0.15.18",
|
||||
"esbuild-openbsd-64": "0.15.18",
|
||||
"esbuild-sunos-64": "0.15.18",
|
||||
"esbuild-windows-32": "0.15.18",
|
||||
"esbuild-windows-64": "0.15.18",
|
||||
"esbuild-windows-arm64": "0.15.18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz",
|
||||
"integrity": "sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz",
|
||||
"integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -318,9 +318,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-arm64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz",
|
||||
"integrity": "sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -334,9 +334,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz",
|
||||
"integrity": "sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz",
|
||||
"integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -350,9 +350,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-arm64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz",
|
||||
"integrity": "sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -366,9 +366,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz",
|
||||
"integrity": "sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz",
|
||||
"integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -382,9 +382,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-arm64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz",
|
||||
"integrity": "sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -398,9 +398,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-32": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz",
|
||||
"integrity": "sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz",
|
||||
"integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@ -414,9 +414,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz",
|
||||
"integrity": "sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz",
|
||||
"integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -430,9 +430,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz",
|
||||
"integrity": "sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz",
|
||||
"integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@ -446,9 +446,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz",
|
||||
"integrity": "sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -462,9 +462,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-mips64le": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz",
|
||||
"integrity": "sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz",
|
||||
"integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
@ -478,9 +478,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-ppc64le": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz",
|
||||
"integrity": "sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz",
|
||||
"integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@ -494,9 +494,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-riscv64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz",
|
||||
"integrity": "sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz",
|
||||
"integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@ -510,9 +510,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-s390x": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz",
|
||||
"integrity": "sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz",
|
||||
"integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@ -526,9 +526,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-netbsd-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz",
|
||||
"integrity": "sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz",
|
||||
"integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -542,9 +542,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-openbsd-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz",
|
||||
"integrity": "sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz",
|
||||
"integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -568,9 +568,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-sunos-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz",
|
||||
"integrity": "sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz",
|
||||
"integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -584,9 +584,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-32": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz",
|
||||
"integrity": "sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz",
|
||||
"integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@ -600,9 +600,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz",
|
||||
"integrity": "sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz",
|
||||
"integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@ -616,9 +616,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-arm64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz",
|
||||
"integrity": "sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@ -947,9 +947,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.8.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
|
||||
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
|
||||
"version": "4.9.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
|
||||
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
@ -1056,16 +1056,16 @@
|
||||
"dev": true
|
||||
},
|
||||
"@esbuild/android-arm": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.13.tgz",
|
||||
"integrity": "sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
|
||||
"integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"@esbuild/linux-loong64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz",
|
||||
"integrity": "sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz",
|
||||
"integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -1094,9 +1094,9 @@
|
||||
}
|
||||
},
|
||||
"anymatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"normalize-path": "^3.0.0",
|
||||
@ -1184,144 +1184,144 @@
|
||||
"dev": true
|
||||
},
|
||||
"esbuild": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.13.tgz",
|
||||
"integrity": "sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz",
|
||||
"integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@esbuild/android-arm": "0.15.13",
|
||||
"@esbuild/linux-loong64": "0.15.13",
|
||||
"esbuild-android-64": "0.15.13",
|
||||
"esbuild-android-arm64": "0.15.13",
|
||||
"esbuild-darwin-64": "0.15.13",
|
||||
"esbuild-darwin-arm64": "0.15.13",
|
||||
"esbuild-freebsd-64": "0.15.13",
|
||||
"esbuild-freebsd-arm64": "0.15.13",
|
||||
"esbuild-linux-32": "0.15.13",
|
||||
"esbuild-linux-64": "0.15.13",
|
||||
"esbuild-linux-arm": "0.15.13",
|
||||
"esbuild-linux-arm64": "0.15.13",
|
||||
"esbuild-linux-mips64le": "0.15.13",
|
||||
"esbuild-linux-ppc64le": "0.15.13",
|
||||
"esbuild-linux-riscv64": "0.15.13",
|
||||
"esbuild-linux-s390x": "0.15.13",
|
||||
"esbuild-netbsd-64": "0.15.13",
|
||||
"esbuild-openbsd-64": "0.15.13",
|
||||
"esbuild-sunos-64": "0.15.13",
|
||||
"esbuild-windows-32": "0.15.13",
|
||||
"esbuild-windows-64": "0.15.13",
|
||||
"esbuild-windows-arm64": "0.15.13"
|
||||
"@esbuild/android-arm": "0.15.18",
|
||||
"@esbuild/linux-loong64": "0.15.18",
|
||||
"esbuild-android-64": "0.15.18",
|
||||
"esbuild-android-arm64": "0.15.18",
|
||||
"esbuild-darwin-64": "0.15.18",
|
||||
"esbuild-darwin-arm64": "0.15.18",
|
||||
"esbuild-freebsd-64": "0.15.18",
|
||||
"esbuild-freebsd-arm64": "0.15.18",
|
||||
"esbuild-linux-32": "0.15.18",
|
||||
"esbuild-linux-64": "0.15.18",
|
||||
"esbuild-linux-arm": "0.15.18",
|
||||
"esbuild-linux-arm64": "0.15.18",
|
||||
"esbuild-linux-mips64le": "0.15.18",
|
||||
"esbuild-linux-ppc64le": "0.15.18",
|
||||
"esbuild-linux-riscv64": "0.15.18",
|
||||
"esbuild-linux-s390x": "0.15.18",
|
||||
"esbuild-netbsd-64": "0.15.18",
|
||||
"esbuild-openbsd-64": "0.15.18",
|
||||
"esbuild-sunos-64": "0.15.18",
|
||||
"esbuild-windows-32": "0.15.18",
|
||||
"esbuild-windows-64": "0.15.18",
|
||||
"esbuild-windows-arm64": "0.15.18"
|
||||
}
|
||||
},
|
||||
"esbuild-android-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz",
|
||||
"integrity": "sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz",
|
||||
"integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-android-arm64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz",
|
||||
"integrity": "sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-darwin-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz",
|
||||
"integrity": "sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz",
|
||||
"integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-darwin-arm64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz",
|
||||
"integrity": "sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-freebsd-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz",
|
||||
"integrity": "sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz",
|
||||
"integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-freebsd-arm64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz",
|
||||
"integrity": "sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-32": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz",
|
||||
"integrity": "sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz",
|
||||
"integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz",
|
||||
"integrity": "sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz",
|
||||
"integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-arm": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz",
|
||||
"integrity": "sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz",
|
||||
"integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-arm64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz",
|
||||
"integrity": "sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-mips64le": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz",
|
||||
"integrity": "sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz",
|
||||
"integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-ppc64le": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz",
|
||||
"integrity": "sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz",
|
||||
"integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-riscv64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz",
|
||||
"integrity": "sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz",
|
||||
"integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-s390x": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz",
|
||||
"integrity": "sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz",
|
||||
"integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-netbsd-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz",
|
||||
"integrity": "sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz",
|
||||
"integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-openbsd-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz",
|
||||
"integrity": "sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz",
|
||||
"integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -1336,30 +1336,30 @@
|
||||
}
|
||||
},
|
||||
"esbuild-sunos-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz",
|
||||
"integrity": "sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz",
|
||||
"integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-windows-32": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz",
|
||||
"integrity": "sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz",
|
||||
"integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-windows-64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz",
|
||||
"integrity": "sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz",
|
||||
"integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-windows-arm64": {
|
||||
"version": "0.15.13",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz",
|
||||
"integrity": "sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg==",
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
@ -1582,9 +1582,9 @@
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.8.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
|
||||
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
|
||||
"version": "4.9.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
|
||||
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
|
||||
"dev": true
|
||||
},
|
||||
"wasm-feature-detect": {
|
||||
|
||||
@ -46,10 +46,16 @@ export const startMapLibre = async (wasmPath: string | undefined, workerPath: st
|
||||
}) : PoolWorker();
|
||||
|
||||
worker.onmessage = (message: MessageEvent) => {
|
||||
// WARNING: Do not modify in_transfer_obj!
|
||||
let in_transfer_obj = message.data;
|
||||
// @ts-ignore TODO singlethreaded_main_entry may not be defined
|
||||
maplibre.singlethreaded_main_entry(ptr, in_transfer_obj)
|
||||
// WARNING: Do not modify data passed from Rust!
|
||||
let in_transfer = message.data;
|
||||
|
||||
const main_entry = maplibre["singlethreaded_main_entry"];
|
||||
|
||||
if (!main_entry) {
|
||||
throw Error("singlethreaded_main_entry is not defined. Maybe the Rust build used the wrong build configuration.")
|
||||
}
|
||||
|
||||
main_entry(ptr, in_transfer)
|
||||
}
|
||||
|
||||
return worker;
|
||||
|
||||
@ -13,7 +13,13 @@ onmessage = async message => {
|
||||
self.onmessage = async message => {
|
||||
// This will queue further commands up until the module is fully initialised:
|
||||
await initialised;
|
||||
// @ts-ignore TODO may not exist
|
||||
await maplibre.multithreaded_worker_entry(message.data);
|
||||
|
||||
const worker_entry = maplibre["multithreaded_worker_entry"]
|
||||
|
||||
if (!worker_entry) {
|
||||
throw Error("multithreaded_worker_entry is not defined. Maybe the Rust build used the wrong build configuration.")
|
||||
}
|
||||
|
||||
await worker_entry(message.data);
|
||||
};
|
||||
}
|
||||
|
||||
@ -15,9 +15,17 @@ onmessage = async message => {
|
||||
self.onmessage = async message => {
|
||||
// This will queue further commands up until the module is fully initialised:
|
||||
await initialised;
|
||||
let procedure_ptr = message.data[0];
|
||||
let input = message.data[1];
|
||||
// @ts-ignore TODO
|
||||
await maplibre.singlethreaded_worker_entry(procedure_ptr, input);
|
||||
|
||||
// WARNING: Do not modify data passed from Rust!
|
||||
const procedure_ptr = message.data[0];
|
||||
const input = message.data[1];
|
||||
|
||||
const worker_entry = maplibre["singlethreaded_worker_entry"];
|
||||
|
||||
if (!worker_entry) {
|
||||
throw Error("singlethreaded_worker_entry is not defined. Maybe the Rust build used the wrong build configuration.")
|
||||
}
|
||||
|
||||
await worker_entry(procedure_ptr, input);
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,15 +1,88 @@
|
||||
//! Errors which can happen in various parts of the library.
|
||||
//! Errors from JS world.
|
||||
|
||||
use js_sys::Error as JSError;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
error::Error,
|
||||
fmt::{Display, Formatter},
|
||||
};
|
||||
|
||||
use js_sys::{Error as JSError, TypeError};
|
||||
use maplibre::io::apc::{CallError, ProcedureError};
|
||||
use thiserror::Error;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WebError(pub String);
|
||||
#[derive(Error, Debug)]
|
||||
pub enum WebError {
|
||||
#[error("JS error type is unknown")]
|
||||
UnknownErrorType,
|
||||
/// Returned if the message is not valid, e.g. if it it is not valid UTF-8.
|
||||
#[error("message string in error is invalid")]
|
||||
InvalidMessage,
|
||||
/// TypeError like it is defined in JS
|
||||
#[error("TypeError from JS")]
|
||||
TypeError(Cow<'static, str>),
|
||||
/// Any other Error
|
||||
#[error("Error from JS")]
|
||||
GenericError(Cow<'static, str>),
|
||||
}
|
||||
|
||||
impl From<JsValue> for WebError {
|
||||
fn from(maybe_error: JsValue) -> Self {
|
||||
assert!(maybe_error.is_instance_of::<JSError>());
|
||||
let error: JSError = maybe_error.dyn_into().unwrap(); // TODO: Remove unwrap
|
||||
WebError(error.message().as_string().unwrap()) // TODO: remove unwrap
|
||||
fn from(value: JsValue) -> Self {
|
||||
if let Some(error) = value.dyn_ref::<TypeError>() {
|
||||
let Some(message) = error
|
||||
.message()
|
||||
.as_string() else { return WebError::InvalidMessage; };
|
||||
|
||||
WebError::TypeError(message.into())
|
||||
} else if let Some(error) = value.dyn_ref::<JSError>() {
|
||||
let Some(message) = error
|
||||
.message()
|
||||
.as_string() else { return WebError::InvalidMessage; };
|
||||
|
||||
WebError::GenericError(message.into())
|
||||
} else {
|
||||
WebError::UnknownErrorType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps several unrelated errors and implements Into<JSValue>. This should be used in Rust
|
||||
/// functions called from JS-land as return error type.
|
||||
#[derive(Debug)]
|
||||
pub enum WrappedError {
|
||||
ProcedureError(ProcedureError),
|
||||
CallError(CallError),
|
||||
WebError(WebError),
|
||||
}
|
||||
|
||||
impl Display for WrappedError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Error from Rust: {:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for WrappedError {}
|
||||
|
||||
impl From<WrappedError> for JsValue {
|
||||
fn from(val: WrappedError) -> Self {
|
||||
JsValue::from_str(&val.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CallError> for WrappedError {
|
||||
fn from(e: CallError) -> Self {
|
||||
WrappedError::CallError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProcedureError> for WrappedError {
|
||||
fn from(e: ProcedureError) -> Self {
|
||||
WrappedError::ProcedureError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WebError> for WrappedError {
|
||||
fn from(e: WebError) -> Self {
|
||||
WrappedError::WebError(e)
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ use maplibre::{
|
||||
use maplibre_winit::{WinitEnvironment, WinitMapWindowConfig};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use crate::platform::http_client::WHATWGFetchHttpClient;
|
||||
use crate::{error::WrappedError, platform::http_client::WHATWGFetchHttpClient};
|
||||
|
||||
mod error;
|
||||
mod platform;
|
||||
@ -65,7 +65,7 @@ type CurrentEnvironment = WinitEnvironment<
|
||||
pub type MapType = Map<CurrentEnvironment>;
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub async fn run_maplibre(new_worker: js_sys::Function) {
|
||||
pub async fn run_maplibre(new_worker: js_sys::Function) -> Result<(), WrappedError> {
|
||||
let mut kernel_builder = KernelBuilder::new()
|
||||
.with_map_window_config(WinitMapWindowConfig::new("maplibre".to_string()))
|
||||
.with_http_client(WHATWGFetchHttpClient::new());
|
||||
@ -77,31 +77,31 @@ pub async fn run_maplibre(new_worker: js_sys::Function) {
|
||||
WHATWGFetchHttpClient::new(),
|
||||
platform::multithreaded::pool_scheduler::WebWorkerPoolScheduler::new(
|
||||
new_worker.clone(),
|
||||
),
|
||||
)?,
|
||||
))
|
||||
.with_scheduler(
|
||||
platform::multithreaded::pool_scheduler::WebWorkerPoolScheduler::new(new_worker),
|
||||
platform::multithreaded::pool_scheduler::WebWorkerPoolScheduler::new(new_worker)?,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(target_feature = "atomics"))]
|
||||
{
|
||||
kernel_builder = kernel_builder
|
||||
.with_apc(platform::singlethreaded::apc::PassingAsyncProcedureCall::new(new_worker, 4))
|
||||
.with_apc(platform::singlethreaded::apc::PassingAsyncProcedureCall::new(new_worker, 4)?)
|
||||
.with_scheduler(maplibre::io::scheduler::NopScheduler);
|
||||
}
|
||||
|
||||
let kernel: Kernel<WinitEnvironment<_, _, _, ()>> = kernel_builder.build();
|
||||
|
||||
let mut map: MapType = Map::new(Style::default(), kernel).unwrap();
|
||||
map.initialize_renderer(RendererBuilder::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let mut map: MapType = Map::new(Style::default(), kernel, RendererBuilder::new()).unwrap();
|
||||
map.initialize_renderer().await.unwrap();
|
||||
|
||||
map.window_mut()
|
||||
.take_event_loop()
|
||||
.expect("Event loop is not available")
|
||||
.run(map, None)
|
||||
.run(map, None);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use async_trait::async_trait;
|
||||
use js_sys::{ArrayBuffer, Uint8Array};
|
||||
use maplibre::{error::Error, io::source_client::HttpClient};
|
||||
use maplibre::io::source_client::{HttpClient, SourceFetchError};
|
||||
use wasm_bindgen::{prelude::*, JsCast};
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use web_sys::{Request, RequestInit, Response, WorkerGlobalScope};
|
||||
@ -14,7 +14,7 @@ impl WHATWGFetchHttpClient {
|
||||
Self {}
|
||||
}
|
||||
|
||||
async fn fetch_array_buffer(url: &str) -> Result<JsValue, JsValue> {
|
||||
async fn fetch_array_buffer(url: &str) -> Result<JsValue, WebError> {
|
||||
let mut opts = RequestInit::new();
|
||||
opts.method("GET");
|
||||
|
||||
@ -22,13 +22,15 @@ impl WHATWGFetchHttpClient {
|
||||
|
||||
// Get the global scope
|
||||
let global = js_sys::global();
|
||||
assert!(global.is_instance_of::<WorkerGlobalScope>());
|
||||
let scope = global.dyn_into::<WorkerGlobalScope>().unwrap(); // TODO: remove unwrap
|
||||
let scope = global
|
||||
.dyn_into::<WorkerGlobalScope>()
|
||||
.map_err(|_e| WebError::TypeError("Unable to cast to WorkerGlobalScope".into()))?;
|
||||
|
||||
// Call fetch on global scope
|
||||
let maybe_response = JsFuture::from(scope.fetch_with_request(&request)).await?;
|
||||
assert!(maybe_response.is_instance_of::<Response>());
|
||||
let response: Response = maybe_response.dyn_into().unwrap(); // TODO: remove unwrap
|
||||
let response: Response = maybe_response
|
||||
.dyn_into()
|
||||
.map_err(|_e| WebError::TypeError("Unable to cast to Response".into()))?;
|
||||
|
||||
// Get ArrayBuffer
|
||||
let maybe_array_buffer = JsFuture::from(response.array_buffer()?).await?;
|
||||
@ -38,8 +40,9 @@ impl WHATWGFetchHttpClient {
|
||||
async fn fetch_bytes(&self, url: &str) -> Result<Vec<u8>, WebError> {
|
||||
let maybe_array_buffer = Self::fetch_array_buffer(url).await?;
|
||||
|
||||
assert!(maybe_array_buffer.is_instance_of::<ArrayBuffer>());
|
||||
let array_buffer: ArrayBuffer = maybe_array_buffer.dyn_into().unwrap(); // TODO: remove unwrap
|
||||
let array_buffer: ArrayBuffer = maybe_array_buffer
|
||||
.dyn_into()
|
||||
.map_err(|_e| WebError::TypeError("Unable to cast to ArrayBuffer".into()))?;
|
||||
|
||||
// Copy data to Vec<u8>
|
||||
let buffer: Uint8Array = Uint8Array::new(&array_buffer);
|
||||
@ -58,9 +61,9 @@ impl Clone for WHATWGFetchHttpClient {
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl HttpClient for WHATWGFetchHttpClient {
|
||||
async fn fetch(&self, url: &str) -> Result<Vec<u8>, Error> {
|
||||
async fn fetch(&self, url: &str) -> Result<Vec<u8>, SourceFetchError> {
|
||||
self.fetch_bytes(url)
|
||||
.await
|
||||
.map_err(|WebError(msg)| Error::Network(msg))
|
||||
.map_err(|e| SourceFetchError(Box::new(e)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,14 +9,19 @@ use rand::prelude::*;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::Worker;
|
||||
|
||||
use crate::error::WebError;
|
||||
|
||||
#[wasm_bindgen()]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_name = newWorker)]
|
||||
fn new_worker() -> JsValue;
|
||||
}
|
||||
|
||||
type NewWorker = Box<dyn Fn() -> Result<Worker, WebError>>;
|
||||
type Execute = Box<dyn (FnOnce() -> Promise) + Send>;
|
||||
|
||||
pub struct WorkerPool {
|
||||
new_worker: Box<dyn Fn() -> Worker>,
|
||||
new_worker: NewWorker,
|
||||
state: Rc<PoolState>,
|
||||
}
|
||||
|
||||
@ -35,7 +40,7 @@ impl PoolState {
|
||||
}
|
||||
|
||||
pub struct Work {
|
||||
func: Box<dyn (FnOnce() -> Promise) + Send>,
|
||||
func: Execute,
|
||||
}
|
||||
|
||||
impl Work {
|
||||
@ -55,7 +60,7 @@ impl WorkerPool {
|
||||
///
|
||||
/// Returns any error that may happen while a JS web worker is created and a
|
||||
/// message is sent to it.
|
||||
pub fn new(initial: usize, new_worker: Box<dyn Fn() -> Worker>) -> Result<WorkerPool, JsValue> {
|
||||
pub fn new(initial: usize, new_worker: NewWorker) -> Result<WorkerPool, WebError> {
|
||||
let pool = WorkerPool {
|
||||
new_worker,
|
||||
state: Rc::new(PoolState {
|
||||
@ -78,9 +83,9 @@ impl WorkerPool {
|
||||
///
|
||||
/// Returns any error that may happen while a JS web worker is created and a
|
||||
/// message is sent to it.
|
||||
fn spawn(&self) -> Result<(), JsValue> {
|
||||
fn spawn(&self) -> Result<(), WebError> {
|
||||
log::info!("spawning new worker");
|
||||
let worker = (self.new_worker)();
|
||||
let worker = (self.new_worker)()?;
|
||||
|
||||
// With a worker spun up send it the module/memory so it can start
|
||||
// instantiating the wasm module. Later it might receive further
|
||||
@ -104,7 +109,7 @@ impl WorkerPool {
|
||||
///
|
||||
/// Returns any error that may happen while a JS web worker is created and a
|
||||
/// message is sent to it.
|
||||
fn worker(&self) -> Result<Worker, JsValue> {
|
||||
fn worker(&self) -> Result<Worker, WebError> {
|
||||
let workers = self.state.workers.borrow();
|
||||
let result = workers.choose(&mut thread_rng());
|
||||
|
||||
@ -130,7 +135,7 @@ impl WorkerPool {
|
||||
///
|
||||
/// Returns any error that may happen while a JS web worker is created and a
|
||||
/// message is sent to it.
|
||||
pub fn execute(&self, f: impl (FnOnce() -> Promise) + Send + 'static) -> Result<(), JsValue> {
|
||||
pub fn execute(&self, f: impl (FnOnce() -> Promise) + Send + 'static) -> Result<(), WebError> {
|
||||
let worker = self.worker()?;
|
||||
let work = Work { func: Box::new(f) };
|
||||
let work_ptr = Box::into_raw(Box::new(work));
|
||||
@ -140,7 +145,7 @@ impl WorkerPool {
|
||||
unsafe {
|
||||
drop(Box::from_raw(work_ptr));
|
||||
}
|
||||
Err(e)
|
||||
Err(e.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,30 +1,29 @@
|
||||
use std::future::Future;
|
||||
|
||||
use maplibre::{error::Error, io::scheduler::Scheduler};
|
||||
use maplibre::{benchmarking::io::scheduler::ScheduleError, io::scheduler::Scheduler};
|
||||
use wasm_bindgen::{prelude::*, JsCast};
|
||||
use web_sys::Worker;
|
||||
|
||||
use super::pool::WorkerPool;
|
||||
use crate::error::WebError;
|
||||
|
||||
pub struct WebWorkerPoolScheduler {
|
||||
pool: WorkerPool,
|
||||
}
|
||||
|
||||
impl WebWorkerPoolScheduler {
|
||||
pub fn new(new_worker: js_sys::Function) -> Self {
|
||||
// TODO: Are expects here oke?
|
||||
pub fn new(new_worker: js_sys::Function) -> Result<Self, WebError> {
|
||||
let pool = WorkerPool::new(
|
||||
1,
|
||||
Box::new(move || {
|
||||
new_worker
|
||||
.call0(&JsValue::undefined())
|
||||
.expect("Unable to call new_worker function")
|
||||
.map_err(WebError::from)?
|
||||
.dyn_into::<Worker>()
|
||||
.expect("new_worker function did not return a Worker")
|
||||
.map_err(|_e| WebError::TypeError("Unable to cast to Worker".into()))
|
||||
}),
|
||||
)
|
||||
.expect("Unable to create WorkerPool");
|
||||
Self { pool }
|
||||
)?;
|
||||
Ok(Self { pool })
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +31,7 @@ impl Scheduler for WebWorkerPoolScheduler {
|
||||
fn schedule<T>(
|
||||
&self,
|
||||
future_factory: impl (FnOnce() -> T) + Send + 'static,
|
||||
) -> Result<(), Error>
|
||||
) -> Result<(), ScheduleError>
|
||||
where
|
||||
T: Future<Output = ()> + 'static,
|
||||
{
|
||||
@ -43,6 +42,6 @@ impl Scheduler for WebWorkerPoolScheduler {
|
||||
Ok(JsValue::undefined())
|
||||
})
|
||||
})
|
||||
.map_err(|e| Error::Scheduler)
|
||||
.map_err(|e| ScheduleError::Scheduling(Box::new(e)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
use maplibre::io::apc::CallError;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
|
||||
use crate::platform::multithreaded::pool::Work;
|
||||
use crate::{platform::multithreaded::pool::Work, WrappedError};
|
||||
|
||||
/// Entry point invoked by the worker.
|
||||
#[wasm_bindgen]
|
||||
pub async fn multithreaded_worker_entry(ptr: u32) -> Result<(), JsValue> {
|
||||
pub async fn multithreaded_worker_entry(ptr: u32) -> Result<(), WrappedError> {
|
||||
let work = unsafe { Box::from_raw(ptr as *mut Work) };
|
||||
JsFuture::from(work.execute()).await?;
|
||||
JsFuture::from(work.execute())
|
||||
.await
|
||||
.map_err(|_e| CallError::Schedule)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1,54 +1,71 @@
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use js_sys::{ArrayBuffer, Uint8Array};
|
||||
use log::error;
|
||||
use maplibre::{
|
||||
error::Error,
|
||||
io::{
|
||||
apc::{AsyncProcedure, AsyncProcedureCall, Context, Input, Message},
|
||||
source_client::SourceClient,
|
||||
},
|
||||
use maplibre::io::{
|
||||
apc::{AsyncProcedure, AsyncProcedureCall, CallError, Context, Input, Message, SendError},
|
||||
source_client::SourceClient,
|
||||
};
|
||||
use rand::{prelude::SliceRandom, thread_rng};
|
||||
use thiserror::Error;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use web_sys::{DedicatedWorkerGlobalScope, Worker};
|
||||
|
||||
use crate::platform::singlethreaded::{
|
||||
transferables::FlatBufferTransferable, UsedContext, UsedHttpClient, UsedTransferables,
|
||||
use crate::{
|
||||
error::WebError,
|
||||
platform::singlethreaded::{
|
||||
transferables::FlatBufferTransferable, UsedContext, UsedHttpClient, UsedTransferables,
|
||||
},
|
||||
};
|
||||
|
||||
/// Error which happens during serialization or deserialization of the tag
|
||||
#[derive(Error, Debug)]
|
||||
#[error("failed to deserialize message tag")]
|
||||
pub struct MessageTagDeserializeError;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SerializedMessageTag {
|
||||
pub enum MessageTag {
|
||||
TileTessellated = 1,
|
||||
LayerUnavailable = 2,
|
||||
LayerTessellated = 3,
|
||||
LayerIndexed = 4,
|
||||
}
|
||||
|
||||
impl SerializedMessageTag {
|
||||
impl MessageTag {
|
||||
pub fn from_message(message: &Message<UsedTransferables>) -> Self {
|
||||
match message {
|
||||
Message::TileTessellated(_) => SerializedMessageTag::TileTessellated,
|
||||
Message::LayerUnavailable(_) => SerializedMessageTag::LayerUnavailable,
|
||||
Message::LayerTessellated(_) => SerializedMessageTag::LayerTessellated,
|
||||
Message::LayerIndexed(_) => SerializedMessageTag::LayerIndexed,
|
||||
Message::TileTessellated(_) => MessageTag::TileTessellated,
|
||||
Message::LayerUnavailable(_) => MessageTag::LayerUnavailable,
|
||||
Message::LayerTessellated(_) => MessageTag::LayerTessellated,
|
||||
Message::LayerIndexed(_) => MessageTag::LayerIndexed,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_u32(tag: u32) -> Option<Self> {
|
||||
pub fn create_message(
|
||||
&self,
|
||||
transferable: FlatBufferTransferable,
|
||||
) -> Message<UsedTransferables> {
|
||||
// TODO: Verify that data matches tag
|
||||
match self {
|
||||
MessageTag::TileTessellated => {
|
||||
Message::<UsedTransferables>::TileTessellated(transferable)
|
||||
}
|
||||
MessageTag::LayerUnavailable => {
|
||||
Message::<UsedTransferables>::LayerUnavailable(transferable)
|
||||
}
|
||||
MessageTag::LayerTessellated => {
|
||||
Message::<UsedTransferables>::LayerTessellated(transferable)
|
||||
}
|
||||
MessageTag::LayerIndexed => Message::<UsedTransferables>::LayerIndexed(transferable),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_u32(tag: u32) -> Result<Self, MessageTagDeserializeError> {
|
||||
match tag {
|
||||
x if x == SerializedMessageTag::LayerUnavailable as u32 => {
|
||||
Some(SerializedMessageTag::LayerUnavailable)
|
||||
}
|
||||
x if x == SerializedMessageTag::LayerTessellated as u32 => {
|
||||
Some(SerializedMessageTag::LayerTessellated)
|
||||
}
|
||||
x if x == SerializedMessageTag::TileTessellated as u32 => {
|
||||
Some(SerializedMessageTag::TileTessellated)
|
||||
}
|
||||
x if x == SerializedMessageTag::LayerIndexed as u32 => {
|
||||
Some(SerializedMessageTag::LayerIndexed)
|
||||
}
|
||||
_ => None,
|
||||
x if x == MessageTag::LayerUnavailable as u32 => Ok(MessageTag::LayerUnavailable),
|
||||
x if x == MessageTag::LayerTessellated as u32 => Ok(MessageTag::LayerTessellated),
|
||||
x if x == MessageTag::TileTessellated as u32 => Ok(MessageTag::TileTessellated),
|
||||
x if x == MessageTag::LayerIndexed as u32 => Ok(MessageTag::LayerIndexed),
|
||||
_ => Err(MessageTagDeserializeError),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -59,10 +76,10 @@ pub struct PassingContext {
|
||||
}
|
||||
|
||||
impl Context<UsedTransferables, UsedHttpClient> for PassingContext {
|
||||
fn send(&self, message: Message<UsedTransferables>) -> Result<(), Error> {
|
||||
let tag = SerializedMessageTag::from_message(&message);
|
||||
fn send(&self, message: Message<UsedTransferables>) -> Result<(), SendError> {
|
||||
let tag = MessageTag::from_message(&message);
|
||||
let transferable = FlatBufferTransferable::from_message(message);
|
||||
let data = &transferable.data[transferable.start..];
|
||||
let data = transferable.data();
|
||||
|
||||
let buffer = ArrayBuffer::new(data.len() as u32);
|
||||
let byte_buffer = Uint8Array::new(&buffer);
|
||||
@ -70,26 +87,15 @@ impl Context<UsedTransferables, UsedHttpClient> for PassingContext {
|
||||
byte_buffer.set(&Uint8Array::view(data), 0);
|
||||
}
|
||||
|
||||
let tag = tag as u32;
|
||||
|
||||
let global: DedicatedWorkerGlobalScope =
|
||||
js_sys::global().dyn_into().map_err(|_e| Error::APC)?;
|
||||
|
||||
let transfer_obj = js_sys::Array::new();
|
||||
transfer_obj.push(&JsValue::from(tag));
|
||||
|
||||
transfer_obj.push(&buffer);
|
||||
|
||||
let transfer = js_sys::Array::new();
|
||||
transfer.push(&buffer);
|
||||
|
||||
// TODO: Verify transfer
|
||||
let global: DedicatedWorkerGlobalScope = js_sys::global()
|
||||
.dyn_into()
|
||||
.map_err(|_e| SendError::Transmission)?;
|
||||
global
|
||||
.post_message_with_transfer(&transfer_obj, &transfer)
|
||||
.map_err(|e| {
|
||||
error!("{:?}", e);
|
||||
Error::APC
|
||||
})
|
||||
.post_message_with_transfer(
|
||||
&js_sys::Array::of2(&JsValue::from(tag as u32), &buffer),
|
||||
&js_sys::Array::of1(&buffer),
|
||||
)
|
||||
.map_err(|_e| SendError::Transmission)
|
||||
}
|
||||
|
||||
fn source_client(&self) -> &SourceClient<UsedHttpClient> {
|
||||
@ -97,47 +103,48 @@ impl Context<UsedTransferables, UsedHttpClient> for PassingContext {
|
||||
}
|
||||
}
|
||||
|
||||
type NewWorker = Box<dyn Fn() -> Result<Worker, WebError>>;
|
||||
pub type ReceivedType = RefCell<Vec<Message<UsedTransferables>>>;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum PassingAPCError {
|
||||
#[error("creating a worker failed")]
|
||||
Worker,
|
||||
}
|
||||
|
||||
pub struct PassingAsyncProcedureCall {
|
||||
new_worker: Box<dyn Fn() -> Worker>,
|
||||
workers: Vec<Worker>,
|
||||
|
||||
received: Rc<ReceivedType>, // FIXME (wasm-executor): Is RefCell fine?
|
||||
received: Rc<ReceivedType>, // FIXME: Is RefCell fine?
|
||||
}
|
||||
|
||||
impl PassingAsyncProcedureCall {
|
||||
pub fn new(new_worker: js_sys::Function, initial_workers: u8) -> Self {
|
||||
pub fn new(new_worker: js_sys::Function, initial_workers: usize) -> Result<Self, WebError> {
|
||||
let received = Rc::new(RefCell::new(vec![]));
|
||||
let received_ref = received.clone();
|
||||
|
||||
let create_new_worker = Box::new(move || {
|
||||
let create_new_worker = || {
|
||||
new_worker
|
||||
.call1(
|
||||
&JsValue::undefined(),
|
||||
&JsValue::from(Rc::into_raw(received_ref.clone()) as u32),
|
||||
)
|
||||
.unwrap() // FIXME (wasm-executor): Remove unwrap
|
||||
.map_err(WebError::from)?
|
||||
.dyn_into::<Worker>()
|
||||
.unwrap() // FIXME (wasm-executor): Remove unwrap
|
||||
});
|
||||
.map_err(|_e| WebError::TypeError("Unable to cast to Worker".into()))
|
||||
};
|
||||
|
||||
let workers = (0..initial_workers)
|
||||
.map(|_| {
|
||||
let worker: Worker = create_new_worker();
|
||||
let mut workers = Vec::with_capacity(initial_workers);
|
||||
|
||||
let array = js_sys::Array::new();
|
||||
array.push(&wasm_bindgen::module());
|
||||
worker.post_message(&array).unwrap(); // FIXME (wasm-executor): Remove unwrap
|
||||
worker
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
for _ in 0..initial_workers {
|
||||
let worker: Worker = create_new_worker()?;
|
||||
|
||||
Self {
|
||||
new_worker: create_new_worker,
|
||||
workers,
|
||||
received,
|
||||
let array = js_sys::Array::of1(&wasm_bindgen::module());
|
||||
worker.post_message(&array).map_err(WebError::from)?;
|
||||
workers.push(worker);
|
||||
}
|
||||
|
||||
Ok(Self { workers, received })
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,14 +159,23 @@ impl AsyncProcedureCall<UsedHttpClient> for PassingAsyncProcedureCall {
|
||||
.pop()
|
||||
}
|
||||
|
||||
fn call(&self, input: Input, procedure: AsyncProcedure<Self::Context>) {
|
||||
let procedure_ptr = procedure as *mut AsyncProcedure<Self::Context> as u32; // FIXME (wasm-executor): is u32 fine, define an overflow safe function?
|
||||
let input = serde_json::to_string(&input).unwrap(); // FIXME (wasm-executor): Remove unwrap
|
||||
fn call(
|
||||
&self,
|
||||
input: Input,
|
||||
procedure: AsyncProcedure<Self::Context>,
|
||||
) -> Result<(), CallError> {
|
||||
let procedure_ptr = procedure as *mut AsyncProcedure<Self::Context> as u32; // FIXME: is u32 fine, define an overflow safe function?
|
||||
let input = serde_json::to_string(&input).map_err(|e| CallError::Serialize(Box::new(e)))?;
|
||||
|
||||
let array = js_sys::Array::new();
|
||||
array.push(&JsValue::from(procedure_ptr));
|
||||
array.push(&JsValue::from(input));
|
||||
let message = js_sys::Array::of2(&JsValue::from(procedure_ptr), &JsValue::from(input));
|
||||
|
||||
self.workers[0].post_message(&array).unwrap(); // FIXME (wasm-executor): Remove unwrap
|
||||
let worker = self
|
||||
.workers
|
||||
.choose(&mut thread_rng())
|
||||
.ok_or(CallError::Schedule)?;
|
||||
|
||||
worker
|
||||
.post_message(&message)
|
||||
.map_err(|_e| CallError::Schedule)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use flatbuffers::FlatBufferBuilder;
|
||||
use js_sys::{ArrayBuffer, Uint8Array};
|
||||
use maplibre::{
|
||||
benchmarking::tessellation::{IndexDataType, OverAlignedVertexBuffer},
|
||||
coords::WorldTileCoords,
|
||||
@ -57,11 +58,24 @@ pub mod tile_tessellated_generated {
|
||||
}
|
||||
|
||||
pub struct FlatBufferTransferable {
|
||||
pub data: Vec<u8>,
|
||||
pub start: usize,
|
||||
data: Vec<u8>,
|
||||
start: usize,
|
||||
}
|
||||
|
||||
impl FlatBufferTransferable {
|
||||
pub fn from_array_buffer(buffer: ArrayBuffer) -> Self {
|
||||
let buffer = Uint8Array::new(&buffer);
|
||||
|
||||
FlatBufferTransferable {
|
||||
data: buffer.to_vec(),
|
||||
start: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u8] {
|
||||
&self.data[self.start..]
|
||||
}
|
||||
|
||||
pub fn from_message(message: Message<UsedTransferables>) -> Self {
|
||||
match message {
|
||||
Message::TileTessellated(transferable) => transferable,
|
||||
@ -220,7 +234,7 @@ impl LayerIndexed for FlatBufferTransferable {
|
||||
}
|
||||
|
||||
fn to_tile_index(self) -> TileIndex {
|
||||
TileIndex::Linear { list: vec![] } // TODO
|
||||
TileIndex::Linear { list: vec![] } // TODO index
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,95 +1,79 @@
|
||||
use std::{mem, rc::Rc};
|
||||
|
||||
use js_sys::{ArrayBuffer, Uint8Array};
|
||||
use log::{error, info};
|
||||
use js_sys::ArrayBuffer;
|
||||
use maplibre::{
|
||||
benchmarking::io::{
|
||||
apc::{AsyncProcedure, Input, Message},
|
||||
apc::{AsyncProcedure, Input},
|
||||
source_client::{HttpSourceClient, SourceClient},
|
||||
},
|
||||
io::transferables::Transferables,
|
||||
io::apc::CallError,
|
||||
};
|
||||
use thiserror::Error;
|
||||
use wasm_bindgen::{prelude::*, JsCast};
|
||||
|
||||
use crate::{
|
||||
error::WrappedError,
|
||||
platform::singlethreaded::{
|
||||
apc::{ReceivedType, SerializedMessageTag},
|
||||
apc::{MessageTag, ReceivedType},
|
||||
transferables::FlatBufferTransferable,
|
||||
PassingContext, UsedContext, UsedTransferables,
|
||||
PassingContext, UsedContext,
|
||||
},
|
||||
WHATWGFetchHttpClient,
|
||||
};
|
||||
|
||||
/// Entry point invoked by the worker.
|
||||
#[wasm_bindgen]
|
||||
pub async fn singlethreaded_worker_entry(procedure_ptr: u32, input: String) -> Result<(), JsValue> {
|
||||
pub async fn singlethreaded_worker_entry(
|
||||
procedure_ptr: u32,
|
||||
input: String,
|
||||
) -> Result<(), WrappedError> {
|
||||
let procedure: AsyncProcedure<UsedContext> = unsafe { mem::transmute(procedure_ptr) };
|
||||
|
||||
let input = serde_json::from_str::<Input>(&input).unwrap(); // FIXME (wasm-executor): Remove unwrap
|
||||
let input =
|
||||
serde_json::from_str::<Input>(&input).map_err(|e| CallError::Deserialize(Box::new(e)))?;
|
||||
|
||||
let context = PassingContext {
|
||||
source_client: SourceClient::new(HttpSourceClient::new(WHATWGFetchHttpClient::new())),
|
||||
};
|
||||
|
||||
let result = (procedure)(input, context).await;
|
||||
|
||||
if let Err(e) = result {
|
||||
error!("{:?}", e); // TODO handle better
|
||||
}
|
||||
procedure(input, context).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("unable to deserialize message sent by postMessage()")]
|
||||
pub struct DeserializeMessage;
|
||||
|
||||
/// Entry point invoked by the main thread.
|
||||
#[wasm_bindgen]
|
||||
pub unsafe fn singlethreaded_main_entry(
|
||||
received_ptr: *const ReceivedType,
|
||||
in_transfer_obj: js_sys::Array,
|
||||
) -> Result<(), JsValue> {
|
||||
// FIXME (wasm-executor): Can we make this call safe? check if it was cloned before?
|
||||
in_transfer: js_sys::Array,
|
||||
) -> Result<(), WrappedError> {
|
||||
let tag = in_transfer
|
||||
.get(0)
|
||||
.as_f64()
|
||||
.ok_or_else(|| CallError::Deserialize(Box::new(DeserializeMessage)))? as u32; // TODO: Is this cast fine?
|
||||
let buffer: ArrayBuffer = in_transfer
|
||||
.get(1)
|
||||
.dyn_into()
|
||||
.map_err(|_e| CallError::Deserialize(Box::new(DeserializeMessage)))?;
|
||||
|
||||
let tag = MessageTag::from_u32(tag).map_err(|e| CallError::Deserialize(Box::new(e)))?;
|
||||
|
||||
let message = tag.create_message(FlatBufferTransferable::from_array_buffer(buffer));
|
||||
|
||||
// FIXME: Can we make this call safe? check if it was cloned before?
|
||||
let received: Rc<ReceivedType> = Rc::from_raw(received_ptr);
|
||||
|
||||
let tag = in_transfer_obj.get(0).as_f64().unwrap() as u32;
|
||||
let tag = SerializedMessageTag::from_u32(tag).unwrap();
|
||||
|
||||
info!("singlethreaded_main_entry {:?}", tag);
|
||||
|
||||
let buffer: ArrayBuffer = in_transfer_obj.get(1).dyn_into().unwrap();
|
||||
let buffer = Uint8Array::new(&buffer);
|
||||
|
||||
type TileTessellated = <UsedTransferables as Transferables>::TileTessellated;
|
||||
type UnavailableLayer = <UsedTransferables as Transferables>::LayerUnavailable;
|
||||
type IndexedLayer = <UsedTransferables as Transferables>::LayerIndexed;
|
||||
|
||||
let transferable = FlatBufferTransferable {
|
||||
data: buffer.to_vec(),
|
||||
start: 0,
|
||||
};
|
||||
|
||||
// TODO: Verify that data matches tag
|
||||
|
||||
let message = match tag {
|
||||
SerializedMessageTag::TileTessellated => {
|
||||
Message::<UsedTransferables>::TileTessellated(transferable)
|
||||
}
|
||||
SerializedMessageTag::LayerUnavailable => {
|
||||
Message::<UsedTransferables>::LayerUnavailable(transferable)
|
||||
}
|
||||
SerializedMessageTag::LayerTessellated => {
|
||||
Message::<UsedTransferables>::LayerTessellated(transferable)
|
||||
}
|
||||
SerializedMessageTag::LayerIndexed => {
|
||||
Message::<UsedTransferables>::LayerIndexed(transferable)
|
||||
}
|
||||
};
|
||||
|
||||
// MAJOR FIXME: Fix mutability
|
||||
received
|
||||
.try_borrow_mut()
|
||||
.expect("Failed to borrow in singlethreaded_main_entry")
|
||||
.push(message);
|
||||
|
||||
mem::forget(received); // FIXME (wasm-executor): Enforce this somehow
|
||||
mem::forget(received); // FIXME: Enforce this somehow
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user