pub struct Agent<C: ?Sized + Config, I: ?Sized + Any, A: Actions<C, I>, S = Unchecked> { /* private fields */ }Expand description
Represents an isolated execution context (an agent) within the simulation.
An Agent encapsulates:
- Subject: The data associated with this agent.
- Lifecycle: The asynchronous logic defining its behavior.
- Execution State: Manages whether the agent is ready, running, or finished.
Agents provide isolation: their internal logic, defined via the Actions
(and typically Behavior) trait, cannot directly access or be influenced
by the lexical scope where the Agent struct was created, due to the HRTB
mechanism employed by Actions. Communication happens through simulation
primitives (scheduling, waiting) and the agent’s final Output.
Agent implements Deref and DerefMut to its subject.
However, mutable access is only practically possible before the agent is
passed to Sim::activate, as activation blocks the access path. This is
enforced by Rust’s borrowing rules at compile time.
Agents are typically created using Agent::new (for types implementing
Behavior) or Agent::build for more configuration options. They must
be pinned (e.g., using core::pin::pin!) before being passed to
Sim::activate.
The generic parameter S defines the Settle strategy, controlling how
the agent’s Output is translated into an ExitStatus. Unchecked is
the default, treating all outcomes as success. Checked interprets
Result, Option, and bool as success/failure indicators.
§Type Parameters
C: The simulation configuration type (Config).I: The type of the agent’s internal state (the “item” or “subject”).A: The type implementingActions, defining the agent’s lifecycle logic.S: TheSettlestrategy (defaults toUnchecked).
§Safety Warning
The order of fields inner and item must not be changed. inner must
come before item. Reversing this order will lead to use-after-free and
undefined behavior because the Share within Inner::Live internally holds
a pointer derived from item, and drop order relies on inner being
dropped first.
Implementations§
Source§impl Agent<(), (), Pending<()>>
impl Agent<(), (), Pending<()>>
Sourcepub fn new<'p, C, I>(
subject: I,
) -> Lease<'p, Agent<C, I, impl Actions<C, I, Output = I::Output> + use<C, I>>>
pub fn new<'p, C, I>( subject: I, ) -> Lease<'p, Agent<C, I, impl Actions<C, I, Output = I::Output> + use<C, I>>>
Creates a new Agent using a type that implements Behavior.
This is the simplest way to create an agent. It infers the agent’s
actions, output type, and name from the Behavior implementation of
I. The agent uses the default Unchecked settle strategy, meaning
its ExitStatus will always be Ok unless it panics or is aborted,
regardless of the Output type (even if it’s a Result::Err).
The provided subject (of type I) becomes the agent’s internal state.
Returns a Lease, which must be pinned before activation.
§Example
struct MyAgent;
impl Behavior for MyAgent {
type Output = ();
async fn actions(&self, sim: &Sim) { /* ... */ }
}
let agent_lease = Agent::new(MyAgent);
let pinned_agent = pin!(agent_lease);
// Pass pinned_agent to sim.activate(...)Sourcepub const fn build<C: ?Sized + Config>() -> Builder<C>
pub const fn build<C: ?Sized + Config>() -> Builder<C>
Creates a Builder for configuring an Agent instance.
Use the builder when you need to customize options like the agent’s name,
initial rank, settle strategy (Checked), or source code location,
or when defining the agent using a state/function tuple instead of a
dedicated Behavior implementation.
§Example
let agent = Agent::build()
.with_subject(MyState)
.with_actions(my_actions)
.with_name("CustomAgent")
.finish();
// Pin and activate agent...Trait Implementations§
Source§impl<C, I, A, S> Active<C> for Agent<C, I, A, S>
impl<C, I, A, S> Active<C> for Agent<C, I, A, S>
Source§fn bind<'p>(
this: Pin<LeasedMut<'p, Self>>,
sctx: &'p Share<C>,
) -> Self::Puck<'p>
fn bind<'p>( this: Pin<LeasedMut<'p, Self>>, sctx: &'p Share<C>, ) -> Self::Puck<'p>
Binds the agent to the simulation context, transitioning it from Born
to Live.
This method is called internally by Sim::activate. It performs the
critical steps:
- Temporarily replaces the
Inner::Bornstate withInner::Bust. - Calls the
action.bind()method (fromprivate::Action) to create the agent’s lifecycle future (RootFuture). - If
bindsucceeds, creates theSharecontext and theRootJob. - Replaces the
Inner::Buststate withInner::Live, containing theRootJobandShare. - Returns the agent’s
Puckhandle.
If action.bind() panics, the agent remains in the Inner::Bust state.
§Safety
Relies on unsafe blocks for lifetime transmutation ('p to 'static
and back) and creating the Share context. These are justified because:
- The
'staticlifetime onRootJobwithinInner::Liveis an internal implementation detail; the actual future only borrows data for'p. The lifetime is transmuted back to'pwhen creating thePuck. Share::newrequires ensuring theitempointer outlivesShare. This is guaranteed by the struct field ordering (innerbeforeitem), and Rust’s drop order guarantees (inneris dropped first).