1use core::{
3 convert::Infallible,
4 fmt,
5 hash::Hash,
6 mem,
7 ops::{RangeFrom, RangeTo},
8};
9
10use crate::{
11 accum::{Accum, AccumObj, Finished},
12 side::Side,
13 strategy::StrategyObj,
14 Strategy,
15};
16
17#[non_exhaustive]
19pub struct CapacityExhausted<'a, A: ?Sized + AccumObj> {
20 pub item: A::Item,
22
23 pub side: Side,
25
26 pub accum: &'a A,
28}
29impl<'a, A: Accum> CapacityExhausted<'a, A> {
30 pub fn erased_accum(self) -> CapacityExhausted<'a, dyn 'a + AccumObj<Item = A::Item>> {
32 CapacityExhausted {
33 item: self.item,
34 side: self.side,
35 accum: self.accum,
36 }
37 }
38}
39impl<'a, A: ?Sized + AccumObj<Item: Copy>> Copy for CapacityExhausted<'a, A> {}
40impl<'a, A: ?Sized + AccumObj<Item: Clone>> Clone for CapacityExhausted<'a, A> {
41 #[inline]
42 fn clone(&self) -> Self {
43 CapacityExhausted {
44 item: self.item.clone(),
45 side: self.side,
46 accum: self.accum,
47 }
48 }
49}
50impl<'a, A: PartialEq + AccumObj<Item: PartialEq>> PartialEq for CapacityExhausted<'a, A> {
51 #[inline]
52 fn eq(&self, rhs: &CapacityExhausted<'a, A>) -> bool {
53 self.item == rhs.item && self.side == rhs.side && self.accum == rhs.accum
54 }
55}
56impl<'a, A: Eq + AccumObj<Item: Eq>> Eq for CapacityExhausted<'a, A> {}
57impl<'a, A: Hash + AccumObj<Item: Hash>> Hash for CapacityExhausted<'a, A> {
58 #[inline]
59 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
60 (&self.item, self.side, self.accum).hash(state);
61 }
62}
63impl<'a, A: fmt::Debug + AccumObj<Item: fmt::Debug>> fmt::Debug for CapacityExhausted<'a, A> {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 f.debug_struct("CapacityExhausted")
66 .field("item", &self.item)
67 .field("side", &self.side)
68 .field("accum", &self.accum)
69 .finish_non_exhaustive()
70 }
71}
72impl<'a, A: ?Sized + Accum> From<Infallible> for CapacityExhausted<'a, A> {
73 #[inline]
74 fn from(err: Infallible) -> CapacityExhausted<'a, A> {
75 match err {}
76 }
77}
78impl<'a, A: ?Sized + AccumObj<Item: fmt::Debug>> fmt::Display for CapacityExhausted<'a, A> {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 write!(f, "capacity exhausted: ")?;
81 let mut list = f.debug_list();
82 list.entries((0..self.accum.len_forward()).filter_map(|idx| self.accum.get_forward(idx)));
83 if self.side == Side::Backward {
84 list.entry(&format_args!(".."));
85 }
86 list.entry(&format_args!("(no room for {:?})", self.item));
87 if self.side == Side::Forward {
88 list.entry(&format_args!(".."));
89 }
90 list.entries(
91 (0..self.accum.len_backward())
92 .rev()
93 .filter_map(|idx| self.accum.get_backward(idx)),
94 );
95 list.finish()
96 }
97}
98
99pub struct FailedStrategy<'a, T, S: ?Sized, V> {
101 pub(crate) side: Side,
103
104 pub(crate) forward: usize,
106
107 pub(crate) backward: usize,
109
110 pub(crate) accum: Finished<'a, T>,
112
113 pub strategy: &'a S,
115
116 pub cause: V,
118}
119impl<'a, T, S: Strategy, V> FailedStrategy<'a, T, S, V> {
120 #[inline]
122 pub fn erased_strategy(self) -> FailedStrategy<'a, T, dyn 'a + StrategyObj, V> {
123 FailedStrategy {
124 side: self.side,
125 forward: self.forward,
126 backward: self.backward,
127 accum: self.accum,
128 strategy: self.strategy,
129 cause: self.cause,
130 }
131 }
132}
133impl<'a, T, S: ?Sized, V> FailedStrategy<'a, T, S, V> {
134 #[inline]
136 pub fn empty(strategy: &'a S, cause: V) -> FailedStrategy<'a, T, S, V> {
137 FailedStrategy {
138 side: Side::Forward,
139 forward: 0,
140 backward: 0,
141 accum: Finished::empty(),
142 strategy,
143 cause,
144 }
145 }
146
147 #[inline]
149 pub fn map<U, F: FnOnce(V) -> U>(self, f: F) -> FailedStrategy<'a, T, S, U> {
150 FailedStrategy {
151 side: self.side,
152 forward: self.forward,
153 backward: self.backward,
154 accum: self.accum,
155 strategy: self.strategy,
156 cause: f(self.cause),
157 }
158 }
159
160 #[inline]
162 pub fn index(&self) -> Option<usize> {
163 match self.side {
164 Side::Forward => self.forward.checked_sub(1),
165 Side::Backward => Some(self.backward),
166 }
167 }
168
169 #[inline]
171 pub fn valid_forward(&self) -> RangeTo<usize> {
172 ..match self.side {
173 Side::Forward => self.forward.saturating_sub(1),
174 Side::Backward => self.forward,
175 }
176 }
177
178 #[inline]
180 pub fn valid_backward(&self) -> RangeFrom<usize> {
181 (match self.side {
182 Side::Forward => self.backward,
183 Side::Backward => self.backward + 1,
184 })..
185 }
186}
187impl<'a, T, S: ?Sized, V: Copy> Copy for FailedStrategy<'a, T, S, V> {}
188impl<'a, T, S: ?Sized, V: Clone> Clone for FailedStrategy<'a, T, S, V> {
189 #[inline]
190 fn clone(&self) -> Self {
191 FailedStrategy {
192 side: self.side,
193 forward: self.forward,
194 backward: self.backward,
195 accum: self.accum,
196 strategy: self.strategy,
197 cause: self.cause.clone(),
198 }
199 }
200}
201impl<'a, T: PartialEq, S: ?Sized + PartialEq, V: PartialEq> PartialEq
202 for FailedStrategy<'a, T, S, V>
203{
204 #[inline]
205 fn eq(&self, rhs: &FailedStrategy<'a, T, S, V>) -> bool {
206 self.side == rhs.side
207 && self.forward == rhs.forward
208 && self.backward == rhs.backward
209 && self.accum == rhs.accum
210 && self.strategy == rhs.strategy
211 && self.cause == rhs.cause
212 }
213}
214impl<'a, T: Eq, S: ?Sized + Eq, V: Eq> Eq for FailedStrategy<'a, T, S, V> {}
215impl<'a, T: Hash, S: ?Sized + Hash, V: Hash> Hash for FailedStrategy<'a, T, S, V> {
216 #[inline]
217 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
218 (
219 self.side,
220 self.forward,
221 self.backward,
222 self.accum,
223 self.strategy,
224 &self.cause,
225 )
226 .hash(state);
227 }
228}
229impl<'a, T: fmt::Debug, S: ?Sized + fmt::Debug, V: fmt::Debug> fmt::Debug
230 for FailedStrategy<'a, T, S, V>
231{
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 f.debug_struct("FailedStrategy")
234 .field("valid_forward", &self.valid_forward())
235 .field("index", &self.index())
236 .field("valid_backward", &self.valid_backward())
237 .field("accum", &self.accum)
238 .field("strategy", &self.strategy)
239 .field("cause", &self.cause)
240 .finish_non_exhaustive()
241 }
242}
243impl<'a, T, S: ?Sized, V> From<Infallible> for FailedStrategy<'a, T, S, V> {
244 #[inline]
245 fn from(err: Infallible) -> FailedStrategy<'a, T, S, V> {
246 match err {}
247 }
248}
249impl<'a, T: fmt::Debug, S: ?Sized + fmt::Display, V: fmt::Display> fmt::Display
250 for FailedStrategy<'a, T, S, V>
251{
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 write!(f, r#"failed strategy "{}": "#, self.strategy)?;
254 let mut list = f.debug_list();
255 let fwd = self.valid_forward();
256 let bwd = self.valid_backward();
257 list.entries(&self.accum.as_slice()[fwd]);
258 if self.side == Side::Backward {
259 list.entry(&..);
260 }
261 if let Some(idx) = self.index() {
262 list.entry(&format_args!(
263 "(unexpected {:?})",
264 self.accum.get_unsigned(idx).unwrap()
265 ));
266 }
267 if self.side == Side::Forward {
268 list.entry(&..);
269 }
270 list.entries(&self.accum.as_slice()[bwd]);
271 list.finish()?;
272 write!(f, " due to verification error: {}", self.cause)
273 }
274}
275
276pub enum AccumVerifyError<'a, A: ?Sized + AccumObj, S: ?Sized, V> {
278 Accum(CapacityExhausted<'a, A>),
280
281 Verify(FailedStrategy<'a, A::Item, S, V>),
283}
284impl<'a, A: ?Sized + Accum, S: Strategy, V> AccumVerifyError<'a, A, S, V> {
285 pub fn erased_strategy(self) -> AccumVerifyError<'a, A, dyn 'a + StrategyObj, V> {
287 match self {
288 AccumVerifyError::Accum(err) => AccumVerifyError::Accum(err),
289 AccumVerifyError::Verify(err) => AccumVerifyError::Verify(err.erased_strategy()),
290 }
291 }
292}
293impl<'a, A: Accum, S: ?Sized + Strategy, V> AccumVerifyError<'a, A, S, V> {
294 pub fn erased_accum(self) -> AccumVerifyError<'a, dyn 'a + AccumObj<Item = A::Item>, S, V> {
296 match self {
297 AccumVerifyError::Accum(err) => AccumVerifyError::Accum(err.erased_accum()),
298 AccumVerifyError::Verify(err) => AccumVerifyError::Verify(err),
299 }
300 }
301}
302impl<'a, A: ?Sized + Accum, S: ?Sized + Strategy, V> AccumVerifyError<'a, A, S, V> {
303 #[inline]
305 pub fn map<U, F: FnOnce(V) -> U>(self, f: F) -> AccumVerifyError<'a, A, S, U> {
306 match self {
307 AccumVerifyError::Accum(err) => AccumVerifyError::Accum(err),
308 AccumVerifyError::Verify(err) => AccumVerifyError::Verify(err.map(f)),
309 }
310 }
311}
312impl<'a, A: Copy + Accum<Item: Copy>, S: ?Sized, V: Copy> Copy for AccumVerifyError<'a, A, S, V> {}
313impl<'a, A: ?Sized + Accum<Item: Clone>, S: ?Sized, V: Clone> Clone
314 for AccumVerifyError<'a, A, S, V>
315{
316 fn clone(&self) -> Self {
317 match self {
318 AccumVerifyError::Accum(err) => AccumVerifyError::Accum(err.clone()),
319 AccumVerifyError::Verify(err) => AccumVerifyError::Verify(err.clone()),
320 }
321 }
322}
323impl<'a, A: PartialEq + Accum<Item: PartialEq>, S: ?Sized + PartialEq, V: PartialEq> PartialEq
324 for AccumVerifyError<'a, A, S, V>
325{
326 #[inline]
327 fn eq(&self, rhs: &AccumVerifyError<'a, A, S, V>) -> bool {
328 match (self, rhs) {
329 (AccumVerifyError::Accum(lhs), AccumVerifyError::Accum(rhs)) => lhs == rhs,
330 (AccumVerifyError::Verify(lhs), AccumVerifyError::Verify(rhs)) => lhs == rhs,
331 _ => false,
332 }
333 }
334}
335impl<'a, A: Eq + Accum<Item: Eq>, S: ?Sized + Eq, V: Eq> Eq for AccumVerifyError<'a, A, S, V> {}
336impl<'a, A: Hash + Accum<Item: Hash>, S: ?Sized + Hash, V: Hash> Hash
337 for AccumVerifyError<'a, A, S, V>
338{
339 #[inline]
340 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
341 mem::discriminant(self).hash(state);
342 match self {
343 AccumVerifyError::Accum(err) => err.hash(state),
344 AccumVerifyError::Verify(err) => err.hash(state),
345 }
346 }
347}
348impl<'a, A: fmt::Debug + Accum<Item: fmt::Debug>, S: ?Sized + fmt::Debug, V: fmt::Debug> fmt::Debug
349 for AccumVerifyError<'a, A, S, V>
350{
351 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
352 match self {
353 AccumVerifyError::Accum(err) => fmt::Debug::fmt(err, f),
354 AccumVerifyError::Verify(err) => fmt::Debug::fmt(err, f),
355 }
356 }
357}
358impl<'a, A: Accum<Item: fmt::Debug>, S: ?Sized + fmt::Display, V: fmt::Display> fmt::Display
359 for AccumVerifyError<'a, A, S, V>
360{
361 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
362 match self {
363 AccumVerifyError::Accum(err) => fmt::Display::fmt(err, f),
364 AccumVerifyError::Verify(err) => fmt::Display::fmt(err, f),
365 }
366 }
367}
368impl<'a, A: ?Sized + Accum, S: ?Sized, V> From<Infallible> for AccumVerifyError<'a, A, S, V> {
369 #[inline]
370 fn from(err: Infallible) -> AccumVerifyError<'a, A, S, V> {
371 match err {}
372 }
373}
374impl<'a, A: ?Sized + Accum, S: ?Sized, V> From<CapacityExhausted<'a, A>>
375 for AccumVerifyError<'a, A, S, V>
376{
377 #[inline]
378 fn from(err: CapacityExhausted<'a, A>) -> AccumVerifyError<'a, A, S, V> {
379 AccumVerifyError::Accum(err)
380 }
381}
382impl<'a, A: ?Sized + Accum, S: ?Sized, V> From<FailedStrategy<'a, A::Item, S, V>>
383 for AccumVerifyError<'a, A, S, V>
384{
385 #[inline]
386 fn from(err: FailedStrategy<'a, A::Item, S, V>) -> AccumVerifyError<'a, A, S, V> {
387 AccumVerifyError::Verify(err)
388 }
389}
390
391#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
393pub enum Inconsistent<'a, T> {
394 Empty,
396
397 Unequal(Unequal<'a, T>),
399}
400impl<'a, T: fmt::Debug> fmt::Display for Inconsistent<'a, T> {
401 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
402 match self {
403 Inconsistent::Empty => write!(f, "no data was returned by iterator"),
404 Inconsistent::Unequal(err) => fmt::Display::fmt(err, f),
405 }
406 }
407}
408
409#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
411#[non_exhaustive]
412pub struct Unequal<'a, T> {
413 pub expected: Option<&'a T>,
417
418 pub actual: &'a T,
420}
421impl<'a, T: fmt::Debug> fmt::Display for Unequal<'a, T> {
422 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
423 let actual = self.actual;
424 match self.expected {
425 Some(expected) => write!(f, "{actual:?} != {expected:?}"),
426 None => write!(f, "extraneous value {actual:?}"),
427 }
428 }
429}
430
431#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
433pub struct InvalidPair<'a, T> {
434 pub pair: (&'a T, &'a T),
436
437 pub(crate) index_is_negative: bool,
439}
440impl<'a, T: fmt::Debug> fmt::Display for InvalidPair<'a, T> {
441 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442 let (lo, hi) = self.pair;
443 if self.index_is_negative {
444 write!(
445 f,
446 "sequence (invalid {lo:?}, {hi:?}) didn't satisfy requirements"
447 )
448 } else {
449 write!(
450 f,
451 "sequence ({lo:?}, invalid {hi:?}) didn't satisfy requirements"
452 )
453 }
454 }
455}
456
457#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
459#[non_exhaustive]
460pub struct InvalidIndex<'a, T> {
461 pub item: &'a T,
463
464 pub index: usize,
466}
467impl<'a, T: fmt::Debug> fmt::Display for InvalidIndex<'a, T> {
468 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
469 let item = self.item;
470 let index = self.index;
471 write!(
472 f,
473 "item {item:?} at index {index:?} didn't satisfy requirements"
474 )
475 }
476}
477
478#[cfg(test)]
479mod tests {
480 use crate::{
481 accum::{Accum, Bounded, Finished},
482 error::{CapacityExhausted, FailedStrategy},
483 side::Side,
484 strategy::Todo,
485 };
486
487 const SLICE: Finished<'static, u32> = Finished::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5);
488
489 #[test]
490 fn failed_insert_fwd() {
491 let error: CapacityExhausted<Bounded<u32, 10>> = CapacityExhausted {
492 item: 4,
493 side: Side::Forward,
494 accum: &Bounded::with_data(&[1, 2, 3], &[8, 9, 10]),
495 };
496 assert_eq!(
497 error.to_string(),
498 "capacity exhausted: [1, 2, 3, (no room for 4), .., 8, 9, 10]"
499 );
500 }
501
502 #[test]
503 fn failed_insert_bwd() {
504 let error: CapacityExhausted<Bounded<u32, 10>> = CapacityExhausted {
505 item: 7,
506 side: Side::Backward,
507 accum: &Bounded::with_data(&[1, 2, 3], &[8, 9, 10]),
508 };
509 assert_eq!(
510 error.to_string(),
511 "capacity exhausted: [1, 2, 3, .., (no room for 7), 8, 9, 10]"
512 );
513 }
514
515 #[test]
516 fn failed_empty() {
517 let error: FailedStrategy<u32, Todo, &str> = FailedStrategy::empty(&Todo, "bad");
518 assert_eq!(
519 error.to_string(),
520 r#"failed strategy "unimplemented": [..] due to verification error: bad"#
521 );
522 }
523
524 #[test]
525 fn failed_empty_fwd_empty() {
526 let error: FailedStrategy<u32, Todo, &str> = FailedStrategy {
527 side: Side::Forward,
528 forward: 1,
529 backward: 10,
530 cause: "bad",
531 accum: SLICE,
532 strategy: &Todo,
533 };
534 assert_eq!(
535 error.to_string(),
536 r#"failed strategy "unimplemented": [(unexpected 1), ..] due to verification error: bad"#
537 );
538 }
539
540 #[test]
541 fn failed_empty_bwd_empty() {
542 let error: FailedStrategy<u32, Todo, &str> = FailedStrategy {
543 side: Side::Backward,
544 forward: 0,
545 backward: 9,
546 cause: "bad",
547 accum: SLICE,
548 strategy: &Todo,
549 };
550 assert_eq!(
551 error.to_string(),
552 r#"failed strategy "unimplemented": [.., (unexpected 10)] due to verification error: bad"#
553 );
554 }
555
556 #[test]
557 fn failed_nonempty_fwd_empty() {
558 let error: FailedStrategy<u32, Todo, &str> = FailedStrategy {
559 side: Side::Forward,
560 forward: 3,
561 backward: 10,
562 cause: "bad",
563 accum: SLICE,
564 strategy: &Todo,
565 };
566 assert_eq!(
567 error.to_string(),
568 r#"failed strategy "unimplemented": [1, 2, (unexpected 3), ..] due to verification error: bad"#
569 );
570 }
571
572 #[test]
573 fn failed_nonempty_bwd_empty() {
574 let error: FailedStrategy<u32, Todo, &str> = FailedStrategy {
575 side: Side::Backward,
576 forward: 3,
577 backward: 9,
578 cause: "bad",
579 accum: SLICE,
580 strategy: &Todo,
581 };
582 assert_eq!(
583 error.to_string(),
584 r#"failed strategy "unimplemented": [1, 2, 3, .., (unexpected 10)] due to verification error: bad"#
585 );
586 }
587
588 #[test]
589 fn failed_empty_fwd_nonempty() {
590 let error: FailedStrategy<u32, Todo, &str> = FailedStrategy {
591 side: Side::Forward,
592 forward: 1,
593 backward: 7,
594 cause: "bad",
595 accum: SLICE,
596 strategy: &Todo,
597 };
598 assert_eq!(
599 error.to_string(),
600 r#"failed strategy "unimplemented": [(unexpected 1), .., 8, 9, 10] due to verification error: bad"#
601 );
602 }
603
604 #[test]
605 fn failed_empty_bwd_nonempty() {
606 let error: FailedStrategy<u32, Todo, &str> = FailedStrategy {
607 side: Side::Backward,
608 forward: 0,
609 backward: 7,
610 cause: "bad",
611 accum: SLICE,
612 strategy: &Todo,
613 };
614 assert_eq!(
615 error.to_string(),
616 r#"failed strategy "unimplemented": [.., (unexpected 8), 9, 10] due to verification error: bad"#
617 );
618 }
619
620 #[test]
621 fn failed_nonempty_fwd_nonempty() {
622 let error: FailedStrategy<u32, Todo, &str> = FailedStrategy {
623 side: Side::Forward,
624 forward: 3,
625 backward: 7,
626 cause: "bad",
627 accum: SLICE,
628 strategy: &Todo,
629 };
630 assert_eq!(
631 error.to_string(),
632 r#"failed strategy "unimplemented": [1, 2, (unexpected 3), .., 8, 9, 10] due to verification error: bad"#
633 );
634 }
635
636 #[test]
637 fn failed_nonempty_bwd_nonempty() {
638 let error: FailedStrategy<u32, Todo, &str> = FailedStrategy {
639 side: Side::Backward,
640 forward: 3,
641 backward: 7,
642 cause: "bad",
643 accum: SLICE,
644 strategy: &Todo,
645 };
646 assert_eq!(
647 error.to_string(),
648 r#"failed strategy "unimplemented": [1, 2, 3, .., (unexpected 8), 9, 10] due to verification error: bad"#
649 );
650 }
651}