1use crate::{Decode, Encode, Error, Reader, Writer};
4use core::{fmt, str::FromStr};
5
6#[cfg(feature = "alloc")]
7use alloc::string::String;
8
9const MAX_LABEL_SIZE: usize = 48;
11
12pub 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#[derive(Clone, Debug, Eq, PartialEq)]
38#[non_exhaustive]
39pub struct LabelError {
40 #[cfg(feature = "alloc")]
42 label: String,
43}
44
45impl LabelError {
46 #[cfg_attr(not(feature = "alloc"), allow(unused_variables))]
48 pub fn new(label: &str) -> Self {
49 Self {
50 #[cfg(feature = "alloc")]
51 label: label.into(),
52 }
53 }
54
55 #[inline]
57 pub fn label(&self) -> &str {
58 #[cfg(not(feature = "alloc"))]
59 {
60 ""
61 }
62 #[cfg(feature = "alloc")]
63 {
64 &self.label
65 }
66 }
67}
68
69impl fmt::Display for LabelError {
70 #[cfg(not(feature = "alloc"))]
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 f.write_str("invalid label")
73 }
74
75 #[cfg(feature = "alloc")]
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77 write!(f, "invalid label: '{}'", self.label)
78 }
79}
80
81#[cfg(feature = "std")]
82impl std::error::Error for LabelError {}