git_actor/signature/
mod.rs

1mod _ref {
2    use bstr::{BStr, ByteSlice};
3
4    use crate::{signature::decode, Signature, SignatureRef};
5
6    impl<'a> SignatureRef<'a> {
7        /// Deserialize a signature from the given `data`.
8        pub fn from_bytes<E>(data: &'a [u8]) -> Result<SignatureRef<'a>, nom::Err<E>>
9        where
10            E: nom::error::ParseError<&'a [u8]> + nom::error::ContextError<&'a [u8]>,
11        {
12            decode(data).map(|(_, t)| t)
13        }
14
15        /// Create an owned instance from this shared one.
16        pub fn to_owned(&self) -> Signature {
17            Signature {
18                name: self.name.to_owned(),
19                email: self.email.to_owned(),
20                time: self.time,
21            }
22        }
23
24        /// Trim whitespace surrounding the name and email and return a new signature.
25        pub fn trim(&self) -> SignatureRef<'a> {
26            SignatureRef {
27                name: self.name.trim().as_bstr(),
28                email: self.email.trim().as_bstr(),
29                time: self.time,
30            }
31        }
32
33        /// Return the actor's name and email, effectively excluding the time stamp of this signature.
34        pub fn actor(&self) -> (&BStr, &BStr) {
35            (self.name, self.email)
36        }
37    }
38}
39
40mod convert {
41    use crate::{Signature, SignatureRef};
42
43    impl Signature {
44        /// An empty signature, similar to 'null'.
45        pub fn empty() -> Self {
46            Signature::default()
47        }
48
49        /// Borrow this instance as immutable
50        pub fn to_ref(&self) -> SignatureRef<'_> {
51            SignatureRef {
52                name: self.name.as_ref(),
53                email: self.email.as_ref(),
54                time: self.time,
55            }
56        }
57    }
58
59    impl From<SignatureRef<'_>> for Signature {
60        fn from(other: SignatureRef<'_>) -> Signature {
61            let SignatureRef { name, email, time } = other;
62            Signature {
63                name: name.to_owned(),
64                email: email.to_owned(),
65                time,
66            }
67        }
68    }
69
70    impl<'a> From<&'a Signature> for SignatureRef<'a> {
71        fn from(other: &'a Signature) -> SignatureRef<'a> {
72            other.to_ref()
73        }
74    }
75}
76
77mod write {
78    use std::io;
79
80    use bstr::{BStr, ByteSlice};
81    use quick_error::quick_error;
82
83    use crate::{Signature, SignatureRef};
84
85    quick_error! {
86        /// The Error produced by [`Signature::write_to()`].
87        #[derive(Debug)]
88        #[allow(missing_docs)]
89        enum Error {
90            IllegalCharacter {
91                display("Signature name or email must not contain '<', '>' or \\n")
92            }
93        }
94    }
95
96    impl From<Error> for io::Error {
97        fn from(err: Error) -> Self {
98            io::Error::new(io::ErrorKind::Other, err)
99        }
100    }
101
102    /// Output
103    impl Signature {
104        /// Serialize this instance to `out` in the git serialization format for actors.
105        pub fn write_to(&self, out: impl io::Write) -> io::Result<()> {
106            self.to_ref().write_to(out)
107        }
108        /// Computes the number of bytes necessary to serialize this signature
109        pub fn size(&self) -> usize {
110            self.to_ref().size()
111        }
112    }
113
114    impl<'a> SignatureRef<'a> {
115        /// Serialize this instance to `out` in the git serialization format for actors.
116        pub fn write_to(&self, mut out: impl io::Write) -> io::Result<()> {
117            out.write_all(validated_token(self.name)?)?;
118            out.write_all(b" ")?;
119            out.write_all(b"<")?;
120            out.write_all(validated_token(self.email)?)?;
121            out.write_all(b"> ")?;
122            self.time.write_to(out)
123        }
124        /// Computes the number of bytes necessary to serialize this signature
125        pub fn size(&self) -> usize {
126            self.name.len() + 2 /* space <*/ + self.email.len() +  2 /* > space */ + self.time.size()
127        }
128    }
129
130    fn validated_token(name: &BStr) -> Result<&BStr, Error> {
131        if name.find_byteset(b"<>\n").is_some() {
132            return Err(Error::IllegalCharacter);
133        }
134        Ok(name)
135    }
136}
137
138///
139mod decode;
140pub use decode::decode;