Skip to content

Commit

Permalink
Merge pull request #739 from swimos/flexible-maps
Browse files Browse the repository at this point in the history
Abstracts `MapStore` and `MapLane` over the underlying map implementation.
  • Loading branch information
SirCipher authored Dec 10, 2024
2 parents 22693a8 + 650a0c8 commit c21a7ea
Show file tree
Hide file tree
Showing 29 changed files with 1,287 additions and 684 deletions.
101 changes: 49 additions & 52 deletions server/swimos_agent/src/agent_lifecycle/item_event/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::cmp::Ordering;
use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
use std::{cmp::Ordering, collections::HashMap};

use frunk::{Coprod, Coproduct};
use futures::future::Either;
Expand All @@ -30,58 +30,52 @@ use crate::lanes::map::{
on_update::{OnUpdate, OnUpdateShared},
MapLaneLifecycle,
},
MapLane, MapLaneEvent,
MapLaneEvent,
};
use crate::stores::MapStore;
use crate::map_storage::MapOpsWithEntry;

use super::{HLeaf, HTree, ItemEvent, ItemEventShared};

#[cfg(test)]
mod tests;

pub type MapLeaf<Context, K, V, LC> = MapBranch<Context, K, V, LC, HLeaf, HLeaf>;
pub type MapBranch<Context, K, V, LC, L, R> = MapLikeBranch<Context, K, V, MapLane<K, V>, LC, L, R>;

pub type MapStoreLeaf<Context, K, V, LC> = MapStoreBranch<Context, K, V, LC, HLeaf, HLeaf>;
pub type MapStoreBranch<Context, K, V, LC, L, R> =
MapLikeBranch<Context, K, V, MapStore<K, V>, LC, L, R>;

pub type MapLifecycleHandler<'a, Context, K, V, LC> = Coprod!(
<LC as OnUpdate<K, V, Context>>::OnUpdateHandler<'a>,
<LC as OnRemove<K, V, Context>>::OnRemoveHandler<'a>,
<LC as OnClear<K, V, Context>>::OnClearHandler<'a>,
pub type MapLifecycleHandler<'a, Context, K, V, M, LC> = Coprod!(
<LC as OnUpdate<K, V, M, Context>>::OnUpdateHandler<'a>,
<LC as OnRemove<K, V, M, Context>>::OnRemoveHandler<'a>,
<LC as OnClear<M, Context>>::OnClearHandler<'a>,
);

pub type MapLifecycleHandlerShared<'a, Context, Shared, K, V, LC> = Coprod!(
<LC as OnUpdateShared<K, V, Context, Shared>>::OnUpdateHandler<'a>,
<LC as OnRemoveShared<K, V, Context, Shared>>::OnRemoveHandler<'a>,
<LC as OnClearShared<K, V, Context, Shared>>::OnClearHandler<'a>,
pub type MapLifecycleHandlerShared<'a, Context, Shared, K, V, M, LC> = Coprod!(
<LC as OnUpdateShared<K, V, M, Context, Shared>>::OnUpdateHandler<'a>,
<LC as OnRemoveShared<K, V, M, Context, Shared>>::OnRemoveHandler<'a>,
<LC as OnClearShared<M, Context, Shared>>::OnClearHandler<'a>,
);

type MapBranchHandler<'a, Context, K, V, LC, L, R> = Either<
type MapBranchHandler<'a, Context, K, V, M, LC, L, R> = Either<
<L as ItemEvent<Context>>::ItemEventHandler<'a>,
Either<
MapLifecycleHandler<'a, Context, K, V, LC>,
MapLifecycleHandler<'a, Context, K, V, M, LC>,
<R as ItemEvent<Context>>::ItemEventHandler<'a>,
>,
>;

