architect_api/utils/
envelope.rs

1#[cfg(feature = "netidx")]
2use crate::TypedMessage;
3use crate::{ComponentId, MessageTopic, UserId};
4use anyhow::Result;
5#[cfg(feature = "netidx")]
6use derive::FromValue;
7use enumflags2::BitFlags;
8#[cfg(feature = "netidx")]
9use netidx_derive::Pack;
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12use uuid::Uuid;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
15#[cfg_attr(feature = "netidx", derive(Pack))]
16#[cfg_attr(feature = "netidx", derive(FromValue))]
17pub enum Address {
18    Component(ComponentId),
19    Channel(UserId, u32),
20    /// For cases like external orderflow where the message doesn't ultimately route
21    /// to any particular client; in this case the message can only be picked up via
22    /// a channel subscription.  This is different from Component(#none) which
23    /// actually goes nowhere and is reserved for SystemControl messages.
24    ChannelSubscriptionOnly,
25}
26
27impl From<ComponentId> for Address {
28    #[inline(always)]
29    fn from(id: ComponentId) -> Self {
30        Self::Component(id)
31    }
32}
33
34impl std::fmt::Display for Address {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        match self {
37            Address::Component(id) => write!(f, "#{}", id),
38            Address::Channel(user_id, channel) => write!(f, "{}:{}", user_id, channel),
39            Address::ChannelSubscriptionOnly => write!(f, "~"),
40        }
41    }
42}
43
44impl Address {
45    #[inline(always)]
46    pub fn is_loopback(&self) -> bool {
47        match self {
48            Address::Component(id) => id.is_loopback(),
49            Address::Channel(..) => false,
50            Address::ChannelSubscriptionOnly => false,
51        }
52    }
53
54    #[inline(always)]
55    pub fn component<T>(id: T) -> Result<Self>
56    where
57        T: TryInto<ComponentId>,
58        <T as TryInto<ComponentId>>::Error: std::error::Error + Send + Sync + 'static,
59    {
60        Ok(Self::Component(id.try_into()?))
61    }
62
63    pub fn component_id(&self) -> Option<ComponentId> {
64        match self {
65            Address::Component(id) => Some(*id),
66            _ => None,
67        }
68    }
69
70    pub fn user_id(&self) -> Option<UserId> {
71        match self {
72            Address::Channel(user_id, _) => Some(*user_id),
73            _ => None,
74        }
75    }
76}
77
78/// Architect components communicate with each other by sending `Envelope`s.
79#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, JsonSchema)]
80#[cfg_attr(feature = "netidx", derive(Pack))]
81#[cfg_attr(feature = "netidx", derive(FromValue))]
82pub struct Envelope<M: 'static> {
83    pub src: Address,
84    pub dst: Address,
85    pub stamp: Stamp,
86    pub msg: M,
87}
88
89impl<M> Envelope<M> {
90    pub fn system_control(msg: M) -> Self {
91        Self {
92            src: Address::Component(ComponentId::none()),
93            dst: Address::Component(ComponentId::none()),
94            stamp: Stamp::new(None, Default::default()),
95            msg,
96        }
97    }
98}
99
100#[cfg(feature = "netidx")]
101impl Envelope<TypedMessage> {
102    pub fn topics(&self) -> BitFlags<MessageTopic> {
103        self.msg.topics() | self.stamp.additional_topics
104    }
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, JsonSchema)]
108#[cfg_attr(feature = "netidx", derive(Pack))]
109#[cfg_attr(feature = "netidx", derive(FromValue))]
110pub struct Stamp {
111    pub user_id: Option<UserId>,
112    pub sequence: Option<Sequence>,
113    pub additional_topics: BitFlags<MessageTopic>,
114}
115
116impl Stamp {
117    // NB alee: not obvious at first glance but sequencing is done by
118    // the core while the other fields are set by the sender and merely
119    // checked by the core.
120    pub fn new(
121        user_id: Option<UserId>,
122        additional_topics: BitFlags<MessageTopic>,
123    ) -> Self {
124        Self { user_id, sequence: None, additional_topics }
125    }
126}
127
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, JsonSchema)]
129#[cfg_attr(feature = "netidx", derive(Pack))]
130#[cfg_attr(feature = "netidx", derive(FromValue))]
131pub enum Sequence {
132    Local(u64),
133    Remote { core_id: Uuid, last_seqno: Option<u64>, seqno: u64 },
134}