use std::collections::HashMap;
use tycho_simulation::tycho_common::models::{protocol::ProtocolComponent, Address};
use crate::{
feed::{events::MarketEvent, market_data::MarketState},
types::ComponentId,
};
pub(crate) fn is_exclusive(component: &ProtocolComponent) -> bool {
component
.static_attributes
.contains_key("is_exclusive")
}
pub(crate) fn remove_exclusive_components(
market: &MarketState,
topology: HashMap<ComponentId, Vec<Address>>,
) -> HashMap<ComponentId, Vec<Address>> {
topology
.into_iter()
.filter(|(id, _)| {
market
.get_component(id)
.is_none_or(|c| !is_exclusive(c))
})
.collect()
}
pub(crate) fn scope_event(market: &MarketState, event: MarketEvent) -> MarketEvent {
let MarketEvent::MarketUpdated { added_components, removed_components, updated_components } =
event;
let added_components = remove_exclusive_components(market, added_components);
let removed_components = filter_component_ids(market, &removed_components);
let updated_components = filter_component_ids(market, &updated_components);
MarketEvent::MarketUpdated { added_components, removed_components, updated_components }
}
fn filter_component_ids(market: &MarketState, ids: &[ComponentId]) -> Vec<ComponentId> {
ids.iter()
.filter(|id| {
market
.get_component(id)
.is_none_or(|c| !is_exclusive(c))
})
.cloned()
.collect()
}
#[cfg(test)]
pub(crate) fn mark_exclusive(component: &mut ProtocolComponent) {
component
.static_attributes
.insert("is_exclusive".to_string(), vec![1u8].into());
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
algorithm::test_utils::{component, token},
feed::{events::MarketEvent, market_data::MarketState},
};
fn exclusive_component(id: &str) -> ProtocolComponent {
let mut c = component(id, &[token(0x01, "A"), token(0x02, "B")]);
mark_exclusive(&mut c);
c
}
fn public_component(id: &str) -> ProtocolComponent {
component(id, &[token(0x01, "A"), token(0x02, "B")])
}
fn market_with(components: Vec<ProtocolComponent>) -> MarketState {
let mut market = MarketState::new();
market.upsert_components(components);
market
}
fn component_with_extension() -> ProtocolComponent {
let mut c = public_component("pub-1");
c.static_attributes
.insert("extension".to_string(), vec![0x55, 0x19].into());
c
}
#[rstest::rstest]
#[case::tagged(exclusive_component("excl-1"), true)]
#[case::missing_attribute(public_component("pub-1"), false)]
#[case::untagged_extension(component_with_extension(), false)]
fn test_is_exclusive(#[case] component: ProtocolComponent, #[case] expected: bool) {
assert_eq!(is_exclusive(&component), expected);
}
#[test]
fn test_remove_exclusive_components() {
let market = market_with(vec![public_component("pub-1"), exclusive_component("excl-1")]);
let topology = market.component_topology();
let filtered = remove_exclusive_components(&market, topology);
assert!(filtered.contains_key("pub-1"));
assert!(!filtered.contains_key("excl-1"));
}
#[test]
fn test_scope_event() {
let market = market_with(vec![public_component("pub-1"), exclusive_component("excl-1")]);
let event = MarketEvent::MarketUpdated {
added_components: HashMap::from([
("pub-1".to_string(), vec![]),
("excl-1".to_string(), vec![]),
]),
removed_components: vec!["pub-1".to_string(), "excl-1".to_string()],
updated_components: vec!["pub-1".to_string(), "excl-1".to_string()],
};
let MarketEvent::MarketUpdated { added_components, removed_components, updated_components } =
scope_event(&market, event);
assert!(added_components.contains_key("pub-1"));
assert!(!added_components.contains_key("excl-1"));
assert_eq!(removed_components, vec!["pub-1".to_string()]);
assert_eq!(updated_components, vec!["pub-1".to_string()]);
}
}