1use super::super::iana::OptionCode;
10use super::super::message_builder::OptBuilder;
11use super::super::name::{Name, ToName};
12use super::super::wire::{Composer, ParseError};
13use super::{ComposeOptData, Opt, OptData, ParseOptData};
14use core::{fmt, hash, mem};
15use core::cmp::Ordering;
16use octseq::builder::OctetsBuilder;
17use octseq::octets::{Octets, OctetsFrom};
18use octseq::parse::Parser;
19
20#[derive(Clone, Copy)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize))]
32#[repr(transparent)]
33pub struct Chain<Name: ?Sized> {
34 start: Name,
36}
37
38impl Chain<()> {
39 pub(super) const CODE: OptionCode = OptionCode::CHAIN;
41}
42
43impl<Name: ?Sized> Chain<Name> {
44 pub fn new(start: Name) -> Self
46 where
47 Name: Sized,
48 {
49 Chain { start }
50 }
51
52 pub fn new_ref(start: &Name) -> &Self {
54 unsafe { mem::transmute(start) }
56 }
57
58 pub fn start(&self) -> &Name {
63 &self.start
64 }
65
66 pub fn into_start(self) -> Name
68 where
69 Name: Sized,
70 {
71 self.start
72 }
73}
74
75impl<Octs> Chain<Name<Octs>> {
76 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
78 parser: &mut Parser<'a, Src>,
79 ) -> Result<Self, ParseError> {
80 Name::parse(parser).map(Self::new)
81 }
82}
83
84impl<Name, SrcName> OctetsFrom<Chain<SrcName>> for Chain<Name>
87where
88 Name: OctetsFrom<SrcName>,
89{
90 type Error = Name::Error;
91
92 fn try_octets_from(src: Chain<SrcName>) -> Result<Self, Self::Error> {
93 Name::try_octets_from(src.start).map(Self::new)
94 }
95}
96
97impl<Name, OtherName> PartialEq<Chain<OtherName>> for Chain<Name>
100where
101 Name: ToName,
102 OtherName: ToName,
103{
104 fn eq(&self, other: &Chain<OtherName>) -> bool {
105 self.start().name_eq(other.start())
106 }
107}
108
109impl<Name: ToName> Eq for Chain<Name> {}
110
111impl<Name, OtherName> PartialOrd<Chain<OtherName>> for Chain<Name>
114where
115 Name: ToName,
116 OtherName: ToName,
117{
118 fn partial_cmp(&self, other: &Chain<OtherName>) -> Option<Ordering> {
119 Some(self.start().name_cmp(other.start()))
120 }
121}
122
123impl<Name: ToName> Ord for Chain<Name> {
124 fn cmp(&self, other: &Self) -> Ordering {
125 self.start().name_cmp(other.start())
126 }
127}
128
129impl<Name: hash::Hash> hash::Hash for Chain<Name> {
132 fn hash<H: hash::Hasher>(&self, state: &mut H) {
133 self.start().hash(state)
134 }
135}
136
137impl<Name> OptData for Chain<Name> {
140 fn code(&self) -> OptionCode {
141 OptionCode::CHAIN
142 }
143}
144
145impl<'a, Octs> ParseOptData<'a, Octs> for Chain<Name<Octs::Range<'a>>>
146where
147 Octs: Octets,
148{
149 fn parse_option(
150 code: OptionCode,
151 parser: &mut Parser<'a, Octs>,
152 ) -> Result<Option<Self>, ParseError> {
153 if code == OptionCode::CHAIN {
154 Self::parse(parser).map(Some)
155 } else {
156 Ok(None)
157 }
158 }
159}
160
161impl<Name: ToName> ComposeOptData for Chain<Name> {
162 fn compose_len(&self) -> u16 {
163 self.start.compose_len()
164 }
165
166 fn compose_option<Target: OctetsBuilder + ?Sized>(
167 &self,
168 target: &mut Target,
169 ) -> Result<(), Target::AppendError> {
170 self.start.compose(target)
171 }
172}
173
174impl<Name: fmt::Display> fmt::Display for Chain<Name> {
177 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
178 write!(f, "{}", self.start)
179 }
180}
181
182impl<Name: fmt::Display> fmt::Debug for Chain<Name> {
183 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184 f.debug_struct("Chain")
185 .field("start", &format_args!("{}", self.start))
186 .finish()
187 }
188}
189
190impl<Octs: Octets> Opt<Octs> {
193 pub fn chain(&self) -> Option<Chain<Name<Octs::Range<'_>>>> {
198 self.first()
199 }
200}
201
202impl<Target: Composer> OptBuilder<'_, Target> {
203 pub fn chain(
210 &mut self,
211 start: impl ToName,
212 ) -> Result<(), Target::AppendError> {
213 self.push(&Chain::new(start))
214 }
215}
216
217#[cfg(test)]
220#[cfg(all(feature = "std", feature = "bytes"))]
221mod test {
222 use super::super::test::test_option_compose_parse;
223 use super::*;
224 use core::str::FromStr;
225 use std::vec::Vec;
226
227 #[test]
228 #[allow(clippy::redundant_closure)] fn chain_compose_parse() {
230 test_option_compose_parse(
231 &Chain::new(Name::<Vec<u8>>::from_str("example.com").unwrap()),
232 |parser| Chain::parse(parser),
233 );
234 }
235}