Skip to content

Commit 9ac881e

Browse files
committed
Added with_entry combinator for JoinValueLane.
1 parent 5d59e84 commit 9ac881e

File tree

6 files changed

+222
-68
lines changed

6 files changed

+222
-68
lines changed

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

Lines changed: 75 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use crate::event_handler::{
4444
};
4545
use crate::event_handler::{GetAgentUri, HandlerAction, SideEffect};
4646
use crate::item::{
47-
MapLikeItem, MutableMapLikeItem, MutableValueLikeItem, ValueLikeItem
47+
InspectableMapLikeItem, MapLikeItem, MutableMapLikeItem, MutableValueLikeItem, ValueLikeItem
4848
};
4949
use crate::lanes::command::{CommandLane, DoCommand};
5050
use crate::lanes::demand::{Cue, DemandLane};
@@ -156,38 +156,43 @@ impl<Agent: 'static> HandlerContext<Agent> {
156156
/// Create an event handler that will get the value of a value lane store of the agent.
157157
///
158158
/// #Arguments
159-
/// * `lane` - Projection to the value lane.
159+
/// * `item` - Projection to the value lane or store.
160160
pub fn get_value<Item, T>(
161161
&self,
162-
lane: fn(&Agent) -> &Item,
162+
item: fn(&Agent) -> &Item,
163163
) -> impl HandlerAction<Agent, Completion = T> + Send + 'static
164164
where
165165
Item: ValueLikeItem<T>,
166166
T: Clone + Send + 'static,
167167
{
168-
Item::get_handler::<Agent>(lane)
168+
Item::get_handler::<Agent>(item)
169169
}
170170

171-
/// Create an event handler that will set a new value into value lane or store of the agent.
171+
/// Create an event handler that will set a new value into a value lane or store of the agent.
172172
///
173173
/// #Arguments
174-
/// * `lane` - Projection to the value lane.
174+
/// * `item` - Projection to the value lane or store.
175175
/// * `value` - The value to set.
176176
pub fn set_value<Item, T>(
177177
&self,
178-
lane: fn(&Agent) -> &Item,
178+
item: fn(&Agent) -> &Item,
179179
value: T,
180180
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'static
181181
where
182182
Item: MutableValueLikeItem<T>,
183183
T: Send + 'static,
184184
{
185-
Item::set_handler::<Agent>(lane, value)
185+
Item::set_handler::<Agent>(item, value)
186186
}
187187

188+
/// Create an event handler that will transform the value of a value lane or store of the agent.
189+
///
190+
/// #Arguments
191+
/// * `item` - Projection to the value lane or store.
192+
/// * `f` - A closure that produces a new value from a reference to the existing value.
188193
pub fn transform_value<'a, Item, T, F>(
189194
&self,
190-
projection: fn(&Agent) -> &Item,
195+
item: fn(&Agent) -> &Item,
191196
f: F,
192197
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'a
193198
where
@@ -196,13 +201,19 @@ impl<Agent: 'static> HandlerContext<Agent> {
196201
T: 'static,
197202
F: FnOnce(&T) -> T + Send + 'a,
198203
{
199-
Item::with_value_handler::<Item, Agent, F, T, T>(projection, f)
200-
.and_then(move |v| Item::set_handler(projection, v))
204+
Item::with_value_handler::<Item, Agent, F, T, T>(item, f)
205+
.and_then(move |v| Item::set_handler(item, v))
201206
}
202207

208+
/// Create an event handler that will inspect the value of a value lane or store and generate a result from it.
209+
/// This differs from using [`Self::get_value`] in that it does not require a clone to be made of the existing value.
210+
///
211+
/// #Arguments
212+
/// * `item` - Projection to the value lane or store.
213+
/// * `f` - A closure that produces a value from a reference to the current value of the item.
203214
pub fn with_value<'a, Item, T, F, B, U>(
204215
&self,
205-
projection: fn(&Agent) -> &Item,
216+
item: fn(&Agent) -> &Item,
206217
f: F,
207218
) -> impl HandlerAction<Agent, Completion = U> + Send + 'a
208219
where
@@ -212,18 +223,18 @@ impl<Agent: 'static> HandlerContext<Agent> {
212223
B: 'static,
213224
F: FnOnce(&B) -> U + Send + 'a,
214225
{
215-
Item::with_value_handler::<Item, Agent, F, B, U>(projection, f)
226+
Item::with_value_handler::<Item, Agent, F, B, U>(item, f)
216227
}
217228