type MapBranchHandlerShared<'a, Context, Shared, K, V, LC, L, R> = Either<
type MapBranchHandlerShared<'a, Context, Shared, K, V, M, LC, L, R> = Either<
<L as ItemEventShared<Context, Shared>>::ItemEventHandler<'a>,
Either<
MapLifecycleHandlerShared<'a, Context, Shared, K, V, LC>,
MapLifecycleHandlerShared<'a, Context, Shared, K, V, M, LC>,
<R as ItemEventShared<Context, Shared>>::ItemEventHandler<'a>,
>,
>;

fn map_handler<'a, Context, K, V, LC>(
event: MapLaneEvent<K, V>,
fn map_handler<'a, Context, K, V, M, LC>(
event: MapLaneEvent<K, V, M>,
lifecycle: &'a LC,
map: &HashMap<K, V>,
) -> MapLifecycleHandler<'a, Context, K, V, LC>
map: &M,
) -> MapLifecycleHandler<'a, Context, K, V, M, LC>
where
K: Hash + Eq,
LC: MapLaneLifecycle<K, V, Context>,
LC: MapLaneLifecycle<K, V, M, Context>,
M: MapOpsWithEntry<K, V, K>,
{
match event {
MapLaneEvent::Update(k, old) => {
Expand All @@ -97,16 +91,17 @@ where
}
}

fn map_handler_shared<'a, Context, Shared, K, V, LC>(
fn map_handler_shared<'a, Context, Shared, K, V, M, LC>(
shared: &'a Shared,
handler_context: HandlerContext<Context>,
event: MapLaneEvent<K, V>,
event: MapLaneEvent<K, V, M>,
lifecycle: &'a LC,
map: &HashMap<K, V>,
) -> MapLifecycleHandlerShared<'a, Context, Shared, K, V, LC>
map: &M,
) -> MapLifecycleHandlerShared<'a, Context, Shared, K, V, M, LC>
where
K: Hash + Eq,
LC: MapLaneLifecycleShared<K, V, Context, Shared>,
LC: MapLaneLifecycleShared<K, V, M, Context, Shared>,
M: MapOpsWithEntry<K, V, K>,
{
match event {
MapLaneEvent::Update(k, old) => {
Expand All @@ -126,19 +121,19 @@ where
}
}

type KeyValue<K, V> = fn((K, V)) -> (K, V);
type MapKeyValue<M, K, V> = fn((&M, K, V)) -> (K, V);
/// Map lane lifecycle as a branch node of an [`HTree`].
pub struct MapLikeBranch<Context, K, V, Item, LC, L, R> {
_type: PhantomData<KeyValue<K, V>>,
pub struct MapLikeBranch<Context, K, V, M, Item, LC, L, R> {
_type: PhantomData<MapKeyValue<M, K, V>>,
label: &'static str,
projection: fn(&Context) -> &Item,
lifecycle: LC,
left: L,
right: R,
}

impl<Context, K, V, Item, LC: Clone, L: Clone, R: Clone> Clone
for MapLikeBranch<Context, K, V, Item, LC, L, R>
impl<Context, K, V, M, Item, LC: Clone, L: Clone, R: Clone> Clone
for MapLikeBranch<Context, K, V, M, Item, LC, L, R>
{
fn clone(&self) -> Self {
Self {
Expand All @@ -152,15 +147,15 @@ impl<Context, K, V, Item, LC: Clone, L: Clone, R: Clone> Clone
}
}

impl<Context, K, V, Item, LC, L: HTree, R: HTree> HTree
for MapLikeBranch<Context, K, V, Item, LC, L, R>
impl<Context, K, V, M, Item, LC, L: HTree, R: HTree> HTree
for MapLikeBranch<Context, K, V, M, Item, LC, L, R>
{
fn label(&self) -> Option<&'static str> {
Some(self.label)
}
}

impl<Context, K, V, Item, LC, L, R> Debug for MapLikeBranch<Context, K, V, Item, LC, L, R>
impl<Context, K, V, M, Item, LC, L, R> Debug for MapLikeBranch<Context, K, V, M, Item, LC, L, R>
where
LC: Debug,
L: Debug,
Expand All @@ -177,13 +172,13 @@ where
}
}

