1use super::super::iana::OptionCode;
11use super::super::message_builder::OptBuilder;
12use super::super::wire::{Composer, ParseError};
13use super::{
14 BuildDataError, LongOptData, Opt, OptData, ComposeOptData, ParseOptData
15};
16use octseq::builder::OctetsBuilder;
17use octseq::octets::{Octets, OctetsFrom};
18use octseq::parse::Parser;
19use core::{borrow, fmt, hash, mem, str};
20use core::cmp::Ordering;
21
22
23#[derive(Clone, Copy)]
35#[repr(transparent)]
36pub struct Nsid<Octs: ?Sized> {
37 octets: Octs,
39}
40
41impl Nsid<()> {
42 pub(super) const CODE: OptionCode = OptionCode::NSID;
44}
45
46#[cfg(feature = "serde")]
47impl<Octs: octseq::serde::SerializeOctets> serde::Serialize for Nsid<Octs> {
48 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
49 where
50 S: serde::Serializer {
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 Octs: AsRef<[u8]> {
62 LongOptData::check_len(octets.as_ref().len())?;
63 Ok(unsafe { Self::from_octets_unchecked(octets) })
64 }
65
66 pub unsafe fn from_octets_unchecked(octets: Octs) -> Self {
73 Nsid { octets }
74 }
75
76 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
78 parser: &mut Parser<'a, Src>
79 ) -> Result<Self, ParseError> {
80 let len = parser.remaining();
81 LongOptData::check_len(len)?;
82 Ok(unsafe { Self::from_octets_unchecked(
83 parser.parse_octets(len)?
84 )})
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 Octs: OctetsFrom<SrcOcts> {
152 type Error = Octs::Error;
153
154 fn try_octets_from(src: Nsid<SrcOcts>) -> Result<Self, Self::Error> {
155 Octs::try_octets_from(src.octets).map(|octets| unsafe {
156 Self::from_octets_unchecked(octets)
157 })
158 }
159}
160
161impl<Octs: AsRef<[u8]> + ?Sized> AsRef<[u8]> for Nsid<Octs> {
164 fn as_ref(&self) -> &[u8] {
165 self.as_slice()
166 }
167}
168
169impl<Octs: AsRef<[u8]> + ?Sized> borrow::Borrow<[u8]> for Nsid<Octs> {
170 fn borrow(&self) -> &[u8] {
171 self.as_slice()
172 }
173}
174
175impl<Octs: ?Sized> OptData for Nsid<Octs> {
178 fn code(&self) -> OptionCode {
179 OptionCode::NSID
180 }
181}
182
183impl<'a, Octs: Octets> ParseOptData<'a, Octs> for Nsid<Octs::Range<'a>> {
184 fn parse_option(
185 code: OptionCode,
186 parser: &mut Parser<'a, Octs>,
187 ) -> Result<Option<Self>, ParseError> {
188 if code == OptionCode::NSID {
189 Self::parse(parser).map(Some)
190 }
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.as_ref().len().try_into().expect("long option data")
200 }
201
202 fn compose_option<Target: OctetsBuilder + ?Sized>(
203 &self, target: &mut Target
204 ) -> Result<(), Target::AppendError> {
205 target.append_slice(self.octets.as_ref())
206 }
207}
208
209impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Nsid<Octs> {
212 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
213 for v in self.octets.as_ref() {
218 write!(f, "{:X} ", *v)?;
219 }
220 if let Ok(s) = str::from_utf8(self.octets.as_ref()) {
221 write!(f, "({})", s)?;
222 }
223 Ok(())
224 }
225}
226
227impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Nsid<Octs> {
228 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229 write!(f, "Nsid({})", self)
230 }
231}
232
233impl<Octs, Other> PartialEq<Other> for Nsid<Octs>
236where
237 Octs: AsRef<[u8]> + ?Sized,
238 Other: AsRef<[u8]> + ?Sized,
239{
240 fn eq(&self, other: &Other) -> bool {
241 self.as_slice().eq(other.as_ref())
242 }
243}
244
245impl<Octs: AsRef<[u8]> + ?Sized> Eq for Nsid<Octs> { }
246
247impl<Octs, Other> PartialOrd<Other> for Nsid<Octs>
250where
251 Octs: AsRef<[u8]> + ?Sized,
252 Other: AsRef<[u8]> + ?Sized,
253{
254 fn partial_cmp(&self, other: &Other) -> Option<Ordering> {
255 self.as_slice().partial_cmp(other.as_ref())
256 }
257}
258
259impl<Octs: AsRef<[u8]> + ?Sized> Ord for Nsid<Octs> {
260 fn cmp(&self, other: &Self) -> Ordering {
261 self.as_slice().cmp(other.as_slice())
262 }
263}
264
265impl<Octs: AsRef<[u8]> + ?Sized> hash::Hash for Nsid<Octs> {
268 fn hash<H: hash::Hasher>(&self, state: &mut H) {
269 self.as_slice().hash(state)
270 }
271}
272
273impl<Octs: Octets> Opt<Octs> {
276 pub fn nsid(&self) -> Option<Nsid<Octs::Range<'_>>> {
282 self.first()
283 }
284}
285
286impl<Target: Composer> OptBuilder<'_, Target> {
287 pub fn nsid(
297 &mut self, data: &(impl AsRef<[u8]> + ?Sized)
298 ) -> Result<(), BuildDataError> {
299 Ok(self.push(Nsid::from_slice(data.as_ref())?)?)
300 }
301
302 pub fn client_nsid(&mut self) -> Result<(), Target::AppendError> {
309 self.push(Nsid::empty())
310 }
311}
312
313#[cfg(test)]
316#[cfg(all(feature = "std", feature = "bytes"))]
317mod test {
318 use super::*;
319 use super::super::test::test_option_compose_parse;
320
321 #[test]
322 #[allow(clippy::redundant_closure)] fn nsid_compose_parse() {
324 test_option_compose_parse(
325 &Nsid::from_octets("foo").unwrap(),
326 |parser| Nsid::parse(parser)
327 );
328 }
329}