1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//! Typed handle to a registered environment key.
//!
//! An [`EnvKey<T>`] is a lightweight, copyable token produced by
//! [`Environment::env_key`](crate::environment::Environment::env_key) after
//! the environment is built. It bundles two pieces of information that systems
//! need when interacting with a specific environment key:
//!
//! - The key's name (`&'static str`), for passing to
//! [`Environment::get`](crate::environment::Environment::get) and
//! [`Environment::set`](crate::environment::Environment::set).
//! - The key's [`ChannelID`], for inserting into
//! [`AccessSets::produces`](crate::engine::systems::AccessSets::produces) or
//! [`AccessSets::consumes`](crate::engine::systems::AccessSets::consumes) so
//! the scheduler can order env writers before env readers of the same key.
//!
//! ## Acquiring a handle
//!
//! ```text
//! let env = EnvironmentBuilder::new()
//! .register::<f32>("interest_rate", 0.05)
//! .build();
//!
//! let rate_key: EnvKey<f32> = env
//! .env_key::<f32>("interest_rate")
//! .expect("interest_rate not registered");
//! ```
//!
//! ## Using the handle in a system
//!
//! ```text
//! struct RateWriterSystem {
//! rate_key: EnvKey<f32>,
//! access: AccessSets,
//! }
//!
//! // During construction - declare the scheduling dependency:
//! let mut access = AccessSets::default();
//! access.produces.insert(rate_key.channel_id());
//!
//! // Inside System::run():
//! fn run(&self, ecs: ECSReference<'_>) -> ECSResult<()> {
//! // ... read env via Arc<Environment> captured in the system ...
//! env.set(self.rate_key.name(), new_rate)?;
//! Ok(())
//! }
//! ```
//!
//! ## Key name requirement
//!
//! [`Environment::env_key`](crate::environment::Environment::env_key) requires
//! a `&'static str`. Environment keys intended for use with typed handles must
//! therefore be registered with string literal names (e.g. `"interest_rate"`).
//! Keys registered with a runtime [`String`] cannot produce handles unless the
//! string happens to alias a `'static` reference.
use PhantomData;
use crateChannelID;
/// A typed, copyable handle to a single registered environment key.
///
/// Systems store one `EnvKey<T>` per environment key they interact with. The
/// handle is used in two ways:
///
/// 1. **Name access** - [`name`](Self::name) returns the `&'static str` to
/// pass to [`Environment::get`](crate::environment::Environment::get) /
/// [`Environment::set`](crate::environment::Environment::set).
///
/// 2. **Scheduling** - [`channel_id`](Self::channel_id) returns the
/// [`ChannelID`] to insert into
/// [`AccessSets::produces`](crate::AccessSets::produces) (for writing
/// systems) or [`AccessSets::consumes`](crate::AccessSets::consumes) (for
/// reading systems), so the scheduler places every writer of this key in an
/// earlier stage than every reader.
///
/// `EnvKey<T>` is [`Copy`] - duplicate it freely. The type parameter `T`
/// is a compile-time marker only; no `T` is stored or accessed at runtime.
///
/// ## Example
///
/// ```text
/// let key: EnvKey<f32> = env.env_key::<f32>("tax_rate").unwrap();
///
/// // Writer system access declaration:
/// access.produces.insert(key.channel_id());
///
/// // Reader system access declaration:
/// access.consumes.insert(key.channel_id());
///
/// // Runtime value access:
/// env.set(key.name(), 0.25_f32)?;
/// let v: f32 = env.get(key.name())?;
/// ```