1use std::{
2 convert::{TryFrom, TryInto},
3 fmt::Display,
4 num::ParseIntError,
5 str::FromStr,
6};
7
8use crate::checksum::Relativity;
9
10pub(crate) fn unresult_iter<I, E>(x: Result<I, E>) -> impl Iterator<Item = Result<I::Item, E>>
13where
14 I: std::iter::Iterator,
15{
16 let (i, e) = match x {
17 Ok(i) => (Some(i.map(Ok)), None),
18 Err(e) => (None, Some(std::iter::once(Err(e)))),
19 };
20 e.into_iter().flatten().chain(i.into_iter().flatten())
21}
22
23pub(crate) fn cart_prod<T: Clone, U: Clone>(a: &[T], b: &[U]) -> Vec<(T, U)> {
25 let mut v = Vec::new();
26 for x in a {
27 for y in b {
28 v.push((x.clone(), y.clone()))
29 }
30 }
31 v
32}
33
34#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
35pub struct InclRange<T: Copy + Ord> {
36 start: T,
37 end: T,
38}
39
40impl<T: Copy + Ord> InclRange<T> {
41 pub fn start(&self) -> T {
42 self.start
43 }
44 pub fn end(&self) -> T {
45 self.end
46 }
47}
48
49pub type SignedInclRange = InclRange<isize>;
50
51impl SignedInclRange {
52 pub fn new(start: isize, end: isize) -> Option<Self> {
53 SignedInclRange { start, end }.valid()
54 }
55 fn valid(self) -> Option<Self> {
56 if (self.start >= 0) == (self.end >= 0) && self.start > self.end {
57 None
58 } else {
59 Some(self)
60 }
61 }
62 pub fn set_start(mut self, start: isize) -> Option<Self> {
63 self.start = start;
64 self.valid()
65 }
66 pub fn set_end(mut self, end: isize) -> Option<Self> {
67 self.end = end;
68 self.valid()
69 }
70 pub fn to_unsigned(self, len: usize) -> Option<UnsignedInclRange> {
71 let unsigned_index = |idx: isize| {
72 if idx < 0 {
73 len.checked_sub(idx.wrapping_neg() as usize)
74 } else {
75 Some(idx as usize)
76 }
77 .and_then(|x| if x < len { Some(x) } else { None })
78 };
79 UnsignedInclRange::new(unsigned_index(self.start)?, unsigned_index(self.end)?)
80 }
81
82 pub fn limit(mut self, len: usize) -> Option<Self> {
83 let signed_max = match isize::try_from(len - 1) {
84 Err(_) => return Some(self),
86 Ok(l) => l,
87 };
88 self.start = self.start.max(-signed_max - 1);
89 self.end = self.end.min(signed_max);
90 self.valid()
91 }
92
93 pub fn slice<T>(self, slice: &[T]) -> Option<&[T]> {
94 let unsigned = self.to_unsigned(slice.len())?;
95 Some(&slice[unsigned.start..=unsigned.end])
96 }
97}
98
99pub fn read_signed_maybe_hex(s: &str) -> Result<isize, ParseIntError> {
100 s.strip_prefix("0x")
101 .map(|s0x| isize::from_str_radix(s0x, 16))
102 .unwrap_or_else(|| s.parse())
103}
104
105impl FromStr for SignedInclRange {
106 type Err = String;
108
109 fn from_str(s: &str) -> Result<Self, Self::Err> {
110 let from_maybe_hex = |s: &str| match s {
111 "" => Ok(None),
112 otherwise => read_signed_maybe_hex(otherwise).map(Some),
113 };
114 let split = s
115 .split(':')
116 .map(from_maybe_hex)
117 .collect::<Result<Vec<_>, _>>()
118 .map_err(|e| e.to_string())?;
119 let invalid = String::from("Range with non-positive length");
120 match *split.as_slice() {
121 [Some(x)] => SignedInclRange::new(x, x).ok_or(invalid),
122 [Some(start), Some(end)] => SignedInclRange::new(start, end).ok_or(invalid),
123 [None, None] => SignedInclRange::new(0, -1).ok_or(invalid),
124 [Some(start), None] => SignedInclRange::new(start, -1).ok_or(invalid),
125 [None, Some(end)] => SignedInclRange::new(0, end).ok_or(invalid),
126 _ => Err(String::from(
127 "Wrong number of colons, range must be either 0xab:0xcd or 0xab by itself",
128 )),
129 }
130 .and_then(|x| {
131 if (x.start >= 0) != (x.end >= 0) {
132 Err(String::from("Range start sign is mismatched with end sign"))
133 } else {
134 Ok(x)
135 }
136 })
137 }
138}
139
140impl Display for SignedInclRange {
141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142 let print_signed = |x: isize, f: &mut std::fmt::Formatter| {
143 if x < 0 {
144 write!(f, "-0x{:x}", -x)
145 } else {
146 write!(f, "0x{:x}", x)
147 }
148 };
149 print_signed(self.start, f)?;
150 write!(f, ":")?;
151 print_signed(self.end, f)
152 }
153}
154
155pub type UnsignedInclRange = InclRange<usize>;
156
157impl UnsignedInclRange {
158 pub fn new(start: usize, end: usize) -> Option<Self> {
159 UnsignedInclRange { start, end }.valid()
160 }
161 fn valid(self) -> Option<Self> {
162 if self.start > self.end {
163 None
164 } else {
165 Some(self)
166 }
167 }
168 pub fn set_start(mut self, start: usize) -> Option<Self> {
169 self.start = start;
170 self.valid()
171 }
172 pub fn set_end(mut self, end: usize) -> Option<Self> {
173 self.end = end;
174 self.valid()
175 }
176 pub fn contains(&self, idx: usize) -> bool {
177 idx >= self.start && idx <= self.end
178 }
179 pub fn len(&self) -> usize {
180 self.end - self.start + 1
181 }
182 pub fn is_empty(&self) -> bool {
183 false
184 }
185 pub fn to_signed(
186 self,
187 start_rel: Relativity,
188 end_rel: Relativity,
189 len: usize,
190 ) -> Option<SignedInclRange> {
191 if self.start >= len || self.end >= len {
192 return None;
193 }
194 let signed_index = |idx: usize, rel| match rel {
195 Relativity::Start => idx.try_into().ok(),
196 Relativity::End => (len - idx)
197 .try_into()
198 .ok()
199 .map(<isize as std::ops::Neg>::neg),
200 };
201 SignedInclRange::new(
202 signed_index(self.start, start_rel)?,
203 signed_index(self.end, end_rel)?,
204 )
205 }
206}