capability.rs (3615B)
1 //! Signer capability declarations. 2 3 use crate::recovery::ReplayCapability; 4 5 /// How a signer implementation obtains signatures. 6 #[non_exhaustive] 7 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 8 #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] 9 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 10 pub enum SignerKind { 11 /// A local adapter performs signing without publishing a remote request. 12 Local, 13 /// A remote service or device performs signing. 14 Remote, 15 /// A composing host mediates signing through an explicit user interaction. 16 HostMediated, 17 } 18 19 /// Cancellation behavior advertised by a signer. 20 #[non_exhaustive] 21 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 22 #[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] 23 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 24 pub enum CancellationSupport { 25 /// Cancellation is observed only before a remote request is published. 26 BeforePublication, 27 /// Cancellation remains observable after publication, without implying 28 /// rollback of the already-published request. 29 BeforeAndAfterPublication, 30 } 31 32 /// Portable signer behavior advertised to a composing host. 33 #[non_exhaustive] 34 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 35 #[cfg_attr(feature = "serde", serde(deny_unknown_fields))] 36 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 37 pub struct SignerCapability { 38 kind: SignerKind, 39 replay: ReplayCapability, 40 cancellation: CancellationSupport, 41 reports_progress: bool, 42 may_require_authentication: bool, 43 } 44 45 impl SignerCapability { 46 /// Creates an explicit capability declaration. 47 #[must_use] 48 pub const fn new( 49 kind: SignerKind, 50 replay: ReplayCapability, 51 cancellation: CancellationSupport, 52 reports_progress: bool, 53 may_require_authentication: bool, 54 ) -> Self { 55 Self { 56 kind, 57 replay, 58 cancellation, 59 reports_progress, 60 may_require_authentication, 61 } 62 } 63 64 /// Returns the implementation kind. 65 #[must_use] 66 pub const fn kind(self) -> SignerKind { 67 self.kind 68 } 69 70 /// Returns the exact replay contract. 71 #[must_use] 72 pub const fn replay(self) -> ReplayCapability { 73 self.replay 74 } 75 76 /// Returns the advertised cancellation contract. 77 #[must_use] 78 pub const fn cancellation(self) -> CancellationSupport { 79 self.cancellation 80 } 81 82 /// Reports whether the signer emits progress updates. 83 #[must_use] 84 pub const fn reports_progress(self) -> bool { 85 self.reports_progress 86 } 87 88 /// Reports whether the signer may emit an authentication challenge. 89 #[must_use] 90 pub const fn may_require_authentication(self) -> bool { 91 self.may_require_authentication 92 } 93 } 94 95 #[cfg(all(test, feature = "serde"))] 96 mod tests { 97 use super::*; 98 99 #[test] 100 fn capability_round_trips_with_stable_wire_labels() { 101 let capability = SignerCapability::new( 102 SignerKind::Remote, 103 ReplayCapability::ExactReplayByRequestId, 104 CancellationSupport::BeforeAndAfterPublication, 105 true, 106 true, 107 ); 108 let encoded = serde_json::to_string(&capability).expect("serialize capability"); 109 let decoded: SignerCapability = 110 serde_json::from_str(&encoded).expect("deserialize capability"); 111 112 assert_eq!(decoded, capability); 113 assert!(encoded.contains("remote")); 114 assert!(encoded.contains("before_and_after_publication")); 115 } 116 }