1use super::super::iana::OptionCode;
11use super::super::message_builder::OptBuilder;
12use super::super::wire::{Composer, ParseError};
13use super::{
14 BuildDataError, ComposeOptData, LongOptData, Opt, OptData, ParseOptData,
15};
16use core::cmp::Ordering;
17use core::{borrow, fmt, hash, mem, str};
18use octseq::builder::OctetsBuilder;
19use octseq::octets::{Octets, OctetsFrom};
20use octseq::parse::Parser;
21
22#[derive(Clone, Copy)]
34#[repr(transparent)]
35pub struct Nsid<Octs: ?Sized> {
36 octets: Octs,
38}
39
40impl Nsid<()> {
41 pub(super) const CODE: OptionCode = OptionCode::NSID;
43}
44
45#[cfg(feature = "serde")]
46impl<Octs: octseq::serde::SerializeOctets> serde::Serialize for Nsid<Octs> {
47 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
48 where
49 S: serde::Serializer,
50 {
51 self.octets.serialize_octets(serializer)
52 }
53}
54
55impl<Octs> Nsid<Octs> {
56 pub fn from_octets(octets: Octs) -> Result<Self, LongOptData>
61 where
62 Octs: AsRef<[u8]>,
63 {
64 LongOptData::check_len(octets.as_ref().len())?;
65 Ok(unsafe { Self::from_octets_unchecked(octets) })
66 }
67
68 pub unsafe fn from_octets_unchecked(octets: Octs) -> Self {
75 Nsid { octets }
76 }
77
78 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
80 parser: &mut Parser<'a, Src>,
81 ) -> Result<Self, ParseError> {
82 let len = parser.remaining();
83 LongOptData::check_len(len)?;
84 Ok(unsafe { Self::from_octets_unchecked(parser.parse_octets(len)?) })
85 }
86}
87
88impl Nsid<[u8]> {
89 pub fn from_slice(slice: &[u8]) -> Result<&Self, LongOptData> {
94 LongOptData::check_len(slice.len())?;
95 Ok(unsafe { Self::from_slice_unchecked(slice) })
96 }
97
98 #[must_use]
105 pub unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
106 mem::transmute(slice)
108 }
109
110 #[must_use]
112 pub fn empty() -> &'static Self {
113 unsafe { Self::from_slice_unchecked(b"") }
114 }
115}
116
117impl<Octs: ?Sized> Nsid<Octs> {
118 pub fn as_octets(&self) -> &Octs {
120 &self.octets
121 }
122
123 pub fn into_octets(self) -> Octs
125 where
126 Octs: Sized,
127 {
128 self.octets
129 }
130
131 pub fn as_slice(&self) -> &[u8]
133 where
134 Octs: AsRef<[u8]>,
135 {
136 self.octets.as_ref()
137 }
138
139 pub fn for_slice(&self) -> &Nsid<[u8]>
141 where
142 Octs: AsRef<[u8]>,
143 {
144 unsafe { Nsid::from_slice_unchecked(self.octets.as_ref()) }
145 }
146}
147
148impl<Octs, SrcOcts> OctetsFrom<Nsid<SrcOcts>> for Nsid<Octs>
151where
152 Octs: OctetsFrom<SrcOcts>,
153{
154 type Error = Octs::Error;
155
156 fn try_octets_from(src: Nsid<SrcOcts>) -> Result<Self, Self::Error> {
157 Octs::try_octets_from(src.octets)
158 .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
159 }
160}
161
162impl<Octs: AsRef<[u8]> + ?Sized> AsRef<[u8]> for Nsid<Octs> {
165 fn as_ref(&self) -> &[u8] {
166 self.as_slice()
167 }
168}
169
170impl<Octs: AsRef<[u8]> + ?Sized> borrow::Borrow<[u8]> for Nsid<Octs> {
171 fn borrow(&self) -> &[u8] {
172 self.as_slice()
173 }
174}
175
176impl<Octs: ?Sized> OptData for Nsid<Octs> {
179 fn code(&self) -> OptionCode {
180 OptionCode::NSID
181 }
182}
183
184impl<'a, Octs: Octets> ParseOptData<'a, Octs> for Nsid<Octs::Range<'a>> {
185 fn parse_option(
186 code: OptionCode,
187 parser: &mut Parser<'a, Octs>,
188 ) -> Result<Option<Self>, ParseError> {
189 if code == OptionCode::NSID {
190 Self::parse(parser).map(Some)
191 } else {
192 Ok(None)
193 }
194 }
195}
196
197impl<Octs: AsRef<[u8]> + ?Sized> ComposeOptData for Nsid<Octs> {
198 fn compose_len(&self) -> u16 {
199 self.octets
200 .as_ref()
201 .len()
202 .try_into()
203 .expect("long option data")
204 }
205
206 fn compose_option<Target: OctetsBuilder + ?Sized>(
207 &self,
208 target: &mut Target,
209 ) -> Result<(), Target::AppendError> {
210 target.append_slice(self.octets.as_ref())
211 }
212}
213
214impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Nsid<Octs> {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 for v in self.octets.as_ref() {
223 write!(f, "{:X} ", *v)?;
224 }
225 if let Ok(s) = str::from_utf8(self.octets.as_ref()) {
226 write!(f, "({})", s)?;
227 }
228 Ok(())
229 }
230}
231
232impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Nsid<Octs> {
233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 write!(f, "Nsid({})", self)
235 }
236}
237
238impl<Octs, Other> PartialEq<Other> for Nsid<Octs>
241where
242 Octs: AsRef<[u8]> + ?Sized,
243 Other: AsRef<[u8]> + ?Sized,
244{
245 fn eq(&self, other: &Other) -> bool {
246 self.as_slice().eq(other.as_ref())
247 }
248}
249
250impl<Octs: AsRef<[u8]> + ?Sized> Eq for Nsid<Octs> {}
251
252impl<Octs, Other> PartialOrd<Other> for Nsid<Octs>
255where
256 Octs: AsRef<[u8]> + ?Sized,
257 Other: AsRef<[u8]> + ?Sized,
258{
259 fn partial_cmp(&self, other: &Other) -> Option<Ordering> {
260 self.as_slice().partial_cmp(other.as_ref())
261 }
262}
263
264impl<Octs: AsRef<[u8]> + ?Sized> Ord for Nsid<Octs> {
265 fn cmp(&self, other: &Self) -> Ordering {
266 self.as_slice().cmp(other.as_slice())
267 }
268}
269
270impl<Octs: AsRef<[u8]> + ?Sized> hash::Hash for Nsid<Octs> {
273 fn hash<H: hash::Hasher>(&self, state: &mut H) {
274 self.as_slice().hash(state)
275 }
276}
277
278impl<Octs: Octets> Opt<Octs> {
281 pub fn nsid(&self) -> Option<Nsid<Octs::Range<'_>>> {
287 self.first()
288 }
289}
290
291impl<Target: Composer> OptBuilder<'_, Target> {
292 pub fn nsid(
302 &mut self,
303 data: &(impl AsRef<[u8]> + ?Sized),
304 ) -> Result<(), BuildDataError> {
305 Ok(self.push(Nsid::from_slice(data.as_ref())?)?)
306 }
307
308 pub fn client_nsid(&mut self) -> Result<(), Target::AppendError> {
315 self.push(Nsid::empty())
316 }
317}
318
319#[cfg(test)]
322#[cfg(all(feature = "std", feature = "bytes"))]
323mod test {
324 use super::super::test::test_option_compose_parse;
325 use super::*;
326
327 #[test]
328 #[allow(clippy::redundant_closure)] fn nsid_compose_parse() {
330 test_option_compose_parse(
331 &Nsid::from_octets("foo").unwrap(),
332 |parser| Nsid::parse(parser),
333 );
334 }
335}