1use core::fmt::{Debug, Write};
2use core::ops::{
3 Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
4};
5use core::{borrow::Borrow, fmt, ops::Deref};
6
7use bytes::Bytes;
8use derive_more::{Display, Error};
9
10#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[repr(transparent)]
17pub struct Component<const MCL: usize>([u8]);
18
19impl<const MCL: usize> Component<MCL> {
20 pub fn new(s: &[u8]) -> Result<&Self, InvalidComponentError> {
32 if s.len() <= MCL {
33 Ok(unsafe { Self::new_unchecked(s) })
34 } else {
35 Err(InvalidComponentError)
36 }
37 }
38
39 pub unsafe fn new_unchecked(s: &[u8]) -> &Self {
56 debug_assert!(s.len() <= MCL);
57 unsafe { &*(s as *const [u8] as *const Self) }
58 }
59
60 pub fn new_mut(s: &mut [u8]) -> Result<&mut Self, InvalidComponentError> {
72 if s.len() <= MCL {
73 Ok(unsafe { Self::new_mut_unchecked(s) })
74 } else {
75 Err(InvalidComponentError)
76 }
77 }
78
79 pub unsafe fn new_mut_unchecked(s: &mut [u8]) -> &mut Self {
97 debug_assert!(s.len() <= MCL);
98 unsafe { &mut *(s as *mut [u8] as *mut Self) }
99 }
100
101 pub fn new_empty() -> &'static Self {
103 unsafe { Self::new_unchecked(&[]) }
104 }
105
106 pub fn as_bytes(&self) -> &[u8] {
113 &self.0
114 }
115
116 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
126 &mut self.0
127 }
128}
129
130impl<const MCL: usize> Deref for Component<MCL> {
131 type Target = [u8];
132
133 fn deref(&self) -> &Self::Target {
134 &self.0
135 }
136}
137
138impl<const MCL: usize> AsRef<[u8]> for Component<MCL> {
139 fn as_ref(&self) -> &[u8] {
140 &self.0
141 }
142}
143
144impl<const MCL: usize> Borrow<[u8]> for Component<MCL> {
145 fn borrow(&self) -> &[u8] {
146 &self.0
147 }
148}
149
150impl<const MCL: usize> fmt::Debug for Component<MCL> {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 f.debug_tuple("Component")
153 .field(&ComponentFmtHelper::new(&self, true))
154 .finish()
155 }
156}
157
158impl<const MCL: usize> fmt::Display for Component<MCL> {
159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160 ComponentFmtHelper::new(&self, true).fmt(f)
161 }
162}
163
164impl<const MCL: usize> IndexMut<usize> for Component<MCL> {
165 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
166 &mut self.0[index]
167 }
168}
169
170impl<const MCL: usize> Index<usize> for Component<MCL> {
171 type Output = u8;
172
173 fn index(&self, index: usize) -> &Self::Output {
174 &self.0[index]
175 }
176}
177
178impl<const MCL: usize> Index<Range<usize>> for Component<MCL> {
179 type Output = Component<MCL>;
180
181 fn index(&self, index: Range<usize>) -> &Self::Output {
182 unsafe { Component::new_unchecked(&self.0[index]) }
186 }
187}
188
189impl<const MCL: usize> Index<RangeFrom<usize>> for Component<MCL> {
190 type Output = Component<MCL>;
191
192 fn index(&self, index: RangeFrom<usize>) -> &Self::Output {
193 unsafe { Component::new_unchecked(&self.0[index]) }
197 }
198}
199
200impl<const MCL: usize> Index<RangeTo<usize>> for Component<MCL> {
201 type Output = Component<MCL>;
202
203 fn index(&self, index: RangeTo<usize>) -> &Self::Output {
204 unsafe { Component::new_unchecked(&self.0[index]) }
208 }
209}
210
211impl<const MCL: usize> Index<RangeFull> for Component<MCL> {
212 type Output = Component<MCL>;
213
214 fn index(&self, index: RangeFull) -> &Self::Output {
215 unsafe { Component::new_unchecked(&self.0[index]) }
219 }
220}
221
222impl<const MCL: usize> Index<RangeInclusive<usize>> for Component<MCL> {
223 type Output = Component<MCL>;
224
225 fn index(&self, index: RangeInclusive<usize>) -> &Self::Output {
226 unsafe { Component::new_unchecked(&self.0[index]) }
230 }
231}
232
233impl<const MCL: usize> Index<RangeToInclusive<usize>> for Component<MCL> {
234 type Output = Component<MCL>;
235
236 fn index(&self, index: RangeToInclusive<usize>) -> &Self::Output {
237 unsafe { Component::new_unchecked(&self.0[index]) }
241 }
242}
243
244#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
248pub struct OwnedComponent<const MCL: usize>(pub(crate) Bytes);
249
250impl<const MCL: usize> OwnedComponent<MCL> {
251 pub fn new(data: &[u8]) -> Result<Self, InvalidComponentError> {
265 if data.len() <= MCL {
266 Ok(unsafe { Self::new_unchecked(data) }) } else {
268 Err(InvalidComponentError)
269 }
270 }
271
272 pub unsafe fn new_unchecked(data: &[u8]) -> Self {
291 debug_assert!(data.len() <= MCL);
292 Self(Bytes::copy_from_slice(data))
293 }
294
295 pub fn new_empty() -> Self {
310 Self(Bytes::new())
311 }
312
313 pub fn as_bytes(&self) -> &[u8] {
320 self.0.as_ref()
321 }
322}
323
324impl<const MCL: usize> Deref for OwnedComponent<MCL> {
325 type Target = [u8];
326
327 fn deref(&self) -> &Self::Target {
328 self.0.deref()
329 }
330}
331
332impl<const MCL: usize> AsRef<[u8]> for OwnedComponent<MCL> {
333 fn as_ref(&self) -> &[u8] {
334 self.0.as_ref()
335 }
336}
337
338impl<const MCL: usize> Borrow<[u8]> for OwnedComponent<MCL> {
339 fn borrow(&self) -> &[u8] {
340 self.0.borrow()
341 }
342}
343
344impl<const MCL: usize> fmt::Debug for OwnedComponent<MCL> {
345 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
346 f.debug_tuple("OwnedComponent")
347 .field(&ComponentFmtHelper::new(self, true))
348 .finish()
349 }
350}
351
352impl<const MCL: usize> fmt::Display for OwnedComponent<MCL> {
353 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
354 ComponentFmtHelper::new(self, true).fmt(f)
355 }
356}
357
358impl<const MCL: usize> Index<usize> for OwnedComponent<MCL> {
359 type Output = u8;
360
361 fn index(&self, index: usize) -> &Self::Output {
362 &self.0[index]
363 }
364}
365
366impl<const MCL: usize> Index<Range<usize>> for OwnedComponent<MCL> {
367 type Output = Component<MCL>;
368
369 fn index(&self, index: Range<usize>) -> &Self::Output {
370 unsafe { Component::new_unchecked(&self.0[index]) }
374 }
375}
376
377impl<const MCL: usize> Index<RangeFrom<usize>> for OwnedComponent<MCL> {
378 type Output = Component<MCL>;
379
380 fn index(&self, index: RangeFrom<usize>) -> &Self::Output {
381 unsafe { Component::new_unchecked(&self.0[index]) }
385 }
386}
387
388impl<const MCL: usize> Index<RangeTo<usize>> for OwnedComponent<MCL> {
389 type Output = Component<MCL>;
390
391 fn index(&self, index: RangeTo<usize>) -> &Self::Output {
392 unsafe { Component::new_unchecked(&self.0[index]) }
396 }
397}
398
399impl<const MCL: usize> Index<RangeFull> for OwnedComponent<MCL> {
400 type Output = Component<MCL>;
401
402 fn index(&self, index: RangeFull) -> &Self::Output {
403 unsafe { Component::new_unchecked(&self.0[index]) }
407 }
408}
409
410impl<const MCL: usize> Index<RangeInclusive<usize>> for OwnedComponent<MCL> {
411 type Output = Component<MCL>;
412
413 fn index(&self, index: RangeInclusive<usize>) -> &Self::Output {
414 unsafe { Component::new_unchecked(&self.0[index]) }
418 }
419}
420
421impl<const MCL: usize> Index<RangeToInclusive<usize>> for OwnedComponent<MCL> {
422 type Output = Component<MCL>;
423
424 fn index(&self, index: RangeToInclusive<usize>) -> &Self::Output {
425 unsafe { Component::new_unchecked(&self.0[index]) }
429 }
430}
431#[derive(Debug, Display, Error, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
440#[display("component length exceeded maximum")]
441pub struct InvalidComponentError;
442
443pub(crate) struct ComponentFmtHelper<'a, T> {
444 component: &'a T,
445 render_empty: bool,
447}
448
449impl<'a, T> ComponentFmtHelper<'a, T> {
450 pub(crate) fn new(component: &'a T, render_empty: bool) -> Self {
451 Self {
452 component,
453 render_empty,
454 }
455 }
456}
457
458impl<'a, T> fmt::Debug for ComponentFmtHelper<'a, T>
459where
460 T: AsRef<[u8]>,
461{
462 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
463 if self.component.as_ref().is_empty() {
464 if self.render_empty {
465 write!(f, "<empty>")
466 } else {
467 Ok(())
468 }
469 } else {
470 for byte in self.component.as_ref().iter() {
471 percent_encode_fmt(f, *byte)?;
472 }
473 Ok(())
474 }
475 }
476}
477
478fn byte_is_unreserved(byte: u8) -> bool {
479 byte.is_ascii_alphanumeric() || byte == b'-' || byte == b'.' || byte == b'_' || byte == b'~'
480}
481
482fn percent_encode_fmt(f: &mut fmt::Formatter<'_>, byte: u8) -> fmt::Result {
483 if byte_is_unreserved(byte) {
484 f.write_char(unsafe { char::from_u32_unchecked(byte as u32) })
485 } else {
486 f.write_char('%')?;
487 let low = byte & 0b0000_1111;
488 let high = byte >> 4;
489 f.write_char(char::from_digit(high as u32, 16).unwrap())?;
490 f.write_char(char::from_digit(low as u32, 16).unwrap())
491 }
492}
493
494#[test]
495#[cfg(feature = "std")]
496fn test_fmt() {
497 assert_eq!(
498 &format!("{}", Component::<17>::new(b"").unwrap()),
499 "<empty>"
500 );
501 assert_eq!(&format!("{}", Component::<17>::new(b" ").unwrap()), "%20");
502 assert_eq!(
503 &format!("{}", Component::<17>::new(b".- ~_ab190%/").unwrap()),
504 ".-%20~_ab190%25%2f"
505 );
506}
507
508#[cfg(test)]
509mod tests {
510 use super::*;
511
512 #[test]
515 fn index_mut() {
516 let base = &mut [b'y', b'a', b'y'];
517 let slice = &mut [b'y', b'a', b'y'][..];
518 let compo = Component::<8>::new_mut(base).unwrap();
519
520 compo[0] = b'b';
521 slice[0] = b'b';
522
523 assert_eq!(&b"bay"[..], slice);
524 assert_eq!(&b"bay"[..], compo.as_bytes());
525 }
526
527 #[test]
528 fn index() {
529 let slice = &b"sunshine"[..];
530 let compo = Component::<8>::new(b"sunshine").unwrap();
531 assert_eq!(slice[1], compo[1]);
532 assert_eq!(slice[5], compo[5]);
533 }
534
535 #[test]
536 #[should_panic]
537 fn index_out_of_bound() {
538 let compo = Component::<8>::new(b"sunshine").unwrap();
539 let _ = &compo[8];
540 }
541
542 #[test]
543 fn range() {
544 let slice = &b"sunshine"[..];
545 let compo = Component::<8>::new(b"sunshine").unwrap();
546 assert_eq!(&slice[1..3], compo[1..3].as_bytes());
547 }
548
549 #[test]
550 fn range_0_0() {
551 let slice = &b"sunshine"[..];
552 let compo = Component::<8>::new(b"sunshine").unwrap();
553 assert_eq!(&slice[0..0], compo[0..0].as_bytes());
554 }
555
556 #[test]
557 fn rangefull() {
558 let slice = &b"sunshine"[..];
559 let compo = Component::<8>::new(b"sunshine").unwrap();
560 assert_eq!(slice, compo[..].as_bytes());
561 }
562
563 #[test]
564 fn rangefrom() {
565 let slice = &b"sunshine"[..];
566 let compo = Component::<8>::new(b"sunshine").unwrap();
567 assert_eq!(&slice[1..], compo[1..].as_bytes());
568 }
569
570 #[test]
571 fn rangeto() {
572 let slice = &b"sunshine"[..];
573 let compo = Component::<8>::new(b"sunshine").unwrap();
574 assert_eq!(&slice[..3], compo[..3].as_bytes());
575 }
576
577 #[test]
578 #[should_panic]
579 #[allow(clippy::reversed_empty_ranges)]
580 fn range_start_bigger_than_end() {
581 let compo = Component::<8>::new(b"sunshine").unwrap();
582 let _ = &compo[2..1];
583 }
584
585 #[test]
586 fn rangefrom_start_equal_component() {
587 let slice = &b"sunshine"[..];
588 let compo = Component::<8>::new(b"sunshine").unwrap();
589 assert_eq!(&slice[8..], compo[8..].as_bytes());
590 }
591
592 #[test]
593 #[should_panic]
594 fn rangefrom_start_bigger_than_component() {
595 let compo = Component::<8>::new(b"sunshine").unwrap();
596 let _ = &compo[9..];
597 }
598
599 #[test]
600 #[should_panic]
601 fn rangeto_end_bigger_than_component() {
602 let compo = Component::<8>::new(b"sunshine").unwrap();
603 let _ = &compo[..9];
604 }
605
606 #[test]
609 fn owned_index() {
610 let slice = &b"sunshine"[..];
611 let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
612 assert_eq!(slice[1], compo[1]);
613 assert_eq!(slice[5], compo[5]);
614 }
615
616 #[test]
617 #[should_panic]
618 fn owned_index_out_of_bound() {
619 let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
620 let _ = &compo[8];
621 }
622
623 #[test]
624 fn owned_range() {
625 let slice = &b"sunshine"[..];
626 let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
627 assert_eq!(&slice[1..3], compo[1..3].as_bytes());
628 }
629
630 #[test]
631 fn owned_range_0_0() {
632 let slice = &b"sunshine"[..];
633 let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
634 assert_eq!(&slice[0..0], compo[0..0].as_bytes());
635 }
636
637 #[test]
638 fn owned_rangefull() {
639 let slice = &b"sunshine"[..];
640 let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
641 assert_eq!(slice, compo[..].as_bytes());
642 }
643
644 #[test]
645 fn owned_rangefrom() {
646 let slice = &b"sunshine"[..];
647 let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
648 assert_eq!(&slice[1..], compo[1..].as_bytes());
649 }
650
651 #[test]
652 fn owned_rangeto() {
653 let slice = &b"sunshine"[..];
654 let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
655 assert_eq!(&slice[..3], compo[..3].as_bytes());
656 }
657
658 #[test]
659 #[should_panic]
660 #[allow(clippy::reversed_empty_ranges)]
661 fn owned_range_start_bigger_than_end() {
662 let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
663 let _ = &compo[2..1];
664 }
665
666 #[test]
667 fn owned_rangefrom_start_equal_component() {
668 let slice = &b"sunshine"[..];
669 let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
670 assert_eq!(&slice[8..], compo[8..].as_bytes());
671 }
672
673 #[test]
674 #[should_panic]
675 fn owned_rangefrom_start_bigger_than_component() {
676 let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
677 let _ = &compo[9..];
678 }
679
680 #[test]
681 #[should_panic]
682 fn owned_rangeto_end_bigger_than_component() {
683 let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
684 let _ = &compo[..9];
685 }
686}