Skip to content

Commit 9e51b3c

Browse files
committed
Deprecate ServiceProvider and ServiceConsumer traits
A `ServiceProvider<Input, Output, Config>` where there is no request-response relationship between the input and output messages is replaced by a `MessageSink<Input, Config> + MessageSource<Output, NoConfig>`. A `ServiceProvider<Request, Response, NoConfig>` where there is a request-response relationship between the request and response messages is replaced by a `Service<Request, Response>. The ServiceConsumer trait has also been deprecated, because closely tight to the ServiceProvider trait. This has some drawbacks. Notably it's a bit less convenient to connect actors. Two method calls are required in many places instead of a single one. Futhermore the method names are not intuitive. The latter point with be addressed in following steps. Signed-off-by: Didier Wenzek <didier.wenzek@free.fr>
1 parent 49ebbbf commit 9e51b3c

File tree

30 files changed

+376
-471
lines changed

30 files changed

+376
-471
lines changed

crates/common/batcher/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ time = { workspace = true }
1515
tokio = { workspace = true, features = ["time"] }
1616

1717
[dev-dependencies]
18+
tedge_actors = { workspace = true, features = ["test-helpers"] }
1819
tokio = { workspace = true, features = ["rt", "macros"] }
1920

2021
[lints]

crates/common/batcher/src/lib.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ use tedge_actors::MessageSource;
2424
use tedge_actors::NoConfig;
2525
use tedge_actors::RuntimeRequest;
2626
use tedge_actors::RuntimeRequestSink;
27-
use tedge_actors::ServiceProvider;
2827
use tedge_actors::SimpleMessageBoxBuilder;
2928

3029
pub struct BatchingActorBuilder<B: Batchable> {
@@ -68,21 +67,6 @@ impl<B: Batchable> BatchingActorBuilder<B> {
6867
}
6968
}
7069

71-
// FIXME: This implementation highlights something new to me.
72-
// For some actor it makes little sense to impl ServiceProvider,
73-
// as the consumer of the outputs is likely a *different* actor as the producer of the inputs
74-
impl<B: Batchable> ServiceProvider<BatchDriverInput<B>, BatchDriverOutput<B>, NoConfig>
75-
for BatchingActorBuilder<B>
76-
{
77-
fn connect_consumer(
78-
&mut self,
79-
config: NoConfig,
80-
response_sender: DynSender<BatchDriverOutput<B>>,
81-
) -> DynSender<BatchDriverInput<B>> {
82-
self.message_box.connect_consumer(config, response_sender)
83-
}
84-
}
85-
8670
impl<B: Batchable> MessageSink<BatchDriverInput<B>, NoConfig> for BatchingActorBuilder<B> {
8771
fn get_config(&self) -> NoConfig {
8872
NoConfig

crates/core/tedge_actors/src/builders.rs

Lines changed: 35 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@
2222
//! - [MessageSource]
2323
//! declares that the actor under construction is a source of output messages,
2424
//! and tells how to connect a [MessageSink] to which the messages will be directed.
25-
//! - [ServiceProvider]
26-
//! declares that the actor under construction is a service provider,
27-
//! that produces output messages as a reaction to input messages.
28-
//! - [ServiceConsumer]:
29-
//! declares that the actor under construction depends on a service provider,
30-
//! and tells how to connect such a [ServiceProvider] to interact with.
3125
//! - [RuntimeRequestSink]:
3226
//! defines how the runtime can connect the actor under construction.
3327
//!
@@ -36,21 +30,11 @@
3630
//! - An actor builder has to implement at least the [Builder] and [RuntimeRequestSink] traits,
3731
//! so the runtime can connect itself to the actor and run it,
3832
//! using its [spawn](crate::Runtime::spawn) method.
39-
//! - An actor builder that *depends* on some service provided by a [ServiceProvider],
40-
//! *must* implement the [ServiceConsumer] trait for the input, output and config types
41-
//! defined by the provider.
42-
//! - Similarly, if an actor needs to connect a [MessageSource],
33+
//! - In order to define its input and output, an actor builder implements the [MessageSource] and [MessageSink] traits.
34+
//! - If an actor needs to connect a [MessageSource],
4335
//! its builder must implement the [MessageSink] trait with the appropriate message and config types.
4436
//! - Vice versa, if an actor needs to send messages to some [MessageSink],
4537
//! its builder must implement the [MessageSource] trait with the appropriate message and config types.
46-
//! - In order to define its input and output, an actor builder implements *either* the [ServiceProvider] trait
47-
//! or the [MessageSource] and [MessageSink] traits.
48-
//! - An actor builder implements the [MessageSource] and [MessageSink] traits
49-
//! when it makes sense for a peer to *only* send messages to or to *only* receive messages
50-
//! from the actor under construction.
51-
//! - An actor builder implements the [ServiceProvider] trait
52-
//! when there is a strong request-response relationship between the messages sent and received,
53-
//! the responses being meaningful only for the actor sending the triggering requests.
5438
//!
5539
//! An actor builder can use a [SimpleMessageBoxBuilder] to ease all these implementations.
5640
//!
@@ -70,7 +54,7 @@
7054
//! under construction needs to send messages to. This is the mirror of the previous responsibility:
7155
//! each builder gives to the others clones of its senders and collects senders from others.
7256
//! - This is why all the actor building traits
73-
//! ([MessageSource], [MessageSink], [ServiceProvider], [ServiceConsumer] and [RuntimeRequestSink])
57+
//! ([MessageSource], [MessageSink] and [RuntimeRequestSink])
7458
//! are related to exchanges of Sender. A sink gives to a source a sender attached to its receiver.
7559
//! - To be precise, the actor builders exchange [DynSender] and not [Sender]. The difference is that
7660
//! a [DynSender] can transform the messages sent by the source to adapt them to the sink expectations,
@@ -213,82 +197,6 @@ pub trait RuntimeRequestSink {
213197
fn get_signal_sender(&self) -> DynSender<RuntimeRequest>;
214198
}
215199

216-
/// A trait that defines that an actor provides a service
217-
/// by accepting `Request` messages and sending `Response` from/to its peers.
218-
///
219-
/// In order to connect to a to `ServiceProvider<Req, Res, Conf>` and avail its services,
220-
/// the peer must be a `ServiceConsumer<Req, Res, Conf>`.
221-
///
222-
/// The config parameter is typically used by the `ServiceConsumer`
223-
/// to register any message filtering criteria to the `ServiceProvider`.
224-
pub trait ServiceProvider<Request: Message, Response: Message, Config> {
225-
/// Connect a peer message box to the message box under construction
226-
fn add_peer(&mut self, peer: &mut impl ServiceConsumer<Request, Response, Config>) {
227-
let config = peer.get_config();
228-
let response_sender = peer.get_response_sender();
229-
let request_sender = self.connect_consumer(config, response_sender);
230-
peer.set_request_sender(request_sender);
231-
}
232-
233-
/// Connect a consumer to the service provider under construction
234-
/// returning to that service consumer a sender for its requests.
235-
///
236-
/// The consumer provides:
237-
/// - a config to filter the responses of interest,
238-
/// - a sender where the responses will have to be sent by the service.
239-
///
240-
/// The consumer is given back:
241-
/// - a sender where its requests will have to be sent to the service.
242-
fn connect_consumer(
243-
&mut self,
244-
config: Config,
245-
response_sender: DynSender<Response>,
246-
) -> DynSender<Request>;
247-
}
248-
249-
/// A trait that defines that the actor under-construction
250-
/// is a consumer of the service provided by another actor that is a `ServiceProvider`.
251-
///
252-
/// A `ServiceConsumer<Req, Res, Conf>` actor can be connected to another actor as its peer
253-
/// if that actor is a `ServiceProvider<Req, Res, Conf>`.
254-
pub trait ServiceConsumer<Request: Message, Response: Message, Config> {
255-
/// Return the config used by this actor to connect the service provider
256-
fn get_config(&self) -> Config;
257-
258-
/// Set the sender to be used by this actor's box to send requests
259-
fn set_request_sender(&mut self, request_sender: DynSender<Request>);
260-
261-
/// Return a sender where the responses to this actor's box have to be sent
262-
fn get_response_sender(&self) -> DynSender<Response>;
263-
264-
/// Connect this client message box to the service message box
265-
fn set_connection(
266-
&mut self,
267-
service: &mut impl ServiceProvider<Request, Response, Config>,
268-
) -> &mut Self
269-
where
270-
Self: Sized,
271-
{
272-
service.add_peer(self);
273-
self
274-
}
275-
276-
/// Connect this client message box to the service message box
277-
///
278-
/// Return the updated client message box.
279-
#[must_use]
280-
fn with_connection(
281-
mut self,
282-
service: &mut impl ServiceProvider<Request, Response, Config>,
283-
) -> Self
284-
where
285-
Self: Sized,
286-
{
287-
service.add_peer(&mut self);
288-
self
289-
}
290-
}
291-
292200
/// A [Builder] of [SimpleMessageBox]
293201
///
294202
/// This builder can be used as a building block for actor builders
@@ -353,42 +261,13 @@ pub trait ServiceConsumer<Request: Message, Response: Message, Config> {
353261
/// }
354262
/// ```
355263
///
356-
/// Similarly, as a `SimpleMessageBoxBuilder` is a [ServiceProvider], this can be used
357-
/// to implement the [ServiceProvider] trait for an actor using a [SimpleMessageBox] for its main input.
358-
///
359-
/// ```
360-
/// # use tedge_actors::{DynSender, NoConfig, ServiceConsumer, ServiceProvider, SimpleMessageBoxBuilder};
361-
/// # type MyActorConfig = i64;
362-
/// # type MyActorInput = i64;
363-
/// # type MyActorOutput = i64;
364-
/// struct MyActorBuilder {
365-
/// config: MyActorConfig,
366-
/// messages: SimpleMessageBoxBuilder<MyActorInput, MyActorOutput>,
367-
/// }
368-
///
369-
/// impl ServiceProvider<MyActorInput, MyActorOutput, NoConfig> for MyActorBuilder {
370-
/// fn connect_consumer(
371-
/// &mut self,
372-
/// config: NoConfig,
373-
/// response_sender: DynSender<MyActorOutput>)
374-
/// -> DynSender<MyActorInput> {
375-
/// self.messages.connect_consumer(config, response_sender)
376-
/// }
377-
/// }
378-
/// ```
379-
///
380264
/// A notable use of [SimpleMessageBox] is for testing.
381-
/// As a `SimpleMessageBoxBuilder` is a [ServiceConsumer]
382-
/// one can use such a builder to connect and test an actor that is a [ServiceProvider].
383-
///
384-
/// Similarly:
385-
/// - A `SimpleMessageBoxBuilder` is a [ServiceProvider] and can be used to test an actor that is a [ServiceConsumer].
386265
/// - A `SimpleMessageBoxBuilder` is a [MessageSource] and can be used to test an actor that is a [MessageSink].
387266
/// - A `SimpleMessageBoxBuilder` is a [MessageSink] and can be used to test an actor that is a [MessageSource].
388267
///
389268
/// ```
390269
/// # use std::convert::Infallible;
391-
/// # use tedge_actors::{Actor, Builder, DynSender, MessageReceiver, NoConfig, RuntimeError, Sender, ServiceConsumer, ServiceProvider, SimpleMessageBox, SimpleMessageBoxBuilder};
270+
/// # use tedge_actors::{Actor, Builder, DynSender, MessageReceiver, MessageSource, MessageSink, NoConfig, RuntimeError, Sender, SimpleMessageBox, SimpleMessageBoxBuilder};
392271
/// # struct MyActorState (i64);
393272
/// # type MyActorConfig = i64;
394273
/// # type MyActorInput = i64;
@@ -412,9 +291,17 @@ pub trait ServiceConsumer<Request: Message, Response: Message, Config> {
412291
/// # MyActorBuilder { config, messages }
413292
/// # }
414293
/// # }
415-
/// # impl ServiceProvider<MyActorInput, MyActorOutput, NoConfig> for MyActorBuilder {
416-
/// # fn connect_consumer(&mut self, config: NoConfig, response_sender: DynSender<MyActorOutput>) -> DynSender<MyActorInput> {
417-
/// # self.messages.connect_consumer(config, response_sender)
294+
/// # impl MessageSource<MyActorOutput, NoConfig> for MyActorBuilder {
295+
/// # fn register_peer(&mut self, config: NoConfig, sender: DynSender<MyActorOutput>) {
296+
/// # self.messages.register_peer(config, sender)
297+
/// # }
298+
/// # }
299+
/// # impl MessageSink<MyActorInput, NoConfig> for MyActorBuilder {
300+
/// # fn get_config(&self) -> NoConfig {
301+
/// # NoConfig
302+
/// # }
303+
/// # fn get_sender(&self) -> DynSender<MyActorInput> {
304+
/// # self.messages.get_sender()
418305
/// # }
419306
/// # }
420307
/// # impl Builder<MyActor> for MyActorBuilder {
@@ -448,7 +335,8 @@ pub trait ServiceConsumer<Request: Message, Response: Message, Config> {
448335
/// // Connect a test box to an actor under test
449336
/// let mut my_actor_builder = MyActorBuilder::new(MyActorConfig::default());
450337
/// let mut test_box_builder = SimpleMessageBoxBuilder::new("Test box", 16);
451-
/// my_actor_builder.add_peer(&mut test_box_builder);
338+
/// my_actor_builder.register_peer(NoConfig, test_box_builder.get_sender());
339+
/// test_box_builder.register_peer(NoConfig, my_actor_builder.get_sender());
452340
///
453341
/// // Build the test box and run the actor
454342
/// let mut test_box = test_box_builder.build();
@@ -489,38 +377,28 @@ impl<I: Message, O: Message> SimpleMessageBoxBuilder<I, O> {
489377
input_receiver,
490378
}
491379
}
492-
}
493380

