1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub struct Span {
7 pub start: usize,
8 pub end: usize,
9}
10
11impl Span {
12 #[inline]
16 pub fn new(start: usize, end: usize) -> Self {
17 assert!(
18 start <= end,
19 "Span::new: start ({start}) must not exceed end ({end})"
20 );
21 Self { start, end }
22 }
23
24 #[inline]
25 pub fn len(&self) -> usize {
26 self.end - self.start
27 }
28
29 #[inline]
30 pub fn is_empty(&self) -> bool {
31 self.start == self.end
32 }
33
34 #[inline]
38 pub fn as_slice<'a>(&self, source: &'a [u8]) -> &'a [u8] {
39 &source[self.start..self.end]
40 }
41
42 #[inline]
45 pub fn try_as_slice<'a>(&self, source: &'a [u8]) -> Option<&'a [u8]> {
46 source.get(self.start..self.end)
47 }
48
49 #[inline]
55 pub fn as_str<'a>(&self, source: &'a [u8]) -> Result<&'a str, std::str::Utf8Error> {
56 std::str::from_utf8(self.as_slice(source))
57 }
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum MarkingType {
63 Portion,
65 Banner,
67 Cab,
69 PageBreak,
74}
75
76#[derive(Debug, Clone, Copy)]
78pub struct MarkingCandidate {
79 pub span: Span,
80 pub kind: MarkingType,
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85pub enum Zone {
86 Header,
87 Footer,
88 Body,
89 Cab,
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub enum DocumentPosition {
96 Start,
97 Body,
98 End,
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn span_new_accepts_equal_bounds() {
107 let s = Span::new(5, 5);
108 assert!(s.is_empty());
109 assert_eq!(s.len(), 0);
110 }
111
112 #[test]
113 fn span_new_accepts_normal_range() {
114 let s = Span::new(2, 7);
115 assert!(!s.is_empty());
116 assert_eq!(s.len(), 5);
117 }
118
119 #[test]
120 #[should_panic(expected = "Span::new")]
121 fn span_new_panics_on_inverted_bounds() {
122 let _ = Span::new(7, 2);
123 }
124
125 #[test]
126 fn try_as_slice_returns_none_when_out_of_bounds() {
127 let buf = b"hello";
128 let s = Span::new(2, 100);
129 assert!(s.try_as_slice(buf).is_none());
130 }
131
132 #[test]
133 fn try_as_slice_returns_bytes_when_in_bounds() {
134 let buf = b"hello";
135 let s = Span::new(1, 4);
136 assert_eq!(s.try_as_slice(buf), Some(&b"ell"[..]));
137 }
138
139 #[test]
140 fn as_str_returns_utf8_slice() {
141 let buf = b"abc";
142 let s = Span::new(0, 3);
143 assert_eq!(s.as_str(buf).unwrap(), "abc");
144 }
145}