hostaddr/domain/
inlined.rs1use core::borrow::Borrow;
53
54#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, derive_more::Display)]
72#[repr(transparent)]
73#[display("{}", self.as_str())]
74pub struct Buffer {
75 buf: [u8; 255],
77}
78
79impl PartialOrd for Buffer {
80 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
81 Some(self.cmp(other))
82 }
83}
84
85impl Ord for Buffer {
86 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
87 self.as_str().cmp(other.as_str())
88 }
89}
90
91#[allow(unused)]
92#[cfg(any(
93 feature = "std",
94 feature = "alloc",
95 feature = "smol_str_0_3",
96 feature = "triomphe_0_1",
97 feature = "bytes_1",
98 feature = "tinyvec_1",
99 feature = "smallvec_1",
100 feature = "bytes_1"
101))]
102macro_rules! impl_from_domain_buffer {
103 ($($as:ident(
104 $($into:ident -> $ty:ty), +$(,)?
105 )), +$(,)?) => {
106 $(
107 $(
108 impl_from_domain_buffer!($as -> $into -> $ty);
109 )*
110 )*
111 };
112 ($as:ident -> $into:ident -> $ty:ty) => {
113 impl From<Buffer> for $ty {
114 fn from(value: Buffer) -> Self {
115 value.$as().$into()
116 }
117 }
118 };
119}
120
121#[cfg(feature = "smol_str_0_3")]
122impl_from_domain_buffer!(as_str -> into -> smol_str_0_3::SmolStr);
123#[cfg(feature = "triomphe_0_1")]
124impl_from_domain_buffer!(as_str -> into -> triomphe_0_1::Arc<str>);
125#[cfg(feature = "triomphe_0_1")]
126impl_from_domain_buffer!(as_bytes -> into -> triomphe_0_1::Arc<[u8]>);
127#[cfg(feature = "bytes_1")]
128const _: () = {
129 use bytes_1::Bytes;
130
131 impl From<Buffer> for Bytes {
132 fn from(value: Buffer) -> Self {
133 Bytes::copy_from_slice(value.as_bytes())
134 }
135 }
136};
137#[cfg(feature = "tinyvec_1")]
138const _: () = {
139 use tinyvec_1::TinyVec;
140
141 impl<const N: usize> From<Buffer> for TinyVec<[u8; N]> {
142 fn from(value: Buffer) -> Self {
143 TinyVec::from(value.as_bytes())
144 }
145 }
146};
147#[cfg(feature = "smallvec_1")]
148const _: () = {
149 use smallvec_1::SmallVec;
150
151 impl<const N: usize> From<Buffer> for SmallVec<[u8; N]> {
152 fn from(value: Buffer) -> Self {
153 SmallVec::from_slice(value.as_bytes())
154 }
155 }
156};
157
158#[cfg(any(feature = "std", feature = "alloc"))]
159const _: () = {
160 use std::{borrow::ToOwned, string::String, vec::Vec};
161
162 impl_from_domain_buffer!(
163 as_str(
164 into -> String,
165 into -> std::sync::Arc<str>,
166 into -> std::boxed::Box<str>,
167 into -> std::rc::Rc<str>,
168 ),
169 as_bytes(
170 into -> Vec<u8>,
171 into -> std::sync::Arc<[u8]>,
172 into -> std::boxed::Box<[u8]>,
173 into -> std::rc::Rc<[u8]>,
174 ),
175 );
176
177 impl From<Buffer> for std::borrow::Cow<'_, str> {
178 fn from(value: Buffer) -> Self {
185 std::borrow::Cow::Owned(value.as_str().to_owned())
186 }
187 }
188
189 impl From<Buffer> for std::borrow::Cow<'_, [u8]> {
190 fn from(value: Buffer) -> Self {
197 std::borrow::Cow::Owned(value.as_bytes().to_owned())
198 }
199 }
200};
201
202impl<'a> From<&'a Buffer> for &'a str {
203 fn from(value: &'a Buffer) -> Self {
213 value.as_str()
214 }
215}
216
217impl<'a> From<&'a Buffer> for &'a [u8] {
218 fn from(value: &'a Buffer) -> Self {
228 value.as_bytes()
229 }
230}
231
232impl Borrow<str> for Buffer {
233 #[inline]
244 fn borrow(&self) -> &str {
245 self.as_ref()
246 }
247}
248
249impl AsRef<[u8]> for Buffer {
250 fn as_ref(&self) -> &[u8] {
260 self.as_bytes()
261 }
262}
263
264impl AsRef<str> for Buffer {
265 fn as_ref(&self) -> &str {
275 self.as_str()
276 }
277}
278
279impl Buffer {
280 #[inline]
281 pub(super) const fn new() -> Self {
282 Self { buf: [0; 255] }
283 }
284
285 #[inline]
287 pub fn as_str(&self) -> &str {
288 unsafe { core::str::from_utf8_unchecked(&self.buf[..self.len()]) }
290 }
291
292 #[inline]
306 pub const fn const_as_str(&self) -> &str {
307 unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
309 }
310
311 #[inline]
313 pub const fn as_bytes(&self) -> &[u8] {
314 let len = self.len();
315 self.buf.split_at(len).0
316 }
317
318 #[inline]
320 pub const fn push(&mut self, byte: u8) -> Result<(), u8> {
321 let len = self.len();
322 if len == 254 {
323 return Err(byte);
324 }
325 self.buf[len] = byte;
326 self.buf[254] += 1;
327 Ok(())
328 }
329
330 #[inline]
331 const fn len(&self) -> usize {
332 *self.buf.last().unwrap() as usize
333 }
334
335 #[inline]
336 pub(super) fn copy_from_slice(slice: &[u8]) -> Self {
337 let len = slice.len();
338 assert!(len <= 254, "domain name too long");
339
340 let mut buf = Self::new();
341 buf.buf[..len].copy_from_slice(slice);
342 buf.buf[254] = len as u8;
343 buf
344 }
345
346 #[inline]
347 pub(super) fn copy_from_str(s: &str) -> Self {
348 Self::copy_from_slice(s.as_bytes())
349 }
350}
351
352impl core::fmt::Write for Buffer {
353 fn write_str(&mut self, s: &str) -> core::fmt::Result {
354 let len = s.len();
355 let pos = self.len();
356 if pos + len > 254 {
357 return Err(core::fmt::Error);
358 }
359 self.buf[pos..pos + len].copy_from_slice(s.as_bytes());
360 *self.buf.last_mut().unwrap() += len as u8;
361 Ok(())
362 }
363}
364
365#[cfg(feature = "serde")]
366const _: () = {
367 #[cfg(any(feature = "std", feature = "alloc"))]
368 use either::Either;
369
370 use serde::{Deserialize, Serialize};
371
372 use super::Domain;
373
374 impl Serialize for Buffer {
375 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
376 where
377 S: serde::Serializer,
378 {
379 if serializer.is_human_readable() {
380 serializer.serialize_str(self.as_str())
381 } else {
382 serializer.serialize_bytes(self.as_bytes())
383 }
384 }
385 }
386
387 impl<'de> Deserialize<'de> for Buffer {
388 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
389 where
390 D: serde::Deserializer<'de>,
391 {
392 if deserializer.is_human_readable() {
393 let s = <&str>::deserialize(deserializer)?;
394
395 #[cfg(any(feature = "std", feature = "alloc"))]
396 {
397 let res = Domain::try_from_str(s).map_err(serde::de::Error::custom)?;
398
399 Ok(match res {
400 Either::Left(d) => Self::copy_from_slice(d.0.as_bytes()),
401 Either::Right(d) => d,
402 })
403 }
404
405 #[cfg(not(any(feature = "std", feature = "alloc")))]
406 {
407 let res = Domain::try_from_ascii_str(s).map_err(serde::de::Error::custom)?;
408 Ok(Self::copy_from_slice(res.0.as_bytes()))
409 }
410 } else {
411 let bytes = <&[u8]>::deserialize(deserializer)?;
412
413 #[cfg(any(feature = "std", feature = "alloc"))]
414 {
415 let res = Domain::try_from_bytes(bytes).map_err(serde::de::Error::custom)?;
416 Ok(match res {
417 Either::Left(d) => Self::copy_from_slice(d.0),
418 Either::Right(d) => d,
419 })
420 }
421
422 #[cfg(not(any(feature = "std", feature = "alloc")))]
423 {
424 let res = Domain::try_from_ascii_bytes(bytes).map_err(serde::de::Error::custom)?;
425 Ok(Self::copy_from_slice(&res.0))
426 }
427 }
428 }
429 }
430};
431
432#[cfg(test)]
433mod test {
434 #[cfg(any(feature = "std", feature = "alloc", feature = "serde"))]
435 #[test]
436 fn test_ord() {
437 use super::*;
438
439 let a = Buffer::copy_from_str("a");
440 let b = Buffer::copy_from_str("b");
441 assert!(a < b);
442
443 assert!(a.partial_cmp(&b) == Some(core::cmp::Ordering::Less));
444 }
445}