1use std::fmt::Display;
2use std::ops::Range;
3use std::ops::RangeBounds;
4use std::ops::RangeFrom;
5use std::ops::RangeFull;
6use std::ops::RangeInclusive;
7use std::ops::RangeTo;
8use std::ops::RangeToInclusive;
9
10use crate::err::Error;
11use crate::error;
12
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
36pub enum Index {
37 Forward(usize),
49
50 Backward(usize),
62
63 List(Vec<usize>),
75
76 Except(Vec<usize>),
88
89 Range(usize, Option<usize>),
109
110 AnyWhere,
118
119 #[default]
120 Null,
121}
122
123impl Index {
124 pub fn parse(dat: &str) -> Result<Self, Error> {
125 use neure::prelude::*;
126
127 let start = re::start();
128 let end = re::end();
129 let sign = "+".or("-").opt().map(|v| Ok(v != Some("-")));
130 let num = char::is_ascii_digit.repeat_one_more();
131 let num = num.map(map::from_str::<usize>());
132
133 let any_parser = "*".map(|_| Ok(Index::anywhere()));
134 let seq_parser = sign
135 .then(num.sep(",").quote("[", "]"))
136 .map(|(s, v)| Ok(if s { Index::list(v) } else { Index::except(v) }));
137 let range_parser = num
138 .opt()
139 .sep_once("..", num.opt())
140 .map(|(beg, end)| Ok(Index::range(beg, end)));
141 let pos_parser = sign.then(num).map(|(s, v)| {
142 Ok(if s {
143 Index::forward(v)
144 } else {
145 Index::backward(v)
146 })
147 });
148
149 let parser = start
150 .then(any_parser.or(seq_parser).or(range_parser).or(pos_parser))
151 ._1()
152 .then(end)
153 ._0();
154
155 CharsCtx::new(dat)
156 .ignore(char::is_ascii_whitespace.repeat_full())
157 .ctor(&parser)
158 .map_err(|_| Error::index_parse(dat, "failed parsing index"))
159 }
160
161 pub fn is_null(&self) -> bool {
162 matches!(self, Self::Null)
163 }
164
165 pub fn is_forward(&self) -> bool {
166 matches!(self, Self::Forward(_))
167 }
168
169 pub fn is_backward(&self) -> bool {
170 matches!(self, Self::Backward(_))
171 }
172
173 pub fn is_list(&self) -> bool {
174 matches!(self, Self::List(_))
175 }
176
177 pub fn is_except(&self) -> bool {
178 matches!(self, Self::Except(_))
179 }
180
181 pub fn is_range(&self) -> bool {
182 matches!(self, Self::Range(_, _))
183 }
184
185 pub fn is_anywhere(&self) -> bool {
186 matches!(self, Self::AnyWhere)
187 }
188
189 pub fn to_help(&self) -> String {
190 match self {
191 Index::Forward(offset) => {
192 format!("{}", offset)
193 }
194 Index::Backward(offset) => {
195 format!("-{}", offset)
196 }
197 Index::List(list) => {
198 format!(
199 "[{}]",
200 list.iter()
201 .map(|v| v.to_string())
202 .collect::<Vec<String>>()
203 .join(", ")
204 )
205 }
206 Index::Except(list) => {
207 format!(
208 "-[{}]",
209 list.iter()
210 .map(|v| v.to_string())
211 .collect::<Vec<String>>()
212 .join(", ")
213 )
214 }
215 Index::Range(start, None) => {
216 format!("{}..", start)
217 }
218 Index::Range(start, Some(end)) => {
219 format!("{}..{}", start, end)
220 }
221 Index::AnyWhere => "*".to_string(),
222 Index::Null => String::default(),
223 }
224 }
225
226 pub fn forward(index: usize) -> Self {
227 Self::Forward(index)
228 }
229
230 pub fn backward(index: usize) -> Self {
231 Self::Backward(index)
232 }
233
234 pub fn list(list: Vec<usize>) -> Self {
235 Self::List(list)
236 }
237
238 pub fn except(list: Vec<usize>) -> Self {
239 Self::Except(list)
240 }
241
242 pub fn range(start: Option<usize>, end: Option<usize>) -> Self {
243 match (start, end) {
244 (None, None) => {
245 panic!("start and end can't both None")
246 }
247 (None, _) => Self::Range(0, end),
248 (Some(start), _) => Self::Range(start, end),
249 }
250 }
251
252 pub(crate) fn from_range(range: &impl RangeBounds<usize>) -> Result<Self, Error> {
253 match (range.start_bound(), range.end_bound()) {
254 (std::ops::Bound::Included(s), std::ops::Bound::Included(e)) => {
255 Ok(Self::range(Some(*s), Some(e + 1)))
256 }
257 (std::ops::Bound::Included(s), std::ops::Bound::Excluded(e)) => {
258 Ok(Self::range(Some(*s), Some(*e)))
259 }
260 (std::ops::Bound::Included(s), std::ops::Bound::Unbounded) => {
261 Ok(Self::range(Some(*s), None))
262 }
263 (std::ops::Bound::Excluded(s), std::ops::Bound::Included(e)) => {
264 if *s == 0 {
265 Err(error!(
266 "start position of Index can't be negative: {:?}",
267 range.start_bound()
268 ))
269 } else {
270 Ok(Self::range(Some(*s - 1), Some(e + 1)))
271 }
272 }
273 (std::ops::Bound::Excluded(s), std::ops::Bound::Excluded(e)) => {
274 if *s == 0 {
275 Err(error!(
276 "start position of Index can't be negative: {:?}",
277 range.start_bound()
278 ))
279 } else {
280 Ok(Self::range(Some(*s - 1), Some(*e)))
281 }
282 }
283 (std::ops::Bound::Excluded(s), std::ops::Bound::Unbounded) => {
284 if *s == 0 {
285 Err(error!(
286 "start position of Index can't be negative: {:?}",
287 range.start_bound()
288 ))
289 } else {
290 Ok(Self::range(Some(*s - 1), None))
291 }
292 }
293 (std::ops::Bound::Unbounded, std::ops::Bound::Included(e)) => {
294 Ok(Self::range(Some(0), Some(*e - 1)))
295 }
296 (std::ops::Bound::Unbounded, std::ops::Bound::Excluded(e)) => {
297 Ok(Self::range(Some(0), Some(*e)))
298 }
299 (std::ops::Bound::Unbounded, std::ops::Bound::Unbounded) => {
300 panic!("start and end of Index can't both unbounded")
301 }
302 }
303 }
304
305 pub fn anywhere() -> Self {
306 Self::AnyWhere
307 }
308
309 pub fn null() -> Self {
310 Self::Null
311 }
312
313 pub fn calc_index(&self, noa_index: usize, noa_count: usize) -> Option<usize> {
314 match self {
315 Self::Forward(offset) => {
316 let offset = *offset;
317
318 if offset < noa_count {
319 return Some(offset);
320 }
321 }
322 Self::Backward(offset) => {
323 let offset = *offset;
324
325 if offset < noa_count {
326 return Some(noa_count - offset - 1);
327 }
328 }
329 Self::List(list) => {
330 for offset in list {
331 let offset = *offset;
332
333 if offset < noa_count && offset == noa_index {
334 return Some(offset);
335 }
336 }
337 }
338 Self::Except(list) => {
339 if noa_index < noa_count && !list.contains(&noa_index) {
340 return Some(noa_index);
341 }
342 }
343 Self::Range(start, end) => match (start, end) {
344 (start, None) => {
345 let start = *start;
346
347 if noa_index >= start {
348 return Some(noa_index);
349 }
350 }
351 (start, Some(end)) => {
352 let start = *start;
353 let end = *end;
354
355 if noa_index >= start && noa_index < end {
356 return Some(noa_index);
357 }
358 }
359 },
360 Self::AnyWhere => {
361 return Some(noa_index);
362 }
363 _ => {}
364 }
365 None
366 }
367}
368
369impl Display for Index {
370 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
371 write!(
372 f,
373 "{}",
374 match self {
375 Index::AnyWhere => "*".to_string(),
376 Index::Null => String::default(),
377 Index::Forward(v) => {
378 format!("{}", v)
379 }
380 Index::Backward(v) => {
381 format!("-{}", v)
382 }
383 Index::Range(s, None) => {
384 format!("{}..", s,)
385 }
386 Index::Range(s, Some(e)) => {
387 format!("{}..{}", s, e)
388 }
389 Index::List(v) => {
390 let strs: Vec<String> = v.iter().map(|v| format!("{}", v)).collect();
391
392 format!("[{}]", strs.join(", "))
393 }
394 Index::Except(v) => {
395 let strs: Vec<String> = v.iter().map(|v| format!("{}", v)).collect();
396
397 format!("-[{}]", strs.join(", "))
398 }
399 }
400 )
401 }
402}
403
404impl TryFrom<String> for Index {
405 type Error = Error;
406
407 fn try_from(value: String) -> Result<Self, Self::Error> {
408 Self::parse(&value)
409 }
410}
411
412impl<'a> TryFrom<&'a str> for Index {
413 type Error = Error;
414
415 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
416 Self::parse(value)
417 }
418}
419
420macro_rules! impl_range_for {
421 ($range:ty) => {
422 impl TryFrom<$range> for Index {
423 type Error = Error;
424
425 fn try_from(value: $range) -> Result<Self, Self::Error> {
426 Self::from_range(&value)
427 }
428 }
429
430 impl<'a> TryFrom<&'a $range> for Index {
431 type Error = Error;
432
433 fn try_from(value: &'a $range) -> Result<Self, Self::Error> {
434 Self::from_range(value)
435 }
436 }
437 };
438}
439
440impl_range_for!(Range<usize>);
441
442impl_range_for!(RangeFrom<usize>);
443
444impl_range_for!(RangeInclusive<usize>);
445
446impl_range_for!(RangeTo<usize>);
447
448impl_range_for!(RangeToInclusive<usize>);
449
450impl_range_for!(RangeFull);
451
452macro_rules! impl_signed_ty_for {
453 ($int:ty) => {
454 impl TryFrom<$int> for Index {
455 type Error = Error;
456
457 fn try_from(value: $int) -> Result<Self, Self::Error> {
458 Ok(if value >= 0 {
459 Self::forward(value as usize)
460 } else {
461 Self::backward((-value) as usize)
462 })
463 }
464 }
465 };
466}
467
468impl_signed_ty_for!(isize);
469
470impl_signed_ty_for!(i128);
471
472impl_signed_ty_for!(i64);
473
474impl_signed_ty_for!(i32);
475
476impl_signed_ty_for!(i16);
477
478impl_signed_ty_for!(i8);
479
480macro_rules! impl_unsigned_ty_for {
481 ($int:ty) => {
482 impl TryFrom<$int> for Index {
483 type Error = Error;
484
485 fn try_from(value: $int) -> Result<Self, Self::Error> {
486 Ok(Self::forward(value as usize))
487 }
488 }
489 };
490}
491
492impl_unsigned_ty_for!(usize);
493
494impl_unsigned_ty_for!(u128);
495
496impl_unsigned_ty_for!(u64);
497
498impl_unsigned_ty_for!(u32);
499
500impl_unsigned_ty_for!(u16);
501
502impl_unsigned_ty_for!(u8);
503
504impl TryFrom<Vec<usize>> for Index {
505 type Error = Error;
506
507 fn try_from(value: Vec<usize>) -> Result<Self, Self::Error> {
508 Ok(Self::list(value))
509 }
510}
511
512impl<const N: usize> TryFrom<[usize; N]> for Index {
513 type Error = Error;
514
515 fn try_from(value: [usize; N]) -> Result<Self, Self::Error> {
516 Ok(Self::list(Vec::from(value)))
517 }
518}