tacacs_plus_protocol/authentication/
data.rs

1use core::fmt;
2
3#[derive(Debug, Clone, PartialEq, Eq, Ord, Hash)]
4enum PacketDataInner<'data> {
5    Borrowed(&'data [u8]),
6
7    #[cfg(feature = "std")]
8    Owned(std::vec::Vec<u8>),
9}
10
11impl PartialOrd for PacketDataInner<'_> {
12    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
13        Some(self.as_ref().cmp(other.as_ref()))
14    }
15}
16
17/// Supplementary authentication data included in an authentication start packet.
18#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct PacketData<'data>(PacketDataInner<'data>);
20
21impl PacketData<'_> {
22    /// Creates an empty [`PacketData`].
23    pub fn new() -> Self {
24        Default::default()
25    }
26}
27
28impl Default for PacketData<'_> {
29    fn default() -> Self {
30        Self(PacketDataInner::Borrowed(&[]))
31    }
32}
33
34/// An error indicating that the provided supplementary authentication was too long to fit in a packet.
35#[derive(Debug, PartialEq, Eq)]
36pub struct DataTooLong(pub(super) ());
37
38impl fmt::Display for DataTooLong {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        write!(
41            f,
42            "data was too long for the data field of an authentication start packet"
43        )
44    }
45}
46
47impl<'data> TryFrom<&'data [u8]> for PacketData<'data> {
48    type Error = DataTooLong;
49
50    fn try_from(value: &'data [u8]) -> Result<Self, Self::Error> {
51        // do length check on data, since the encoded length has to fit in a single byte
52        if u8::try_from(value.len()).is_ok() {
53            Ok(Self(PacketDataInner::Borrowed(value)))
54        } else {
55            Err(DataTooLong(()))
56        }
57    }
58}
59
60#[cfg(feature = "std")]
61impl TryFrom<std::vec::Vec<u8>> for PacketData<'_> {
62    type Error = DataTooLong;
63
64    fn try_from(value: std::vec::Vec<u8>) -> Result<Self, Self::Error> {
65        // as above, encoded length must fit in a single octet
66        if u8::try_from(value.len()).is_ok() {
67            Ok(Self(PacketDataInner::Owned(value)))
68        } else {
69            Err(DataTooLong(()))
70        }
71    }
72}
73
74impl AsRef<[u8]> for PacketDataInner<'_> {
75    fn as_ref(&self) -> &[u8] {
76        match self {
77            Self::Borrowed(data) => data,
78
79            #[cfg(feature = "std")]
80            Self::Owned(vec) => vec,
81        }
82    }
83}
84
85impl PacketData<'_> {
86    // the len_without_is_empty lint is suppressed since we already effectively have an AsRef impl via as_bytes
87    /// Returns the length of the underlying data, which is guaranteed to fit in a `u8`.
88    #[allow(clippy::len_without_is_empty)]
89    pub fn len(&self) -> u8 {
90        // SAFETY: the length of the inner data is checked to fit in a u8 in the TryFrom impls
91        u8::try_from(self.as_bytes().len()).unwrap()
92    }
93
94    /// Returns the byte representation of this packet data.
95    pub fn as_bytes(&self) -> &[u8] {
96        self.0.as_ref()
97    }
98}