domain/base/
charstr.rs

1//! Character strings.
2//!
3//! The somewhat ill-named `<character-string>` is defined in [RFC 1035] as
4//! binary information of up to 255 octets. As such, it doesn’t necessarily
5//! contain (ASCII-) characters nor is it a string in a Rust-sense.
6//!
7//! An existing, immutable character string is represented by the type
8//! [`CharStr`]. The type [`CharStrBuilder`] allows constructing a character
9//! string from individual octets or octets slices.
10//!
11//! In wire-format, character strings are encoded as one octet giving the
12//! length followed by the actual data in that many octets. The length octet
13//! is not part of the content wrapped by [`CharStr`], it contains the data
14//! only.
15//!
16//! A [`CharStr`] can be constructed from a string via the `FromStr`
17//! trait. In this case, the string must consist only of printable ASCII
18//! characters. Space and double quote are allowed and will be accepted with
19//! their ASCII value. Other values need to be escaped via a backslash
20//! followed by the three-digit decimal representation of the value. In
21//! addition, a backslash followed by a non-digit printable ASCII character
22//! is accepted, too, with the ASCII value of this character used.
23//!
24//! [RFC 1035]: https://tools.ietf.org/html/rfc1035
25
26use super::cmp::CanonicalOrd;
27use super::scan::{BadSymbol, Scanner, Symbol, SymbolCharsError};
28use super::wire::{Compose, ParseError};
29#[cfg(feature = "bytes")]
30use bytes::BytesMut;
31use core::{cmp, fmt, hash, str};
32use octseq::builder::FreezeBuilder;
33#[cfg(feature = "serde")]
34use octseq::serde::{DeserializeOctets, SerializeOctets};
35use octseq::{
36    EmptyBuilder, FromBuilder, IntoBuilder, Octets, OctetsBuilder,
37    OctetsFrom, Parser, ShortBuf, Truncate,
38};
39#[cfg(feature = "std")]
40use std::vec::Vec;
41
42//------------ CharStr -------------------------------------------------------
43
44/// The content of a DNS character string.
45///
46/// A character string consists of up to 255 octets of binary data. This type
47/// wraps an octets sequence. It is guaranteed to always be at most 255 octets
48/// in length. It derefs into the underlying octets for working with the
49/// content in a familiar way.
50///
51/// As per [RFC 1035], character strings compare ignoring ASCII case.
52/// `CharStr`’s implementations of the `std::cmp` traits act accordingly.
53///
54/// [RFC 1035]: https://tools.ietf.org/html/rfc1035
55#[derive(Clone)]
56pub struct CharStr<Octs: ?Sized>(Octs);
57
58impl CharStr<()> {
59    /// Character strings have a maximum length of 255 octets.
60    pub const MAX_LEN: usize = 255;
61}
62
63impl<Octs: ?Sized> CharStr<Octs> {
64    /// Creates a new empty character string.
65    #[must_use]
66    pub fn empty() -> Self
67    where
68        Octs: From<&'static [u8]>,
69    {
70        CharStr(b"".as_ref().into())
71    }
72
73    /// Creates a new character string from an octets value.
74    ///
75    /// Returns succesfully if `octets` can indeed be used as a
76    /// character string, i.e., it is not longer than 255 bytes.
77    pub fn from_octets(octets: Octs) -> Result<Self, CharStrError>
78    where
79        Octs: AsRef<[u8]> + Sized,
80    {
81        CharStr::check_slice(octets.as_ref())?;
82        Ok(unsafe { Self::from_octets_unchecked(octets) })
83    }
84
85    /// Creates a character string from octets without length check.
86    ///
87    /// # Safety
88    ///
89    /// The caller has to make sure that `octets` is at most 255 octets
90    /// long. Otherwise, the behavior is undefined.
91    pub unsafe fn from_octets_unchecked(octets: Octs) -> Self
92    where
93        Octs: Sized,
94    {
95        CharStr(octets)
96    }
97}
98
99impl CharStr<[u8]> {
100    /// Creates a character string from an octets slice.
101    pub fn from_slice(slice: &[u8]) -> Result<&Self, CharStrError> {
102        Self::check_slice(slice)?;
103        Ok(unsafe { Self::from_slice_unchecked(slice) })
104    }
105
106    /// Creates a new empty character string on an octets slice.
107    #[must_use]
108    pub fn empty_slice() -> &'static Self {
109        unsafe { Self::from_slice_unchecked(b"".as_ref()) }
110    }
111
112    /// Creates a character string from an octets slice without checking.
113    ///
114    /// # Safety
115    ///
116    /// The caller has to make sure that `octets` is at most 255 octets
117    /// long. Otherwise, the behaviour is undefined.
118    #[must_use]
119    pub unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
120        &*(slice as *const [u8] as *const Self)
121    }
122
123    /// Creates a character string from a mutable slice without checking.
124    ///
125    /// # Safety
126    ///
127    /// The caller has to make sure that `octets` is at most 255 octets
128    /// long. Otherwise, the behaviour is undefined.
129    unsafe fn from_slice_mut_unchecked(slice: &mut [u8]) -> &mut Self {
130        &mut *(slice as *mut [u8] as *mut Self)
131    }
132
133    /// Checks whether an octets slice contains a correct character string.
134    fn check_slice(slice: &[u8]) -> Result<(), CharStrError> {
135        if slice.len() > CharStr::MAX_LEN {
136            Err(CharStrError)
137        } else {
138            Ok(())
139        }
140    }
141}
142
143impl<Octs: ?Sized> CharStr<Octs> {
144    /// Creates a new empty builder for this character string type.
145    #[must_use]
146    pub fn builder() -> CharStrBuilder<Octs::Builder>
147    where
148        Octs: IntoBuilder,
149        Octs::Builder: EmptyBuilder,
150    {
151        CharStrBuilder::new()
152    }
153
154    /// Converts the character string into a builder.
155    pub fn into_builder(self) -> CharStrBuilder<Octs::Builder>
156    where
157        Octs: IntoBuilder + Sized,
158        <Octs as IntoBuilder>::Builder: AsRef<[u8]>,
159    {
160        unsafe {
161            CharStrBuilder::from_builder_unchecked(IntoBuilder::into_builder(
162                self.0,
163            ))
164        }
165    }
166
167    /// Converts the character string into its underlying octets value.
168    pub fn into_octets(self) -> Octs
169    where
170        Octs: Sized,
171    {
172        self.0
173    }
174
175    /// Returns a character string atop a slice of the content.
176    pub fn for_slice(&self) -> &CharStr<[u8]>
177    where
178        Octs: AsRef<[u8]>,
179    {
180        unsafe { CharStr::from_slice_unchecked(self.0.as_ref()) }
181    }
182
183    /// Returns a character string atop a mutable slice of the content.
184    pub fn for_slice_mut(&mut self) -> &mut CharStr<[u8]>
185    where
186        Octs: AsMut<[u8]>,
187    {
188        unsafe { CharStr::from_slice_mut_unchecked(self.0.as_mut()) }
189    }
190
191    /// Returns a reference to a slice of the character string’s data.
192    pub fn as_slice(&self) -> &[u8]
193    where
194        Octs: AsRef<[u8]>,
195    {
196        self.0.as_ref()
197    }
198
199    /// Returns a reference to a mutable slice of the character string’s data.
200    pub fn as_slice_mut(&mut self) -> &mut [u8]
201    where
202        Octs: AsMut<[u8]>,
203    {
204        self.0.as_mut()
205    }
206
207    /// Parses a character string from the beginning of a parser.
208    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
209        parser: &mut Parser<'a, Src>,
210    ) -> Result<Self, ParseError>
211    where
212        Octs: Sized,
213    {
214        let len = parser.parse_u8()? as usize;
215        parser
216            .parse_octets(len)
217            .map(|bytes| unsafe { Self::from_octets_unchecked(bytes) })
218            .map_err(Into::into)
219    }
220}
221
222impl<Octs: AsRef<[u8]> + ?Sized> CharStr<Octs> {
223    /// Returns the length of the character string.
224    ///
225    /// This is the length of the content only, i.e., without the extra
226    /// length octet added for the wire format.
227    pub fn len(&self) -> usize {
228        self.as_slice().len()
229    }
230
231    /// Returns whether the character string is empty.
232    pub fn is_empty(&self) -> bool {
233        self.as_slice().is_empty()
234    }
235
236    /// Returns an iterator over the octets of the character string.
237    pub fn iter(&self) -> Iter {
238        Iter {
239            octets: self.as_slice(),
240        }
241    }
242}
243
244impl CharStr<[u8]> {
245    /// Skips over a character string at the beginning of a parser.
246    pub fn skip<Src: Octets + ?Sized>(
247        parser: &mut Parser<Src>,
248    ) -> Result<(), ParseError> {
249        let len = parser.parse_u8()?;
250        parser.advance(len.into()).map_err(Into::into)
251    }
252}
253
254impl<Octs: AsRef<[u8]> + ?Sized> CharStr<Octs> {
255    /// Returns the length of the wire format representation.
256    pub fn compose_len(&self) -> u16 {
257        u16::try_from(self.0.as_ref().len() + 1).expect("long charstr")
258    }
259
260    /// Appends the wire format representation to an octets builder.
261    pub fn compose<Target: OctetsBuilder + ?Sized>(
262        &self,
263        target: &mut Target,
264    ) -> Result<(), Target::AppendError> {
265        u8::try_from(self.0.as_ref().len())
266            .expect("long charstr")
267            .compose(target)?;
268        target.append_slice(self.0.as_ref())
269    }
270}
271
272impl<Octets> CharStr<Octets> {
273    /// Scans the presentation format from a scanner.
274    pub fn scan<S: Scanner<Octets = Octets>>(
275        scanner: &mut S,
276    ) -> Result<Self, S::Error> {
277        scanner.scan_charstr()
278    }
279}
280
281//--- OctetsFrom
282
283impl<Octs, SrcOcts> OctetsFrom<CharStr<SrcOcts>> for CharStr<Octs>
284where
285    Octs: OctetsFrom<SrcOcts>,
286{
287    type Error = Octs::Error;
288
289    fn try_octets_from(
290        source: CharStr<SrcOcts>,
291    ) -> Result<Self, Self::Error> {
292        Octs::try_octets_from(source.0)
293            .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
294    }
295}
296
297//--- FromStr
298
299impl<Octets> str::FromStr for CharStr<Octets>
300where
301    Octets: FromBuilder,
302    <Octets as FromBuilder>::Builder: OctetsBuilder
303        + FreezeBuilder<Octets = Octets>
304        + EmptyBuilder
305        + AsRef<[u8]>,
306{
307    type Err = FromStrError;
308
309    fn from_str(s: &str) -> Result<Self, Self::Err> {
310        // Most likely, everything is ASCII so take `s`’s length as capacity.
311        let mut builder =
312            CharStrBuilder::<<Octets as FromBuilder>::Builder>::with_capacity(
313                s.len(),
314            );
315        let mut chars = s.chars();
316        while let Some(symbol) = Symbol::from_chars(&mut chars)? {
317            if builder.len() == CharStr::MAX_LEN {
318                return Err(FromStrError::LongString);
319            }
320            builder.append_slice(&[symbol.into_octet()?])?
321        }
322        Ok(builder.finish())
323    }
324}
325
326//--- AsRef and AsMut
327//
328// No Borrow as character strings compare ignoring case.
329
330impl<Octets: AsRef<U> + ?Sized, U: ?Sized> AsRef<U> for CharStr<Octets> {
331    fn as_ref(&self) -> &U {
332        self.0.as_ref()
333    }
334}
335
336impl<Octets: AsMut<U> + ?Sized, U: ?Sized> AsMut<U> for CharStr<Octets> {
337    fn as_mut(&mut self) -> &mut U {
338        self.0.as_mut()
339    }
340}
341
342//--- PartialEq and Eq
343
344impl<T, U> PartialEq<U> for CharStr<T>
345where
346    T: AsRef<[u8]> + ?Sized,
347    U: AsRef<[u8]> + ?Sized,
348{
349    fn eq(&self, other: &U) -> bool {
350        self.as_slice().eq_ignore_ascii_case(other.as_ref())
351    }
352}
353
354impl<T: AsRef<[u8]> + ?Sized> Eq for CharStr<T> {}
355
356//--- PartialOrd, Ord, and CanonicalOrd
357
358impl<T, U> PartialOrd<U> for CharStr<T>
359where
360    T: AsRef<[u8]> + ?Sized,
361    U: AsRef<[u8]> + ?Sized,
362{
363    fn partial_cmp(&self, other: &U) -> Option<cmp::Ordering> {
364        self.0
365            .as_ref()
366            .iter()
367            .map(u8::to_ascii_lowercase)
368            .partial_cmp(other.as_ref().iter().map(u8::to_ascii_lowercase))
369    }
370}
371
372impl<T: AsRef<[u8]> + ?Sized> Ord for CharStr<T> {
373    fn cmp(&self, other: &Self) -> cmp::Ordering {
374        self.0
375            .as_ref()
376            .iter()
377            .map(u8::to_ascii_lowercase)
378            .cmp(other.0.as_ref().iter().map(u8::to_ascii_lowercase))
379    }
380}
381
382impl<T, U> CanonicalOrd<CharStr<U>> for CharStr<T>
383where
384    T: AsRef<[u8]> + ?Sized,
385    U: AsRef<[u8]> + ?Sized,
386{
387    fn canonical_cmp(&self, other: &CharStr<U>) -> cmp::Ordering {
388        match self.0.as_ref().len().cmp(&other.0.as_ref().len()) {
389            cmp::Ordering::Equal => {}
390            other => return other,
391        }
392        self.as_slice().cmp(other.as_slice())
393    }
394}
395
396//--- Hash
397
398impl<T: AsRef<[u8]> + ?Sized> hash::Hash for CharStr<T> {
399    fn hash<H: hash::Hasher>(&self, state: &mut H) {
400        self.0
401            .as_ref()
402            .iter()
403            .map(u8::to_ascii_lowercase)
404            .for_each(|ch| ch.hash(state))
405    }
406}
407
408//--- Display and Debug
409
410impl<T: AsRef<[u8]> + ?Sized> fmt::Display for CharStr<T> {
411    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
412        for &ch in self.0.as_ref() {
413            fmt::Display::fmt(&Symbol::from_octet(ch), f)?;
414        }
415        Ok(())
416    }
417}
418
419impl<T: AsRef<[u8]> + ?Sized> fmt::LowerHex for CharStr<T> {
420    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
421        for ch in self.0.as_ref() {
422            write!(f, "{:02x}", ch)?;
423        }
424        Ok(())
425    }
426}
427
428impl<T: AsRef<[u8]> + ?Sized> fmt::UpperHex for CharStr<T> {
429    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
430        for ch in self.0.as_ref() {
431            write!(f, "{:02X}", ch)?;
432        }
433        Ok(())
434    }
435}
436
437impl<T: AsRef<[u8]> + ?Sized> fmt::Debug for CharStr<T> {
438    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
439        f.debug_tuple("CharStr")
440            .field(&format_args!("{}", self))
441            .finish()
442    }
443}
444
445//--- IntoIterator
446
447impl<T: AsRef<[u8]>> IntoIterator for CharStr<T> {
448    type Item = u8;
449    type IntoIter = IntoIter<T>;
450
451    fn into_iter(self) -> Self::IntoIter {
452        IntoIter::new(self.0)
453    }
454}
455
456impl<'a, T: AsRef<[u8]> + ?Sized + 'a> IntoIterator for &'a CharStr<T> {
457    type Item = u8;
458    type IntoIter = Iter<'a>;
459
460    fn into_iter(self) -> Self::IntoIter {
461        Iter::new(self.0.as_ref())
462    }
463}
464
465//--- Serialize and Deserialize
466
467#[cfg(feature = "serde")]
468impl<T> serde::Serialize for CharStr<T>
469where
470    T: AsRef<[u8]> + SerializeOctets + ?Sized,
471{
472    fn serialize<S: serde::Serializer>(
473        &self,
474        serializer: S,
475    ) -> Result<S::Ok, S::Error> {
476        if serializer.is_human_readable() {
477            serializer.serialize_newtype_struct(
478                "CharStr",
479                &format_args!("{}", self),
480            )
481        } else {
482            serializer.serialize_newtype_struct(
483                "CharStr",
484                &self.0.as_serialized_octets(),
485            )
486        }
487    }
488}
489
490#[cfg(feature = "serde")]
491impl<'de, Octets> serde::Deserialize<'de> for CharStr<Octets>
492where
493    Octets: FromBuilder + DeserializeOctets<'de>,
494    <Octets as FromBuilder>::Builder: OctetsBuilder
495        + FreezeBuilder<Octets = Octets>
496        + EmptyBuilder
497        + AsRef<[u8]>,
498{
499    fn deserialize<D: serde::Deserializer<'de>>(
500        deserializer: D,
501    ) -> Result<Self, D::Error> {
502        use core::marker::PhantomData;
503        use core::str::FromStr;
504
505        struct InnerVisitor<'de, T: DeserializeOctets<'de>>(T::Visitor);
506
507        impl<'de, Octets> serde::de::Visitor<'de> for InnerVisitor<'de, Octets>
508        where
509            Octets: FromBuilder + DeserializeOctets<'de>,
510            <Octets as FromBuilder>::Builder: OctetsBuilder
511                + FreezeBuilder<Octets = Octets>
512                + EmptyBuilder
513                + AsRef<[u8]>,
514        {
515            type Value = CharStr<Octets>;
516
517            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
518                f.write_str("a character string")
519            }
520
521            fn visit_str<E: serde::de::Error>(
522                self,
523                v: &str,
524            ) -> Result<Self::Value, E> {
525                CharStr::from_str(v).map_err(E::custom)
526            }
527
528            fn visit_borrowed_bytes<E: serde::de::Error>(
529                self,
530                value: &'de [u8],
531            ) -> Result<Self::Value, E> {
532                self.0.visit_borrowed_bytes(value).and_then(|octets| {
533                    CharStr::from_octets(octets).map_err(E::custom)
534                })
535            }
536
537            #[cfg(feature = "std")]
538            fn visit_byte_buf<E: serde::de::Error>(
539                self,
540                value: std::vec::Vec<u8>,
541            ) -> Result<Self::Value, E> {
542                self.0.visit_byte_buf(value).and_then(|octets| {
543                    CharStr::from_octets(octets).map_err(E::custom)
544                })
545            }
546        }
547
548        struct NewtypeVisitor<T>(PhantomData<T>);
549
550        impl<'de, Octets> serde::de::Visitor<'de> for NewtypeVisitor<Octets>
551        where
552            Octets: FromBuilder + DeserializeOctets<'de>,
553            <Octets as FromBuilder>::Builder: OctetsBuilder
554                + FreezeBuilder<Octets = Octets>
555                + EmptyBuilder
556                + AsRef<[u8]>,
557        {
558            type Value = CharStr<Octets>;
559
560            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
561                f.write_str("a character string")
562            }
563
564            fn visit_newtype_struct<D: serde::Deserializer<'de>>(
565                self,
566                deserializer: D,
567            ) -> Result<Self::Value, D::Error> {
568                if deserializer.is_human_readable() {
569                    deserializer
570                        .deserialize_str(InnerVisitor(Octets::visitor()))
571                } else {
572                    Octets::deserialize_with_visitor(
573                        deserializer,
574                        InnerVisitor(Octets::visitor()),
575                    )
576                }
577            }
578        }
579
580        deserializer.deserialize_newtype_struct(
581            "CharStr",
582            NewtypeVisitor(PhantomData),
583        )
584    }
585}
586
587//------------ CharStrBuilder ------------------------------------------------
588
589/// A builder for a character string.
590///
591/// This type wraps an [`OctetsBuilder`] and in turn implements the
592/// [`OctetsBuilder`] trait, making sure that the content cannot grow beyond
593/// the 255 octet limit of a character string.
594#[derive(Clone)]
595pub struct CharStrBuilder<Builder>(Builder);
596
597impl<Builder: EmptyBuilder> CharStrBuilder<Builder> {
598    /// Creates a new empty builder with default capacity.
599    #[must_use]
600    pub fn new() -> Self {
601        CharStrBuilder(Builder::empty())
602    }
603
604    /// Creates a new empty builder with the given capacity.
605    #[must_use]
606    pub fn with_capacity(capacity: usize) -> Self {
607        CharStrBuilder(Builder::with_capacity(capacity))
608    }
609}
610
611impl<Builder: OctetsBuilder + AsRef<[u8]>> CharStrBuilder<Builder> {
612    /// Creates a character string builder from an octet sequence unchecked.
613    ///
614    /// Since the buffer may already be longer than it is allowed to be, this
615    /// is unsafe.
616    unsafe fn from_builder_unchecked(builder: Builder) -> Self {
617        CharStrBuilder(builder)
618    }
619
620    /// Creates a character string builder from an octet sequence.
621    ///
622    /// If the octet sequence is longer than 255 octets, an error is
623    /// returned.
624    pub fn from_builder(builder: Builder) -> Result<Self, CharStrError> {
625        if builder.as_ref().len() > CharStr::MAX_LEN {
626            Err(CharStrError)
627        } else {
628            Ok(unsafe { Self::from_builder_unchecked(builder) })
629        }
630    }
631}
632
633#[cfg(feature = "std")]
634impl CharStrBuilder<Vec<u8>> {
635    /// Creates a new empty characater string builder atop an octets vec.
636    #[must_use]
637    pub fn new_vec() -> Self {
638        Self::new()
639    }
640
641    /// Creates a new empty builder atop an octets vec with a given capacity.
642    #[must_use]
643    pub fn vec_with_capacity(capacity: usize) -> Self {
644        Self::with_capacity(capacity)
645    }
646}
647
648#[cfg(feature = "bytes")]
649impl CharStrBuilder<BytesMut> {
650    /// Creates a new empty builder for a bytes value.
651    pub fn new_bytes() -> Self {
652        Self::new()
653    }
654
655    /// Creates a new empty builder for a bytes value with a given capacity.
656    pub fn bytes_with_capacity(capacity: usize) -> Self {
657        Self::with_capacity(capacity)
658    }
659}
660
661impl<Builder> CharStrBuilder<Builder> {
662    /// Returns an octet slice of the string assembled so far.
663    pub fn as_slice(&self) -> &[u8]
664    where
665        Builder: AsRef<[u8]>,
666    {
667        self.0.as_ref()
668    }
669
670    /// Converts the builder into an imutable character string.
671    pub fn finish(self) -> CharStr<Builder::Octets>
672    where
673        Builder: FreezeBuilder,
674    {
675        unsafe { CharStr::from_octets_unchecked(self.0.freeze()) }
676    }
677}
678
679impl<Builder: AsRef<[u8]>> CharStrBuilder<Builder> {
680    /// Returns the length of the assembled character string.
681    ///
682    /// This is the length of the content only, i.e., without the extra
683    /// length octet added for the wire format.
684    pub fn len(&self) -> usize {
685        self.as_slice().len()
686    }
687
688    /// Returns whether the character string is empty.
689    pub fn is_empty(&self) -> bool {
690        self.as_slice().is_empty()
691    }
692}
693
694//--- Default
695
696impl<Builder: EmptyBuilder> Default for CharStrBuilder<Builder> {
697    fn default() -> Self {
698        Self::new()
699    }
700}
701
702//--- OctetsBuilder and Truncate
703
704impl<Builder> OctetsBuilder for CharStrBuilder<Builder>
705where
706    Builder: OctetsBuilder + AsRef<[u8]>,
707{
708    type AppendError = ShortBuf;
709
710    fn append_slice(
711        &mut self,
712        slice: &[u8],
713    ) -> Result<(), Self::AppendError> {
714        if self.0.as_ref().len() + slice.len() > CharStr::MAX_LEN {
715            return Err(ShortBuf);
716        }
717        self.0.append_slice(slice).map_err(Into::into)
718    }
719}
720
721impl<Builder: Truncate> Truncate for CharStrBuilder<Builder> {
722    fn truncate(&mut self, len: usize) {
723        self.0.truncate(len)
724    }
725}
726
727//--- AsRef and AsMut
728
729impl<Builder: AsRef<[u8]>> AsRef<[u8]> for CharStrBuilder<Builder> {
730    fn as_ref(&self) -> &[u8] {
731        self.0.as_ref()
732    }
733}
734
735impl<Builder: AsMut<[u8]>> AsMut<[u8]> for CharStrBuilder<Builder> {
736    fn as_mut(&mut self) -> &mut [u8] {
737        self.0.as_mut()
738    }
739}
740
741//------------ IntoIter ------------------------------------------------------
742
743/// The iterator type for `IntoIterator` for a character string itself.
744pub struct IntoIter<T> {
745    octets: T,
746    len: usize,
747    pos: usize,
748}
749
750impl<T: AsRef<[u8]>> IntoIter<T> {
751    pub(crate) fn new(octets: T) -> Self {
752        IntoIter {
753            len: octets.as_ref().len(),
754            octets,
755            pos: 0,
756        }
757    }
758}
759
760impl<T: AsRef<[u8]>> Iterator for IntoIter<T> {
761    type Item = u8;
762
763    fn next(&mut self) -> Option<Self::Item> {
764        if self.pos == self.len {
765            None
766        } else {
767            let res = self.octets.as_ref()[self.pos];
768            self.pos += 1;
769            Some(res)
770        }
771    }
772}
773
774//------------ Iter ----------------------------------------------------------
775
776/// The iterator type for `IntoIterator` for a reference to a character string.
777pub struct Iter<'a> {
778    octets: &'a [u8],
779}
780
781impl<'a> Iter<'a> {
782    pub(crate) fn new(octets: &'a [u8]) -> Self {
783        Iter { octets }
784    }
785}
786
787impl<'a> Iterator for Iter<'a> {
788    type Item = u8;
789
790    fn next(&mut self) -> Option<Self::Item> {
791        let (res, octets) = self.octets.split_first()?;
792        self.octets = octets;
793        Some(*res)
794    }
795}
796
797//============ Error Types ===================================================
798
799//------------ CharStrError --------------------------------------------------
800
801/// A byte sequence does not represent a valid character string.
802///
803/// This can only mean that the sequence is longer than 255 bytes.
804#[derive(Clone, Copy, Debug, Eq, PartialEq)]
805pub struct CharStrError;
806
807impl fmt::Display for CharStrError {
808    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
809        f.write_str("long character string")
810    }
811}
812
813#[cfg(feature = "std")]
814impl std::error::Error for CharStrError {}
815
816//------------ FromStrError --------------------------------------------
817
818/// An error happened when converting a Rust string to a DNS character string.
819#[derive(Clone, Copy, Debug, Eq, PartialEq)]
820#[non_exhaustive]
821pub enum FromStrError {
822    /// A character string has more than 255 octets.
823    LongString,
824
825    SymbolChars(SymbolCharsError),
826
827    /// An illegal character was encountered.
828    ///
829    /// Only printable ASCII characters are allowed.
830    BadSymbol(BadSymbol),
831
832    /// The octet builder’s buffer was too short for the data.
833    ShortBuf,
834}
835
836//--- From
837
838impl From<SymbolCharsError> for FromStrError {
839    fn from(err: SymbolCharsError) -> FromStrError {
840        FromStrError::SymbolChars(err)
841    }
842}
843
844impl From<BadSymbol> for FromStrError {
845    fn from(err: BadSymbol) -> FromStrError {
846        FromStrError::BadSymbol(err)
847    }
848}
849
850impl From<ShortBuf> for FromStrError {
851    fn from(_: ShortBuf) -> FromStrError {
852        FromStrError::ShortBuf
853    }
854}
855
856//--- Display and Error
857
858impl fmt::Display for FromStrError {
859    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
860        match *self {
861            FromStrError::LongString => {
862                f.write_str("character string with more than 255 octets")
863            }
864            FromStrError::SymbolChars(ref err) => err.fmt(f),
865            FromStrError::BadSymbol(ref err) => err.fmt(f),
866            FromStrError::ShortBuf => ShortBuf.fmt(f),
867        }
868    }
869}
870
871#[cfg(feature = "std")]
872impl std::error::Error for FromStrError {}
873
874//============ Testing =======================================================
875
876#[cfg(test)]
877#[cfg(feature = "std")]
878mod test {
879    use super::*;
880    use octseq::builder::infallible;
881    use std::vec::Vec;
882
883    type CharStrRef<'a> = CharStr<&'a [u8]>;
884
885    #[test]
886    fn from_slice() {
887        assert_eq!(
888            CharStr::from_slice(b"01234").unwrap().as_slice(),
889            b"01234"
890        );
891        assert_eq!(CharStr::from_slice(b"").unwrap().as_slice(), b"");
892        assert!(CharStr::from_slice(&vec![0; 255]).is_ok());
893        assert!(CharStr::from_slice(&vec![0; 256]).is_err());
894    }
895
896    #[test]
897    fn from_octets() {
898        assert_eq!(
899            CharStr::from_octets("01234").unwrap().as_slice(),
900            b"01234"
901        );
902        assert_eq!(CharStr::from_octets("").unwrap().as_slice(), b"");
903        assert!(CharStr::from_octets(vec![0; 255]).is_ok());
904        assert!(CharStr::from_octets(vec![0; 256]).is_err());
905    }
906
907    #[test]
908    fn from_str() {
909        use std::str::{from_utf8, FromStr};
910
911        type Cs = CharStr<Vec<u8>>;
912
913        assert_eq!(Cs::from_str("foo").unwrap().as_slice(), b"foo");
914        assert_eq!(Cs::from_str("f\\oo").unwrap().as_slice(), b"foo");
915        assert_eq!(Cs::from_str("foo\\112").unwrap().as_slice(), b"foo\x70");
916        assert_eq!(
917            Cs::from_str("\"foo\\\"2\"").unwrap().as_slice(),
918            b"\"foo\"2\""
919        );
920        assert_eq!(Cs::from_str("06 dii").unwrap().as_slice(), b"06 dii");
921        assert!(Cs::from_str("0\\").is_err());
922        assert!(Cs::from_str("0\\2").is_err());
923        assert!(Cs::from_str("0\\2a").is_err());
924        assert!(Cs::from_str("ö").is_err());
925        assert!(Cs::from_str("\x06").is_err());
926        assert!(Cs::from_str(from_utf8(&[b'a'; 256]).unwrap()).is_err());
927    }
928
929    #[test]
930    fn parse() {
931        let mut parser = Parser::from_static(b"12\x03foo\x02bartail");
932        parser.advance(2).unwrap();
933        let foo = CharStrRef::parse(&mut parser).unwrap();
934        let bar = CharStrRef::parse(&mut parser).unwrap();
935        assert_eq!(foo.as_slice(), b"foo");
936        assert_eq!(bar.as_slice(), b"ba");
937        assert_eq!(parser.peek_all(), b"rtail");
938
939        assert!(
940            CharStrRef::parse(&mut Parser::from_static(b"\x04foo")).is_err(),
941        )
942    }
943
944    #[test]
945    fn compose() {
946        let mut target = Vec::new();
947        let val = CharStr::from_slice(b"foo").unwrap();
948        infallible(val.compose(&mut target));
949        assert_eq!(target, b"\x03foo".as_ref());
950
951        let mut target = Vec::new();
952        let val = CharStr::from_slice(b"").unwrap();
953        infallible(val.compose(&mut target));
954        assert_eq!(target, &b"\x00"[..]);
955    }
956
957    fn are_eq(l: &[u8], r: &[u8]) -> bool {
958        CharStr::from_slice(l).unwrap() == CharStr::from_slice(r).unwrap()
959    }
960
961    #[test]
962    fn eq() {
963        assert!(are_eq(b"abc", b"abc"));
964        assert!(!are_eq(b"abc", b"def"));
965        assert!(!are_eq(b"abc", b"ab"));
966        assert!(!are_eq(b"abc", b"abcd"));
967        assert!(are_eq(b"ABC", b"abc"));
968        assert!(!are_eq(b"ABC", b"def"));
969        assert!(!are_eq(b"ABC", b"ab"));
970        assert!(!are_eq(b"ABC", b"abcd"));
971        assert!(are_eq(b"", b""));
972        assert!(!are_eq(b"", b"A"));
973    }
974
975    fn is_ord(l: &[u8], r: &[u8], order: cmp::Ordering) {
976        assert_eq!(
977            CharStr::from_slice(l)
978                .unwrap()
979                .cmp(CharStr::from_slice(r).unwrap()),
980            order
981        )
982    }
983
984    #[test]
985    fn ord() {
986        use std::cmp::Ordering::*;
987
988        is_ord(b"abc", b"ABC", Equal);
989        is_ord(b"abc", b"a", Greater);
990        is_ord(b"abc", b"A", Greater);
991        is_ord(b"a", b"BC", Less);
992    }
993
994    #[test]
995    fn append_slice() {
996        let mut o = CharStrBuilder::new_vec();
997        o.append_slice(b"foo").unwrap();
998        assert_eq!(o.finish().as_slice(), b"foo");
999
1000        let mut o = CharStrBuilder::from_builder(vec![0; 254]).unwrap();
1001        o.append_slice(b"f").unwrap();
1002        assert_eq!(o.len(), 255);
1003        assert!(o.append_slice(b"f").is_err());
1004
1005        let mut o =
1006            CharStrBuilder::from_builder(vec![b'f', b'o', b'o']).unwrap();
1007        o.append_slice(b"bar").unwrap();
1008        assert_eq!(o.as_ref(), b"foobar");
1009        assert!(o.append_slice(&[0u8; 250][..]).is_err());
1010        o.append_slice(&[0u8; 249][..]).unwrap();
1011        assert_eq!(o.len(), 255);
1012    }
1013
1014    #[cfg(feature = "serde")]
1015    #[test]
1016    fn ser_de() {
1017        use serde_test::{assert_tokens, Configure, Token};
1018
1019        assert_tokens(
1020            &CharStr::from_octets(vec![b'f', b'o', 0x12])
1021                .unwrap()
1022                .compact(),
1023            &[
1024                Token::NewtypeStruct { name: "CharStr" },
1025                Token::ByteBuf(b"fo\x12"),
1026            ],
1027        );
1028
1029        assert_tokens(
1030            &CharStr::from_octets(vec![b'f', b'o', 0x12])
1031                .unwrap()
1032                .readable(),
1033            &[
1034                Token::NewtypeStruct { name: "CharStr" },
1035                Token::Str("fo\\018"),
1036            ],
1037        );
1038    }
1039}