218229
/// Create an event handler that will update an entry in a map lane or store of the agent.
219230
///
220231
/// #Arguments
221-
/// * `lane` - Projection to the map lane.
232+
/// * `item` - Projection to the map lane or store.
222233
/// * `key - The key to update.
223234
/// * `value` - The new value.
224235
pub fn update<Item, K, V>(
225236
&self,
226-
lane: fn(&Agent) -> &Item,
237+
item: fn(&Agent) -> &Item,
227238
key: K,
228239
value: V,
229240
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'static
@@ -232,18 +243,46 @@ impl<Agent: 'static> HandlerContext<Agent> {
232243
K: Send + Clone + Eq + Hash + 'static,
233244
V: Send + 'static,
234245
{
235-
Item::update_handler::<Agent>(lane, key, value)
246+
Item::update_handler::<Agent>(item, key, value)
236247
}
237248

238-
/// Create an event handler that will transform the value in an entry of a map lane or store of the agent.
249+
/// Create an event handler that will inspect an entry in the map and produce a new value from it.
250+
/// This differs from using [`Self::get_entry`] in that it does not require that a clone be made of the existing value.
239251
///
240252
/// #Arguments
241-
/// * `lane` - Projection to the map lane.
253+
/// * `item` - Projection to the map lane or store.
242254
/// * `key - The key to update.
243255
/// * `f` - A function to apple to the entry in the map.
256+
pub fn with_entry<'a, Item, K, V, F, B, U>(
257+
&self,
258+
item: fn(&Agent) -> &Item,
259+
key: K,
260+
f: F
261+
) -> impl HandlerAction<Agent, Completion = U> + Send + 'a
262+
where
263+
Agent: 'static,
264+
Item: InspectableMapLikeItem<K, V> + 'static,
265+
K: Send + Clone + Eq + Hash + 'static,
266+
V: Borrow<B> + 'static,
267+
B: ?Sized + 'static,
268+
F: FnOnce(Option<&B>) -> U + Send + 'a,
269+
{
270+
Item::with_entry_handler::<Agent, F, B, U>(item, key, f)
271+
}
272+
273+
274+
/// Create an event handler that will transform the value in an entry of a map lane or store of the agent.
275+
/// If map contains an entry with that key, it will be updated (or removed) based on the result of the calling
276+
/// the closure on it. If the map does not contain an entry with that key, the closure will be called with [`None`]
277+
/// and an entry will be inserted if it returns a value.
278+
///
279+
/// #Arguments
280+
/// * `item` - Projection to the map lane.
281+
/// * `key - The key to update.
282+
/// * `f` - A closure to apply to the entry in the map to produce the replacement.
244283
pub fn transform_entry<'a, Item, K, V, F>(
245284
&self,
246-
lane: fn(&Agent) -> &Item,
285+
item: fn(&Agent) -> &Item,
247286
key: K,
248287
f: F,
249288
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'a
@@ -254,51 +293,51 @@ impl<Agent: 'static> HandlerContext<Agent> {
254293
V: 'static,
255294
F: FnOnce(Option<&V>) -> Option<V> + Send + 'a,
256295
{
257-
Item::transform_entry_handler::<Agent, F>(lane, key, f)
296+
Item::transform_entry_handler::<Agent, F>(item, key, f)
258297
}
259298

