Skip to main content

slint_mapping/
source.rs

1//! [`TileSource`] — the adapter trait every map data source implements.
2//!
3//! The framework only ever asks a source for a single tile by
4//! `(x, y, z)`; it doesn't care whether the source reads PNG files
5//! from disk, decodes vector MVT, or hits a remote HTTP endpoint with
6//! a cache. Implementations are responsible for their own internal
7//! threading / caching; the call here is synchronous and is expected
8//! to return quickly (`None` is a perfectly fine answer for "not
9//! ready yet" — the controller will ask again on the next refresh).
10
11/// One tile request. Coordinates are tile-space integers at zoom
12/// level `z`; see [`crate::projection`] for the math.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub struct TileKey {
15    pub x: u32,
16    pub y: u32,
17    pub z: u8,
18}
19
20/// An on-disk or in-memory tile source. Adapters implement this.
21pub trait TileSource: Send + Sync {
22    /// Return the tile at `(x, y, z)`, or `None` if it isn't available
23    /// (out of bounds, missing from disk, not yet downloaded, …).
24    /// Implementations must not block the caller for long — kick off
25    /// any expensive fetch on a background task and return `None` until
26    /// the result lands in your cache.
27    fn tile(&self, key: TileKey) -> Option<slint::Image>;
28
29    /// Tile edge length in pixels. Default 256 matches every common
30    /// slippy-map source; vector / retina sources may emit 512.
31    fn tile_size(&self) -> u32 {
32        256
33    }
34
35    /// Inclusive maximum zoom level this source serves. Used by the
36    /// controller to clamp user-initiated zoom. Default is "any zoom
37    /// up to Web Mercator's practical ceiling".
38    fn max_zoom(&self) -> u8 {
39        22
40    }
41
42    /// Inclusive minimum zoom level. Default 0 (whole world in one tile).
43    fn min_zoom(&self) -> u8 {
44        0
45    }
46
47    /// Drop any queued (but not yet started) work for keys NOT in
48    /// `keep`. Default no-op — synchronous sources have no in-flight
49    /// work to cancel. Fetching / decoding implementations should
50    /// override this so rapidly-panning consumers don't accumulate
51    /// off-screen requests that waste bandwidth on tiles nobody will
52    /// see by the time they arrive.
53    fn cancel_all_except(&self, _keep: &std::collections::HashSet<TileKey>) {}
54}
55
56// Blanket impl so a `Box<dyn TileSource>` is itself a `TileSource`,
57// letting consumers swap sources at runtime without writing a shim.
58impl<T: TileSource + ?Sized> TileSource for Box<T> {
59    fn tile(&self, key: TileKey) -> Option<slint::Image> {
60        (**self).tile(key)
61    }
62    fn tile_size(&self) -> u32 {
63        (**self).tile_size()
64    }
65    fn min_zoom(&self) -> u8 {
66        (**self).min_zoom()
67    }
68    fn max_zoom(&self) -> u8 {
69        (**self).max_zoom()
70    }
71    fn cancel_all_except(&self, keep: &std::collections::HashSet<TileKey>) {
72        (**self).cancel_all_except(keep)
73    }
74}