libp2p_pubsub_common/service/service_trait.rs
1#![allow(unused_variables)]
2
3use std::task::{Context, Poll};
4
5use crate::service::context_handles::{OnEventCtx, PollCtx};
6
7pub type InEvent<T> = <T as Service>::InEvent;
8pub type OutEvent<T> = <T as Service>::OutEvent;
9
10/// A service is a stateful object that handle input events and can be polled for events.
11///
12/// The service state can only be mutated by handling input events. The service can emit events
13/// either by enqueueing them into the output mailbox or by returning a `Poll::Ready` event.
14///
15/// Typically a service implementation only needs to implement either the [`Service::on_event`]
16/// method or the [`Service::poll`] method. The [`Service::on_event`] method is useful for services
17/// that are event-driven, while the [`Service::poll`] method is useful for services that are
18/// polling-driven.
19///
20/// See [`on_event`](#method.on_event) and [`poll`](#method.poll) methods for more details.
21pub trait Service: 'static {
22 type InEvent: 'static;
23 type OutEvent: 'static;
24
25 /// Handle an input event.
26 ///
27 /// To emit an event, enqueueing it into the output mailbox, use the [`OnEventCtx::emit`]
28 /// method. To emit a batch of events, use the [`OnEventCtx::emit_batch`] method.
29 ///
30 /// ```ignore
31 /// use libp2p_pubsub_common::service::Service;
32 /// use libp2p_pubsub_common::service::OnEventCtx;
33 ///
34 /// impl Service for MyService {
35 /// type InEvent = MyInEvent;
36 /// type OutEvent = MyOutEvent;
37 ///
38 /// fn on_event(&mut self, scv_cx: &mut OnEventCtx<'_, Self::OutEvent>, ev: Self::InEvent) {
39 /// // ...
40 /// scv_cx.emit(event); // Emit an event.
41 /// scv_cx.emit_batch([event1, event2]); // Emit a batch of events.
42 /// // ...
43 /// }
44 /// }
45 ///```
46 fn on_event(&mut self, svc_cx: &mut OnEventCtx<'_, Self::OutEvent>, ev: Self::InEvent) {}
47
48 /// Poll the service for events.
49 ///
50 /// There are different ways to access the service context input mailbox events:
51 ///
52 /// - Using the [`PollCtx::len`] and [`PollCtx::is_empty`] methods to check if there are any
53 /// events in the input mailbox. This can be useful to apply backpressure to the upstream
54 /// service.
55 /// - Using the [`PollCtx::pop_next`] method to pop the next event from the input mailbox.
56 ///
57 /// On the other hand, to emit an event, one can use one of the following methods:
58 /// - Using the the [`PollCtx::emit`] to enqueue an event to the output mailbox. Or using the
59 /// [`PollCtx::emit_batch`] method to enqueue a batch of events.
60 /// - Returning a `Poll::Ready(event)` to skip the output mailbox and return the event
61 /// directly to the downstream service.
62 ///
63 /// ```ignore
64 /// use libp2p_pubsub_common::service::Service;
65 /// use libp2p_pubsub_common::service::PollCtx;
66 ///
67 /// impl Service for MyService {
68 /// type InEvent = MyInEvent;
69 /// type OutEvent = MyOutEvent;
70 ///
71 /// fn poll(&mut self, scv_cx: &mut PollCtx<'_, Self::InEvent, Self::OutEvent>, cx: &mut Context<'_>) {
72 /// // ...
73 /// scv_cx.emit(event); // Emit an event.
74 /// scv_cx.emit_batch([event1, event2]); // Emit a batch of events.
75 /// // ...
76 /// Poll::Ready(event); // Return an event to the downstream service.
77 /// }
78 /// }
79 ///```
80 fn poll(
81 &mut self,
82 svc_cx: PollCtx<'_, Self::InEvent, Self::OutEvent>,
83 cx: &mut Context<'_>,
84 ) -> Poll<Self::OutEvent> {
85 let (mut inbox_cx, outbox_cx) = svc_cx.split();
86
87 let mut on_event_cx = outbox_cx.into();
88 while let Some(event) = inbox_cx.pop_next() {
89 self.on_event(&mut on_event_cx, event);
90 }
91
92 Poll::Pending
93 }
94}