260299
/// Create an event handler that will remove an entry from a map lane or store of the agent.
261300
///
262301
/// #Arguments
263-
/// * `lane` - Projection to the map lane.
302+
/// * `item` - Projection to the map lane or store.
264303
/// * `key - The key to remove.
265304
pub fn remove<Item, K, V>(
266305
&self,
267-
lane: fn(&Agent) -> &Item,
306+
item: fn(&Agent) -> &Item,
268307
key: K,
269308
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'static
270309
where
271310
Item: MutableMapLikeItem<K, V>,
272311
K: Send + Clone + Eq + Hash + 'static,
273312
V: Send + 'static,
274313
{
275-
Item::remove_handler::<Agent>(lane, key)
314+
Item::remove_handler::<Agent>(item, key)
276315
}
277316

278317
/// Create an event handler that will clear a map lane or store of the agent.
279318
///
280319
/// #Arguments
281-
/// * `lane` - Projection to the map lane.
320+
/// * `item` - Projection to the map lane or store.
282321
pub fn clear<Item, K, V>(
283322
&self,
284-
lane: fn(&Agent) -> &Item,
323+
item: fn(&Agent) -> &Item,
285324
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'static
286325
where
287326
Item: MutableMapLikeItem<K, V>,
288327
K: Send + Clone + Eq + Hash + 'static,
289328
V: Send + 'static,
290329
{
291-
Item::clear_handler::<Agent>(lane)
330+
Item::clear_handler::<Agent>(item)
292331
}
293332

294333
/// Create an event handler that replaces the entire contents of a map lane or store.
295334
///
296335
/// #Arguments
297-
/// * `lane` - Projection to the map lane.
336+
/// * `item` - Projection to the map lane or store.
298337
/// * `entries` - The new entries for the lane.
299338
pub fn replace_map<Item, K, V, I>(
300339
&self,
301-
lane: fn(&Agent) -> &Item,
340+
item: fn(&Agent) -> &Item,
302341
entries: I,
303342
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'static
304343
where
@@ -311,44 +350,44 @@ impl<Agent: 'static> HandlerContext<Agent> {
311350
let context = *self;
312351
let insertions = entries
313352
.into_iter()
314-
.map(move |(k, v)| context.update(lane, k, v));
315-
self.clear(lane).followed_by(Sequentially::new(insertions))
353+
.map(move |(k, v)| context.update(item, k, v));
354+
self.clear(item).followed_by(Sequentially::new(insertions))
316355
}
317356

318357
/// Create an event handler that will attempt to get an entry from a map-like item of the agent.
319358
/// This includes map lanes and stores and join lanes.
320359
///
321360
/// #Arguments
322-
/// * `lane` - Projection to the map lane.
361+
/// * `item` - Projection to the map-like item.
323362
/// * `key - The key to fetch.
324363
pub fn get_entry<Item, K, V>(
325364
&self,
326-
lane: fn(&Agent) -> &Item,
365+
item: fn(&Agent) -> &Item,
327366
key: K,
328367
) -> impl HandlerAction<Agent, Completion = Option<V>> + Send + 'static
329368
where
330369
Item: MapLikeItem<K, V>,
331370
K: Send + Clone + Eq + Hash + 'static,
332371
V: Send + Clone + 'static,
333372
{
334-
Item::get_handler::<Agent>(lane, key)
373+
Item::get_handler::<Agent>(item, key)
335374
}
336375

337376
/// Create an event handler that will attempt to get the entire contents of a map-like item of the
338377
/// agent. This includes map lanes and stores and join lanes.
339378
///
340379
/// #Arguments
341-
/// * `lane` - Projection to the map lane.
380+
/// * `item` - Projection to the map-like item.
342381
pub fn get_map<Item, K, V>(
343382
&self,
344-
lane: fn(&Agent) -> &Item,
383+
item: fn(&Agent) -> &Item,
345384
) -> impl HandlerAction<Agent, Completion = HashMap<K, V>> + Send + 'static
346385
where
347386
Item: MapLikeItem<K, V>,
348387
K: Send + Clone + Eq + Hash + 'static,
349388
V: Send + Clone + 'static,
350389
{
351-
Item::get_map_handler::<Agent>(lane)
390+
Item::get_map_handler::<Agent>(item)
352391
}
353392

354393
/// Create an event handler that will send a command to a command lane of the agent.

server/swimos_agent/src/lanes/join/value/mod.rs

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use std::any::{Any, TypeId};
1616
use std::borrow::Borrow;
1717
use std::collections::hash_map::Entry;
1818
use std::hash::Hash;
19+
use std::marker::PhantomData;
1920
use std::{cell::RefCell, collections::HashMap};
2021

2122
use bytes::BytesMut;
@@ -28,7 +29,7 @@ use uuid::Uuid;
2829
use crate::agent_model::downlink::OpenEventDownlinkAction;
2930
use crate::config::SimpleDownlinkConfig;
3031
use crate::event_handler::{EventHandler, EventHandlerError, Modification};
31-
use crate::item::MapLikeItem;
32+
use crate::item::{InspectableMapLikeItem, MapLikeItem};
3233
use crate::{
3334
agent_model::WriteResult,
3435
event_handler::{ActionContext, HandlerAction, StepResult},
@@ -427,6 +428,53 @@ impl<C, K, V> JoinValueAddDownlink<C, K, V> {
427428
}
428429
}
429430

431+
432+
pub struct JoinValueLaneWithEntry<C, K, V, F, B: ?Sized> {
433+
projection: for<'a> fn(&'a C) -> &'a JoinValueLane<K, V>,
434+
key: K,
435+
f: Option<F>,
436+
_type: PhantomData<fn(&B)>,
437+
}
438+
439+
impl<C, K, V, F, B: ?Sized> JoinValueLaneWithEntry<C, K, V, F, B> {
440+
441+
pub fn new(projection: for<'a> fn(&'a C) -> &'a JoinValueLane<K, V>,
442+
key: K, f: F) -> Self {
443+
JoinValueLaneWithEntry {
444+
projection,
445+
key,
446+
f: Some(f),
447+
_type: PhantomData,
448+
}
449+
}
450+
}
451+
452+
impl<'a, C, K, V, F, B, U> HandlerAction<C> for JoinValueLaneWithEntry<C, K, V, F, B>
453+
where
454+
K: Eq + Hash + 'static,
455+
C: 'a,
456+
B: ?Sized + 'static,
457+
V: Borrow<B>,
458+
F: FnOnce(Option<&B>) -> U + Send + 'a,
459+
{
460+
type Completion = U;
461+
462+
fn step(
463+
&mut self,
464+
_action_context: &mut ActionContext<C>,
465+
_meta: AgentMetadata,
466+
context: &C,
467+
) -> StepResult<Self::Completion> {
468+
if let Some(f) = self.f.take() {
469+
let item = (self.projection)(context);
470+
StepResult::done(item.inner.with_entry(&self.key, f))
471+
} else {
472+
StepResult::after_done()
473+
}
474+
}
475+
}
476+
477+
430478
impl<K, V> MapLikeItem<K, V> for JoinValueLane<K, V>
431479
where
432480
K: Clone + Eq + Hash + Send + 'static,
@@ -448,3 +496,31 @@ where
448496
JoinValueLaneGetMap::new(projection)
449497
}
450498
}
499+
500+
impl<K, V> InspectableMapLikeItem<K, V> for JoinValueLane<K, V>
501+
where
502+
K: Clone + Eq + Hash + Send + 'static,
503+
V: Send + 'static,
504+
{
505+
type WithEntryHandler<'a, C, F, B, U> = JoinValueLaneWithEntry<C, K, V, F, B>
506+
where
507+
Self: 'static,
508+
C: 'a,
509+
B: ?Sized + 'static,
510+
V: Borrow<B>,
511+
F: FnOnce(Option<&B>) -> U + Send + 'a;
512+
513+
fn with_entry_handler<'a, C, F, B, U>(
514+
projection: fn(&C) -> &Self,
515+
key: K,
516+
f: F,
517+
) -> Self::WithEntryHandler<'a, C, F, B, U>
518+
where
519+
Self: 'static,
520+
C: 'a,
521+
B: ?Sized + 'static,
522+
V: Borrow<B>,
523+
F: FnOnce(Option<&B>) -> U + Send + 'a {
524+
JoinValueLaneWithEntry::new(projection, key, f)
525+
}
526+
}

0 commit comments

Comments
 (0)