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}