Skip to main content

rustial_engine/
lib.rs

1#![warn(missing_docs)]
2#![cfg_attr(not(test), deny(clippy::unwrap_used))]
3// ---------------------------------------------------------------------------
4//! # rustial-engine
5//!
6//! Framework-agnostic 2.5D map engine for the [rustial](https://crates.io/crates/rustial)
7//! geospatial library.
8//!
9//! This crate owns the **core logic** of the map: camera control, layer
10//! management, tile fetching, terrain elevation, vector tessellation,
11//! 3D model placement, and the per-frame update loop that produces a
12//! [`FrameOutput`] consumed by renderers.
13//!
14//! ## Design principles
15//!
16//! | Principle | How it is enforced |
17//! |-----------|--------------------|
18//! | **No GPU code** | Zero dependency on `wgpu`, `bevy`, or any graphics API. Renderers live in separate crates. |
19//! | **No windowing** | No `winit`, no event loop. Input arrives via [`InputEvent`] values pushed by the host. |
20//! | **No async runtime** | Tile I/O uses a synchronous send/poll pattern ([`HttpClient`], [`TileSource`]) so the engine can be embedded anywhere. |
21//! | **Thread-safe** | All public types are `Send + Sync`. [`MapState`] is designed to sit behind an `RwLock`. |
22//! | **Precision** | Coordinates are `f64` (meters, WGS-84). Camera-relative rendering avoids f32 jitter at large Mercator values. |
23//!
24//! ## Module map
25//!
26//! | Module / File | Visibility | Purpose |
27//! |---------------|------------|---------|
28//! | [`camera`] | private | [`Camera`], [`CameraConstraints`], [`CameraController`], [`CameraMode`] |
29//! | [`camera_animator`] | private | [`CameraAnimator`] -- smooth zoom, rotation, and pan momentum |
30//! | [`geometry`] | private | OGC-style geometry model ([`Feature`], [`Geometry`], [`Polygon`], ...) |
31//! | [`input`] | private | [`InputEvent`] enum (Pan, Zoom, Rotate, Resize) |
32//! | [`interaction`] | **public** | Canonical interaction event and target types layered on top of picking |
33//! | [`io`] | **public** | [`HttpClient`], [`HttpRequest`], [`HttpResponse`], [`SharedHttpClient`], [`FetchPool`], [`DiskCache`]* |
34//! | [`layer`] | private | [`Layer`] trait + [`LayerId`] |
35//! | [`layers`] | **public** | [`LayerStack`], [`TileLayer`], [`VectorLayer`], [`ModelLayer`] |
36//! | [`map_state`] | private | [`MapState`], [`FrameOutput`] |
37//! | [`models`] | **public** | [`ModelMesh`], [`ModelInstance`], [`AltitudeMode`] |
38//! | [`simplify`] | private | Douglas-Peucker line simplification |
39//! | [`terrain`] | **public** | [`TerrainManager`], [`TerrainConfig`], elevation sources, mesh building |
40//! | [`tessellator`] | private | Polygon triangulation + thick-line stroking |
41//! | [`tile_cache`] | private | LRU tile cache |
42//! | [`tile_manager`] | private | Tile request scheduling with parent-tile fallback |
43//! | [`tile_request_coordinator`] | private | Cross-source tile request coordination and global budget allocation |
44//! | [`tile_source`] | private | [`TileSource`] trait, [`TileData`], [`TileDecoder`] |
45//! | [`tile_source_http`] | private | [`HttpTileSource`] (URL-template HTTP fetcher) |
46//! | [`geojson`] | **public*** | GeoJSON parser (behind the `geojson` feature flag) |
47//! | [`style`] | **public** | Map style system -- layer configuration, paint, and update logic |
48//! | [`symbols`] | **public** | Symbol and cartography foundation -- sprite atlases, placement, and collision |
49//!
50//! *Items marked with `*` require a Cargo feature flag.
51//!
52//! ## Feature flags
53//!
54//! | Flag | Default | Description |
55//! |------|---------|-------------|
56//! | `geojson` | off | Enables the GeoJSON parser ([`parse_geojson`]) and its `serde`/`serde_json` dependencies. |
57//! | `shapefile` | off | Enables the Shapefile parser ([`parse_shapefile`]) and its `shapefile` dependency. |
58//! | `gltf` | off | Enables [`ModelMesh::from_gltf`] for GLTF/GLB 3D model loading. |
59//! | `obj` | off | Enables [`ModelMesh::from_obj`] for Wavefront OBJ 3D model loading. |
60//! | `disk-cache` | off | Enables [`DiskCache`] for flat-file on-disk tile persistence. |
61//!
62//! ## Re-exported dependency
63//!
64//! This crate depends on [`glam`](https://docs.rs/glam) (workspace version)
65//! for matrix and vector math. The `glam` types appear in public signatures
66//! (e.g. [`FrameOutput::view_projection`] is a `glam::DMat4`). Downstream
67//! crates that interact with these values should use the same `glam` version
68//! declared in the workspace `Cargo.toml`.
69// ---------------------------------------------------------------------------
70
71// ---------------------------------------------------------------------------
72// Modules
73// ---------------------------------------------------------------------------
74
75#[path = "math/bounds.rs"]
76mod bounds;
77#[path = "math/coord.rs"]
78mod coord;
79#[path = "math/elevation.rs"]
80mod elevation;
81#[path = "math/ellipsoid.rs"]
82mod ellipsoid;
83#[path = "math/equirectangular.rs"]
84mod equirectangular;
85#[path = "math/frustum.rs"]
86mod frustum;
87#[path = "math/geodesic.rs"]
88mod geodesic;
89#[path = "math/globe.rs"]
90mod globe;
91#[path = "math/mercator.rs"]
92mod mercator;
93#[path = "math/projection.rs"]
94mod projection;
95#[path = "math/tile.rs"]
96mod tile;
97#[path = "math/vertical_perspective.rs"]
98mod vertical_perspective;
99
100mod camera;
101mod camera_animator;
102mod camera_projection;
103pub(crate) mod geo_wrap;
104pub mod async_data;
105pub mod cluster;
106pub mod expression;
107#[cfg(feature = "geojson")]
108pub mod geojson;
109#[cfg(feature = "shapefile")]
110pub mod shapefile_parser;
111mod geometry;
112pub mod event_emitter;
113pub mod gesture;
114pub mod geometry_ops;
115pub mod image_compare;
116mod input;
117pub mod interaction;
118pub mod interaction_manager;
119pub mod io;
120mod layer;
121pub mod layers;
122mod map_state;
123pub mod models;
124pub mod picking;
125pub mod query;
126pub mod regression;
127pub mod shapes;
128mod simplify;
129mod streamed_payload;
130pub mod terrain;
131mod tessellator;
132mod tile_cache;
133mod tile_lifecycle;
134mod tile_manager;
135mod tile_source;
136mod tile_source_http;
137mod tile_source_vector_http;
138mod pooled_tile_source;
139mod tile_request_coordinator;
140pub mod tilejson;
141pub mod mvt;
142pub mod style;
143#[cfg(feature = "style-json")]
144pub mod style_json;
145pub mod symbols;
146pub mod visualization;
147pub mod loading_placeholder;
148
149pub mod precision_invariants;
150
151#[cfg(test)]
152mod support_contract;
153#[cfg(test)]
154mod visualization_contract;
155
156pub extern crate self as rustial_math;
157
158// ---------------------------------------------------------------------------
159// Re-exports -- Math primitives
160// ---------------------------------------------------------------------------
161
162pub use bounds::{GeoBounds, WorldBounds};
163pub use coord::{GeoCoord, WorldCoord};
164pub use elevation::ElevationGrid;
165pub use ellipsoid::Ellipsoid;
166pub use equirectangular::Equirectangular;
167pub use frustum::{
168    Frustum, Plane, PLANE_BOTTOM, PLANE_FAR, PLANE_LEFT, PLANE_NEAR, PLANE_RIGHT, PLANE_TOP,
169};
170pub use geodesic::{
171    GeodesicResult, VincentyConvergenceError, geodesic_destination, geodesic_destination_on,
172    geodesic_distance, geodesic_distance_on,
173};
174pub use globe::Globe;
175pub use mercator::WebMercator;
176pub use projection::Projection;
177pub use tile::{
178    CoveringCamera, CoveringTilesOptions, FlatTileSelectionConfig, FlatTileView, MAX_ZOOM,
179    TileCoord, TileId, geo_to_tile, geo_to_tile_checked, tile_bounds_world, tile_to_geo,
180    tile_xy_to_geo, visible_tiles, visible_tiles_checked, visible_tiles_covering,
181    visible_tiles_flat_view, visible_tiles_flat_view_capped,
182    visible_tiles_flat_view_capped_with_config, visible_tiles_flat_view_refined_capped,
183    visible_tiles_flat_view_refined_capped_with_config, visible_tiles_flat_view_with_config,
184    visible_tiles_frustum, visible_tiles_lod,
185};
186pub use vertical_perspective::VerticalPerspective;
187
188// ---------------------------------------------------------------------------
189// Re-exports -- Camera & Input
190// ---------------------------------------------------------------------------
191
192pub use camera::{Camera, CameraConstraints, CameraController, CameraMode};
193pub use camera_animator::{CameraAnimator, EaseToOptions, FlyToOptions};
194pub use camera_projection::CameraProjection;
195pub use input::{InputEvent, TouchContact, TouchPhase};
196pub use interaction::{
197    InteractionButton, InteractionEvent, InteractionEventKind, InteractionModifiers,
198    InteractionTarget, InteractionTargetKind, PointerKind, ScreenPoint,
199};
200pub use interaction_manager::{InteractionConfig, InteractionManager};
201
202// ---------------------------------------------------------------------------
203// Re-exports -- Layer system
204// ---------------------------------------------------------------------------
205
206pub use layer::{Layer, LayerId, LayerKind};
207pub use layers::{BackgroundLayer, CallbackFrameProvider, CircleInstanceData, DynamicImageOverlayLayer, FrameData, FrameProvider, FrameProviderFactory, HillshadeLayer, HillshadeParams, ImageOverlayData, ImageOverlayLayer, LayerStack, ModelLayer, PatternImage, TileLayer, VectorLayer, VectorMeshData, VectorRenderMode, VectorStyle};
208pub use style::{
209    BackgroundStyleLayer, CircleStyleLayer, FillExtrusionStyleLayer, FillStyleLayer,
210    FromFeatureStateProperty, GeoJsonSource, HeatmapStyleLayer, HillshadeStyleLayer,
211    LineStyleLayer, MapStyle, ModelSource, ModelStyleLayer, RasterSource, RasterStyleLayer,
212    StyleDocument, StyleError, StyleEvalContext, StyleEvalContextFull, StyleLayer, StyleLayerId,
213    StyleLayerMeta, StyleProjection, StyleSource, StyleSourceId, StyleSourceKind, StyleValue,
214    SymbolStyleLayer, TerrainSource, VectorStyleLayer, VectorTileSource, ImageSource,
215    VideoSource, CanvasSource,
216    // Fog / atmosphere configuration.
217    FogConfig, ComputedFog, atmospheric_clear_color, compute_fog,
218    // Feature-state-driven style resolution helpers.
219    circle_style_with_state, fill_extrusion_style_with_state, fill_style_with_state,
220    heatmap_style_with_state, line_style_with_state, symbol_style_with_state,
221    vector_style_with_state,
222};
223pub use expression::{
224    Expression, ExprEvalContext, NumericExpression, StringExpression, BoolExpression,
225};
226#[cfg(feature = "style-json")]
227pub use style_json::{
228    parse_style_json, StyleSourceRegistry, StyleSpecDocument, StyleSpecError,
229    StyleSpecLayer, StyleSpecLayerType, StyleSpecSource, StyleSpecSourceType,
230    StyleSpecProjection, StyleSpecProjectionType, StyleSpecTerrain,
231};
232
233// ---------------------------------------------------------------------------
234// Re-exports -- Map state & frame output
235// ---------------------------------------------------------------------------
236
237pub use map_state::{
238    FitBoundsOptions, FitBoundsPadding, FrameOutput, MapState, TilePipelineDiagnostics,
239};
240pub use event_emitter::{EventEmitter, ListenerId};
241pub use loading_placeholder::{LoadingPlaceholder, PlaceholderGenerator, PlaceholderStyle};
242pub use regression::{
243    TilePipelineRegressionEvaluation, TilePipelineRegressionParseError,
244    TilePipelineRegressionSample, TilePipelineRegressionSummary,
245    TilePipelineRegressionThresholds, TilePipelineRegressionViolation,
246    TILE_PIPELINE_REGRESSION_CSV_HEADER,
247};
248
249// ---------------------------------------------------------------------------
250// Re-exports -- Geometry & vector data
251// ---------------------------------------------------------------------------
252
253pub use geometry::{
254    Feature, FeatureCollection, Geometry, LineString, MultiLineString, MultiPoint, MultiPolygon,
255    Point, Polygon, PropertyValue,
256};
257
258pub use cluster::{ClusterOptions, PointCluster};
259pub use gesture::GestureRecognizer;
260
261#[cfg(feature = "geojson")]
262pub use geojson::{parse_geojson, GeoJsonError};
263
264#[cfg(feature = "shapefile")]
265pub use shapefile_parser::{parse_shapefile, ShapefileError};
266
267pub use simplify::{simplify_douglas_peucker, simplify_polygon_ring};
268pub use tessellator::{stroke_line, stroke_line_styled, StrokeLineResult, triangulate_polygon, triangulate_polygon_with_holes};
269pub use geometry_ops::{
270    bearing, geometry_bbox, geometry_centroid, initial_bearing,
271    interpolate_great_circle, linestring_length, polygon_area, ring_area,
272};
273
274// ---------------------------------------------------------------------------
275// Re-exports -- Tile engine
276// ---------------------------------------------------------------------------
277
278pub use tile_cache::{TileCache, TileCacheEntry, TileCacheStats};
279pub use tile_lifecycle::{
280    TileLifecycleDiagnostics, TileLifecycleEvent, TileLifecycleEventKind,
281    TileLifecycleRecord,
282};
283pub use tile_manager::{
284    TileManager, TileManagerCounters, TilePixelRect, TileSelectionConfig, TileSelectionStats,
285    TileTextureRegion, VisibleTile, VisibleTileSet,
286};
287pub use tile_request_coordinator::{
288    CoordinatorConfig, CoordinatorStats, SourcePriority, TileRequestCoordinator,
289};
290pub use tile_source::{
291    DecodedImage, RasterMipChain, RasterMipLevel, RawVectorPayload, RevalidationHint, TileData,
292    TileDecoder, TileError, TileFreshness, TileResponse, TileSource, TileSourceDiagnostics,
293    TileSourceFailureDiagnostics, VectorTileData,
294};
295pub use tile_source_http::HttpTileSource;
296pub use tile_source_vector_http::HttpVectorTileSource;
297pub use pooled_tile_source::{
298    PooledRasterTileSourceConfig, PooledTileSource, DEFAULT_RASTER_TILE_URL,
299    DEFAULT_RASTER_TILE_USER_AGENT,
300};
301
302// ---------------------------------------------------------------------------
303// Re-exports -- I/O
304// ---------------------------------------------------------------------------
305
306pub use io::{FetchPool, HttpClient, HttpRequest, HttpResponse, SharedHttpClient};
307
308#[cfg(all(feature = "disk-cache", not(target_arch = "wasm32")))]
309pub use io::{DiskCache, DiskCacheError};
310
311// ---------------------------------------------------------------------------
312// Re-exports -- Terrain & elevation
313// ---------------------------------------------------------------------------
314
315pub use terrain::{
316    expand_with_clamped_border, interior_dims, patch_border_edge, patch_changed_tiles,
317    BackfillState, NEIGHBOR_OFFSETS,
318    build_terrain_descriptor, build_terrain_descriptor_with_source, build_terrain_mesh,
319    build_terrain_mesh_with_source, elevation_region_in_texture_space, materialize_terrain_mesh,
320    prepare_hillshade_raster, skirt_height, ElevationSource, ElevationSourceDiagnostics,
321    ElevationSourceFailureDiagnostics, FlatElevationSource, HttpElevationSource,
322    PreparedHillshadeRaster, QuantizedMeshSource, TerrainConfig,
323    TerrainDiagnostics, TerrainElevationTexture, TerrainError, TerrainManager, TerrainMeshData,
324    TerrainRgbEncoding,
325};
326
327// ---------------------------------------------------------------------------
328// Re-exports -- 3D models
329// ---------------------------------------------------------------------------
330
331pub use models::{AltitudeMode, ModelInstance, ModelLoadError, ModelMesh};
332
333// ---------------------------------------------------------------------------
334// Re-exports -- Symbols and cartography foundation
335// ---------------------------------------------------------------------------
336
337pub use symbols::{
338    GlyphAtlas, GlyphAtlasEntry, GlyphKey, GlyphProvider, GlyphQuad, GlyphRaster, ImageManager,
339    PlacedSymbol, ProceduralGlyphProvider, SpriteImage, SpriteSheet,
340    SymbolAnchor, SymbolAssetDependencies, SymbolAssetRegistry, SymbolCandidate,
341    SymbolCollisionBox, SymbolPlacementConfig, SymbolPlacementEngine,
342    SymbolIconTextFit, SymbolPlacement, SymbolTextJustify, SymbolTextTransform,
343    SymbolWritingMode,
344    layout_symbol_glyphs,
345    cross_tile_index::{CrossTileSymbolIndex, SymbolCandidateEntry},
346};
347
348// ---------------------------------------------------------------------------
349// Re-exports -- Query API
350// ---------------------------------------------------------------------------
351
352pub use query::{
353    FeatureState, FeatureStateId, GeoBBox, QueriedFeature, QueryOptions,
354    geometry_intersects_bbox,
355};
356
357// ---------------------------------------------------------------------------
358// Re-exports -- Picking API
359// ---------------------------------------------------------------------------
360
361pub use picking::{
362    HitCategory, HitProvenance, NonPickableLayerKind, PickHit, PickOptions, PickQuery,
363    PickResult, PickableLayerKind,
364};
365
366// ---------------------------------------------------------------------------
367// Re-exports -- Visualization primitives
368// ---------------------------------------------------------------------------
369
370pub use visualization::{
371    ColorRamp, ColorStop, ColumnInstance, ColumnInstanceSet, ExtrusionParams,
372    GeoGrid, GridExtrusionLayer, GridScalarLayer, InstancedColumnLayer,
373    LabeledStop, LegendSpec, NormalizationMode, PointCloudLayer, PointInstance,
374    PointInstanceSet, ScalarField2D, VisualizationOverlay,
375};
376
377// ---------------------------------------------------------------------------
378// Re-exports -- Image comparison (cross-renderer parity)
379// ---------------------------------------------------------------------------
380
381pub use image_compare::{compute_rmse, count_differing_pixels, differing_pixel_fraction};
382
383// ---------------------------------------------------------------------------
384// Re-exports -- TileJSON metadata
385// ---------------------------------------------------------------------------
386
387pub use tilejson::{TileJson, TileJsonError, TileScheme, VectorLayerMeta};
388#[cfg(feature = "style-json")]
389pub use tilejson::{parse_tilejson, parse_tilejson_value};
390
391// ---------------------------------------------------------------------------
392// Re-exports -- MVT decoder
393// ---------------------------------------------------------------------------
394
395pub use mvt::{decode_mvt, DecodedVectorTile, MvtDecodeOptions, MvtError};
396
397// ---------------------------------------------------------------------------
398// Re-exports -- Async data pipeline
399// ---------------------------------------------------------------------------
400
401pub use async_data::{
402    DataTaskPool, DataTaskResultReceiver, ThreadDataTaskPool,
403    TerrainTaskInput, TerrainTaskOutput, TerrainCacheKey,
404    VectorTaskInput, VectorTaskOutput, VectorCacheKey,
405    VectorBucketKey, partition_features_by_tile,
406    MvtDecodeOutput,
407    AsyncVisualizationPipeline, VisualizationTaskOutput,
408};
409
410// ---------------------------------------------------------------------------
411// Compile-time Send + Sync assertions
412//
413// Every public data type that downstream code may share across threads
414// must be Send + Sync.  These zero-cost assertions catch regressions at
415// compile time rather than in production.
416// ---------------------------------------------------------------------------
417
418#[allow(dead_code)]
419const _: () = {
420    fn assert_send_sync<T: Send + Sync>() {}
421    fn assertions() {
422        // Math primitives
423        assert_send_sync::<GeoCoord>();
424        assert_send_sync::<WorldCoord>();
425        assert_send_sync::<GeoBounds>();
426        assert_send_sync::<WorldBounds>();
427        assert_send_sync::<Ellipsoid>();
428        assert_send_sync::<Frustum>();
429        assert_send_sync::<Plane>();
430        assert_send_sync::<TileId>();
431        assert_send_sync::<TileCoord>();
432        assert_send_sync::<FlatTileSelectionConfig>();
433        assert_send_sync::<FlatTileView>();
434        assert_send_sync::<CoveringCamera>();
435        assert_send_sync::<CoveringTilesOptions>();
436        assert_send_sync::<GeodesicResult>();
437        assert_send_sync::<ElevationGrid>();
438        assert_send_sync::<VincentyConvergenceError>();
439        assert_send_sync::<WebMercator>();
440        assert_send_sync::<Equirectangular>();
441        assert_send_sync::<Globe>();
442        assert_send_sync::<VerticalPerspective>();
443
444        // Camera & input
445        assert_send_sync::<Camera>();
446        assert_send_sync::<CameraConstraints>();
447        assert_send_sync::<CameraMode>();
448        assert_send_sync::<CameraProjection>();
449        assert_send_sync::<CameraAnimator>();
450        assert_send_sync::<InputEvent>();
451
452        // Layer system
453        assert_send_sync::<BackgroundLayer>();
454        assert_send_sync::<HillshadeLayer>();
455        assert_send_sync::<LayerId>();
456        assert_send_sync::<LayerStack>();
457        assert_send_sync::<TileLayer>();
458        assert_send_sync::<VectorLayer>();
459        assert_send_sync::<ModelLayer>();
460        assert_send_sync::<VectorStyle>();
461        assert_send_sync::<VectorMeshData>();
462        assert_send_sync::<StyleDocument>();
463        assert_send_sync::<MapStyle>();
464
465        // Map state
466        assert_send_sync::<MapState>();
467        assert_send_sync::<FrameOutput>();
468        assert_send_sync::<FeatureState>();
469        assert_send_sync::<FeatureStateId>();
470        assert_send_sync::<QueriedFeature>();
471        assert_send_sync::<QueryOptions>();
472
473        // Picking
474        assert_send_sync::<PickQuery>();
475        assert_send_sync::<PickOptions>();
476        assert_send_sync::<PickHit>();
477        assert_send_sync::<PickResult>();
478
479        // Geometry
480        assert_send_sync::<Feature>();
481        assert_send_sync::<FeatureCollection>();
482        assert_send_sync::<Geometry>();
483        assert_send_sync::<PropertyValue>();
484
485        // Tile engine
486        assert_send_sync::<TileCache>();
487        assert_send_sync::<TileCacheEntry>();
488        assert_send_sync::<TileCacheStats>();
489        assert_send_sync::<TileManager>();
490        assert_send_sync::<TileManagerCounters>();
491        assert_send_sync::<TilePixelRect>();
492        assert_send_sync::<TileSelectionConfig>();
493        assert_send_sync::<TileSelectionStats>();
494        assert_send_sync::<TilePipelineDiagnostics>();
495        assert_send_sync::<TileTextureRegion>();
496        assert_send_sync::<VisibleTile>();
497        assert_send_sync::<VisibleTileSet>();
498        assert_send_sync::<DecodedImage>();
499        assert_send_sync::<RasterMipChain>();
500        assert_send_sync::<RasterMipLevel>();
501        assert_send_sync::<TileData>();
502        assert_send_sync::<TileError>();
503        assert_send_sync::<TileSourceDiagnostics>();
504        assert_send_sync::<PooledTileSource>();
505        assert_send_sync::<VectorTileData>();
506
507        // TileJSON
508        assert_send_sync::<TileJson>();
509        assert_send_sync::<TileJsonError>();
510        assert_send_sync::<TileScheme>();
511        assert_send_sync::<VectorLayerMeta>();
512
513        // MVT
514        assert_send_sync::<MvtDecodeOptions>();
515        assert_send_sync::<MvtError>();
516
517        // I/O
518        assert_send_sync::<FetchPool>();
519        assert_send_sync::<HttpRequest>();
520        assert_send_sync::<HttpResponse>();
521
522        // Terrain
523        assert_send_sync::<TerrainConfig>();
524        assert_send_sync::<TerrainError>();
525        assert_send_sync::<TerrainManager>();
526        assert_send_sync::<TerrainMeshData>();
527        assert_send_sync::<PreparedHillshadeRaster>();
528        assert_send_sync::<TerrainRgbEncoding>();
529        assert_send_sync::<TerrainSource>();
530        assert_send_sync::<VectorTileSource>();
531        assert_send_sync::<ImageSource>();
532        assert_send_sync::<VideoSource>();
533        assert_send_sync::<CanvasSource>();
534        assert_send_sync::<GlyphAtlas>();
535        assert_send_sync::<GlyphAtlasEntry>();
536        assert_send_sync::<GlyphKey>();
537        assert_send_sync::<GlyphRaster>();
538        assert_send_sync::<ImageManager>();
539        assert_send_sync::<PlacedSymbol>();
540        assert_send_sync::<ProceduralGlyphProvider>();
541        assert_send_sync::<SpriteImage>();
542        assert_send_sync::<SpriteSheet>();
543        assert_send_sync::<SymbolAnchor>();
544        assert_send_sync::<SymbolAssetDependencies>();
545        assert_send_sync::<SymbolAssetRegistry>();
546        assert_send_sync::<SymbolCandidate>();
547        assert_send_sync::<SymbolCollisionBox>();
548        assert_send_sync::<SymbolPlacementConfig>();
549        assert_send_sync::<SymbolPlacementEngine>();
550        assert_send_sync::<SymbolWritingMode>();
551
552        // Models
553        assert_send_sync::<ModelInstance>();
554        assert_send_sync::<ModelMesh>();
555        assert_send_sync::<AltitudeMode>();
556        assert_send_sync::<GeoJsonSource>();
557        assert_send_sync::<ModelSource>();
558
559        // Visualization
560        assert_send_sync::<GeoGrid>();
561        assert_send_sync::<ScalarField2D>();
562        assert_send_sync::<ColorRamp>();
563        assert_send_sync::<ColorStop>();
564        assert_send_sync::<LegendSpec>();
565        assert_send_sync::<ColumnInstance>();
566        assert_send_sync::<ColumnInstanceSet>();
567        assert_send_sync::<PointInstance>();
568        assert_send_sync::<PointInstanceSet>();
569        assert_send_sync::<GridScalarLayer>();
570        assert_send_sync::<GridExtrusionLayer>();
571        assert_send_sync::<InstancedColumnLayer>();
572        assert_send_sync::<PointCloudLayer>();
573        assert_send_sync::<VisualizationOverlay>();
574    }
575};