lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

capability.rs (6514B)


      1 //! Transport-neutral capability vocabulary.
      2 
      3 use radroots_protocol::capability::v1 as protocol;
      4 
      5 /// Product maturity of a transport capability.
      6 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
      7 #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
      8 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
      9 pub enum Maturity {
     10     /// Contract may change without compatibility guarantees.
     11     Experimental,
     12     /// Contract is available for preview use.
     13     Preview,
     14     /// Contract is supported as stable.
     15     Stable,
     16 }
     17 
     18 /// Current runtime availability of a transport capability.
     19 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
     20 #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
     21 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
     22 pub enum Availability {
     23     /// Fully available.
     24     Available,
     25     /// Available with reduced functionality.
     26     Degraded,
     27     /// Not currently available.
     28     Unavailable,
     29 }
     30 
     31 impl From<protocol::Maturity> for Maturity {
     32     fn from(value: protocol::Maturity) -> Self {
     33         match value {
     34             protocol::Maturity::Experimental => Self::Experimental,
     35             protocol::Maturity::Preview => Self::Preview,
     36             protocol::Maturity::Stable => Self::Stable,
     37         }
     38     }
     39 }
     40 
     41 impl From<Maturity> for protocol::Maturity {
     42     fn from(value: Maturity) -> Self {
     43         match value {
     44             Maturity::Experimental => Self::Experimental,
     45             Maturity::Preview => Self::Preview,
     46             Maturity::Stable => Self::Stable,
     47         }
     48     }
     49 }
     50 
     51 impl From<protocol::Availability> for Availability {
     52     fn from(value: protocol::Availability) -> Self {
     53         match value {
     54             protocol::Availability::Available => Self::Available,
     55             protocol::Availability::Degraded => Self::Degraded,
     56             protocol::Availability::Unavailable => Self::Unavailable,
     57         }
     58     }
     59 }
     60 
     61 impl From<Availability> for protocol::Availability {
     62     fn from(value: Availability) -> Self {
     63         match value {
     64             Availability::Available => Self::Available,
     65             Availability::Degraded => Self::Degraded,
     66             Availability::Unavailable => Self::Unavailable,
     67         }
     68     }
     69 }
     70 
     71 /// Operations supported by an event source.
     72 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
     73 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
     74 pub struct SourceCapabilities {
     75     fetch: bool,
     76     discovery: bool,
     77 }
     78 
     79 impl SourceCapabilities {
     80     /// No source operations are supported.
     81     pub const NONE: Self = Self {
     82         fetch: false,
     83         discovery: false,
     84     };
     85 
     86     /// Bounded fetch is supported.
     87     pub const FETCH: Self = Self {
     88         fetch: true,
     89         discovery: false,
     90     };
     91 
     92     /// Sets discovery support.
     93     #[must_use]
     94     pub const fn with_discovery(mut self, discovery: bool) -> Self {
     95         self.discovery = discovery;
     96         self
     97     }
     98 
     99     /// Whether bounded fetch is supported.
    100     pub const fn can_fetch(self) -> bool {
    101         self.fetch
    102     }
    103 
    104     /// Whether target discovery is supported.
    105     pub const fn can_discover(self) -> bool {
    106         self.discovery
    107     }
    108 }
    109 
    110 impl From<&protocol::TransportDescriptor> for SourceCapabilities {
    111     fn from(value: &protocol::TransportDescriptor) -> Self {
    112         Self {
    113             fetch: value.can_fetch,
    114             discovery: value.can_discover,
    115         }
    116     }
    117 }
    118 
    119 /// Operations supported by an event sink.
    120 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
    121 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
    122 pub struct SinkCapabilities {
    123     deliver: bool,
    124     gateway_forwarding: bool,
    125     receipt_observation: bool,
    126 }
    127 
    128 impl SinkCapabilities {
    129     /// No sink operations are supported.
    130     pub const NONE: Self = Self {
    131         deliver: false,
    132         gateway_forwarding: false,
    133         receipt_observation: false,
    134     };
    135 
    136     /// Delivery is supported.
    137     pub const DELIVER: Self = Self {
    138         deliver: true,
    139         gateway_forwarding: false,
    140         receipt_observation: false,
    141     };
    142 
    143     /// Sets gateway-forwarding support.
    144     #[must_use]
    145     pub const fn with_gateway_forwarding(mut self, supported: bool) -> Self {
    146         self.gateway_forwarding = supported;
    147         self
    148     }
    149 
    150     /// Sets receipt-observation support.
    151     #[must_use]
    152     pub const fn with_receipt_observation(mut self, supported: bool) -> Self {
    153         self.receipt_observation = supported;
    154         self
    155     }
    156 
    157     /// Whether delivery is supported.
    158     pub const fn can_deliver(self) -> bool {
    159         self.deliver
    160     }
    161 
    162     /// Whether gateway forwarding is supported.
    163     pub const fn can_gateway_forward(self) -> bool {
    164         self.gateway_forwarding
    165     }
    166 
    167     /// Whether delivery receipt observation is supported.
    168     pub const fn can_observe_receipts(self) -> bool {
    169         self.receipt_observation
    170     }
    171 }
    172 
    173 impl From<&protocol::TransportDescriptor> for SinkCapabilities {
    174     fn from(value: &protocol::TransportDescriptor) -> Self {
    175         Self {
    176             deliver: value.can_deliver,
    177             gateway_forwarding: value.can_gateway_forward,
    178             receipt_observation: value.can_observe_receipts,
    179         }
    180     }
    181 }
    182 
    183 #[cfg(test)]
    184 mod tests {
    185     use super::*;
    186 
    187     #[test]
    188     fn capability_values_cover_all_flags_and_protocol_enum_conversions() {
    189         let source = SourceCapabilities::FETCH.with_discovery(true);
    190         assert!(source.can_fetch());
    191         assert!(source.can_discover());
    192         assert!(!SourceCapabilities::NONE.can_fetch());
    193         assert!(!SourceCapabilities::NONE.can_discover());
    194 
    195         let sink = SinkCapabilities::DELIVER
    196             .with_gateway_forwarding(true)
    197             .with_receipt_observation(true);
    198         assert!(sink.can_deliver());
    199         assert!(sink.can_gateway_forward());
    200         assert!(sink.can_observe_receipts());
    201         assert!(!SinkCapabilities::NONE.can_deliver());
    202 
    203         for maturity in [Maturity::Experimental, Maturity::Preview, Maturity::Stable] {
    204             let protocol_value: protocol::Maturity = maturity.into();
    205             assert_eq!(Maturity::from(protocol_value), maturity);
    206         }
    207         for availability in [
    208             Availability::Available,
    209             Availability::Degraded,
    210             Availability::Unavailable,
    211         ] {
    212             let protocol_value: protocol::Availability = availability.into();
    213             assert_eq!(Availability::from(protocol_value), availability);
    214         }
    215     }
    216 }