solana_signer/
signers.rs

1use {
2    crate::{Signer, SignerError},
3    solana_pubkey::Pubkey,
4    solana_signature::Signature,
5};
6
7/// Convenience trait for working with mixed collections of `Signer`s
8pub trait Signers {
9    fn pubkeys(&self) -> Vec<Pubkey>;
10    fn try_pubkeys(&self) -> Result<Vec<Pubkey>, SignerError>;
11    fn sign_message(&self, message: &[u8]) -> Vec<Signature>;
12    fn try_sign_message(&self, message: &[u8]) -> Result<Vec<Signature>, SignerError>;
13    fn is_interactive(&self) -> bool;
14}
15
16/// Any `T` where `T` impls `IntoIterator` yielding
17/// `Signer`s implements `Signers`.
18///
19/// This includes `[&dyn Signer]`, `[Box<dyn Signer>]`,
20/// `[&dyn Signer; N]`, `Vec<dyn Signer>`, `Vec<Keypair>`, etc.
21///
22/// When used as a generic function param, `&T`
23/// should be used instead of `T` where T: Signers, due to the `?Sized` bounds on T.
24/// E.g. [Signer] implements `Signers`, but `&[Signer]` does not
25impl<T: ?Sized, S: Signer + ?Sized> Signers for T
26where
27    for<'a> &'a T: IntoIterator<Item = &'a S>,
28{
29    fn pubkeys(&self) -> Vec<Pubkey> {
30        self.into_iter().map(|keypair| keypair.pubkey()).collect()
31    }
32
33    fn try_pubkeys(&self) -> Result<Vec<Pubkey>, SignerError> {
34        self.into_iter()
35            .map(|keypair| keypair.try_pubkey())
36            .collect()
37    }
38
39    fn sign_message(&self, message: &[u8]) -> Vec<Signature> {
40        self.into_iter()
41            .map(|keypair| keypair.sign_message(message))
42            .collect()
43    }
44
45    fn try_sign_message(&self, message: &[u8]) -> Result<Vec<Signature>, SignerError> {
46        self.into_iter()
47            .map(|keypair| keypair.try_sign_message(message))
48            .collect()
49    }
50
51    fn is_interactive(&self) -> bool {
52        self.into_iter().any(|s| s.is_interactive())
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    struct Foo;
61    impl Signer for Foo {
62        fn try_pubkey(&self) -> Result<Pubkey, SignerError> {
63            Ok(Pubkey::default())
64        }
65        fn try_sign_message(&self, _message: &[u8]) -> Result<Signature, SignerError> {
66            Ok(Signature::default())
67        }
68        fn is_interactive(&self) -> bool {
69            false
70        }
71    }
72
73    struct Bar;
74    impl Signer for Bar {
75        fn try_pubkey(&self) -> Result<Pubkey, SignerError> {
76            Ok(Pubkey::default())
77        }
78        fn try_sign_message(&self, _message: &[u8]) -> Result<Signature, SignerError> {
79            Ok(Signature::default())
80        }
81        fn is_interactive(&self) -> bool {
82            false
83        }
84    }
85
86    #[test]
87    fn test_dyn_keypairs_compile() {
88        let xs: Vec<Box<dyn Signer>> = vec![Box::new(Foo {}), Box::new(Bar {})];
89        assert_eq!(
90            xs.sign_message(b""),
91            vec![Signature::default(), Signature::default()],
92        );
93
94        // Same as above, but less compiler magic.
95        let xs_ref: &[Box<dyn Signer>] = &xs;
96        assert_eq!(
97            Signers::sign_message(xs_ref, b""),
98            vec![Signature::default(), Signature::default()],
99        );
100    }
101
102    #[test]
103    fn test_dyn_keypairs_by_ref_compile() {
104        let foo = Foo {};
105        let bar = Bar {};
106        let xs: Vec<&dyn Signer> = vec![&foo, &bar];
107        assert_eq!(
108            xs.sign_message(b""),
109            vec![Signature::default(), Signature::default()],
110        );
111
112        // Same as above, but less compiler magic.
113        let xs_ref: &[&dyn Signer] = &xs;
114        assert_eq!(
115            Signers::sign_message(xs_ref, b""),
116            vec![Signature::default(), Signature::default()],
117        );
118    }
119}