Skip to content

Commit 849bc1f

Browse files
authored
Merge pull request #740 from swimos/flexible-map-dls
Support for different map kinds in map downlinks.
2 parents c21a7ea + 7332289 commit 849bc1f

File tree

14 files changed

+440
-380
lines changed

14 files changed

+440
-380
lines changed

server/swimos_agent/src/agent_lifecycle/utility/downlink_builder/map.rs

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
use std::borrow::Borrow;
1616

17-
use std::collections::HashMap;
1817
use std::hash::Hash;
1918
use std::marker::PhantomData;
2019
use swimos_api::address::Address;
@@ -27,6 +26,7 @@ use crate::downlink_lifecycle::{
2726
OnFailed, OnFailedShared, OnSynced, OnSyncedShared, StatefulMapLifecycle, StatelessMapLifecycle,
2827
};
2928
use crate::lifecycle_fn::{WithHandlerContext, WithHandlerContextBorrow};
29+
use crate::map_storage::MapOpsWithEntry;
3030
use crate::{
3131
agent_model::downlink::{MapDownlinkHandle, OpenMapDownlinkAction},
3232
config::MapDownlinkConfig,
@@ -38,21 +38,24 @@ use crate::{
3838
event_handler::HandlerAction,
3939
};
4040

41+
type DlBuilderType<K, V, M, Context> = fn(Context) -> (K, V, M);
42+
4143
/// A builder for constructing a map downlink. Each lifecycle event handler is independent and, by
4244
/// default, they all do nothing.
4345
pub struct StatelessMapDownlinkBuilder<
4446
Context,
4547
K,
4648
V,
47-
LC = StatelessMapDownlinkLifecycle<Context, K, V>,
49+
M,
50+
LC = StatelessMapDownlinkLifecycle<Context, K, V, M>,
4851
> {
49-
_type: PhantomData<fn(Context) -> (K, V)>,
52+
_type: PhantomData<DlBuilderType<K, V, M, Context>>,
5053
address: Address<Text>,
5154
config: MapDownlinkConfig,
5255
inner: LC,
5356
}
5457

55-
impl<Context, K, V> StatelessMapDownlinkBuilder<Context, K, V> {
58+
impl<Context, K, V, M> StatelessMapDownlinkBuilder<Context, K, V, M> {
5659
pub fn new(address: Address<Text>, config: MapDownlinkConfig) -> Self {
5760
StatelessMapDownlinkBuilder {
5861
_type: PhantomData,
@@ -63,20 +66,20 @@ impl<Context, K, V> StatelessMapDownlinkBuilder<Context, K, V> {
6366
}
6467
}
6568

66-
type StatefulBuilderVar<Context, K, V, State> = (fn(Context, State) -> (K, V), State);
69+
type StatefulBuilderVar<Context, K, V, M, State> = (fn(Context, State) -> (K, V, M), State);
6770

6871
/// A builder for constructing a map downlink. The lifecycle event handlers share state and, by default,
6972
/// they all do nothing.
70-
pub struct StatefulMapDownlinkBuilder<Context, K, V, State, LC> {
71-
_type: PhantomData<StatefulBuilderVar<Context, K, V, State>>,
73+
pub struct StatefulMapDownlinkBuilder<Context, K, V, M, State, LC> {
74+
_type: PhantomData<StatefulBuilderVar<Context, K, V, M, State>>,
7275
address: Address<Text>,
7376
config: MapDownlinkConfig,
7477
inner: LC,
7578
}
7679

77-
impl<Context, K, V, LC> StatelessMapDownlinkBuilder<Context, K, V, LC>
80+
impl<Context, K, V, M, LC> StatelessMapDownlinkBuilder<Context, K, V, M, LC>
7881
where
79-
LC: StatelessMapLifecycle<Context, K, V>,
82+
LC: StatelessMapLifecycle<Context, K, V, M>,
8083
{
8184
/// Specify a handler for the `on_linked` event.
8285
///
@@ -85,7 +88,7 @@ where
8588
pub fn on_linked<F>(
8689
self,
8790
handler: F,
88-
) -> StatelessMapDownlinkBuilder<Context, K, V, LC::WithOnLinked<WithHandlerContext<F>>>
91+
) -> StatelessMapDownlinkBuilder<Context, K, V, M, LC::WithOnLinked<WithHandlerContext<F>>>
8992
where
9093
WithHandlerContext<F>: OnLinked<Context>,
9194
{
@@ -110,9 +113,9 @@ where
110113
pub fn on_synced<F>(
111114
self,
112115
handler: F,
113-
) -> StatelessMapDownlinkBuilder<Context, K, V, LC::WithOnSynced<WithHandlerContext<F>>>
116+
) -> StatelessMapDownlinkBuilder<Context, K, V, M, LC::WithOnSynced<WithHandlerContext<F>>>
114117
where
115-
WithHandlerContext<F>: OnSynced<HashMap<K, V>, Context>,
118+
WithHandlerContext<F>: OnSynced<M, Context>,
116119
{
117120
let StatelessMapDownlinkBuilder {
118121
address,
@@ -135,7 +138,7 @@ where
135138
pub fn on_unlinked<F>(
136139
self,
137140
handler: F,
138-
) -> StatelessMapDownlinkBuilder<Context, K, V, LC::WithOnUnlinked<WithHandlerContext<F>>>
141+
) -> StatelessMapDownlinkBuilder<Context, K, V, M, LC::WithOnUnlinked<WithHandlerContext<F>>>
139142
where
140143
WithHandlerContext<F>: OnUnlinked<Context>,
141144
{
@@ -160,7 +163,7 @@ where
160163
pub fn on_failed<F>(
161164
self,
162165
handler: F,
163-
) -> StatelessMapDownlinkBuilder<Context, K, V, LC::WithOnFailed<WithHandlerContext<F>>>
166+
) -> StatelessMapDownlinkBuilder<Context, K, V, M, LC::WithOnFailed<WithHandlerContext<F>>>
164167
where
165168
WithHandlerContext<F>: OnFailed<Context>,
166169
{
@@ -185,11 +188,17 @@ where
185188
pub fn on_update<F, B>(
186189
self,
187190
handler: F,
188-
) -> StatelessMapDownlinkBuilder<Context, K, V, LC::WithOnUpdate<WithHandlerContextBorrow<F, B>>>
191+
) -> StatelessMapDownlinkBuilder<
192+
Context,
193+
K,
194+
V,
195+
M,
196+
LC::WithOnUpdate<WithHandlerContextBorrow<F, B>>,
197+
>
189198
where
190199
B: ?Sized,
191200
V: Borrow<B>,
192-
WithHandlerContextBorrow<F, B>: OnDownlinkUpdate<K, V, Context>,
201+
WithHandlerContextBorrow<F, B>: OnDownlinkUpdate<K, V, M, Context>,
193202
{
194203
let StatelessMapDownlinkBuilder {
195204
address,
@@ -212,9 +221,9 @@ where
212221
pub fn on_remove<F>(
213222
self,
214223
handler: F,
215-
) -> StatelessMapDownlinkBuilder<Context, K, V, LC::WithOnRemove<WithHandlerContext<F>>>
224+
) -> StatelessMapDownlinkBuilder<Context, K, V, M, LC::WithOnRemove<WithHandlerContext<F>>>
216225
where
217-
WithHandlerContext<F>: OnDownlinkRemove<K, V, Context>,
226+
WithHandlerContext<F>: OnDownlinkRemove<K, V, M, Context>,
218227
{
219228
let StatelessMapDownlinkBuilder {
220229
address,
@@ -237,9 +246,9 @@ where
237246
pub fn on_clear<F>(
238247
self,
239248
handler: F,
240-
) -> StatelessMapDownlinkBuilder<Context, K, V, LC::WithOnClear<WithHandlerContext<F>>>
249+
) -> StatelessMapDownlinkBuilder<Context, K, V, M, LC::WithOnClear<WithHandlerContext<F>>>
241250
where
242-
WithHandlerContext<F>: OnDownlinkClear<K, V, Context>,
251+
WithHandlerContext<F>: OnDownlinkClear<M, Context>,
243252
{
244253
let StatelessMapDownlinkBuilder {
245254
address,
@@ -261,7 +270,7 @@ where
261270
pub fn with_state<State: Send>(
262271
self,
263272
state: State,
264-
) -> StatefulMapDownlinkBuilder<Context, K, V, State, LC::WithShared<State>> {
273+
) -> StatefulMapDownlinkBuilder<Context, K, V, M, State, LC::WithShared<State>> {
265274
let StatelessMapDownlinkBuilder {
266275
address,
267276
config,
@@ -277,14 +286,15 @@ where
277286
}
278287
}
279288

280-
impl<Context, K, V, LC> StatelessMapDownlinkBuilder<Context, K, V, LC>
289+
impl<Context, K, V, M, LC> StatelessMapDownlinkBuilder<Context, K, V, M, LC>
281290
where
282291
Context: AgentDescription + 'static,
283292
K: Form + Hash + Eq + Ord + Clone + Send + Sync + 'static,
284293
K::Rec: Send,
285294
V: Form + Send + Sync + 'static,
286295
V::Rec: Send,
287-
LC: StatelessMapLifecycle<Context, K, V> + 'static,
296+
M: Default + MapOpsWithEntry<K, V, K> + Send + 'static,
297+
LC: StatelessMapLifecycle<Context, K, V, M> + 'static,
288298
{
289299
/// Complete the downlink and create a [`HandlerAction`] that will open the downlink when it is
290300
/// executed.
@@ -301,9 +311,9 @@ where
301311
}
302312
}
303313

304-
impl<Context, K, V, State, LC> StatefulMapDownlinkBuilder<Context, K, V, State, LC>
314+
impl<Context, K, V, M, State, LC> StatefulMapDownlinkBuilder<Context, K, V, M, State, LC>
305315
where
306-
LC: StatefulMapLifecycle<Context, State, K, V> + 'static,
316+
LC: StatefulMapLifecycle<Context, State, K, V, M> + 'static,
307317
{
308318
/// Specify a handler for the `on_linked` event.
309319
///
@@ -312,7 +322,7 @@ where
312322
pub fn on_linked<F>(
313323
self,
314324
handler: F,
315-
) -> StatefulMapDownlinkBuilder<Context, K, V, State, LC::WithOnLinked<FnHandler<F>>>
325+
) -> StatefulMapDownlinkBuilder<Context, K, V, M, State, LC::WithOnLinked<FnHandler<F>>>
316326
where
317327
FnHandler<F>: OnLinkedShared<Context, State>,
318328
{
@@ -337,9 +347,9 @@ where
337347
pub fn on_synced<F>(
338348
self,
339349
handler: F,
340-
) -> StatefulMapDownlinkBuilder<Context, K, V, State, LC::WithOnSynced<FnHandler<F>>>
350+
) -> StatefulMapDownlinkBuilder<Context, K, V, M, State, LC::WithOnSynced<FnHandler<F>>>
341351
where
342-
FnHandler<F>: OnSyncedShared<HashMap<K, V>, Context, State>,
352+
FnHandler<F>: OnSyncedShared<M, Context, State>,
343353
{
344354
let StatefulMapDownlinkBuilder {
345355
address,
@@ -362,7 +372,7 @@ where
362372
pub fn on_unlinked<F>(
363373
self,
364374
handler: F,
365-
) -> StatefulMapDownlinkBuilder<Context, K, V, State, LC::WithOnUnlinked<FnHandler<F>>>
375+
) -> StatefulMapDownlinkBuilder<Context, K, V, M, State, LC::WithOnUnlinked<FnHandler<F>>>
366376
where
367377
FnHandler<F>: OnUnlinkedShared<Context, State>,
368378
{
@@ -387,7 +397,7 @@ where
387397
pub fn on_failed<F>(
388398
self,
389399
handler: F,
390-
) -> StatefulMapDownlinkBuilder<Context, K, V, State, LC::WithOnFailed<FnHandler<F>>>
400+
) -> StatefulMapDownlinkBuilder<Context, K, V, M, State, LC::WithOnFailed<FnHandler<F>>>
391401
where
392402
FnHandler<F>: OnFailedShared<Context, State>,
393403
{
@@ -409,14 +419,15 @@ where
409419
///
410420
/// # Arguments
411421
/// * `handler` - The event handler.
422+
#[allow(clippy::type_complexity)]
412423
pub fn on_update<F, B>(
413424
self,
414425
handler: F,
415-
) -> StatefulMapDownlinkBuilder<Context, K, V, State, LC::WithOnUpdate<BorrowHandler<F, B>>>
426+
) -> StatefulMapDownlinkBuilder<Context, K, V, M, State, LC::WithOnUpdate<BorrowHandler<F, B>>>
416427
where
417428
B: ?Sized,
418429
V: Borrow<B>,
419-
BorrowHandler<F, B>: OnDownlinkUpdateShared<K, V, Context, State>,
430+
BorrowHandler<F, B>: OnDownlinkUpdateShared<K, V, M, Context, State>,
420431
{
421432
let StatefulMapDownlinkBuilder {
422433
address,
@@ -439,9 +450,9 @@ where
439450
pub fn on_remove<F>(
440451
self,
441452
handler: F,
442-
) -> StatefulMapDownlinkBuilder<Context, K, V, State, LC::WithOnRemove<FnHandler<F>>>
453+
) -> StatefulMapDownlinkBuilder<Context, K, V, M, State, LC::WithOnRemove<FnHandler<F>>>
443454
where
444-
FnHandler<F>: OnDownlinkRemoveShared<K, V, Context, State>,
455+
FnHandler<F>: OnDownlinkRemoveShared<K, V, M, Context, State>,
445456
{
446457
let StatefulMapDownlinkBuilder {
447458
address,
@@ -464,9 +475,9 @@ where
464475
pub fn on_clear<F>(
465476
self,
466477
handler: F,
467-
) -> StatefulMapDownlinkBuilder<Context, K, V, State, LC::WithOnClear<FnHandler<F>>>
478+
) -> StatefulMapDownlinkBuilder<Context, K, V, M, State, LC::WithOnClear<FnHandler<F>>>
468479
where
469-
FnHandler<F>: OnDownlinkClearShared<K, V, Context, State>,
480+
FnHandler<F>: OnDownlinkClearShared<M, Context, State>,
470481
{
471482
let StatefulMapDownlinkBuilder {
472483
address,
@@ -483,15 +494,16 @@ where
483494
}
484495
}
485496

486-
impl<Context, K, V, State, LC> StatefulMapDownlinkBuilder<Context, K, V, State, LC>
497+
impl<Context, K, V, M, State, LC> StatefulMapDownlinkBuilder<Context, K, V, M, State, LC>
487498
where
488499
Context: AgentDescription + 'static,
489500
K: Form + Hash + Eq + Ord + Clone + Send + Sync + 'static,
490501
K::Rec: Send,
491502
V: Form + Send + Sync + 'static,
492503
V::Rec: Send,
504+
M: Default + MapOpsWithEntry<K, V, K> + Send + 'static,
493505
State: Send + 'static,
494-
LC: StatefulMapLifecycle<Context, State, K, V> + 'static,
506+
LC: StatefulMapLifecycle<Context, State, K, V, M> + 'static,
495507
{
496508
/// Complete the downlink and create a [`HandlerAction`] that will open the downlink when it is
497509
/// executed.

server/swimos_agent/src/agent_lifecycle/utility/mod.rs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ use crate::lanes::join_map::JoinMapAddDownlink;
5858
use crate::lanes::join_value::{JoinValueAddDownlink, JoinValueLane};
5959
use crate::lanes::supply::{Supply, SupplyLane};
6060
use crate::lanes::{DemandMapLane, JoinMapLane, OpenLane};
61+
use crate::map_storage::MapOpsWithEntry;
6162

6263
pub use self::downlink_builder::event::{
6364
StatefulEventDownlinkBuilder, StatelessEventDownlinkBuilder,
@@ -472,7 +473,7 @@ impl<Agent: AgentDescription + 'static> HandlerContext<Agent> {
472473
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'static
473474
where
474475
L: Any + Clone + Eq + Hash + Send + 'static,
475-
K: Any + Form + Clone + Eq + Hash + Send + Ord + 'static,
476+
K: Any + Form + Clone + Eq + Hash + Ord + Send + 'static,
476477
V: Form + Send + 'static,
477478
K::Rec: Send,
478479
V::BodyRec: Send,
@@ -793,7 +794,7 @@ impl<Agent: 'static> HandlerContext<Agent> {
793794
/// * `lane` - The lane to downlink from.
794795
/// * `config` - Configuration parameters for the downlink.
795796
/// * `lifecycle` - Lifecycle events for the downlink.
796-
pub fn open_map_downlink<K, V, LC>(
797+
pub fn open_map_downlink<K, V, M, LC>(
797798
&self,
798799
host: Option<&str>,
799800
node: &str,
@@ -802,9 +803,10 @@ impl<Agent: 'static> HandlerContext<Agent> {
802803
config: MapDownlinkConfig,
803804
) -> impl HandlerAction<Agent, Completion = MapDownlinkHandle<K, V>> + Send + 'static
804805
where
805-
K: Form + Hash + Eq + Ord + Clone + Send + Sync + 'static,
806+
K: Form + Hash + Eq + Clone + Send + Sync + 'static,
806807
V: Form + Send + Sync + 'static,
807-
LC: MapDownlinkLifecycle<K, V, Agent> + Send + 'static,
808+
M: Default + MapOpsWithEntry<K, V, K> + Send + 'static,
809+
LC: MapDownlinkLifecycle<K, V, M, Agent> + Send + 'static,
808810
K::Rec: Send,
809811
V::Rec: Send,
810812
{
@@ -885,9 +887,33 @@ impl<Agent: 'static> HandlerContext<Agent> {
885887
node: &str,
886888
lane: &str,
887889
config: MapDownlinkConfig,
888-
) -> StatelessMapDownlinkBuilder<Agent, K, V>
890+
) -> StatelessMapDownlinkBuilder<Agent, K, V, HashMap<K, V>>
889891
where
890-
K: Form + Hash + Eq + Ord + Clone + Send + Sync + 'static,
892+
K: Form + Hash + Eq + Clone + Send + Sync + 'static,
893+
K::Rec: Send,
894+
V: Form + Send + Sync + 'static,
895+
V::Rec: Send,
896+
{
897+
StatelessMapDownlinkBuilder::new(Address::text(host, node, lane), config)
898+
}
899+
900+
/// Create a builder to construct a request to open a map downlink, using the specified map type
901+
/// as the backing representation of the downlink.
902+
/// # Arguments
903+
/// * `host` - The remote host at which the agent resides (a local agent if not specified).
904+
/// * `node` - The node URI of the agent.
905+
/// * `lane` - The lane to downlink from.
906+
/// * `config` - Configuration parameters for the downlink.
907+
pub fn map_downlink_builder_for<K, V, M>(
908+
&self,
909+
host: Option<&str>,
910+
node: &str,
911+
lane: &str,
912+
config: MapDownlinkConfig,
913+
) -> StatelessMapDownlinkBuilder<Agent, K, V, M>
914+
where
915+
M: MapOpsWithEntry<K, V, K>,
916+
K: Form + Hash + Eq + Clone + Send + Sync + 'static,
891917
K::Rec: Send,
892918
V: Form + Send + Sync + 'static,
893919
V::Rec: Send,
@@ -1048,7 +1074,7 @@ impl<Agent, L, K, V> JoinMapContext<Agent, L, K, V>
10481074
where
10491075
Agent: 'static,
10501076
L: Any + Clone + Eq + Hash + Send + 'static,
1051-
K: Any + Form + Clone + Eq + Hash + Ord + Send + 'static,
1077+
K: Any + Form + Clone + Eq + Hash + Send + 'static,
10521078
V: Form + Send + 'static,
10531079
K::Rec: Send,
10541080
V::BodyRec: Send,

0 commit comments

Comments
 (0)