494-
/// A `SimpleMessageBoxBuilder<Request,Response>` is a [ServiceProvider]
495-
/// accepting `Request` and sending back `Response`, with no specific config.
496-
impl<Req: Message, Res: Message, Config> ServiceProvider<Req, Res, Config>
497-
for SimpleMessageBoxBuilder<Req, Res>
498-
{
499-
fn connect_consumer(
381+
/// Connect this client message box to the service message box
382+
pub fn set_connection<Config>(
500383
&mut self,
501-
_config: Config,
502-
response_sender: DynSender<Res>,
503-
) -> DynSender<Req> {
504-
self.output_sender = response_sender;
505-
self.input_sender.sender_clone()
506-
}
507-
}
508-
509-
/// A `SimpleMessageBoxBuilder<Request,Response>` is a [ServiceConsumer]
510-
/// sending `Request` and expecting back `Response`, with no specific config.
511-
impl<Req: Message, Res: Message> ServiceConsumer<Req, Res, NoConfig>
512-
for SimpleMessageBoxBuilder<Res, Req>
513-
{
514-
fn get_config(&self) -> NoConfig {
515-
NoConfig
516-
}
517-
518-
fn set_request_sender(&mut self, request_sender: DynSender<Req>) {
519-
self.output_sender = request_sender;
384+
config: Config,
385+
service: &mut (impl MessageSink<O, NoConfig> + MessageSource<I, Config>),
386+
) {
387+
service.register_peer(config, self.input_sender.sender_clone());
388+
self.register_peer(NoConfig, service.get_sender());
520389
}
521390

522-
fn get_response_sender(&self) -> DynSender<Res> {
523-
self.input_sender.sender_clone()
391+
/// Connect this client message box to the service message box
392+
///
393+
/// Return the updated client message box.
394+
#[must_use]
395+
pub fn with_connection<Config>(
396+
mut self,
397+
config: Config,
398+
service: &mut (impl MessageSink<O, NoConfig> + MessageSource<I, Config>),
399+
) -> Self {
400+
self.set_connection(config, service);
401+
self
524402
}
525403
}
526404

crates/core/tedge_actors/src/converter.rs

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
//! # use crate::tedge_actors::ConvertingActor;
1515
//! # use crate::tedge_actors::RuntimeError;
1616
//! # use crate::tedge_actors::SimpleMessageBoxBuilder;
17-
//! # use crate::tedge_actors::ServiceConsumer;
1817
//! struct Repeater;
1918
//!
2019
//! impl Converter for Repeater {
@@ -39,7 +38,7 @@
3938
//! # use tedge_actors::{Actor, Builder, MessageReceiver, MessageSource, NoConfig, Sender};
4039
//! # use tedge_actors::test_helpers::MessageReceiverExt;
4140
//! let mut actor = ConvertingActor::builder("Repeater", Repeater, NoConfig);
42-
//! let mut test_box = SimpleMessageBoxBuilder::new("Test", 16).with_connection(&mut actor).build().with_timeout(Duration::from_millis(100));
41+
//! let mut test_box = SimpleMessageBoxBuilder::new("Test", 16).with_connection(NoConfig, &mut actor).build().with_timeout(Duration::from_millis(100));
4342
//! tokio::spawn(async move { actor.build().run().await });
4443
//!
4544
//! test_box.send((3, 42)).await?;
@@ -67,7 +66,6 @@ use crate::RuntimeError;
6766
use crate::RuntimeRequest;
6867
use crate::RuntimeRequestSink;
6968
use crate::Sender;
70-
use crate::ServiceProvider;
7169
use crate::SimpleMessageBox;
7270
use crate::SimpleMessageBoxBuilder;
7371
use async_trait::async_trait;
@@ -191,7 +189,6 @@ impl<C: Converter> ConvertingActor<C> {
191189
/// # use tedge_actors::MessageSink;
192190
/// # use tedge_actors::MessageSource;
193191
/// # use tedge_actors::NoConfig;
194-
/// # use tedge_actors::ServiceProvider;
195192
/// # #[derive(Debug)]
196193
/// # struct MqttMessage;
197194
/// # #[derive(Clone)]
@@ -245,6 +242,10 @@ impl<C: Converter, Config> ConvertingActorBuilder<C, Config> {
245242
message_box: SimpleMessageBoxBuilder::new(name, 16), // FIXME: capacity should not be hardcoded
246243
}
247244
}
245+
246+
pub fn get_input_sender(&self) -> DynSender<C::Input> {
247+
self.message_box.get_sender()
248+
}
248249
}
249250

250251
impl<C: Converter, Config> Builder<ConvertingActor<C>> for ConvertingActorBuilder<C, Config> {
@@ -285,18 +286,6 @@ where
285286
}
286287
}
287288

