Skip to main content

ssh_encoding/
label.rs

1//! Convenience trait for decoding/encoding string labels.
2
3use crate::{Decode, Encode, Error, Reader, Writer};
4use core::{fmt, str::FromStr};
5
6#[cfg(feature = "alloc")]
7use alloc::string::String;
8
9/// Maximum size of any algorithm name/identifier.
10const MAX_LABEL_SIZE: usize = 48;
11
12/// Labels for e.g. cryptographic algorithms.
13///
14/// Receives a blanket impl of [`Decode`] and [`Encode`].
15pub trait Label: AsRef<str> + FromStr<Err = LabelError> {}
16
17impl<T: Label> Decode for T {
18    type Error = Error;
19
20    fn decode(reader: &mut impl Reader) -> Result<Self, Error> {
21        let mut buf = [0u8; MAX_LABEL_SIZE];
22        Ok(reader.read_string(buf.as_mut())?.parse()?)
23    }
24}
25
26impl<T: Label> Encode for T {
27    fn encoded_len(&self) -> Result<usize, Error> {
28        self.as_ref().encoded_len()
29    }
30
31    fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> {
32        self.as_ref().encode(writer)
33    }
34}
35
36/// Errors related to labels.
37#[derive(Clone, Debug, Eq, PartialEq)]
38#[non_exhaustive]
39pub struct LabelError {
40    /// The label that was considered invalid.
41    #[cfg(feature = "alloc")]
42    label: String,
43}
44
45impl LabelError {
46    /// Create a new [`LabelError`] for the given invalid label.
47    #[cfg_attr(not(feature = "alloc"), allow(unused_variables))]
48    #[must_use]
49    pub fn new(label: &str) -> Self {
50        Self {
51            #[cfg(feature = "alloc")]
52            label: label.into(),
53        }
54    }
55
56    /// The invalid label string (if available).
57    #[inline]
58    #[must_use]
59    pub fn label(&self) -> &str {
60        #[cfg(not(feature = "alloc"))]
61        {
62            ""
63        }
64        #[cfg(feature = "alloc")]
65        {
66            &self.label
67        }
68    }
69}
70
71impl core::error::Error for LabelError {}
72
73impl fmt::Display for LabelError {
74    #[cfg(not(feature = "alloc"))]
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        f.write_str("invalid label")
77    }
78
79    #[cfg(feature = "alloc")]
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        write!(f, "invalid label: '{}'", self.label)
82    }
83}