diff --git a/src/base/charstr.rs b/src/base/charstr.rs index 13fd11c7..0fc5f8ab 100644 --- a/src/base/charstr.rs +++ b/src/base/charstr.rs @@ -27,7 +27,7 @@ use super::cmp::CanonicalOrd; use super::scan::{BadSymbol, Scanner, Symbol, SymbolCharsError}; use super::wire::{Compose, ParseError}; #[cfg(feature = "bytes")] -use bytes::{Bytes, BytesMut}; +use bytes::BytesMut; use core::{cmp, fmt, hash, ops, str}; use octseq::builder::FreezeBuilder; #[cfg(feature = "serde")] @@ -72,11 +72,8 @@ impl CharStr { where Octs: AsRef<[u8]> + Sized, { - if octets.as_ref().len() > 255 { - Err(CharStrError) - } else { - Ok(unsafe { Self::from_octets_unchecked(octets) }) - } + CharStr::check_slice(octets.as_ref())?; + Ok(unsafe { Self::from_octets_unchecked(octets) }) } /// Creates a character string from octets without length check. @@ -84,14 +81,58 @@ impl CharStr { /// # Safety /// /// The caller has to make sure that `octets` is at most 255 octets - /// long. Otherwise, the behaviour is undefined. + /// long. Otherwise, the behavior is undefined. pub unsafe fn from_octets_unchecked(octets: Octs) -> Self where Octs: Sized, { CharStr(octets) } +} +impl CharStr<[u8]> { + /// Creates a character string from an octets slice. + pub fn from_slice(slice: &[u8]) -> Result<&Self, CharStrError> { + Self::check_slice(slice)?; + Ok(unsafe { Self::from_slice_unchecked(slice) }) + } + + /// Creates a new empty character string on an octets slice. + pub fn empty_slice() -> &'static Self { + unsafe { Self::from_slice_unchecked(b"".as_ref()) } + } + + /// Creates a character string from an octets slice without checking. + /// + /// # Safety + /// + /// The caller has to make sure that `octets` is at most 255 octets + /// long. Otherwise, the behaviour is undefined. + pub unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self { + &*(slice as *const [u8] as *const Self) + } + + /// Creates a character string from a mutable slice without checking. + /// + /// # Safety + /// + /// The caller has to make sure that `octets` is at most 255 octets + /// long. Otherwise, the behaviour is undefined. + unsafe fn from_slice_mut_unchecked(slice: &mut [u8]) -> &mut Self { + &mut *(slice as *mut [u8] as *mut Self) + } + + /// Checks whether an octets slice contains a correct character string. + fn check_slice(slice: &[u8]) -> Result<(), CharStrError> { + if slice.len() > 255 { + Err(CharStrError) + } else { + Ok(()) + } + } +} + +impl CharStr { /// Creates a new empty builder for this character string type. pub fn builder() -> CharStrBuilder where @@ -123,19 +164,19 @@ impl CharStr { } /// Returns a character string atop a slice of the content. - pub fn for_slice(&self) -> CharStr<&[u8]> + pub fn for_slice(&self) -> &CharStr<[u8]> where Octs: AsRef<[u8]>, { - unsafe { CharStr::from_octets_unchecked(self.0.as_ref()) } + unsafe { CharStr::from_slice_unchecked(self.0.as_ref()) } } /// Returns a character string atop a mutable slice of the content. - pub fn for_slice_mut(&mut self) -> CharStr<&mut [u8]> + pub fn for_slice_mut(&mut self) -> &mut CharStr<[u8]> where Octs: AsMut<[u8]>, { - unsafe { CharStr::from_octets_unchecked(self.0.as_mut()) } + unsafe { CharStr::from_slice_mut_unchecked(self.0.as_mut()) } } /// Returns a reference to a slice of the character string’s data. @@ -206,36 +247,6 @@ impl CharStr { } } -#[cfg(feature = "bytes")] -#[cfg_attr(docsrs, doc(cfg(feature = "bytes")))] -impl CharStr { - /// Creates a new character string from a bytes value. - /// - /// Returns succesfully if the bytes slice can indeed be used as a - /// character string, i.e., it is not longer than 255 bytes. - pub fn from_bytes(bytes: Bytes) -> Result { - if bytes.len() > 255 { - Err(CharStrError) - } else { - Ok(unsafe { Self::from_octets_unchecked(bytes) }) - } - } -} - -impl CharStr<[u8]> { - /// Creates a new character string from an octet slice. - /// - /// If the byte slice is longer than 255 bytes, the function will return - /// an error. - pub fn from_slice(slice: &[u8]) -> Result<&Self, CharStrError> { - if slice.len() > 255 { - Err(CharStrError) - } else { - Ok(unsafe { &*(slice as *const [u8] as *const CharStr<[u8]>) }) - } - } -} - //--- OctetsFrom impl OctetsFrom> for CharStr @@ -282,6 +293,8 @@ where } //--- Deref and AsRef +// +// No Borrow as character strings compare ignoring case. impl ops::Deref for CharStr { type Target = Octets; @@ -375,7 +388,7 @@ impl + ?Sized> hash::Hash for CharStr { } } -//--- Display +//--- Display and Debug impl + ?Sized> fmt::Display for CharStr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -404,6 +417,14 @@ impl + ?Sized> fmt::UpperHex for CharStr { } } +impl + ?Sized> fmt::Debug for CharStr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("CharStr") + .field(&format_args!("{}", self)) + .finish() + } +} + //--- IntoIterator impl> IntoIterator for CharStr { @@ -424,20 +445,13 @@ impl<'a, T: AsRef<[u8]> + ?Sized + 'a> IntoIterator for &'a CharStr { } } -//--- Debug - -impl + ?Sized> fmt::Debug for CharStr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("CharStr") - .field(&format_args!("{}", self)) - .finish() - } -} - //--- Serialize and Deserialize #[cfg(feature = "serde")] -impl + SerializeOctets> serde::Serialize for CharStr { +impl serde::Serialize for CharStr +where + T: AsRef<[u8]> + SerializeOctets + ?Sized, +{ fn serialize( &self, serializer: S, @@ -775,7 +789,7 @@ pub struct CharStrError; impl fmt::Display for CharStrError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("illegal character string") + f.write_str("long character string") } } @@ -863,22 +877,14 @@ mod test { } #[test] - #[cfg(feature = "bytes")] - fn from_bytes() { + fn from_octets() { assert_eq!( - CharStr::from_bytes(bytes::Bytes::from_static(b"01234")) - .unwrap() - .as_slice(), + CharStr::from_octets("01234").unwrap().as_slice(), b"01234" ); - assert_eq!( - CharStr::from_bytes(bytes::Bytes::from_static(b"")) - .unwrap() - .as_slice(), - b"" - ); - assert!(CharStr::from_bytes(vec![0; 255].into()).is_ok()); - assert!(CharStr::from_bytes(vec![0; 256].into()).is_err()); + assert_eq!(CharStr::from_octets("").unwrap().as_slice(), b""); + assert!(CharStr::from_octets(vec![0; 255]).is_ok()); + assert!(CharStr::from_octets(vec![0; 256]).is_err()); } #[test] diff --git a/src/base/message.rs b/src/base/message.rs index b691c896..0d1ac9d7 100644 --- a/src/base/message.rs +++ b/src/base/message.rs @@ -22,7 +22,7 @@ use super::wire::{Composer, ParseError}; use crate::rdata::rfc1035::Cname; use core::marker::PhantomData; use core::{fmt, mem}; -use octseq::{Octets, OctetsFrom, Parser, ShortBuf}; +use octseq::{Octets, OctetsFrom, Parser}; //------------ Message ------------------------------------------------------- @@ -156,35 +156,67 @@ pub struct Message { /// # Creation and Conversion /// -impl Message { +impl Message { /// Creates a message from an octets sequence. /// /// This fails if the slice is too short to even contain a complete /// header section. No further checks are done, though, so if this /// function returns ok, the message may still be broken with other /// methods returning errors later one. - pub fn from_octets(octets: Octs) -> Result + pub fn from_octets(octets: Octs) -> Result where - Octs: AsRef<[u8]> + Sized, + Octs: AsRef<[u8]>, { - if octets.as_ref().len() < mem::size_of::() { - Err(ShortBuf) - } else { - Ok(unsafe { Self::from_octets_unchecked(octets) }) - } + Message::check_slice(octets.as_ref())?; + Ok(unsafe { Self::from_octets_unchecked(octets) }) } /// Creates a message from a bytes value without checking. /// + /// # Safety + /// /// The methods for header access rely on the octets being at least as - /// long as a header, so this is unsafe. - pub(super) unsafe fn from_octets_unchecked(octets: Octs) -> Self - where - Octs: Sized, - { + /// long as a header. If the sequence is shorter, the behavior is + /// undefined. + pub(super) unsafe fn from_octets_unchecked(octets: Octs) -> Self { Message { octets } } +} +impl Message<[u8]> { + /// Creates a message from an octets slice. + /// + /// This fails if the slice is too short to even contain a complete + /// header section. No further checks are done, though, so if this + /// function returns ok, the message may still be broken with other + /// methods returning errors later one. + pub fn from_slice(slice: &[u8]) -> Result<&Self, ShortMessage> { + Message::check_slice(slice)?; + Ok(unsafe { Self::from_slice_unchecked(slice) }) + } + + /// Creates a message from a bytes value without checking. + /// + /// # Safety + /// + /// The methods for header access rely on the octets being at least as + /// long as a header. If the sequence is shorter, the behavior is + /// undefined. + unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self { + &*(slice as *const [u8] as *const Self) + } + + /// Checks that the slice can be used for a message. + fn check_slice(slice: &[u8]) -> Result<(), ShortMessage> { + if slice.len() < mem::size_of::() { + Err(ShortMessage(())) + } else { + Ok(()) + } + } +} + +impl Message { /// Returns a reference to the underlying octets sequence. pub fn as_octets(&self) -> &Octs { &self.octets @@ -222,9 +254,7 @@ impl Message { where Octs: AsRef<[u8]>, { - unsafe { - &*(self.octets.as_ref() as *const [u8] as *const Message<[u8]>) - } + unsafe { Message::from_slice_unchecked(self.octets.as_ref()) } } } @@ -596,6 +626,9 @@ impl Message { //--- AsRef +// Octs here can’t be ?Sized or it’ll conflict with AsRef<[u8]> below. +// But [u8] is covered by that impl anyway, so no harm done. +// impl AsRef for Message { fn as_ref(&self) -> &Octs { &self.octets @@ -931,7 +964,7 @@ impl<'a, Octs: Octets + ?Sized> RecordSection<'a, Octs> { } } -//--- Clone +//--- Clone and Copy impl<'a, Octs: ?Sized> Clone for RecordSection<'a, Octs> { fn clone(&self) -> Self { @@ -1103,6 +1136,21 @@ where //============ Error Types =================================================== +//------------ ShortMessage -------------------------------------------------- + +/// A message was too short to even contain the header. +#[derive(Clone, Copy, Debug)] +pub struct ShortMessage(()); + +impl fmt::Display for ShortMessage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("short message") + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ShortMessage {} + //------------ CopyRecordsError ---------------------------------------------- /// An error occurrd while copying records. diff --git a/src/base/message_builder.rs b/src/base/message_builder.rs index 0c9b235a..f02db5ae 100644 --- a/src/base/message_builder.rs +++ b/src/base/message_builder.rs @@ -234,7 +234,7 @@ impl MessageBuilder { /// /// The method converts the message builder into an answer builder ready /// to receive the answer for the question. - pub fn start_answer( + pub fn start_answer( mut self, msg: &Message, rcode: Rcode, @@ -1505,12 +1505,12 @@ where /// header values of the record and push options to the record data. /// /// [`AdditionalBuilder::opt`]: struct.AdditonalBuilder.html#method.opt -pub struct OptBuilder<'a, Target: AsRef<[u8]> + AsMut<[u8]>> { +pub struct OptBuilder<'a, Target: ?Sized> { start: usize, target: &'a mut Target, } -impl<'a, Target: Composer> OptBuilder<'a, Target> { +impl<'a, Target: Composer + ?Sized> OptBuilder<'a, Target> { /// Creates a new opt builder atop an additional builder. fn new(target: &'a mut Target) -> Result { let start = target.as_ref().len(); @@ -1544,7 +1544,7 @@ impl<'a, Target: Composer> OptBuilder<'a, Target> { } /// Appends an option to the OPT record. - pub fn push( + pub fn push( &mut self, opt: &Opt, ) -> Result<(), Target::AppendError> { diff --git a/src/base/name/dname.rs b/src/base/name/dname.rs index e8123e5a..e6eac8c4 100644 --- a/src/base/name/dname.rs +++ b/src/base/name/dname.rs @@ -13,7 +13,7 @@ use super::traits::{ToDname, ToLabelIter}; use bytes::Bytes; use core::ops::{Bound, RangeBounds}; use core::str::FromStr; -use core::{cmp, fmt, hash, ops, str}; +use core::{cmp, fmt, hash, str}; use octseq::builder::{EmptyBuilder, FreezeBuilder, FromBuilder, Truncate}; use octseq::octets::{Octets, OctetsFrom}; use octseq::parse::Parser; @@ -258,11 +258,11 @@ impl Dname { } /// Returns a domain name for the octets slice of the content. - pub fn for_slice(&self) -> Dname<&[u8]> + pub fn for_slice(&self) -> &Dname<[u8]> where Octs: AsRef<[u8]>, { - unsafe { Dname::from_octets_unchecked(self.0.as_ref()) } + unsafe { Dname::from_slice_unchecked(self.0.as_ref()) } } } @@ -275,6 +275,12 @@ impl + ?Sized> Dname { pub fn is_root(&self) -> bool { self.0.as_ref().len() == 1 } + + /// Returns the length of the domain name. + #[allow(clippy::len_without_is_empty)] // never empty ... + pub fn len(&self) -> usize { + self.0.as_ref().len() + } } /// # Working with Labels @@ -495,7 +501,7 @@ impl + ?Sized> Dname { } } -impl> Dname { +impl + ?Sized> Dname { /// Splits the name into two at the given position. /// /// Returns a pair of the left and right part of the split name. @@ -531,7 +537,7 @@ impl> Dname { /// it is out of bounds. pub fn truncate(mut self, len: usize) -> RelativeDname where - Octs: Truncate, + Octs: Truncate + Sized, { self.check_index(len); self.0.truncate(len); @@ -574,7 +580,7 @@ impl> Dname { base: &N, ) -> Result, Self> where - Octs: Truncate, + Octs: Truncate + Sized, { if self.ends_with(base) { let len = self.0.as_ref().len() - usize::from(base.compose_len()); @@ -620,18 +626,16 @@ impl Dname { } } -//--- Deref and AsRef +//--- AsRef -impl ops::Deref for Dname { - type Target = Octs; - - fn deref(&self) -> &Octs { +impl AsRef for Dname { + fn as_ref(&self) -> &Octs { &self.0 } } -impl + ?Sized, T: ?Sized> AsRef for Dname { - fn as_ref(&self) -> &T { +impl + ?Sized> AsRef<[u8]> for Dname { + fn as_ref(&self) -> &[u8] { self.0.as_ref() } } @@ -807,7 +811,7 @@ impl + ?Sized> fmt::Debug for Dname { #[cfg(feature = "serde")] impl serde::Serialize for Dname where - Octs: AsRef<[u8]> + SerializeOctets, + Octs: AsRef<[u8]> + SerializeOctets + ?Sized, { fn serialize( &self, diff --git a/src/base/name/relative.rs b/src/base/name/relative.rs index f5611bd0..a64f22ab 100644 --- a/src/base/name/relative.rs +++ b/src/base/name/relative.rs @@ -12,7 +12,7 @@ use super::traits::{ToLabelIter, ToRelativeDname}; use bytes::Bytes; use core::cmp::Ordering; use core::ops::{Bound, RangeBounds}; -use core::{cmp, fmt, hash, ops}; +use core::{cmp, fmt, hash}; #[cfg(feature = "serde")] use octseq::builder::{EmptyBuilder, FromBuilder}; use octseq::builder::{FreezeBuilder, IntoBuilder, Truncate}; @@ -206,11 +206,11 @@ impl RelativeDname { } /// Returns a domain name for the octets slice of the content. - pub fn for_slice(&self) -> RelativeDname<&[u8]> + pub fn for_slice(&self) -> &RelativeDname<[u8]> where Octs: AsRef<[u8]>, { - unsafe { RelativeDname::from_octets_unchecked(self.0.as_ref()) } + unsafe { RelativeDname::from_slice_unchecked(self.0.as_ref()) } } } @@ -270,6 +270,20 @@ impl RelativeDname { } } +/// # Properties +/// +impl + ?Sized> RelativeDname { + /// Returns the length of the name. + pub fn len(&self) -> usize { + self.0.as_ref().len() + } + + /// Returns whether the name is empty. + pub fn is_empty(&self) -> bool { + self.0.as_ref().is_empty() + } +} + /// # Working with Labels /// impl + ?Sized> RelativeDname { @@ -406,7 +420,7 @@ impl + ?Sized> RelativeDname { } } -impl> RelativeDname { +impl + ?Sized> RelativeDname { /// Splits the name into two at the given position. /// /// Returns a pair of the left and right part of the split name. @@ -500,18 +514,16 @@ impl> RelativeDname { } } -//--- Deref and AsRef +//--- AsRef -impl ops::Deref for RelativeDname { - type Target = Octs; - - fn deref(&self) -> &Octs { +impl AsRef for RelativeDname { + fn as_ref(&self) -> &Octs { &self.0 } } -impl + ?Sized, T: ?Sized> AsRef for RelativeDname { - fn as_ref(&self) -> &T { +impl + ?Sized> AsRef<[u8]> for RelativeDname { + fn as_ref(&self) -> &[u8] { self.0.as_ref() } } @@ -643,7 +655,7 @@ impl + ?Sized> fmt::Debug for RelativeDname { #[cfg(feature = "serde")] impl serde::Serialize for RelativeDname where - Octs: AsRef<[u8]> + SerializeOctets, + Octs: AsRef<[u8]> + SerializeOctets + ?Sized, { fn serialize( &self, diff --git a/src/base/name/uncertain.rs b/src/base/name/uncertain.rs index 94b36d34..f5ed6151 100644 --- a/src/base/name/uncertain.rs +++ b/src/base/name/uncertain.rs @@ -320,8 +320,17 @@ where //--- AsRef -impl, T> AsRef for UncertainDname { - fn as_ref(&self) -> &T { +impl AsRef for UncertainDname { + fn as_ref(&self) -> &Octs { + match *self { + UncertainDname::Absolute(ref name) => name.as_ref(), + UncertainDname::Relative(ref name) => name.as_ref(), + } + } +} + +impl> AsRef<[u8]> for UncertainDname { + fn as_ref(&self) -> &[u8] { match *self { UncertainDname::Absolute(ref name) => name.as_ref(), UncertainDname::Relative(ref name) => name.as_ref(), diff --git a/src/base/opt/mod.rs b/src/base/opt/mod.rs index 16cb077b..244b6d92 100644 --- a/src/base/opt/mod.rs +++ b/src/base/opt/mod.rs @@ -71,7 +71,7 @@ use octseq::parse::Parser; /// [`iter`]: #method.iter /// [`OptRecord`]: struct.OptRecord.html #[derive(Clone)] -pub struct Opt { +pub struct Opt { octets: Octs, } @@ -81,13 +81,54 @@ impl> Opt { /// The function checks whether the octets contain a sequence of /// options. It does not check whether the options themselves are valid. pub fn from_octets(octets: Octs) -> Result { - let mut parser = Parser::from_ref(octets.as_ref()); + Opt::check_slice(octets.as_ref())?; + Ok(Opt { octets }) + } + + /// Parses OPT record data from the beginning of a parser. + pub fn parse<'a, Src: Octets = Octs> + ?Sized>( + parser: &mut Parser<'a, Src>, + ) -> Result { + let len = parser.remaining(); + Self::from_octets(parser.parse_octets(len)?) + } +} + +impl Opt<[u8]> { + /// Creates OPT record data from an octets slice. + pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> { + Self::check_slice(slice)?; + Ok(unsafe { Self::from_slice_unchecked(slice) }) + } + + /// Creates OPT record data from an octets slice without checking. + /// + /// # Safety + /// + /// The caller needs to ensure that the slice contains correctly encoded + /// OPT record data. The data of the options themselves does not need to + /// be correct. + unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self { + &*(slice as *const [u8] as *const Self) + } + + /// Checks that the slice contains acceptable OPT record data. + fn check_slice(slice: &[u8]) -> Result<(), ParseError> { + let mut parser = Parser::from_ref(slice); while parser.remaining() > 0 { parser.advance(2)?; let len = parser.parse_u16()?; parser.advance(len as usize)?; } - Ok(Opt { octets }) + Ok(()) + } +} + +impl + ?Sized> Opt { + /// Returns the length of the OPT record data. + #[allow(clippy::len_without_is_empty)] // never empty. + pub fn len(&self) -> usize { + self.octets.as_ref().len() } /// Returns an iterator over options of a given type. @@ -101,13 +142,6 @@ impl> Opt { { OptIter::new(&self.octets) } - - pub fn parse<'a, Src: Octets = Octs> + ?Sized>( - parser: &mut Parser<'a, Src>, - ) -> Result { - let len = parser.remaining(); - Self::from_octets(parser.parse_octets(len)?) - } } //--- OctetsFrom @@ -127,29 +161,29 @@ where impl PartialEq> for Opt where - Octs: AsRef<[u8]>, - Other: AsRef<[u8]>, + Octs: AsRef<[u8]> + ?Sized, + Other: AsRef<[u8]> + ?Sized, { fn eq(&self, other: &Opt) -> bool { self.octets.as_ref().eq(other.octets.as_ref()) } } -impl> Eq for Opt {} +impl + ?Sized> Eq for Opt {} //--- PartialOrd and Ord impl PartialOrd> for Opt where - Octs: AsRef<[u8]>, - Other: AsRef<[u8]>, + Octs: AsRef<[u8]> + ?Sized, + Other: AsRef<[u8]> + ?Sized, { fn partial_cmp(&self, other: &Opt) -> Option { self.octets.as_ref().partial_cmp(other.octets.as_ref()) } } -impl> Ord for Opt { +impl + ?Sized> Ord for Opt { fn cmp(&self, other: &Self) -> Ordering { self.octets.as_ref().cmp(other.octets.as_ref()) } @@ -157,7 +191,7 @@ impl> Ord for Opt { //--- Hash -impl> hash::Hash for Opt { +impl + ?Sized> hash::Hash for Opt { fn hash(&self, state: &mut H) { self.octets.as_ref().hash(state) } @@ -165,7 +199,7 @@ impl> hash::Hash for Opt { //--- RecordData, ParseRecordData, and ComposeRecordData -impl RecordData for Opt { +impl RecordData for Opt { fn rtype(&self) -> Rtype { Rtype::Opt } @@ -187,7 +221,7 @@ where } } -impl> ComposeRecordData for Opt { +impl + ?Sized> ComposeRecordData for Opt { fn rdlen(&self, _compress: bool) -> Option { Some(u16::try_from(self.octets.as_ref().len()).expect("long OPT")) } @@ -209,14 +243,14 @@ impl> ComposeRecordData for Opt { //--- Display -impl> fmt::Display for Opt { +impl + ?Sized> fmt::Display for Opt { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // XXX TODO Print this properly. f.write_str("OPT ...") } } -impl> fmt::Debug for Opt { +impl + ?Sized> fmt::Debug for Opt { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("Opt(")?; fmt::Display::fmt(self, f)?; @@ -527,7 +561,7 @@ impl OptionHeader { /// particular option. After such an error you can continue to iterate until /// `None` indicates that you’ve reached the end of the record. #[derive(Clone, Debug)] -pub struct OptIter<'a, Octs: Octets, D: ParseOptData<'a, Octs>> { +pub struct OptIter<'a, Octs: ?Sized, D> { /// A parser for the OPT record data. parser: Parser<'a, Octs>, @@ -535,7 +569,11 @@ pub struct OptIter<'a, Octs: Octets, D: ParseOptData<'a, Octs>> { marker: PhantomData, } -impl<'a, Octs: Octets, D: ParseOptData<'a, Octs>> OptIter<'a, Octs, D> { +impl<'a, Octs, D> OptIter<'a, Octs, D> +where + Octs: Octets + ?Sized, + D: ParseOptData<'a, Octs>, +{ /// Creates an iterator from a reference to the OPT record data. fn new(octets: &'a Octs) -> Self { OptIter { @@ -565,7 +603,7 @@ impl<'a, Octs: Octets, D: ParseOptData<'a, Octs>> OptIter<'a, Octs, D> { impl<'a, Octs, Data> Iterator for OptIter<'a, Octs, Data> where - Octs: Octets, + Octs: Octets + ?Sized, Data: ParseOptData<'a, Octs>, { type Item = Result; diff --git a/src/base/opt/rfc5001.rs b/src/base/opt/rfc5001.rs index 0c73f0fd..659a3bbc 100644 --- a/src/base/opt/rfc5001.rs +++ b/src/base/opt/rfc5001.rs @@ -17,7 +17,7 @@ use core::cmp::Ordering; /// /// Specified in RFC 5001. #[derive(Clone, Copy, Debug)] -pub struct Nsid { +pub struct Nsid { octets: Octs, } @@ -32,47 +32,83 @@ impl Nsid { let len = parser.remaining(); parser.parse_octets(len).map(Nsid::from_octets).map_err(Into::into) } +} +impl Nsid<[u8]> { + pub fn from_slice(slice: &[u8]) -> &Self { + unsafe { &*(slice as *const [u8] as *const Self) } + } + + pub fn from_slice_mut(slice: &mut [u8]) -> &mut Self { + unsafe { &mut *(slice as *mut [u8] as *mut Self) } + } +} + +impl Nsid { pub fn as_octets(&self) -> &Octs { &self.octets } - pub fn into_octets(self) -> Octs { + pub fn into_octets(self) -> Octs + where + Octs: Sized, + { self.octets } pub fn as_slice(&self) -> &[u8] - where Octs: AsRef<[u8]> { + where + Octs: AsRef<[u8]>, + { self.octets.as_ref() } pub fn as_slice_mut(&mut self) -> &mut [u8] - where Octs: AsMut<[u8]> { + where + Octs: AsMut<[u8]>, + { self.octets.as_mut() } + + pub fn for_slice(&self) -> &Nsid<[u8]> + where + Octs: AsRef<[u8]> + { + Nsid::from_slice(self.octets.as_ref()) + } + + pub fn for_slice_mut(&mut self) -> &mut Nsid<[u8]> + where + Octs: AsMut<[u8]> + { + Nsid::from_slice_mut(self.octets.as_mut()) + } } //--- AsRef, AsMut, Borrow, BorrowMut -impl> AsRef<[u8]> for Nsid { +impl + ?Sized> AsRef<[u8]> for Nsid { fn as_ref(&self) -> &[u8] { self.as_slice() } } -impl> AsMut<[u8]> for Nsid { +impl + ?Sized> AsMut<[u8]> for Nsid { fn as_mut(&mut self) -> &mut [u8] { self.as_slice_mut() } } -impl> borrow::Borrow<[u8]> for Nsid { +impl + ?Sized> borrow::Borrow<[u8]> for Nsid { fn borrow(&self) -> &[u8] { self.as_slice() } } -impl + AsRef<[u8]>> borrow::BorrowMut<[u8]> for Nsid { +impl borrow::BorrowMut<[u8]> for Nsid +where + Octs: AsMut<[u8]> + AsRef<[u8]> + ?Sized +{ fn borrow_mut(&mut self) -> &mut [u8] { self.as_slice_mut() } @@ -80,7 +116,7 @@ impl + AsRef<[u8]>> borrow::BorrowMut<[u8]> for Nsid { //--- OptData etc. -impl OptData for Nsid { +impl OptData for Nsid { fn code(&self) -> OptionCode { OptionCode::Nsid } @@ -100,7 +136,7 @@ impl<'a, Octs: Octets> ParseOptData<'a, Octs> for Nsid> { } } -impl> ComposeOptData for Nsid { +impl + ?Sized> ComposeOptData for Nsid { fn compose_len(&self) -> u16 { self.octets.as_ref().len().try_into().expect("long option data") } @@ -114,7 +150,7 @@ impl> ComposeOptData for Nsid { //--- Display -impl> fmt::Display for Nsid { +impl + ?Sized> fmt::Display for Nsid { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // RFC 5001 § 2.4: // | User interfaces MUST read and write the contents of the NSID @@ -132,23 +168,31 @@ impl> fmt::Display for Nsid { //--- PartialEq and Eq -impl, Other: AsRef<[u8]>> PartialEq for Nsid { +impl PartialEq for Nsid +where + Octs: AsRef<[u8]> + ?Sized, + Other: AsRef<[u8]> + ?Sized, +{ fn eq(&self, other: &Other) -> bool { self.as_slice().eq(other.as_ref()) } } -impl> Eq for Nsid { } +impl + ?Sized> Eq for Nsid { } //--- PartialOrd and Ord -impl, Other: AsRef<[u8]>> PartialOrd for Nsid { +impl PartialOrd for Nsid +where + Octs: AsRef<[u8]> + ?Sized, + Other: AsRef<[u8]> + ?Sized, +{ fn partial_cmp(&self, other: &Other) -> Option { self.as_slice().partial_cmp(other.as_ref()) } } -impl> Ord for Nsid { +impl + ?Sized> Ord for Nsid { fn cmp(&self, other: &Self) -> Ordering { self.as_slice().cmp(other.as_slice()) } @@ -156,7 +200,7 @@ impl> Ord for Nsid { //--- Hash -impl> hash::Hash for Nsid { +impl + ?Sized> hash::Hash for Nsid { fn hash(&self, state: &mut H) { self.as_slice().hash(state) } @@ -167,9 +211,9 @@ impl> hash::Hash for Nsid { impl<'a, Target: Composer> OptBuilder<'a, Target> { pub fn nsid( - &mut self, data: &impl AsRef<[u8]> + &mut self, data: &(impl AsRef<[u8]> + ?Sized) ) -> Result<(), Target::AppendError> { - self.push(&Nsid::from_octets(data.as_ref())) + self.push(Nsid::from_slice(data.as_ref())) } } diff --git a/src/base/opt/rfc6975.rs b/src/base/opt/rfc6975.rs index c37a5822..9d2c84cd 100644 --- a/src/base/opt/rfc6975.rs +++ b/src/base/opt/rfc6975.rs @@ -16,7 +16,7 @@ use core::cmp::Ordering; macro_rules! option_type { ( $name:ident, $fn:ident ) => { #[derive(Clone, Copy, Debug)] - pub struct $name { + pub struct $name { octets: Octs, } @@ -25,29 +25,6 @@ macro_rules! option_type { $name { octets } } - pub fn as_octets(&self) -> &Octs { - &self.octets - } - - pub fn into_octets(self) -> Octs { - self.octets - } - - pub fn as_slice(&self) -> &[u8] - where Octs: AsRef<[u8]> { - self.octets.as_ref() - } - - pub fn as_slice_mut(&mut self) -> &mut [u8] - where Octs: AsMut<[u8]> { - self.octets.as_mut() - } - - pub fn iter(&self) -> SecAlgsIter - where Octs: AsRef<[u8]> { - SecAlgsIter::new(self.octets.as_ref()) - } - pub fn parse<'a, Src: Octets = Octs> + ?Sized>( parser: &mut Parser<'a, Src> ) -> Result { @@ -58,21 +35,79 @@ macro_rules! option_type { } } + impl $name<[u8]> { + pub fn from_slice(slice: &[u8]) -> &Self { + unsafe { &*(slice as *const [u8] as *const Self) } + } + + pub fn from_slice_mut(slice: &mut [u8]) -> &mut Self { + unsafe { &mut *(slice as *mut [u8] as *mut Self) } + } + } + + impl $name { + pub fn as_octets(&self) -> &Octs { + &self.octets + } + + pub fn into_octets(self) -> Octs + where + Octs: Sized, + { + self.octets + } + + pub fn as_slice(&self) -> &[u8] + where + Octs: AsRef<[u8]>, + { + self.octets.as_ref() + } + + pub fn as_slice_mut(&mut self) -> &mut [u8] + where + Octs: AsMut<[u8]>, + { + self.octets.as_mut() + } + + pub fn for_slice(&self) -> &$name<[u8]> + where + Octs: AsRef<[u8]>, + { + $name::from_slice(self.octets.as_ref()) + } + + pub fn for_slice_mut(&mut self) -> &mut $name<[u8]> + where + Octs: AsMut<[u8]>, + { + $name::from_slice_mut(self.octets.as_mut()) + } + + pub fn iter(&self) -> SecAlgsIter + where + Octs: AsRef<[u8]>, + { + SecAlgsIter::new(self.octets.as_ref()) + } + } + //--- AsRef, AsMut, Borrow, BorrowMut - impl> AsRef<[u8]> for $name { + impl + ?Sized> AsRef<[u8]> for $name { fn as_ref(&self) -> &[u8] { self.as_slice() } } - impl> AsMut<[u8]> for $name { + impl + ?Sized> AsMut<[u8]> for $name { fn as_mut(&mut self) -> &mut [u8] { self.as_slice_mut() } } - impl> borrow::Borrow<[u8]> for $name { + impl + ?Sized> borrow::Borrow<[u8]> for $name { fn borrow(&self) -> &[u8] { self.as_slice() } @@ -80,7 +115,7 @@ macro_rules! option_type { impl borrow::BorrowMut<[u8]> for $name where - Octs: AsMut<[u8]> + AsRef<[u8]>, + Octs: AsMut<[u8]> + AsRef<[u8]> + ?Sized, { fn borrow_mut(&mut self) -> &mut [u8] { self.as_slice_mut() @@ -89,7 +124,7 @@ macro_rules! option_type { //--- OptData etc. - impl OptData for $name { + impl OptData for $name { fn code(&self) -> OptionCode { OptionCode::$name } @@ -110,7 +145,7 @@ macro_rules! option_type { } } - impl> ComposeOptData for $name { + impl + ?Sized> ComposeOptData for $name { fn compose_len(&self) -> u16 { self.octets.as_ref().len().try_into().expect("long option data") } @@ -125,7 +160,7 @@ macro_rules! option_type { //--- IntoIter - impl<'a, Octs: AsRef<[u8]>> IntoIterator for &'a $name { + impl<'a, Octs: AsRef<[u8]> + ?Sized> IntoIterator for &'a $name { type Item = SecAlg; type IntoIter = SecAlgsIter<'a>; @@ -136,7 +171,7 @@ macro_rules! option_type { //--- Display - impl> fmt::Display for $name { + impl + ?Sized> fmt::Display for $name { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut first = true; @@ -156,29 +191,29 @@ macro_rules! option_type { impl PartialEq for $name where - Octs: AsRef<[u8]>, - Other: AsRef<[u8]>, + Octs: AsRef<[u8]> + ?Sized, + Other: AsRef<[u8]> + ?Sized, { fn eq(&self, other: &Other) -> bool { self.as_slice().eq(other.as_ref()) } } - impl> Eq for $name { } + impl + ?Sized> Eq for $name { } //--- PartialOrd and Ord impl PartialOrd for $name where - Octs: AsRef<[u8]>, - Other: AsRef<[u8]>, + Octs: AsRef<[u8]> + ?Sized, + Other: AsRef<[u8]> + ?Sized, { fn partial_cmp(&self, other: &Other) -> Option { self.as_slice().partial_cmp(other.as_ref()) } } - impl> Ord for $name { + impl + ?Sized> Ord for $name { fn cmp(&self, other: &Self) -> Ordering { self.as_slice().cmp(other.as_slice()) } @@ -186,7 +221,7 @@ macro_rules! option_type { //--- Hash - impl> hash::Hash for $name { + impl + ?Sized> hash::Hash for $name { fn hash(&self, state: &mut H) { self.as_slice().hash(state) } @@ -196,7 +231,7 @@ macro_rules! option_type { impl<'a, Target: Composer> OptBuilder<'a, Target> { pub fn $fn( - &mut self, octets: &impl AsRef<[u8]> + &mut self, octets: &(impl AsRef<[u8]> + ?Sized) ) -> Result<(), Target::AppendError> { self.push(&$name::from_octets(octets.as_ref())) } diff --git a/src/base/opt/rfc8145.rs b/src/base/opt/rfc8145.rs index 02e02c87..98b70875 100644 --- a/src/base/opt/rfc8145.rs +++ b/src/base/opt/rfc8145.rs @@ -15,38 +15,15 @@ use core::convert::TryInto; //------------ KeyTag ------------------------------------------------------- #[derive(Clone, Debug)] -pub struct KeyTag { +pub struct KeyTag { octets: Octs, } impl KeyTag { - pub fn new(octets: Octs) -> Self { + pub fn from_octets(octets: Octs) -> Self { KeyTag { octets } } - pub fn as_octets(&self) -> &Octs { - &self.octets - } - - pub fn into_octets(self) -> Octs { - self.octets - } - - pub fn as_slice(&self) -> &[u8] - where Octs: AsRef<[u8]> { - self.octets.as_ref() - } - - pub fn as_slice_mut(&mut self) -> &mut [u8] - where Octs: AsMut<[u8]> { - self.octets.as_mut() - } - - pub fn iter(&self) -> KeyTagIter - where Octs: AsRef<[u8]> { - KeyTagIter(self.octets.as_ref()) - } - pub fn parse<'a, Src: Octets = Octs> + ?Sized>( parser: &mut Parser<'a, Src> ) -> Result { @@ -55,32 +32,77 @@ impl KeyTag { Err(FormError::new("invalid keytag length").into()) } else { - Ok(Self::new(parser.parse_octets(len)?)) + Ok(Self::from_octets(parser.parse_octets(len)?)) } } } +impl KeyTag<[u8]> { + pub fn from_slice(slice: &[u8]) -> &Self { + unsafe { &*(slice as *const [u8] as *const Self) } + } + + pub fn from_slice_mut(slice: &mut [u8]) -> &mut Self { + unsafe { &mut *(slice as *mut [u8] as *mut Self) } + } +} + +impl KeyTag { + pub fn as_octets(&self) -> &Octs { + &self.octets + } + + pub fn into_octets(self) -> Octs + where + Octs: Sized, + { + self.octets + } + + pub fn as_slice(&self) -> &[u8] + where + Octs: AsRef<[u8]>, + { + self.octets.as_ref() + } + + pub fn as_slice_mut(&mut self) -> &mut [u8] + where + Octs: AsMut<[u8]>, + { + self.octets.as_mut() + } + + pub fn iter(&self) -> KeyTagIter + where Octs: AsRef<[u8]> { + KeyTagIter(self.octets.as_ref()) + } +} + //--- AsRef, AsMut, Borrow, BorrowMut -impl> AsRef<[u8]> for KeyTag { +impl + ?Sized> AsRef<[u8]> for KeyTag { fn as_ref(&self) -> &[u8] { self.as_slice() } } -impl> AsMut<[u8]> for KeyTag { +impl + ?Sized> AsMut<[u8]> for KeyTag { fn as_mut(&mut self) -> &mut [u8] { self.as_slice_mut() } } -impl> borrow::Borrow<[u8]> for KeyTag { +impl + ?Sized> borrow::Borrow<[u8]> for KeyTag { fn borrow(&self) -> &[u8] { self.as_slice() } } -impl + AsRef<[u8]>> borrow::BorrowMut<[u8]> for KeyTag { +impl borrow::BorrowMut<[u8]> for KeyTag +where + Octs: AsMut<[u8]> + AsRef<[u8]> + ?Sized +{ fn borrow_mut(&mut self) -> &mut [u8] { self.as_slice_mut() } @@ -88,7 +110,7 @@ impl + AsRef<[u8]>> borrow::BorrowMut<[u8]> for KeyTag { //--- OptData -impl OptData for KeyTag { +impl OptData for KeyTag { fn code(&self) -> OptionCode { OptionCode::KeyTag } @@ -108,7 +130,7 @@ impl<'a, Octs: Octets> ParseOptData<'a, Octs> for KeyTag> { } } -impl> ComposeOptData for KeyTag { +impl + ?Sized> ComposeOptData for KeyTag { fn compose_len(&self) -> u16 { self.octets.as_ref().len().try_into().expect("long option data") } @@ -123,7 +145,7 @@ impl> ComposeOptData for KeyTag { //--- IntoIterator -impl<'a, Octs: AsRef<[u8]>> IntoIterator for &'a KeyTag { +impl<'a, Octs: AsRef<[u8]> + ?Sized> IntoIterator for &'a KeyTag { type Item = u16; type IntoIter = KeyTagIter<'a>; @@ -135,7 +157,7 @@ impl<'a, Octs: AsRef<[u8]>> IntoIterator for &'a KeyTag { //--- Display -impl> fmt::Display for KeyTag { +impl + ?Sized> fmt::Display for KeyTag { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut first = true; @@ -154,23 +176,31 @@ impl> fmt::Display for KeyTag { //--- PartialEq and Eq -impl, Other: AsRef<[u8]>> PartialEq for KeyTag { +impl PartialEq for KeyTag +where + Octs: AsRef<[u8]> + ?Sized, + Other: AsRef<[u8]> + ?Sized, +{ fn eq(&self, other: &Other) -> bool { self.as_slice().eq(other.as_ref()) } } -impl> Eq for KeyTag { } +impl + ?Sized> Eq for KeyTag { } //--- PartialOrd and Ord -impl, Other: AsRef<[u8]>> PartialOrd for KeyTag { +impl PartialOrd for KeyTag +where + Octs: AsRef<[u8]> + ?Sized, + Other: AsRef<[u8]> + ?Sized, +{ fn partial_cmp(&self, other: &Other) -> Option { self.as_slice().partial_cmp(other.as_ref()) } } -impl> Ord for KeyTag { +impl + ?Sized> Ord for KeyTag { fn cmp(&self, other: &Self) -> Ordering { self.as_slice().cmp(other.as_slice()) } @@ -178,7 +208,7 @@ impl> Ord for KeyTag { //--- Hash -impl> hash::Hash for KeyTag { +impl + ?Sized> hash::Hash for KeyTag { fn hash(&self, state: &mut H) { self.as_slice().hash(state) } @@ -209,7 +239,7 @@ impl<'a> Iterator for KeyTagIter<'a> { impl<'a, Target: Composer> OptBuilder<'a, Target> { pub fn key_tag( - &mut self, tags: &impl AsRef<[u16]> + &mut self, tags: &(impl AsRef<[u16]> + ?Sized) ) -> Result<(), Target::AppendError> { self.push_raw_option( OptionCode::KeyTag, @@ -237,7 +267,7 @@ mod test { #[test] fn nsid_compose_parse() { test_option_compose_parse( - &KeyTag::new("fooo"), + &KeyTag::from_octets("fooo"), |parser| KeyTag::parse(parser) ); } diff --git a/src/rdata/macros.rs b/src/rdata/macros.rs index c961cfba..957d4321 100644 --- a/src/rdata/macros.rs +++ b/src/rdata/macros.rs @@ -8,12 +8,12 @@ macro_rules! rdata_types { $module:ident::{ $( zone { - $( $mtype:ident $( < $( $mn:ident ),* > )*, )* + $( $mtype:ident $( < $( $mn:ident ),* > ),* $(,)? )* } )* $( pseudo { - $( $ptype:ident $( < $( $pn:ident ),* > )*, )* + $( $ptype:ident $( < $( $pn:ident ),* > ),* $(,)? )* } )* @@ -26,6 +26,10 @@ macro_rules! rdata_types { }; )* + $( + pub mod $module; + )* + use crate::base::name::{ParsedDname, PushError, ToDname}; use crate::base::wire::Composer; use crate::base::rdata::ComposeRecordData; diff --git a/src/rdata/mod.rs b/src/rdata/mod.rs index e186b999..05d69b34 100644 --- a/src/rdata/mod.rs +++ b/src/rdata/mod.rs @@ -47,20 +47,10 @@ #[macro_use] mod macros; -pub mod rfc1035; -pub mod rfc2782; -pub mod rfc2845; -pub mod rfc3596; -pub mod rfc4034; -pub mod rfc5155; -pub mod rfc6672; -pub mod rfc7344; -pub mod svcb; - -// The rdata_types! macro (defined in self::macros) re-exports the record data -// types here and creates the ZoneRecordData and AllRecordData enums -// containing all record types that can appear in a zone and all record -// types that exist. +// The rdata_types! macro (defined in self::macros) defines the modules +// containing the record data types, re-exports those here, and creates the +// ZoneRecordData and AllRecordData enums containing all record types that +// can appear in a zone file and all record types that exist. // // All record data types listed here MUST have the same name as the // `Rtype` variant they implement – some of the code implemented by the macro @@ -69,10 +59,8 @@ pub mod svcb; // Add any new module here and then add all record types in that module that // can appear in zone files under "zone" and all others under "pseudo". // Your type can be generic over an octet type "O" and a domain name type "N". -// Add these as needed. -// -// Each type entry has to be followed by a comma, even the last one. The macro -// is messy enough as it is ... +// Add these as needed. Trait bounds on them differ for different methods, so +// check the bounds on ZoneRecordData and AllRecordData if there are errors. rdata_types! { rfc1035::{ zone { @@ -92,7 +80,7 @@ rdata_types! { Txt, } pseudo { - Null, + Null } } rfc2782::{ diff --git a/src/rdata/rfc1035.rs b/src/rdata/rfc1035.rs index 66b34600..6807fb6f 100644 --- a/src/rdata/rfc1035.rs +++ b/src/rdata/rfc1035.rs @@ -1553,11 +1553,11 @@ impl fmt::Display for Soa { /// /// The Txt record type is defined in RFC 1035, section 3.3.14. #[derive(Clone)] -pub struct Txt(Octs); +pub struct Txt(Octs); impl Txt { /// Creates a new Txt record from a single character string. - pub fn try_from_slice(text: &[u8]) -> Result + pub fn build_from_slice(text: &[u8]) -> Result where ::Builder: EmptyBuilder + AsRef<[u8]> + AsMut<[u8]>, @@ -1568,19 +1568,77 @@ impl Txt { } } -impl> Txt { - /// Creates a new TXT record from its encoded content. - pub fn from_octets(octets: Octs) -> Result { - let mut tmp = octets.as_ref(); - while !tmp.is_empty() { - if tmp.len() <= tmp[0] as usize { - return Err(CharStrError); - } - tmp = &tmp[(tmp[0] as usize) + 1..]; - } - Ok(Txt(octets)) +impl Txt { + /// Creates new TXT record data from its encoded content. + pub fn from_octets(octets: Octs) -> Result + where + Octs: AsRef<[u8]> + { + Txt::check_slice(octets.as_ref())?; + Ok(unsafe { Txt::from_octets_unchecked(octets) }) } + /// Creates new TXT record data without checking. + /// + /// # Safety + /// + /// The passed octets must contain correctly encoded TXT record data, + /// that is a sequence of encoded character strings. + unsafe fn from_octets_unchecked(octets: Octs) -> Self { + Txt(octets) + } + + pub fn parse<'a, Src: Octets = Octs> + ?Sized>( + parser: &mut Parser<'a, Src>, + ) -> Result + where Octs: AsRef<[u8]> { + let len = parser.remaining(); + let text = parser.parse_octets(len)?; + let mut tmp = Parser::from_ref(text.as_ref()); + while tmp.remaining() != 0 { + CharStr::skip(&mut tmp)? + } + Ok(Txt(text)) + } + + pub fn scan>( + scanner: &mut S, + ) -> Result { + scanner.scan_charstr_entry().map(Txt) + } +} + +impl Txt<[u8]> { + /// Creates new TXT record data on an octets slice. + pub fn from_slice(slice: &[u8]) -> Result<&Self, CharStrError> { + Txt::check_slice(slice)?; + Ok(unsafe { Txt::from_slice_unchecked(slice) }) + } + + /// Creates new TXT record data on an octets slice without checking. + /// + /// # Safety + /// + /// The passed octets must contain correctly encoded TXT record data, + /// that is a sequence of encoded character strings. + unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self { + unsafe { &*(slice as *const [u8] as *const Self) } + } + + /// Checks that a slice contains correctly encoded TXT data. + fn check_slice(mut slice: &[u8]) -> Result<(), CharStrError> { + while let Some(&len) = slice.first() { + let len = usize::from(len); + if slice.len() <= len { + return Err(CharStrError); + } + slice = &slice[len + 1..]; + } + Ok(()) + } +} + +impl + ?Sized> Txt { /// Returns an iterator over the text items. /// /// The Txt format contains one or more length-delimited byte strings. @@ -1593,8 +1651,9 @@ impl> Txt { TxtCharStrIter(Parser::from_ref(self.0.as_ref())) } + /// Returns the content if it consists of a single character string. pub fn as_flat_slice(&self) -> Option<&[u8]> { - if self.0.as_ref()[0] as usize == self.0.as_ref().len() - 1 { + if usize::from(self.0.as_ref()[0]) == self.0.as_ref().len() - 1 { Some(&self.0.as_ref()[1..]) } else { None @@ -1642,28 +1701,6 @@ impl> Txt { } } -impl Txt { - pub fn scan>( - scanner: &mut S, - ) -> Result { - scanner.scan_charstr_entry().map(Txt) - } -} - -impl> Txt { - pub fn parse<'a, Src: Octets = Octs> + ?Sized>( - parser: &mut Parser<'a, Src>, - ) -> Result { - let len = parser.remaining(); - let text = parser.parse_octets(len)?; - let mut tmp = Parser::from_ref(text.as_ref()); - while tmp.remaining() != 0 { - CharStr::skip(&mut tmp)? - } - Ok(Txt(text)) - } -} - impl Txt { pub(super) fn convert_octets>( self, @@ -2287,19 +2324,19 @@ mod test { #[test] fn txt_from_slice() { let short = b"01234"; - let txt: Txt> = Txt::try_from_slice(short).unwrap(); + let txt: Txt> = Txt::build_from_slice(short).unwrap(); assert_eq!(Some(&short[..]), txt.as_flat_slice()); assert_eq!(short.to_vec(), txt.text::>()); // One full slice let full = short.repeat(51); - let txt: Txt> = Txt::try_from_slice(&full).unwrap(); + let txt: Txt> = Txt::build_from_slice(&full).unwrap(); assert_eq!(Some(&full[..]), txt.as_flat_slice()); assert_eq!(full.to_vec(), txt.text::>()); // Two slices: 255, 5 let long = short.repeat(52); - let txt: Txt> = Txt::try_from_slice(&long).unwrap(); + let txt: Txt> = Txt::build_from_slice(&long).unwrap(); assert_eq!(None, txt.as_flat_slice()); assert_eq!(long.to_vec(), txt.text::>());