288-
impl<C: Converter, Config> ServiceProvider<C::Input, C::Output, NoConfig>
289-
for ConvertingActorBuilder<C, Config>
290-
{
291-
fn connect_consumer(
292-
&mut self,
293-
config: NoConfig,
294-
response_sender: DynSender<C::Output>,
295-
) -> DynSender<C::Input> {
296-
self.message_box.connect_consumer(config, response_sender)
297-
}
298-
}
299-
300289
impl<C: Converter, Config> RuntimeRequestSink for ConvertingActorBuilder<C, Config> {
301290
fn get_signal_sender(&self) -> DynSender<RuntimeRequest> {
302291
self.message_box.get_signal_sender()

crates/core/tedge_actors/src/examples/calculator_server.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ mod tests {
8181
use crate::ChannelError;
8282
use crate::ServerActor;
8383
use crate::ServerMessageBoxBuilder;
84-
use crate::ServiceConsumer;
8584
use crate::SimpleMessageBoxBuilder;
8685

8786
#[tokio::test]
@@ -94,7 +93,7 @@ mod tests {
9493
let mut probe = Probe::new();
9594
player_box_builder
9695
.with_probe(&mut probe)
97-
.set_connection(&mut service_box_builder);
96+
.connect_to_server(&mut service_box_builder);
9897

9998
// Spawn the actors
10099
tokio::spawn(async move {

0 commit comments

Comments
 (0)