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 }