pub trait Environment {
type Observation: Clone + Send + Sync + 'static;
type Action: Clone + Send + Sync + 'static;
type Info: Default + Clone + Send + Sync + 'static;
// Required methods
fn step(
&mut self,
action: Self::Action,
) -> StepResult<Self::Observation, Self::Info>;
fn reset(&mut self, seed: Option<u64>) -> (Self::Observation, Self::Info);
fn sample_action(&self, rng: &mut impl Rng) -> Self::Action;
// Provided method
fn episode_extras(&self) -> HashMap<String, f64> { ... }
}Expand description
The core environment trait.
Defines the contract that all RL environments must satisfy, regardless of whether they run headless in ember-rl or are visualised via bevy-gym.
§Design principles
-
Type-safe observation and action spaces:
ObservationandActionare associated types. The compiler enforces correctness; there are no runtime Box/Discrete/Dict space objects. -
Typed
Info: auxiliary data isSelf::Info, notdict[str, Any]. If you don’t need it, use()and getDefaultfor free. -
No
render(): visualisation is entirely bevy-gym’s concern. rl-traits knows nothing about rendering. -
No
close(): implementDropif your environment holds resources. -
Bevy-compatible by design:
Send + Sync + 'staticbounds on associated types mean implementations can be used as BevyComponents directly, enabling free ECS-based parallelisation in bevy-gym viaQuery::par_iter_mut().
§Example
use rl_traits::{Environment, StepResult, EpisodeStatus};
use rand::Rng;
struct BanditsEnv {
arms: [f64; 4],
rng: rand::rngs::SmallRng,
}
impl Environment for BanditsEnv {
type Observation = (); // stateless — observation is always ()
type Action = usize; // pull arm 0..3
type Info = ();
fn step(&mut self, action: usize) -> StepResult<(), ()> {
let reward = self.rng.gen::<f64>() * self.arms[action];
StepResult::new((), reward, EpisodeStatus::Continuing, ())
}
fn reset(&mut self, _seed: Option<u64>) -> ((), ()) {
((), ())
}
fn sample_action(&self, rng: &mut impl Rng) -> usize {
rng.gen_range(0..4)
}
}Required Associated Types§
Sourcetype Observation: Clone + Send + Sync + 'static
type Observation: Clone + Send + Sync + 'static
The observation type produced by step() and reset().
Send + Sync + 'static are required for Bevy ECS compatibility.
Required Methods§
Sourcefn step(
&mut self,
action: Self::Action,
) -> StepResult<Self::Observation, Self::Info>
fn step( &mut self, action: Self::Action, ) -> StepResult<Self::Observation, Self::Info>
Advance the environment by one timestep.
The caller is responsible for checking StepResult::is_done() and
calling reset() before the next episode.
Sourcefn reset(&mut self, seed: Option<u64>) -> (Self::Observation, Self::Info)
fn reset(&mut self, seed: Option<u64>) -> (Self::Observation, Self::Info)
Reset the environment to an initial state, starting a new episode.
If seed is Some(u64), the environment should use it to seed its
internal RNG for deterministic reproduction of episodes.
Sourcefn sample_action(&self, rng: &mut impl Rng) -> Self::Action
fn sample_action(&self, rng: &mut impl Rng) -> Self::Action
Sample a random action from this environment’s action space.
Used by random exploration agents and for initial data collection.
The rng is caller-supplied so exploration randomness can be seeded
and tracked independently from environment randomness.
Provided Methods§
Sourcefn episode_extras(&self) -> HashMap<String, f64>
fn episode_extras(&self) -> HashMap<String, f64>
Per-episode scalar metrics reported at episode end.
Override this to expose environment-specific statistics (e.g. collisions, tiles explored, distance travelled). The default returns an empty map. These are merged into training records alongside algorithm-level extras.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.