Skip to content

Commit 4e0981d

Browse files
Merge pull request #620 from swimos/with-value
Improves combinators that inspect/transform the contents of lanes.
2 parents 5333365 + 005eda0 commit 4e0981d

File tree

16 files changed

+1091
-208
lines changed

16 files changed

+1091
-208
lines changed

example_apps/tutorial_app/src/unit_agent.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@ fn update_histogram(
153153
item: HistoryItem,
154154
) -> impl EventHandler<UnitAgent> {
155155
let bucket = bucket_of(&item.timestamp);
156-
context.with_entry(UnitAgent::HISTOGRAM, bucket, |maybe| {
157-
let mut counter = maybe.unwrap_or_default();
156+
context.transform_entry(UnitAgent::HISTOGRAM, bucket, |maybe| {
157+
let mut counter = maybe.copied().unwrap_or_default();
158158
counter.count += rand::thread_rng().gen_range(0..20);
159159
Some(counter)
160160
})

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

Lines changed: 113 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
use std::any::Any;
16+
use std::borrow::Borrow;
1617
use std::fmt::Debug;
1718
use std::hash::Hash;
1819
use std::time::Duration;
@@ -41,7 +42,7 @@ use crate::event_handler::{
4142
};
4243
use crate::event_handler::{GetAgentUri, HandlerAction, SideEffect};
4344
use crate::item::{
44-
JoinLikeItem, MapLikeItem, MutableMapLikeItem, MutableValueLikeItem, TransformableMapLikeItem,
45+
InspectableMapLikeItem, JoinLikeItem, MapLikeItem, MutableMapLikeItem, MutableValueLikeItem,
4546
ValueLikeItem,
4647
};
4748
use crate::lanes::command::{CommandLane, DoCommand};
@@ -157,45 +158,86 @@ impl<Agent: 'static> HandlerContext<Agent> {
157158

158159
/// Create an event handler that will get the value of a value lane store of the agent.
159160
///
160-
/// # Arguments
161-
/// * `lane` - Projection to the value lane.
161+
/// #Arguments
162+
/// * `item` - Projection to the value lane or store.
162163
pub fn get_value<Item, T>(
163164
&self,
164-
lane: fn(&Agent) -> &Item,
165+
item: fn(&Agent) -> &Item,
165166
) -> impl HandlerAction<Agent, Completion = T> + Send + 'static
166167
where
167168
Item: ValueLikeItem<T>,
168169
T: Clone + Send + 'static,
169170
{
170-
Item::get_handler::<Agent>(lane)
171+
Item::get_handler::<Agent>(item)
171172
}
172173

173-
/// Create an event handler that will set a new value into value lane or store of the agent.
174+
/// Create an event handler that will set a new value into a value lane or store of the agent.
174175
///
175-
/// # Arguments
176-
/// * `lane` - Projection to the value lane.
176+
/// #Arguments
177+
/// * `item` - Projection to the value lane or store.
177178
/// * `value` - The value to set.
178179
pub fn set_value<Item, T>(
179180
&self,
180-
lane: fn(&Agent) -> &Item,
181+
item: fn(&Agent) -> &Item,
181182
value: T,
182183
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'static
183184
where
184185
Item: MutableValueLikeItem<T>,
185186
T: Send + 'static,
186187
{
187-
Item::set_handler::<Agent>(lane, value)
188+
Item::set_handler::<Agent>(item, value)
189+
}
190+
191+
/// Create an event handler that will transform the value of a value lane or store of the agent.
192+
///
193+
/// #Arguments
194+
/// * `item` - Projection to the value lane or store.
195+
/// * `f` - A closure that produces a new value from a reference to the existing value.
196+
pub fn transform_value<'a, Item, T, F>(
197+
&self,
198+
item: fn(&Agent) -> &Item,
199+
f: F,
200+
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'a
201+
where
202+
Agent: 'static,
203+
Item: ValueLikeItem<T> + MutableValueLikeItem<T> + 'static,
204+
T: 'static,
205+
F: FnOnce(&T) -> T + Send + 'a,
206+
{
207+
Item::with_value_handler::<Item, Agent, F, T, T>(item, f)
208+
.and_then(move |v| Item::set_handler(item, v))
209+
}
210+
211+
/// Create an event handler that will inspect the value of a value lane or store and generate a result from it.
212+
/// This differs from using [`Self::get_value`] in that it does not require a clone to be made of the existing value.
213+
///
214+
/// #Arguments
215+
/// * `item` - Projection to the value lane or store.
216+
/// * `f` - A closure that produces a value from a reference to the current value of the item.
217+
pub fn with_value<'a, Item, T, F, B, U>(
218+
&self,
219+
item: fn(&Agent) -> &Item,
220+
f: F,
221+
) -> impl HandlerAction<Agent, Completion = U> + Send + 'a
222+
where
223+
Agent: 'static,
224+
Item: ValueLikeItem<T> + 'static,
225+
T: Borrow<B>,
226+
B: 'static,
227+
F: FnOnce(&B) -> U + Send + 'a,
228+
{
229+
Item::with_value_handler::<Item, Agent, F, B, U>(item, f)
188230
}
189231

190232
/// Create an event handler that will update an entry in a map lane or store of the agent.
191233
///
192-
/// # Arguments
193-
/// * `lane` - Projection to the map lane.
234+
/// #Arguments
235+
/// * `item` - Projection to the map lane or store.
194236
/// * `key - The key to update.
195237
/// * `value` - The new value.
196238
pub fn update<Item, K, V>(
197239
&self,
198-
lane: fn(&Agent) -> &Item,
240+
item: fn(&Agent) -> &Item,
199241
key: K,
200242
value: V,
201243
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'static
@@ -204,73 +246,100 @@ impl<Agent: 'static> HandlerContext<Agent> {
204246
K: Send + Clone + Eq + Hash + 'static,
205247
V: Send + 'static,
206248
{
207-
Item::update_handler::<Agent>(lane, key, value)
249+
Item::update_handler::<Agent>(item, key, value)
208250
}
209251

210-
/// Create an event handler that will transform the value in an entry of a map lane or store of the agent.
252+
/// Create an event handler that will inspect an entry in the map and produce a new value from it.
253+
/// This differs from using [`Self::get_entry`] in that it does not require that a clone be made of the existing value.
211254
///
212-
/// # Arguments
213-
/// * `lane` - Projection to the map lane.
255+
/// #Arguments
256+
/// * `item` - Projection to the map lane or store.
214257
/// * `key - The key to update.
215258
/// * `f` - A function to apple to the entry in the map.
216-
pub fn with_entry<'a, Item, K, V, F>(
259+
pub fn with_entry<'a, Item, K, V, F, B, U>(
217260
&self,
218-
lane: fn(&Agent) -> &Item,
261+
item: fn(&Agent) -> &Item,
262+
key: K,
263+
f: F,
264+
) -> impl HandlerAction<Agent, Completion = U> + Send + 'a
265+
where
266+
Agent: 'static,
267+
Item: InspectableMapLikeItem<K, V> + 'static,
268+
K: Send + Clone + Eq + Hash + 'static,
269+
V: Borrow<B> + 'static,
270+
B: ?Sized + 'static,
271+
F: FnOnce(Option<&B>) -> U + Send + 'a,
272+
{
273+
Item::with_entry_handler::<Agent, F, B, U>(item, key, f)
274+
}
275+
276+
/// Create an event handler that will transform the value in an entry of a map lane or store of the agent.
277+
/// If the map contains an entry with that key, it will be updated (or removed) based on the result of the calling
278+
/// the closure on it. If the map does not contain an entry with that key, the closure will be called with [`None`]
279+
/// and an entry will be inserted if it returns a value.
280+
///
281+
/// #Arguments
282+
/// * `item` - Projection to the map lane.
283+
/// * `key - The key to update.
284+
/// * `f` - A closure to apply to the entry in the map to produce the replacement.
285+
pub fn transform_entry<'a, Item, K, V, F>(
286+
&self,
287+
item: fn(&Agent) -> &Item,
219288
key: K,
220289
f: F,
221290
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'a
222291
where
223292
Agent: 'static,
224-
Item: TransformableMapLikeItem<K, V> + 'static,
293+
Item: MutableMapLikeItem<K, V> + 'static,
225294
K: Send + Clone + Eq + Hash + 'static,
226-
V: Clone + 'static,
227-
F: FnOnce(Option<V>) -> Option<V> + Send + 'a,
295+
V: 'static,
296+
F: FnOnce(Option<&V>) -> Option<V> + Send + 'a,
228297
{
229-
Item::with_handler::<Agent, F>(lane, key, f)
298+
Item::transform_entry_handler::<Agent, F>(item, key, f)
230299
}
231300

232301
/// Create an event handler that will remove an entry from a map lane or store of the agent.
233302
///
234-
/// # Arguments
235-
/// * `lane` - Projection to the map lane.
303+
/// #Arguments
304+
/// * `item` - Projection to the map lane or store.
236305
/// * `key - The key to remove.
237306
pub fn remove<Item, K, V>(
238307
&self,
239-
lane: fn(&Agent) -> &Item,
308+
item: fn(&Agent) -> &Item,
240309
key: K,
241310
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'static
242311
where
243312
Item: MutableMapLikeItem<K, V>,
244313
K: Send + Clone + Eq + Hash + 'static,
245314
V: Send + 'static,
246315
{
247-
Item::remove_handler::<Agent>(lane, key)
316+
Item::remove_handler::<Agent>(item, key)
248317
}
249318

250319
/// Create an event handler that will clear a map lane or store of the agent.
251320
///
252-
/// # Arguments
253-
/// * `lane` - Projection to the map lane.
321+
/// #Arguments
322+
/// * `item` - Projection to the map lane or store.
254323
pub fn clear<Item, K, V>(
255324
&self,
256-
lane: fn(&Agent) -> &Item,
325+
item: fn(&Agent) -> &Item,
257326
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'static
258327
where
259328
Item: MutableMapLikeItem<K, V>,
260329
K: Send + Clone + Eq + Hash + 'static,
261330
V: Send + 'static,
262331
{
263-
Item::clear_handler::<Agent>(lane)
332+
Item::clear_handler::<Agent>(item)
264333
}
265334

266335
/// Create an event handler that replaces the entire contents of a map lane or store.
267336
///
268-
/// # Arguments
269-
/// * `lane` - Projection to the map lane.
337+
/// #Arguments
338+
/// * `item` - Projection to the map lane or store.
270339
/// * `entries` - The new entries for the lane.
271340
pub fn replace_map<Item, K, V, I>(
272341
&self,
273-
lane: fn(&Agent) -> &Item,
342+
item: fn(&Agent) -> &Item,
274343
entries: I,
275344
) -> impl HandlerAction<Agent, Completion = ()> + Send + 'static
276345
where
@@ -283,44 +352,44 @@ impl<Agent: 'static> HandlerContext<Agent> {
283352
let context = *self;
284353
let insertions = entries
285354
.into_iter()
286-
.map(move |(k, v)| context.update(lane, k, v));
287-
self.clear(lane).followed_by(Sequentially::new(insertions))
355+
.map(move |(k, v)| context.update(item, k, v));
356+
self.clear(item).followed_by(Sequentially::new(insertions))
288357
}
289358

290359
/// Create an event handler that will attempt to get an entry from a map-like item of the agent.
291360
/// This includes map lanes and stores and join lanes.
292361
///
293-
/// # Arguments
294-
/// * `lane` - Projection to the map lane.
362+
/// #Arguments
363+
/// * `item` - Projection to the map-like item.
295364
/// * `key - The key to fetch.
296365
pub fn get_entry<Item, K, V>(
297366
&self,
298-
lane: fn(&Agent) -> &Item,
367+
item: fn(&Agent) -> &Item,
299368
key: K,
300369
) -> impl HandlerAction<Agent, Completion = Option<V>> + Send + 'static
301370
where
302371
Item: MapLikeItem<K, V>,
303372
K: Send + Clone + Eq + Hash + 'static,
304373
V: Send + Clone + 'static,
305374
{
306-
Item::get_handler::<Agent>(lane, key)
375+
Item::get_handler::<Agent>(item, key)
307376
}
308377

309378
/// Create an event handler that will attempt to get the entire contents of a map-like item of the
310379
/// agent. This includes map lanes and stores and join lanes.
311380
///
312-
/// # Arguments
313-
/// * `lane` - Projection to the map lane.
381+
/// #Arguments
382+
/// * `item` - Projection to the map-like item.
314383
pub fn get_map<Item, K, V>(
315384
&self,
316-
lane: fn(&Agent) -> &Item,
385+
item: fn(&Agent) -> &Item,
317386
) -> impl HandlerAction<Agent, Completion = HashMap<K, V>> + Send + 'static
318387
where
319388
Item: MapLikeItem<K, V>,
320389
K: Send + Clone + Eq + Hash + 'static,
321390
V: Send + Clone + 'static,
322391
{
323-
Item::get_map_handler::<Agent>(lane)
392+
Item::get_map_handler::<Agent>(item)
324393
}
325394

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

0 commit comments

Comments
 (0)