impl<Context, K, V, Item, LC> MapLikeBranch<Context, K, V, Item, LC, HLeaf, HLeaf> {
impl<Context, K, V, M, Item, LC> MapLikeBranch<Context, K, V, M, Item, LC, HLeaf, HLeaf> {
pub fn leaf(label: &'static str, projection: fn(&Context) -> &Item, lifecycle: LC) -> Self {
MapLikeBranch::new(label, projection, lifecycle, HLeaf, HLeaf)
}
}

impl<Context, K, V, Item, LC, L, R> MapLikeBranch<Context, K, V, Item, LC, L, R>
impl<Context, K, V, M, Item, LC, L, R> MapLikeBranch<Context, K, V, M, Item, LC, L, R>
where
L: HTree,
R: HTree,
Expand Down Expand Up @@ -212,16 +207,17 @@ where
}
}

impl<Context, K, V, Item, LC, L, R> ItemEvent<Context>
for MapLikeBranch<Context, K, V, Item, LC, L, R>
impl<Context, K, V, M, Item, LC, L, R> ItemEvent<Context>
for MapLikeBranch<Context, K, V, M, Item, LC, L, R>
where
K: Clone + Eq + Hash,
Item: MapItem<K, V>,
LC: MapLaneLifecycle<K, V, Context>,
Item: MapItem<K, V, M>,
LC: MapLaneLifecycle<K, V, M, Context>,
L: HTree + ItemEvent<Context>,
R: HTree + ItemEvent<Context>,
M: MapOpsWithEntry<K, V, K>,
{
type ItemEventHandler<'a> = MapBranchHandler<'a, Context, K, V, LC, L, R>
type ItemEventHandler<'a> = MapBranchHandler<'a, Context, K, V, M, LC, L, R>
where
Self: 'a;

Expand Down Expand Up @@ -253,16 +249,17 @@ where
}
}

impl<Context, Shared, K, V, Item, LC, L, R> ItemEventShared<Context, Shared>
for MapLikeBranch<Context, K, V, Item, LC, L, R>
impl<Context, Shared, K, V, M, Item, LC, L, R> ItemEventShared<Context, Shared>
for MapLikeBranch<Context, K, V, M, Item, LC, L, R>
where
K: Clone + Eq + Hash,
Item: MapItem<K, V>,
LC: MapLaneLifecycleShared<K, V, Context, Shared>,
Item: MapItem<K, V, M>,
LC: MapLaneLifecycleShared<K, V, M, Context, Shared>,
L: HTree + ItemEventShared<Context, Shared>,
R: HTree + ItemEventShared<Context, Shared>,
M: MapOpsWithEntry<K, V, K>,
{
type ItemEventHandler<'a> = MapBranchHandlerShared<'a, Context, Shared, K, V, LC, L, R>
type ItemEventHandler<'a> = MapBranchHandlerShared<'a, Context, Shared, K, V, M, LC, L, R>
where
Self: 'a,
Shared: 'a;
Expand Down
14 changes: 10 additions & 4 deletions server/swimos_agent/src/agent_lifecycle/item_event/map/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use swimos_model::Text;
use swimos_utilities::routing::RouteUri;

use crate::{
agent_lifecycle::item_event::{tests::run_handler, HLeaf, ItemEvent, MapBranch, MapLeaf},
agent_lifecycle::item_event::{tests::run_handler, HLeaf, ItemEvent},
event_handler::{ActionContext, HandlerAction, StepResult},
lanes::map::{
lifecycle::{on_clear::OnClear, on_remove::OnRemove, on_update::OnUpdate},
Expand All @@ -29,6 +29,12 @@ use crate::{
meta::AgentMetadata,
};

use super::MapLikeBranch;

type MapLeaf<Context, K, V, M, LC> = MapBranch<Context, K, V, M, LC, HLeaf, HLeaf>;
type MapBranch<Context, K, V, M, LC, L, R> =
MapLikeBranch<Context, K, V, M, MapLane<K, V, M>, LC, L, R>;

struct TestAgent {
first: MapLane<i32, i32>,
second: MapLane<i32, Text>,
Expand Down Expand Up @@ -248,7 +254,7 @@ impl<K, V> FakeLifecycle<K, V> {
}
}

impl<K, V> OnUpdate<K, V, TestAgent> for FakeLifecycle<K, V>
impl<K, V> OnUpdate<K, V, HashMap<K, V>, TestAgent> for FakeLifecycle<K, V>
where
K: Clone + Send + 'static,
V: Clone + Send + 'static,
Expand All @@ -268,7 +274,7 @@ where
}
}

impl<K, V> OnRemove<K, V, TestAgent> for FakeLifecycle<K, V>
impl<K, V> OnRemove<K, V, HashMap<K, V>, TestAgent> for FakeLifecycle<K, V>
where
K: Clone + Send + 'static,
V: Clone + Send + 'static,
Expand All @@ -287,7 +293,7 @@ where
}
}

