Skip to main content

willow_data_model/paths/
component.rs

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/// A slice of a [Path Component](https://willowprotocol.org/specs/data-model/index.html#Component).
11///
12/// This type statically enforces a [max\_component\_length](https://willowprotocol.org/specs/data-model/index.html#max_component_length) of `MCL`. Otherwise, it is basically a regular `[u8]`.
13///
14/// This is an *unsized* type, meaning that it must always be used behind a pointer like `&` or [`Box`](std::boxed::Box).
15#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[repr(transparent)]
17pub struct Component<const MCL: usize>([u8]);
18
19impl<const MCL: usize> Component<MCL> {
20    /// Creates a reference to a [`Component`] from a reference to a byte slice. Returns [`None`] if the slice is longer than `MCL`.
21    ///
22    /// Aside from checking the length, this is a cost-free conversion.
23    ///
24    /// #### Examples
25    ///
26    /// ```
27    /// use willow_data_model::prelude::*;
28    /// assert!(Component::<3>::new(b"yay").is_ok());
29    /// assert!(Component::<3>::new(b"too_long").is_err());
30    /// ```
31    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    /// Creates a reference to a [`Component`] from a reference to a byte slice, without verifying its length.
40    ///
41    /// This is a cost-free conversion.
42    ///
43    /// #### Safety
44    ///
45    /// Supplying a slice of length strictly greater than `MCL` may trigger undefined behavior,
46    /// either immediately, or on any subsequent function invocation that operates on the resulting [`Component`].
47    ///
48    /// #### Examples
49    ///
50    /// ```
51    /// use willow_data_model::prelude::*;
52    /// let unchecked_component = unsafe { Component::<3>::new_unchecked(b"yay") };
53    /// assert_eq!(unchecked_component.as_ref(), b"yay");
54    /// ```
55    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    /// Creates a mutable reference to a [`Component`] from a mutable reference to a byte slice. Returns [`None`] if the slice is longer than `MCL`.
61    ///
62    /// Aside from checking the length, this is a cost-free conversion.
63    ///
64    /// #### Examples
65    ///
66    /// ```
67    /// use willow_data_model::prelude::*;
68    /// assert!(Component::<3>::new_mut(&mut [b'y', b'a', b'y']).is_ok());
69    /// assert!(Component::<3>::new_mut(&mut [b'n', b'o', b'p', b'e']).is_err());
70    /// ```
71    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    /// Creates a mutable reference to a [`Component`] from a mutable reference to a byte slice, without verifying its length.
80    ///
81    /// This is a cost-free conversion.
82    ///
83    /// #### Safety
84    ///
85    /// Supplying a slice of length strictly greater than `MCL` may trigger undefined behavior,
86    /// either immediately, or on any subsequent function invocation that operates on the resulting [`Component`].
87    ///
88    /// #### Examples
89    ///
90    /// ```
91    /// use willow_data_model::prelude::*;
92    /// let mut buf = [b'y', b'a', b'y'];
93    /// let unchecked_component = unsafe { Component::<3>::new_mut_unchecked(&mut buf[..]) };
94    /// assert_eq!(unchecked_component.as_ref(), &mut [b'y', b'a', b'y']);
95    /// ```
96    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    /// Creates a `&'static` reference to the empty component.
102    pub fn new_empty() -> &'static Self {
103        unsafe { Self::new_unchecked(&[]) }
104    }
105
106    /// Returns the raw bytes of the component.
107    ///
108    /// ```
109    /// use willow_data_model::prelude::*;
110    /// assert_eq!(Component::<3>::new(b"yay").unwrap().as_bytes(), b"yay");
111    /// ```
112    pub fn as_bytes(&self) -> &[u8] {
113        &self.0
114    }
115
116    /// Returns a mutable reference to the raw bytes of the component.
117    ///
118    /// ```
119    /// use willow_data_model::prelude::*;
120    /// assert_eq!(
121    ///     Component::<3>::new_mut(&mut [b'y', b'a', b'y']).unwrap().as_bytes_mut(),
122    ///     &mut [b'y', b'a', b'y'],
123    /// );
124    /// ```
125    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        // SAFETY: This call to `Component::new_unchecked` is safe because
183        // indexing into a slice of length at most MCL never yields a slice
184        // of length greater than MCL.
185        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        // SAFETY: This call to `Component::new_unchecked` is safe because
194        // indexing into a slice of length at most MCL never yields a slice
195        // of length greater than MCL.
196        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        // SAFETY: This call to `Component::new_unchecked` is safe because
205        // indexing into a slice of length at most MCL never yields a slice
206        // of length greater than MCL.
207        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        // SAFETY: This call to `Component::new_unchecked` is safe because
216        // indexing into a slice of length at most MCL never yields a slice
217        // of length greater than MCL.
218        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        // SAFETY: This call to `Component::new_unchecked` is safe because
227        // indexing into a slice of length at most MCL never yields a slice
228        // of length greater than MCL.
229        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        // SAFETY: This call to `Component::new_unchecked` is safe because
238        // indexing into a slice of length at most MCL never yields a slice
239        // of length greater than MCL.
240        unsafe { Component::new_unchecked(&self.0[index]) }
241    }
242}
243
244/// An owned [component](https://willowprotocol.org/specs/data-model/index.html#Component) of a Willow [Path](https://willowprotocol.org/specs/data-model/index.html#Path), using reference counting for cheap cloning. Typically obtained from a [`Path`](super::Path) instead of being created independently.
245///
246/// This type enforces a const-generic [maximum component length](https://willowprotocol.org/specs/data-model/index.html#max_component_length). Use the [`AsRef`], [`Deref`], or [`Borrow`] implementation to access wrapped the immutable byte slice.
247#[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    /// Creates an [`OwnedComponent`] by copying data from a byte slice. Returns [`None`] if the slice is longer than `MCL`.
252    ///
253    /// #### Complexity
254    ///
255    /// Runs in `O(n)`, where `n` is the length of the slice. Performs a single allocation of `O(n)` bytes.
256    ///
257    /// #### Examples
258    ///
259    /// ```
260    /// use willow_data_model::prelude::*;
261    /// assert!(OwnedComponent::<3>::new(b"yay").is_ok());
262    /// assert!(OwnedComponent::<3>::new(b"too_long").is_err());
263    /// ```
264    pub fn new(data: &[u8]) -> Result<Self, InvalidComponentError> {
265        if data.len() <= MCL {
266            Ok(unsafe { Self::new_unchecked(data) }) // Safe because we just checked the length.
267        } else {
268            Err(InvalidComponentError)
269        }
270    }
271
272    /// Creates an [`OwnedComponent`] by copying data from a byte slice, without verifying its length.
273    ///
274    /// #### Safety
275    ///
276    /// Supplying a slice of length strictly greater than `MCL` may trigger undefined behavior,
277    /// either immediately, or on any subsequent function invocation that operates on the resulting [`OwnedComponent`].
278    ///
279    /// #### Complexity
280    ///
281    /// Runs in `O(n)`, where `n` is the length of the slice. Performs a single allocation of `O(n)` bytes.
282    ///
283    /// #### Examples
284    ///
285    /// ```
286    /// use willow_data_model::prelude::*;
287    /// let unchecked_component = unsafe { OwnedComponent::<3>::new_unchecked(b"yay") };
288    /// assert_eq!(unchecked_component.as_ref(), b"yay");
289    /// ```
290    pub unsafe fn new_unchecked(data: &[u8]) -> Self {
291        debug_assert!(data.len() <= MCL);
292        Self(Bytes::copy_from_slice(data))
293    }
294
295    /// Returns an empty [`OwnedComponent`].
296    ///
297    /// #### Complexity
298    ///
299    /// Runs in `O(1)`, performs no allocations.
300    ///
301    /// #### Examples
302    ///
303    /// ```
304    /// use willow_data_model::prelude::*;
305    /// let empty_component = OwnedComponent::<3>::new_empty();
306    /// assert_eq!(empty_component.as_ref(), &[]);
307    /// assert_eq!(empty_component, OwnedComponent::<3>::default());
308    /// ```
309    pub fn new_empty() -> Self {
310        Self(Bytes::new())
311    }
312
313    /// Returns the raw bytes of the component.
314    ///
315    /// ```
316    /// use willow_data_model::prelude::*;
317    /// assert_eq!(OwnedComponent::<3>::new(b"yay").unwrap().as_bytes(), b"yay");
318    /// ```
319    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        // SAFETY: This call to `Component::new_unchecked` is safe because
371        // indexing into a slice of length at most MCL never yields a slice
372        // of length greater than MCL.
373        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        // SAFETY: This call to `Component::new_unchecked` is safe because
382        // indexing into a slice of length at most MCL never yields a slice
383        // of length greater than MCL.
384        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        // SAFETY: This call to `Component::new_unchecked` is safe because
393        // indexing into a slice of length at most MCL never yields a slice
394        // of length greater than MCL.
395        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        // SAFETY: This call to `Component::new_unchecked` is safe because
404        // indexing into a slice of length at most MCL never yields a slice
405        // of length greater than MCL.
406        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        // SAFETY: This call to `Component::new_unchecked` is safe because
415        // indexing into a slice of length at most MCL never yields a slice
416        // of length greater than MCL.
417        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        // SAFETY: This call to `Component::new_unchecked` is safe because
426        // indexing into a slice of length at most MCL never yields a slice
427        // of length greater than MCL.
428        unsafe { Component::new_unchecked(&self.0[index]) }
429    }
430}
431/// An error arising from trying to construct a [`Component`] of length strictly greater than the `MCL` ([max\_component\_length](https://willowprotocol.org/specs/data-model/index.html#max_component_length)).
432///
433/// #### Example
434///
435/// ```
436/// use willow_data_model::prelude::*;
437/// assert_eq!(Component::<4>::new(b"too_long"), Err(InvalidComponentError));
438/// ```
439#[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    /// If `true`, renders empty components as `"<empty>"`, if `false` renders them as `""` (the empty string).
446    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    // Component tests
513
514    #[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    // OwnedComponent tests
607
608    #[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}