maplibre/render/
eventually.rs

1use std::mem;
2
3use crate::{coords::WorldTileCoords, render::tile_view_pattern::HasTile, tcs::world::World};
4
5/// Wrapper around a resource which can be initialized or uninitialized.
6/// Uninitialized resourced can be initialized by calling [`Eventually::initialize()`].
7pub enum Eventually<T> {
8    Initialized(T),
9    Uninitialized,
10}
11
12pub trait HasChanged {
13    type Criteria: Eq;
14
15    fn has_changed(&self, criteria: &Self::Criteria) -> bool;
16}
17
18impl<T> HasChanged for Option<T>
19where
20    T: HasChanged,
21{
22    type Criteria = T::Criteria;
23
24    fn has_changed(&self, criteria: &Self::Criteria) -> bool {
25        match self {
26            None => true,
27            Some(value) => value.has_changed(criteria),
28        }
29    }
30}
31
32impl<T> Eventually<T>
33where
34    T: HasChanged,
35{
36    #[tracing::instrument(name = "reinitialize", skip_all)]
37    pub fn reinitialize(&mut self, f: impl FnOnce() -> T, criteria: &T::Criteria) {
38        let should_replace = match &self {
39            Eventually::Initialized(current) => current.has_changed(criteria),
40            Eventually::Uninitialized => true,
41        };
42
43        if should_replace {
44            *self = Eventually::Initialized(f());
45        }
46    }
47}
48impl<T> Eventually<T> {
49    #[tracing::instrument(name = "initialize", skip_all)]
50    pub fn initialize(&mut self, f: impl FnOnce() -> T) -> &mut T {
51        if let Eventually::Uninitialized = self {
52            *self = Eventually::Initialized(f());
53        }
54
55        match self {
56            Eventually::Initialized(data) => data,
57            Eventually::Uninitialized => panic!("not initialized"),
58        }
59    }
60
61    pub fn take(&mut self) -> Eventually<T> {
62        mem::replace(self, Eventually::Uninitialized)
63    }
64
65    pub fn expect_initialized_mut(&mut self, message: &str) -> &mut T {
66        match self {
67            Eventually::Initialized(value) => value,
68            Eventually::Uninitialized => panic!("{message}"),
69        }
70    }
71}
72
73impl<T> Default for Eventually<T> {
74    fn default() -> Self {
75        Eventually::Uninitialized
76    }
77}
78
79impl<T> HasTile for Eventually<T>
80where
81    T: HasTile,
82{
83    fn has_tile(&self, coords: WorldTileCoords, world: &World) -> bool {
84        match self {
85            Eventually::Initialized(value) => value.has_tile(coords, world),
86            Eventually::Uninitialized => false,
87        }
88    }
89}