use std::marker::PhantomData;
use std::time::Duration;
use crate::__private::surface::{ComponentBoundSurface, TypedIoSurface};
use crate::bundle::ParticipantAssets as ParticipantAssetResolver;
use crate::bundle::RuntimeBundle;
use crate::bus::{
AskQuery, DEFAULT_QUERY_TIMEOUT, Endpoint, Event, EventPublisher, EventReceiver, Observed,
Publish, Querier, QueryEndpoint, RobotEndpoint, RobotInstant, Sample, SamplePublisher,
SampleReceiver, ServeQuery, Setpoint, SetpointPublisher, SetpointReceiver, State,
StatePublisher, StateView, StepToken, StreamDelivered, StreamPublisher, StreamReceiver,
Subscribe, TimelineId, Topic,
};
use crate::bus::{BusHandle, ParticipantId};
use crate::model::Robot;
use crate::participant::api::Participant;
use crate::participant::managed::{ManagedTaskOutput, ManagedTaskPolicy, ManagedTasks};
use crate::participant::query::QueryRegistration;
pub(crate) type TimelineRetention = Box<dyn Fn(TimelineId) + Send + Sync>;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct QueryContext {
producer: crate::bus::ProducerId,
}
impl QueryContext {
pub(crate) fn new(producer: crate::bus::ProducerId) -> Self {
Self { producer }
}
pub fn producer(&self) -> crate::bus::ProducerId {
self.producer
}
}
pub struct SetupContext<R: Participant> {
bus: BusHandle,
bundle: Option<RuntimeBundle>,
participant_id: ParticipantId,
managed_tasks: ManagedTasks,
timeline_retentions: Vec<TimelineRetention>,
queries: Vec<QueryRegistration<R>>,
_runtime: PhantomData<fn() -> R>,
}
impl<R: Participant> SetupContext<R> {
pub fn producer(&self) -> crate::bus::ProducerId {
self.bus.producer()
}
pub async fn participant_ready_events(
&self,
) -> crate::Result<crate::bus::ParticipantReadyEvents> {
Ok(self.bus.participant_ready_events().await?)
}
pub async fn participant_ready_events_for(
&self,
participant: &crate::bus::ParticipantId,
) -> crate::Result<crate::bus::ParticipantReadyEvents> {
Ok(self.bus.participant_ready_events_for(participant).await?)
}
pub async fn observe_participant_ready_for(
&self,
participant: &crate::bus::ParticipantId,
callback: impl Fn(crate::bus::ParticipantReadyEvent) + Send + Sync + 'static,
) -> crate::Result<crate::bus::ParticipantReadyObserver> {
Ok(self
.bus
.observe_participant_ready_for(participant, callback)
.await?)
}
pub(crate) fn new(
bus: BusHandle,
bundle: Option<RuntimeBundle>,
participant_id: ParticipantId,
) -> Self {
SetupContext {
bus,
bundle,
participant_id,
managed_tasks: ManagedTasks::default(),
timeline_retentions: Vec::new(),
queries: Vec::new(),
_runtime: PhantomData,
}
}
pub fn spawn_managed<F>(&mut self, name: impl Into<String>, future: F)
where
F: std::future::Future + Send + 'static,
F::Output: ManagedTaskOutput,
{
self.spawn_managed_with(name, ManagedTaskPolicy::Critical, future);
}
pub fn spawn_managed_with<F>(
&mut self,
name: impl Into<String>,
policy: ManagedTaskPolicy,
future: F,
) where
F: std::future::Future + Send + 'static,
F::Output: ManagedTaskOutput,
{
self.managed_tasks.spawn(name, policy, future);
}
pub(crate) fn take_managed_tasks(&mut self) -> ManagedTasks {
std::mem::take(&mut self.managed_tasks)
}
pub(crate) fn register_timeline_retention(
&mut self,
retention: impl Fn(TimelineId) + Send + Sync + 'static,
) {
self.timeline_retentions.push(Box::new(retention));
}
pub(crate) fn take_timeline_retentions(&mut self) -> Vec<TimelineRetention> {
std::mem::take(&mut self.timeline_retentions)
}
pub(crate) fn take_query_registrations(&mut self) -> Vec<QueryRegistration<R>> {
std::mem::take(&mut self.queries)
}
pub fn robot(&self) -> crate::Result<&Robot> {
Ok(self.bundle()?.robot())
}
pub fn assets(&self) -> crate::Result<&ParticipantAssetResolver> {
Ok(self.bundle()?.assets())
}
fn bundle(&self) -> crate::Result<&RuntimeBundle> {
self.bundle.as_ref().ok_or_else(|| {
anyhow::anyhow!(
"no bundle is bound (this participant was launched without a bundle root)"
)
})
}
}
impl<R: Participant + TypedIoSurface> SetupContext<R> {
pub fn state_publisher<E: RobotEndpoint + Endpoint<Semantics = State>>(
&self,
topic: Topic<Publish<E>>,
) -> crate::Result<StatePublisher<E>> {
Ok(StatePublisher::new(self.bus.clone(), &topic)?)
}
pub fn sample_publisher<E: RobotEndpoint + Endpoint<Semantics = Sample>>(
&self,
topic: Topic<Publish<E>>,
) -> crate::Result<SamplePublisher<E>> {
Ok(SamplePublisher::new(self.bus.clone(), &topic)?)
}
pub fn setpoint_publisher<E: RobotEndpoint + Endpoint<Semantics = Setpoint>>(
&self,
topic: Topic<Publish<E>>,
) -> crate::Result<SetpointPublisher<E>> {
Ok(SetpointPublisher::new(self.bus.clone(), &topic)?)
}
pub fn event_publisher<E: RobotEndpoint + Endpoint<Semantics = Event>>(
&self,
topic: Topic<Publish<E>>,
) -> crate::Result<EventPublisher<E>> {
Ok(EventPublisher::new(self.bus.clone(), &topic)?)
}
pub fn stream_publisher<E: RobotEndpoint>(
&self,
topic: Topic<Publish<E>>,
) -> crate::Result<StreamPublisher<E>>
where
E::Semantics: StreamDelivered,
{
Ok(StreamPublisher::new(self.bus.clone(), &topic)?)
}
pub async fn state_view<E: RobotEndpoint + Endpoint<Semantics = State>>(
&mut self,
topic: Topic<Subscribe<E>>,
) -> crate::Result<StateView<E>> {
let handle = StateView::new(&self.bus, &topic).await?;
let retained = handle.timeline_retention();
self.register_timeline_retention(move |timeline| {
retained.retain(timeline);
});
Ok(handle)
}
#[doc(hidden)]
pub async fn state_view_with_admission<
E: RobotEndpoint + Endpoint<Semantics = State>,
F: Fn(&Observed<E>) -> bool + Send + Sync + 'static,
>(
&mut self,
topic: Topic<Subscribe<E>>,
admission: F,
) -> crate::Result<StateView<E>> {
let handle = StateView::new_with_admission(&self.bus, &topic, admission).await?;
let retained = handle.timeline_retention();
self.register_timeline_retention(move |timeline| {
retained.retain(timeline);
});
Ok(handle)
}
pub async fn setpoint_receiver<E: RobotEndpoint + Endpoint<Semantics = Setpoint>>(
&mut self,
topic: Topic<Subscribe<E>>,
) -> crate::Result<SetpointReceiver<E>> {
let handle = SetpointReceiver::new(&self.bus, &topic).await?;
let retained = handle.timeline_retention();
self.register_timeline_retention(move |timeline| {
retained.retain(timeline);
});
Ok(handle)
}
pub async fn event_receiver<E: RobotEndpoint + Endpoint<Semantics = Event>>(
&mut self,
topic: Topic<Subscribe<E>>,
) -> crate::Result<EventReceiver<E>> {
let handle = EventReceiver::new(&self.bus, &topic).await?;
let retained = handle.timeline_retention();
self.register_timeline_retention(move |timeline| {
retained.retain(timeline);
});
Ok(handle)
}
pub async fn sample_receiver<E: RobotEndpoint + Endpoint<Semantics = Sample>>(
&mut self,
topic: Topic<Subscribe<E>>,
) -> crate::Result<SampleReceiver<E>> {
let handle = SampleReceiver::new(&self.bus, &topic).await?;
let retained = handle.timeline_retention();
self.register_timeline_retention(move |timeline| {
retained.retain(timeline);
});
Ok(handle)
}
pub async fn stream_receiver<E: RobotEndpoint>(
&mut self,
topic: Topic<Subscribe<E>>,
) -> crate::Result<StreamReceiver<E>>
where
E::Semantics: StreamDelivered,
{
let handle = StreamReceiver::new(&self.bus, &topic).await?;
let retained = handle.timeline_retention();
self.register_timeline_retention(move |timeline| {
retained.retain(timeline);
});
Ok(handle)
}
pub fn querier<E: QueryEndpoint>(
&self,
topic: Topic<AskQuery<E>>,
) -> crate::Result<Querier<E>> {
Ok(Querier::new(
self.bus.clone(),
&topic,
DEFAULT_QUERY_TIMEOUT,
)?)
}
pub fn query<E, H>(&mut self, topic: Topic<ServeQuery<E>>, handler: H) -> crate::Result<()>
where
E: QueryEndpoint,
H: for<'a> Fn(
&'a R,
&'a R::Api,
QueryContext,
E,
&'a mut R::State,
) -> crate::bus::QueryResult<E::Response>
+ Send
+ Sync
+ 'static,
{
let topic = topic.key().to_string();
if self
.queries
.iter()
.any(|registration| registration.topic() == topic)
{
anyhow::bail!("duplicate query binding for '{topic}'");
}
self.queries
.push(QueryRegistration::new::<E, E::Response, H>(topic, handler));
Ok(())
}
}
impl<R: Participant + ComponentBoundSurface> SetupContext<R> {
pub fn component(&self) -> crate::Result<crate::model::robot::ComponentView<'_>> {
let id = &self.participant_id;
self.robot()?.component(id.as_str()).ok_or_else(|| {
anyhow::anyhow!("this driver's id '{id}' is not a component instance of the robot")
})
}
}
#[derive(Clone, Copy, Debug)]
pub struct StepContext {
pub token: StepToken,
pub step_index: u64,
pub dt: Duration,
pub missed_ticks: u32,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ResetContext {
pub previous_timeline: TimelineId,
pub new_timeline: TimelineId,
}
impl StepContext {
pub fn now(&self) -> RobotInstant {
crate::bus::StepStamp::instant(&self.token)
}
pub fn timeline(&self) -> TimelineId {
self.now().timeline()
}
}