Skip to main content

cougr_core/query/
state.rs

1use crate::query::SimpleQuery;
2use crate::simple_world::EntityId as SimpleEntityId;
3use crate::simple_world::SimpleWorld;
4use soroban_sdk::{Env, Vec};
5
6/// Version-aware cache for a `SimpleQuery`.
7#[derive(Debug, Clone)]
8pub struct SimpleQueryState {
9    query: SimpleQuery,
10    cached_results: Vec<SimpleEntityId>,
11    cached_version: u64,
12}
13
14impl SimpleQueryState {
15    pub fn new(query: SimpleQuery, env: &Env) -> Self {
16        Self {
17            query,
18            cached_results: Vec::new(env),
19            cached_version: 0,
20        }
21    }
22
23    pub fn execute<'a>(&'a mut self, world: &SimpleWorld, env: &Env) -> &'a Vec<SimpleEntityId> {
24        if self.cached_version != world.version() {
25            self.cached_results = self.query.execute(world, env);
26            self.cached_version = world.version();
27        }
28        &self.cached_results
29    }
30
31    pub fn invalidate(&mut self) {
32        self.cached_version = 0;
33    }
34
35    pub fn is_valid(&self, world_version: u64) -> bool {
36        self.cached_version == world_version
37    }
38
39    pub fn query(&self) -> &SimpleQuery {
40        &self.query
41    }
42}
43
44/// Cached query for `SimpleWorld` that avoids re-scanning when the world hasn't changed.
45///
46/// Tracks a single component type and caches matching entity IDs.
47/// Automatically invalidates when the world version changes.
48///
49/// # Example
50/// ```
51/// use cougr_core::query::SimpleQueryCache;
52/// use cougr_core::simple_world::SimpleWorld;
53/// use soroban_sdk::{symbol_short, Bytes, Env};
54///
55/// let env = Env::default();
56/// let mut world = SimpleWorld::new(&env);
57/// let entity = world.spawn_entity();
58/// world.add_component(entity, symbol_short!("position"), Bytes::new(&env));
59///
60/// let mut cache = SimpleQueryCache::new(symbol_short!("position"), &env);
61/// let entities = cache.execute(&world, &env);
62/// assert_eq!(entities.len(), 1);
63/// let entities2 = cache.execute(&world, &env);
64/// assert_eq!(entities2.len(), 1);
65/// ```
66pub struct SimpleQueryCache {
67    state: SimpleQueryState,
68}
69
70impl SimpleQueryCache {
71    /// Create a new query cache for a specific component type
72    pub fn new(component_type: soroban_sdk::Symbol, env: &Env) -> Self {
73        Self {
74            state: SimpleQueryState::new(SimpleQuery::new(env).with_component(component_type), env),
75        }
76    }
77
78    /// Create a cache from an explicit `SimpleQuery`.
79    pub fn from_query(query: SimpleQuery, env: &Env) -> Self {
80        Self {
81            state: SimpleQueryState::new(query, env),
82        }
83    }
84
85    /// Execute the query, returning cached results if the world hasn't changed.
86    pub fn execute(&mut self, world: &SimpleWorld, env: &Env) -> &Vec<SimpleEntityId> {
87        self.state.execute(world, env)
88    }
89
90    /// Force invalidation of the cache.
91    pub fn invalidate(&mut self) {
92        self.state.invalidate();
93    }
94
95    /// Check if the cache is up-to-date with the given world version.
96    pub fn is_valid(&self, world_version: u64) -> bool {
97        self.state.is_valid(world_version)
98    }
99
100    /// Returns the underlying query.
101    pub fn query(&self) -> &SimpleQuery {
102        self.state.query()
103    }
104}