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;
8
9/// A slice of a [Path Component](https://willowprotocol.org/specs/data-model/index.html#Component).
10///
11/// This type statically enforces a [**m**ax\_**c**omponent\_**l**ength](https://willowprotocol.org/specs/data-model/index.html#max_component_length) of `MCL`. Otherwise, it is basically a regular `[u8]`.
12///
13/// This is an *unsized* type, meaning that it must always be used behind a pointer like `&` or [`Box`].
14#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
15#[repr(transparent)]
16pub struct Component<const MCL: usize>([u8]);
17
18impl<const MCL: usize> Component<MCL> {
19    /// Creates a reference to a [`Component`] from a reference to a byte slice. Returns [`None`] if the slice is longer than `MCL`.
20    ///
21    /// Aside from checking the length, this is a cost-free conversion.
22    ///
23    /// #### Examples
24    ///
25    /// ```
26    /// use willow_data_model::prelude::*;
27    /// assert!(Component::<3>::new(b"yay").is_ok());
28    /// assert!(Component::<3>::new(b"too_long").is_err());
29    /// ```
30    pub fn new(s: &[u8]) -> Result<&Self, InvalidComponentError> {
31        if s.len() <= MCL {
32            Ok(unsafe { Self::new_unchecked(s) })
33        } else {
34            Err(InvalidComponentError)
35        }
36    }
37
38    /// Creates a reference to a [`Component`] from a reference to a byte slice, without verifying its length.
39    ///
40    /// This is a cost-free conversion.
41    ///
42    /// #### Safety
43    ///
44    /// Supplying a slice of length strictly greater than `MCL` may trigger undefined behavior,
45    /// either immediately, or on any subsequent function invocation that operates on the resulting [`Component`].
46    ///
47    /// #### Examples
48    ///
49    /// ```
50    /// use willow_data_model::prelude::*;
51    /// let unchecked_component = unsafe { Component::<3>::new_unchecked(b"yay") };
52    /// assert_eq!(unchecked_component.as_ref(), b"yay");
53    /// ```
54    pub unsafe fn new_unchecked(s: &[u8]) -> &Self {
55        debug_assert!(s.len() <= MCL);
56        unsafe { &*(s as *const [u8] as *const Self) }
57    }
58
59    /// Creates a mutable reference to a [`Component`] from a mutable reference to a byte slice. Returns [`None`] if the slice is longer than `MCL`.
60    ///
61    /// Aside from checking the length, this is a cost-free conversion.
62    ///
63    /// #### Examples
64    ///
65    /// ```
66    /// use willow_data_model::prelude::*;
67    /// assert!(Component::<3>::new_mut(&mut [b'y', b'a', b'y']).is_ok());
68    /// assert!(Component::<3>::new_mut(&mut [b'n', b'o', b'p', b'e']).is_err());
69    /// ```
70    pub fn new_mut(s: &mut [u8]) -> Result<&mut Self, InvalidComponentError> {
71        if s.len() <= MCL {
72            Ok(unsafe { Self::new_mut_unchecked(s) })
73        } else {
74            Err(InvalidComponentError)
75        }
76    }
77
78    /// Creates a mutable reference to a [`Component`] from a mutable reference to a byte slice, without verifying its length.
79    ///
80    /// This is a cost-free conversion.
81    ///
82    /// #### Safety
83    ///
84    /// Supplying a slice of length strictly greater than `MCL` may trigger undefined behavior,
85    /// either immediately, or on any subsequent function invocation that operates on the resulting [`Component`].
86    ///
87    /// #### Examples
88    ///
89    /// ```
90    /// use willow_data_model::prelude::*;
91    /// let mut buf = [b'y', b'a', b'y'];
92    /// let unchecked_component = unsafe { Component::<3>::new_mut_unchecked(&mut buf[..]) };
93    /// assert_eq!(unchecked_component.as_ref(), &mut [b'y', b'a', b'y']);
94    /// ```
95    pub unsafe fn new_mut_unchecked(s: &mut [u8]) -> &mut Self {
96        debug_assert!(s.len() <= MCL);
97        unsafe { &mut *(s as *mut [u8] as *mut Self) }
98    }
99
100    /// Creates a `&'static` reference to the empty component.
101    pub fn new_empty() -> &'static Self {
102        unsafe { Self::new_unchecked(&[]) }
103    }
104
105    /// Returns the raw bytes of the component.
106    ///
107    /// ```
108    /// use willow_data_model::prelude::*;
109    /// assert_eq!(Component::<3>::new(b"yay").unwrap().as_bytes(), b"yay");
110    /// ```
111    pub fn as_bytes(&self) -> &[u8] {
112        &self.0
113    }
114
115    /// Returns a mutable reference to the raw bytes of the component.
116    ///
117    /// ```
118    /// use willow_data_model::prelude::*;
119    /// assert_eq!(
120    ///     Component::<3>::new_mut(&mut [b'y', b'a', b'y']).unwrap().as_bytes_mut(),
121    ///     &mut [b'y', b'a', b'y'],
122    /// );
123    /// ```
124    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
125        &mut self.0
126    }
127}
128
129impl<const MCL: usize> Deref for Component<MCL> {
130    type Target = [u8];
131
132    fn deref(&self) -> &Self::Target {
133        &self.0
134    }
135}
136
137impl<const MCL: usize> AsRef<[u8]> for Component<MCL> {
138    fn as_ref(&self) -> &[u8] {
139        &self.0
140    }
141}
142
143impl<const MCL: usize> Borrow<[u8]> for Component<MCL> {
144    fn borrow(&self) -> &[u8] {
145        &self.0
146    }
147}
148
149impl<const MCL: usize> fmt::Debug for Component<MCL> {
150    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151        f.debug_tuple("Component")
152            .field(&ComponentFmtHelper::new(&self, true))
153            .finish()
154    }
155}
156
157impl<const MCL: usize> fmt::Display for Component<MCL> {
158    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159        ComponentFmtHelper::new(&self, true).fmt(f)
160    }
161}
162
163impl<const MCL: usize> IndexMut<usize> for Component<MCL> {
164    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
165        &mut self.0[index]
166    }
167}
168
169impl<const MCL: usize> Index<usize> for Component<MCL> {
170    type Output = u8;
171
172    fn index(&self, index: usize) -> &Self::Output {
173        &self.0[index]
174    }
175}
176
177impl<const MCL: usize> Index<Range<usize>> for Component<MCL> {
178    type Output = Component<MCL>;
179
180    fn index(&self, index: Range<usize>) -> &Self::Output {
181        // SAFETY: This call to `Component::new_unchecked` is safe because
182        // indexing into a slice of length at most MCL never yields a slice
183        // of length greater than MCL.
184        unsafe { Component::new_unchecked(&self.0[index]) }
185    }
186}
187
188impl<const MCL: usize> Index<RangeFrom<usize>> for Component<MCL> {
189    type Output = Component<MCL>;
190
191    fn index(&self, index: RangeFrom<usize>) -> &Self::Output {
192        // SAFETY: This call to `Component::new_unchecked` is safe because
193        // indexing into a slice of length at most MCL never yields a slice
194        // of length greater than MCL.
195        unsafe { Component::new_unchecked(&self.0[index]) }
196    }
197}
198
199impl<const MCL: usize> Index<RangeTo<usize>> for Component<MCL> {
200    type Output = Component<MCL>;
201
202    fn index(&self, index: RangeTo<usize>) -> &Self::Output {
203        // SAFETY: This call to `Component::new_unchecked` is safe because
204        // indexing into a slice of length at most MCL never yields a slice
205        // of length greater than MCL.
206        unsafe { Component::new_unchecked(&self.0[index]) }
207    }
208}
209
210impl<const MCL: usize> Index<RangeFull> for Component<MCL> {
211    type Output = Component<MCL>;
212
213    fn index(&self, index: RangeFull) -> &Self::Output {
214        // SAFETY: This call to `Component::new_unchecked` is safe because
215        // indexing into a slice of length at most MCL never yields a slice
216        // of length greater than MCL.
217        unsafe { Component::new_unchecked(&self.0[index]) }
218    }
219}
220
221impl<const MCL: usize> Index<RangeInclusive<usize>> for Component<MCL> {
222    type Output = Component<MCL>;
223
224    fn index(&self, index: RangeInclusive<usize>) -> &Self::Output {
225        // SAFETY: This call to `Component::new_unchecked` is safe because
226        // indexing into a slice of length at most MCL never yields a slice
227        // of length greater than MCL.
228        unsafe { Component::new_unchecked(&self.0[index]) }
229    }
230}
231
232impl<const MCL: usize> Index<RangeToInclusive<usize>> for Component<MCL> {
233    type Output = Component<MCL>;
234
235    fn index(&self, index: RangeToInclusive<usize>) -> &Self::Output {
236        // SAFETY: This call to `Component::new_unchecked` is safe because
237        // indexing into a slice of length at most MCL never yields a slice
238        // of length greater than MCL.
239        unsafe { Component::new_unchecked(&self.0[index]) }
240    }
241}
242
243/// 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.
244///
245/// 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.
246#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
247pub struct OwnedComponent<const MCL: usize>(pub(crate) Bytes);
248
249impl<const MCL: usize> OwnedComponent<MCL> {
250    /// Creates an [`OwnedComponent`] by copying data from a byte slice. Returns [`None`] if the slice is longer than `MCL`.
251    ///
252    /// #### Complexity
253    ///
254    /// Runs in `O(n)`, where `n` is the length of the slice. Performs a single allocation of `O(n)` bytes.
255    ///
256    /// #### Examples
257    ///
258    /// ```
259    /// use willow_data_model::prelude::*;
260    /// assert!(OwnedComponent::<3>::new(b"yay").is_ok());
261    /// assert!(OwnedComponent::<3>::new(b"too_long").is_err());
262    /// ```
263    pub fn new(data: &[u8]) -> Result<Self, InvalidComponentError> {
264        if data.len() <= MCL {
265            Ok(unsafe { Self::new_unchecked(data) }) // Safe because we just checked the length.
266        } else {
267            Err(InvalidComponentError)
268        }
269    }
270
271    /// Creates an [`OwnedComponent`] by copying data from a byte slice, without verifying its length.
272    ///
273    /// #### Safety
274    ///
275    /// Supplying a slice of length strictly greater than `MCL` may trigger undefined behavior,
276    /// either immediately, or on any subsequent function invocation that operates on the resulting [`OwnedComponent`].
277    ///
278    /// #### Complexity
279    ///
280    /// Runs in `O(n)`, where `n` is the length of the slice. Performs a single allocation of `O(n)` bytes.
281    ///
282    /// #### Examples
283    ///
284    /// ```
285    /// use willow_data_model::prelude::*;
286    /// let unchecked_component = unsafe { OwnedComponent::<3>::new_unchecked(b"yay") };
287    /// assert_eq!(unchecked_component.as_ref(), b"yay");
288    /// ```
289    pub unsafe fn new_unchecked(data: &[u8]) -> Self {
290        debug_assert!(data.len() <= MCL);
291        Self(Bytes::copy_from_slice(data))
292    }
293
294    /// Returns an empty [`OwnedComponent`].
295    ///
296    /// #### Complexity
297    ///
298    /// Runs in `O(1)`, performs no allocations.
299    ///
300    /// #### Examples
301    ///
302    /// ```
303    /// use willow_data_model::prelude::*;
304    /// let empty_component = OwnedComponent::<3>::new_empty();
305    /// assert_eq!(empty_component.as_ref(), &[]);
306    /// assert_eq!(empty_component, OwnedComponent::<3>::default());
307    /// ```
308    pub fn new_empty() -> Self {
309        Self(Bytes::new())
310    }
311
312    /// Returns the raw bytes of the component.
313    ///
314    /// ```
315    /// use willow_data_model::prelude::*;
316    /// assert_eq!(OwnedComponent::<3>::new(b"yay").unwrap().as_bytes(), b"yay");
317    /// ```
318    pub fn as_bytes(&self) -> &[u8] {
319        self.0.as_ref()
320    }
321}
322
323impl<const MCL: usize> Deref for OwnedComponent<MCL> {
324    type Target = [u8];
325
326    fn deref(&self) -> &Self::Target {
327        self.0.deref()
328    }
329}
330
331impl<const MCL: usize> AsRef<[u8]> for OwnedComponent<MCL> {
332    fn as_ref(&self) -> &[u8] {
333        self.0.as_ref()
334    }
335}
336
337impl<const MCL: usize> Borrow<[u8]> for OwnedComponent<MCL> {
338    fn borrow(&self) -> &[u8] {
339        self.0.borrow()
340    }
341}
342
343impl<const MCL: usize> fmt::Debug for OwnedComponent<MCL> {
344    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
345        f.debug_tuple("OwnedComponent")
346            .field(&ComponentFmtHelper::new(self, true))
347            .finish()
348    }
349}
350
351impl<const MCL: usize> fmt::Display for OwnedComponent<MCL> {
352    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
353        ComponentFmtHelper::new(self, true).fmt(f)
354    }
355}
356
357impl<const MCL: usize> Index<usize> for OwnedComponent<MCL> {
358    type Output = u8;
359
360    fn index(&self, index: usize) -> &Self::Output {
361        &self.0[index]
362    }
363}
364
365impl<const MCL: usize> Index<Range<usize>> for OwnedComponent<MCL> {
366    type Output = Component<MCL>;
367
368    fn index(&self, index: Range<usize>) -> &Self::Output {
369        // SAFETY: This call to `Component::new_unchecked` is safe because
370        // indexing into a slice of length at most MCL never yields a slice
371        // of length greater than MCL.
372        unsafe { Component::new_unchecked(&self.0[index]) }
373    }
374}
375
376impl<const MCL: usize> Index<RangeFrom<usize>> for OwnedComponent<MCL> {
377    type Output = Component<MCL>;
378
379    fn index(&self, index: RangeFrom<usize>) -> &Self::Output {
380        // SAFETY: This call to `Component::new_unchecked` is safe because
381        // indexing into a slice of length at most MCL never yields a slice
382        // of length greater than MCL.
383        unsafe { Component::new_unchecked(&self.0[index]) }
384    }
385}
386
387impl<const MCL: usize> Index<RangeTo<usize>> for OwnedComponent<MCL> {
388    type Output = Component<MCL>;
389
390    fn index(&self, index: RangeTo<usize>) -> &Self::Output {
391        // SAFETY: This call to `Component::new_unchecked` is safe because
392        // indexing into a slice of length at most MCL never yields a slice
393        // of length greater than MCL.
394        unsafe { Component::new_unchecked(&self.0[index]) }
395    }
396}
397
398impl<const MCL: usize> Index<RangeFull> for OwnedComponent<MCL> {
399    type Output = Component<MCL>;
400
401    fn index(&self, index: RangeFull) -> &Self::Output {
402        // SAFETY: This call to `Component::new_unchecked` is safe because
403        // indexing into a slice of length at most MCL never yields a slice
404        // of length greater than MCL.
405        unsafe { Component::new_unchecked(&self.0[index]) }
406    }
407}
408
409impl<const MCL: usize> Index<RangeInclusive<usize>> for OwnedComponent<MCL> {
410    type Output = Component<MCL>;
411
412    fn index(&self, index: RangeInclusive<usize>) -> &Self::Output {
413        // SAFETY: This call to `Component::new_unchecked` is safe because
414        // indexing into a slice of length at most MCL never yields a slice
415        // of length greater than MCL.
416        unsafe { Component::new_unchecked(&self.0[index]) }
417    }
418}
419
420impl<const MCL: usize> Index<RangeToInclusive<usize>> for OwnedComponent<MCL> {
421    type Output = Component<MCL>;
422
423    fn index(&self, index: RangeToInclusive<usize>) -> &Self::Output {
424        // SAFETY: This call to `Component::new_unchecked` is safe because
425        // indexing into a slice of length at most MCL never yields a slice
426        // of length greater than MCL.
427        unsafe { Component::new_unchecked(&self.0[index]) }
428    }
429}
430
431#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
432/// 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)).
433///
434/// #### Example
435///
436/// ```
437/// use willow_data_model::prelude::*;
438/// assert_eq!(Component::<4>::new(b"too_long"), Err(InvalidComponentError));
439/// ```
440pub struct InvalidComponentError;
441
442impl core::fmt::Display for InvalidComponentError {
443    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
444        write!(
445            f,
446            "Length of a component exceeded the maximum component length"
447        )
448    }
449}
450
451impl core::error::Error for InvalidComponentError {}
452
453pub(crate) struct ComponentFmtHelper<'a, T> {
454    component: &'a T,
455    /// If `true`, renders empty components as `"<empty>"`, if `false` renders them as `""` (the empty string).
456    render_empty: bool,
457}
458
459impl<'a, T> ComponentFmtHelper<'a, T> {
460    pub(crate) fn new(component: &'a T, render_empty: bool) -> Self {
461        Self {
462            component,
463            render_empty,
464        }
465    }
466}
467
468impl<'a, T> fmt::Debug for ComponentFmtHelper<'a, T>
469where
470    T: AsRef<[u8]>,
471{
472    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
473        if self.component.as_ref().is_empty() {
474            if self.render_empty {
475                write!(f, "<empty>")
476            } else {
477                Ok(())
478            }
479        } else {
480            for byte in self.component.as_ref().iter() {
481                percent_encode_fmt(f, *byte)?;
482            }
483            Ok(())
484        }
485    }
486}
487
488fn byte_is_unreserved(byte: u8) -> bool {
489    byte.is_ascii_alphanumeric() || byte == b'-' || byte == b'.' || byte == b'_' || byte == b'~'
490}
491
492fn percent_encode_fmt(f: &mut fmt::Formatter<'_>, byte: u8) -> fmt::Result {
493    if byte_is_unreserved(byte) {
494        f.write_char(unsafe { char::from_u32_unchecked(byte as u32) })
495    } else {
496        f.write_char('%')?;
497        let low = byte & 0b0000_1111;
498        let high = byte >> 4;
499        f.write_char(char::from_digit(high as u32, 16).unwrap())?;
500        f.write_char(char::from_digit(low as u32, 16).unwrap())
501    }
502}
503
504#[test]
505#[cfg(feature = "std")]
506fn test_fmt() {
507    assert_eq!(
508        &format!("{}", Component::<17>::new(b"").unwrap()),
509        "<empty>"
510    );
511    assert_eq!(&format!("{}", Component::<17>::new(b" ").unwrap()), "%20");
512    assert_eq!(
513        &format!("{}", Component::<17>::new(b".- ~_ab190%/").unwrap()),
514        ".-%20~_ab190%25%2f"
515    );
516}
517
518#[cfg(test)]
519mod tests {
520    use super::*;
521
522    // Component tests
523
524    #[test]
525    fn index_mut() {
526        let base = &mut [b'y', b'a', b'y'];
527        let slice = &mut [b'y', b'a', b'y'][..];
528        let compo = Component::<8>::new_mut(base).unwrap();
529
530        compo[0] = b'b';
531        slice[0] = b'b';
532
533        assert_eq!(&b"bay"[..], slice);
534        assert_eq!(&b"bay"[..], compo.as_bytes());
535    }
536
537    #[test]
538    fn index() {
539        let slice = &b"sunshine"[..];
540        let compo = Component::<8>::new(b"sunshine").unwrap();
541        assert_eq!(slice[1], compo[1]);
542        assert_eq!(slice[5], compo[5]);
543    }
544
545    #[test]
546    #[should_panic]
547    fn index_out_of_bound() {
548        let compo = Component::<8>::new(b"sunshine").unwrap();
549        let _ = &compo[8];
550    }
551
552    #[test]
553    fn range() {
554        let slice = &b"sunshine"[..];
555        let compo = Component::<8>::new(b"sunshine").unwrap();
556        assert_eq!(&slice[1..3], compo[1..3].as_bytes());
557    }
558
559    #[test]
560    fn range_0_0() {
561        let slice = &b"sunshine"[..];
562        let compo = Component::<8>::new(b"sunshine").unwrap();
563        assert_eq!(&slice[0..0], compo[0..0].as_bytes());
564    }
565
566    #[test]
567    fn rangefull() {
568        let slice = &b"sunshine"[..];
569        let compo = Component::<8>::new(b"sunshine").unwrap();
570        assert_eq!(slice, compo[..].as_bytes());
571    }
572
573    #[test]
574    fn rangefrom() {
575        let slice = &b"sunshine"[..];
576        let compo = Component::<8>::new(b"sunshine").unwrap();
577        assert_eq!(&slice[1..], compo[1..].as_bytes());
578    }
579
580    #[test]
581    fn rangeto() {
582        let slice = &b"sunshine"[..];
583        let compo = Component::<8>::new(b"sunshine").unwrap();
584        assert_eq!(&slice[..3], compo[..3].as_bytes());
585    }
586
587    #[test]
588    #[should_panic]
589    #[allow(clippy::reversed_empty_ranges)]
590    fn range_start_bigger_than_end() {
591        let compo = Component::<8>::new(b"sunshine").unwrap();
592        let _ = &compo[2..1];
593    }
594
595    #[test]
596    fn rangefrom_start_equal_component() {
597        let slice = &b"sunshine"[..];
598        let compo = Component::<8>::new(b"sunshine").unwrap();
599        assert_eq!(&slice[8..], compo[8..].as_bytes());
600    }
601
602    #[test]
603    #[should_panic]
604    fn rangefrom_start_bigger_than_component() {
605        let compo = Component::<8>::new(b"sunshine").unwrap();
606        let _ = &compo[9..];
607    }
608
609    #[test]
610    #[should_panic]
611    fn rangeto_end_bigger_than_component() {
612        let compo = Component::<8>::new(b"sunshine").unwrap();
613        let _ = &compo[..9];
614    }
615
616    // OwnedComponent tests
617
618    #[test]
619    fn owned_index() {
620        let slice = &b"sunshine"[..];
621        let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
622        assert_eq!(slice[1], compo[1]);
623        assert_eq!(slice[5], compo[5]);
624    }
625
626    #[test]
627    #[should_panic]
628    fn owned_index_out_of_bound() {
629        let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
630        let _ = &compo[8];
631    }
632
633    #[test]
634    fn owned_range() {
635        let slice = &b"sunshine"[..];
636        let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
637        assert_eq!(&slice[1..3], compo[1..3].as_bytes());
638    }
639
640    #[test]
641    fn owned_range_0_0() {
642        let slice = &b"sunshine"[..];
643        let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
644        assert_eq!(&slice[0..0], compo[0..0].as_bytes());
645    }
646
647    #[test]
648    fn owned_rangefull() {
649        let slice = &b"sunshine"[..];
650        let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
651        assert_eq!(slice, compo[..].as_bytes());
652    }
653
654    #[test]
655    fn owned_rangefrom() {
656        let slice = &b"sunshine"[..];
657        let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
658        assert_eq!(&slice[1..], compo[1..].as_bytes());
659    }
660
661    #[test]
662    fn owned_rangeto() {
663        let slice = &b"sunshine"[..];
664        let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
665        assert_eq!(&slice[..3], compo[..3].as_bytes());
666    }
667
668    #[test]
669    #[should_panic]
670    #[allow(clippy::reversed_empty_ranges)]
671    fn owned_range_start_bigger_than_end() {
672        let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
673        let _ = &compo[2..1];
674    }
675
676    #[test]
677    fn owned_rangefrom_start_equal_component() {
678        let slice = &b"sunshine"[..];
679        let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
680        assert_eq!(&slice[8..], compo[8..].as_bytes());
681    }
682
683    #[test]
684    #[should_panic]
685    fn owned_rangefrom_start_bigger_than_component() {
686        let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
687        let _ = &compo[9..];
688    }
689
690    #[test]
691    #[should_panic]
692    fn owned_rangeto_end_bigger_than_component() {
693        let compo = OwnedComponent::<8>::new(b"sunshine").unwrap();
694        let _ = &compo[..9];
695    }
696}