impl<K, V> OnClear<K, V, TestAgent> for FakeLifecycle<K, V>
impl<K, V> OnClear<HashMap<K, V>, TestAgent> for FakeLifecycle<K, V>
where
K: Clone + Send + 'static,
V: Clone + Send + 'static,
Expand Down
5 changes: 1 addition & 4 deletions server/swimos_agent/src/agent_lifecycle/item_event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,7 @@ pub use demand_map::{
DemandMapBranch, DemandMapLeaf, DemandMapLifecycleHandler, DemandMapLifecycleHandlerShared,
};
pub use http::{HttpBranch, HttpLeaf};
pub use map::{
MapBranch, MapLeaf, MapLifecycleHandler, MapLifecycleHandlerShared, MapLikeBranch,
MapStoreBranch, MapStoreLeaf,
};
pub use map::{MapLifecycleHandler, MapLifecycleHandlerShared, MapLikeBranch};
pub use value::{
ValueBranch, ValueLeaf, ValueLifecycleHandler, ValueLifecycleHandlerShared, ValueLikeBranch,
ValueStoreBranch, ValueStoreLeaf,
Expand Down
10 changes: 5 additions & 5 deletions server/swimos_agent/src/agent_lifecycle/utility/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,13 +234,13 @@ impl<Agent: AgentDescription + 'static> HandlerContext<Agent> {
) -> impl HandlerAction<Agent, Completion = U> + Send + 'a
where
Agent: 'static,
Item: InspectableMapLikeItem<K, V> + 'static,
Item: InspectableMapLikeItem<K, V, B> + 'static,
K: Send + Clone + Eq + Hash + 'static,
V: Borrow<B> + 'static,
B: ?Sized + 'static,
F: FnOnce(Option<&B>) -> U + Send + 'a,
{
Item::with_entry_handler::<Agent, F, B, U>(item, key, f)
Item::with_entry_handler::<Agent, F, U>(item, key, f)
}

/// Create an event handler that will transform the value in an entry of a map lane or store of the agent.
Expand Down Expand Up @@ -326,12 +326,12 @@ impl<Agent: AgentDescription + 'static> HandlerContext<Agent> {
///
/// #Arguments
/// * `item` - Projection to the map-like item.
pub fn get_map<Item, K, V>(
pub fn get_map<Item, K, V, M>(
&self,
item: fn(&Agent) -> &Item,
) -> impl HandlerAction<Agent, Completion = HashMap<K, V>> + Send + 'static
) -> impl HandlerAction<Agent, Completion = M> + Send + 'static
where
Item: MapLikeItem<K, V>,
Item: MapLikeItem<K, V, M>,
K: Send + Clone + Eq + Hash + 'static,
V: Send + Clone + 'static,
{
Expand Down
Loading

0 comments on commit c21a7ea

Please sign in to comment.