1use std::fmt;
2use std::io;
3
4#[derive(Debug)]
6pub enum Error {
7 Io(io::Error),
9 InvalidFormat(String),
11 Unsupported(String),
13 Other(String),
15}
16
17impl fmt::Display for Error {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 match self {
20 Error::Io(e) => write!(f, "I/O error: {e}"),
21 Error::InvalidFormat(msg) => write!(f, "Invalid HDF5 format: {msg}"),
22 Error::Unsupported(msg) => write!(f, "Unsupported: {msg}"),
23 Error::Other(msg) => write!(f, "{msg}"),
24 }
25 }
26}
27
28impl std::error::Error for Error {
29 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
30 match self {
31 Error::Io(e) => Some(e),
32 _ => None,
33 }
34 }
35}
36
37impl From<io::Error> for Error {
38 fn from(e: io::Error) -> Self {
39 Error::Io(e)
40 }
41}
42
43pub type Result<T> = std::result::Result<T, Error>;
45
46#[derive(Debug, Clone, PartialEq, Eq)]
48pub struct ErrorClass {
49 pub library: String,
50 pub class_name: String,
51 pub version: String,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq)]
56pub struct ErrorMessage {
57 pub message: String,
58}
59
60#[derive(Debug, Clone, PartialEq, Eq)]
62pub struct ErrorEvent {
63 pub request: String,
64 pub completed: bool,
65 pub error: Option<String>,
66}
67
68#[derive(Debug, Clone, Default, PartialEq, Eq)]
70pub struct ErrorEventSet {
71 events: Vec<ErrorEvent>,
72 op_counter: u64,
73 insert_callback_registered: bool,
74 complete_callback_registered: bool,
75}
76
77#[derive(Debug, Clone, PartialEq, Eq)]
79pub struct ErrorStackEntry {
80 pub class_name: String,
81 pub major: String,
82 pub minor: String,
83 pub description: String,
84}
85
86#[derive(Debug, Clone, Default, PartialEq, Eq)]
88pub struct ErrorStack {
89 entries: Vec<ErrorStackEntry>,
90 auto_enabled: bool,
91}
92
93impl ErrorClass {
94 pub fn register_class(
96 library: impl Into<String>,
97 class_name: impl Into<String>,
98 version: impl Into<String>,
99 ) -> Self {
100 Self {
101 library: library.into(),
102 class_name: class_name.into(),
103 version: version.into(),
104 }
105 }
106
107 pub fn register_class_internal(
109 library: impl Into<String>,
110 class_name: impl Into<String>,
111 version: impl Into<String>,
112 ) -> Self {
113 Self::register_class(library, class_name, version)
114 }
115
116 pub fn unregister_class(self) {}
118
119 pub fn unregister_class_internal(self) {}
121
122 pub fn class_name(&self) -> &str {
124 &self.class_name
125 }
126}
127
128impl ErrorMessage {
129 pub fn create_msg(message: impl Into<String>) -> Self {
131 Self {
132 message: message.into(),
133 }
134 }
135
136 pub fn create_msg_internal(message: impl Into<String>) -> Self {
138 Self::create_msg(message)
139 }
140
141 pub fn get_msg(&self) -> &str {
143 &self.message
144 }
145
146 pub fn get_msg_internal(&self) -> &str {
148 self.get_msg()
149 }
150
151 pub fn close_msg(self) {}
153
154 pub fn close_msg_cb(self) {}
156
157 pub fn close_msg_internal(self) {}
159
160 pub fn free_msg(self) {}
162}
163
164impl ErrorEvent {
165 pub fn event_new(request: impl Into<String>) -> Self {
167 Self {
168 request: request.into(),
169 completed: false,
170 error: None,
171 }
172 }
173
174 pub fn event_free(self) {}
176
177 pub fn event_completed(&mut self) {
179 self.completed = true;
180 }
181
182 pub fn handle_fail(&mut self, error: impl Into<String>) {
184 self.completed = true;
185 self.error = Some(error.into());
186 }
187}
188
189impl ErrorEventSet {
190 pub fn init_package() -> Self {
192 Self::default()
193 }
194
195 pub fn term_package(&mut self) {
197 self.events.clear();
198 }
199
200 pub fn create() -> Self {
202 Self::default()
203 }
204
205 pub fn create_internal() -> Self {
207 Self::create()
208 }
209
210 pub fn close_cb(self) {}
212
213 pub fn close_internal(self) {}
215
216 pub fn list_append(&mut self, event: ErrorEvent) {
218 self.events.push(event);
219 self.op_counter = self.op_counter.saturating_add(1);
220 }
221
222 pub fn list_count(&self) -> usize {
224 self.events.len()
225 }
226
227 pub fn list_iterate<F>(&self, mut callback: F)
229 where
230 F: FnMut(&ErrorEvent),
231 {
232 for event in &self.events {
233 callback(event);
234 }
235 }
236
237 pub fn events(&self) -> impl Iterator<Item = &ErrorEvent> {
239 self.events.iter()
240 }
241
242 pub fn list_remove(&mut self, index: usize) -> Option<ErrorEvent> {
244 if index < self.events.len() {
245 Some(self.events.remove(index))
246 } else {
247 None
248 }
249 }
250
251 pub fn insert(&mut self, request: impl Into<String>) {
253 self.insert_request(request);
254 }
255
256 pub fn insert_request(&mut self, request: impl Into<String>) {
258 self.insert_request_internal(request);
259 }
260
261 pub fn insert_request_internal(&mut self, request: impl Into<String>) {
263 self.list_append(ErrorEvent::event_new(request));
264 }
265
266 pub fn requests(&self) -> impl Iterator<Item = &str> {
268 self.events.iter().map(|event| event.request.as_str())
269 }
270
271 pub fn get_requests_with<F>(&self, mut callback: F)
273 where
274 F: FnMut(&str),
275 {
276 for request in self.requests() {
277 callback(request);
278 }
279 }
280
281 #[deprecated(note = "use requests() or get_requests_with() to avoid allocating a Vec<String>")]
283 pub fn get_requests(&self) -> Vec<String> {
284 self.requests().map(str::to_owned).collect()
285 }
286
287 pub fn get_count(&self) -> usize {
289 self.events.len()
290 }
291
292 pub fn get_op_counter(&self) -> u64 {
294 self.op_counter
295 }
296
297 pub fn wait(&mut self) -> usize {
299 let mut completed = 0;
300 for event in &mut self.events {
301 if !event.completed {
302 event.event_completed();
303 completed += 1;
304 }
305 }
306 completed
307 }
308
309 pub fn cancel(&mut self) -> usize {
311 let mut canceled = 0;
312 for event in &mut self.events {
313 if !event.completed {
314 event.completed = true;
315 event.error = Some("canceled".into());
316 canceled += 1;
317 }
318 }
319 canceled
320 }
321
322 pub fn get_err_status(&self) -> bool {
324 self.events.iter().any(|event| event.error.is_some())
325 }
326
327 pub fn get_err_count(&self) -> usize {
329 self.events
330 .iter()
331 .filter(|event| event.error.is_some())
332 .count()
333 }
334
335 pub fn err_info(&self) -> impl Iterator<Item = &str> {
337 self.events
338 .iter()
339 .filter_map(|event| event.error.as_deref())
340 }
341
342 pub fn get_err_info_with<F>(&self, mut callback: F)
344 where
345 F: FnMut(&str),
346 {
347 for error in self.err_info() {
348 callback(error);
349 }
350 }
351
352 #[deprecated(note = "use err_info() or get_err_info_with() to avoid allocating a Vec<String>")]
354 pub fn get_err_info(&self) -> Vec<String> {
355 self.err_info().map(str::to_owned).collect()
356 }
357
358 pub fn close_failed_cb(&mut self) {
360 self.events.retain(|event| event.error.is_none());
361 }
362
363 pub fn register_insert_func(&mut self, registered: bool) {
365 self.insert_callback_registered = registered;
366 }
367
368 pub fn register_complete_func(&mut self, registered: bool) {
370 self.complete_callback_registered = registered;
371 }
372
373 pub fn has_insert_callback(&self) -> bool {
375 self.insert_callback_registered
376 }
377
378 pub fn has_complete_callback(&self) -> bool {
380 self.complete_callback_registered
381 }
382}
383
384impl ErrorStackEntry {
385 pub fn new(
386 class_name: impl Into<String>,
387 major: impl Into<String>,
388 minor: impl Into<String>,
389 description: impl Into<String>,
390 ) -> Self {
391 Self {
392 class_name: class_name.into(),
393 major: major.into(),
394 minor: minor.into(),
395 description: description.into(),
396 }
397 }
398
399 pub fn copy_stack_entry(&self) -> Self {
401 self.clone()
402 }
403
404 pub fn set_stack_entry(
406 &mut self,
407 class_name: impl Into<String>,
408 major: impl Into<String>,
409 minor: impl Into<String>,
410 description: impl Into<String>,
411 ) {
412 *self = Self::new(class_name, major, minor, description);
413 }
414}
415
416impl ErrorStack {
417 pub fn init() -> Self {
419 Self::default()
420 }
421
422 pub fn init_package() -> Self {
424 Self::init()
425 }
426
427 pub fn term_package(&mut self) {
429 self.entries.clear();
430 }
431
432 pub fn user_cb_prepare(&self) -> bool {
434 true
435 }
436
437 pub fn get_current_stack(&self) -> Self {
439 self.clone()
440 }
441
442 pub fn get_current_stack_internal(&self) -> Self {
444 self.get_current_stack()
445 }
446
447 pub fn set_current_stack(&mut self, other: Self) {
449 *self = other;
450 }
451
452 pub fn set_current_stack_internal(&mut self, other: Self) {
454 self.set_current_stack(other);
455 }
456
457 pub fn close_stack(self) {}
459
460 pub fn close_stack_internal(self) {}
462
463 pub fn get_num(&self) -> usize {
465 self.entries.len()
466 }
467
468 pub fn get_num_internal(&self) -> usize {
470 self.get_num()
471 }
472
473 pub fn push_stack(&mut self, entry: ErrorStackEntry) {
475 self.entries.push(entry);
476 }
477
478 pub fn push1(&mut self, entry: ErrorStackEntry) {
480 self.push_stack(entry);
481 }
482
483 pub fn printf_stack(&mut self, entry: ErrorStackEntry) {
485 self.push_stack(entry);
486 }
487
488 pub fn append_stack(&mut self, other: &Self) {
490 self.entries.extend(other.entries.iter().cloned());
491 }
492
493 pub fn pop(&mut self, count: usize) {
495 let keep = self.entries.len().saturating_sub(count);
496 self.entries.truncate(keep);
497 }
498
499 pub fn pop_internal(&mut self, count: usize) {
501 self.pop(count);
502 }
503
504 pub fn clear2(&mut self) {
506 self.entries.clear();
507 }
508
509 pub fn clear1(&mut self) {
511 self.clear2();
512 }
513
514 pub fn clear_stack(&mut self) {
516 self.clear2();
517 }
518
519 pub fn clear_entries(&mut self) {
521 self.clear2();
522 }
523
524 pub fn destroy_stack(&mut self) {
526 self.clear2();
527 }
528
529 pub fn entries(&self) -> impl Iterator<Item = &ErrorStackEntry> {
531 self.entries.iter()
532 }
533
534 pub fn print_into<W>(&self, writer: &mut W) -> fmt::Result
536 where
537 W: fmt::Write + ?Sized,
538 {
539 for (index, entry) in self.entries.iter().enumerate() {
540 if index > 0 {
541 writer.write_char('\n')?;
542 }
543 writer.write_str(&entry.description)?;
544 }
545 Ok(())
546 }
547
548 pub fn print_with<F>(&self, mut callback: F)
550 where
551 F: FnMut(&str),
552 {
553 for entry in &self.entries {
554 callback(&entry.description);
555 }
556 }
557
558 #[deprecated(note = "use print_into() or print_with() to avoid allocating a String")]
560 pub fn print(&self) -> String {
561 let mut output = String::new();
562 self.print_into(&mut output)
563 .expect("writing to String cannot fail");
564 output
565 }
566
567 #[deprecated(note = "use print_into() or print_with() to avoid allocating a String")]
569 pub fn print2(&self) -> String {
570 let mut output = String::new();
571 self.print_into(&mut output)
572 .expect("writing to String cannot fail");
573 output
574 }
575
576 pub fn walk<F>(&self, mut callback: F)
578 where
579 F: FnMut(&ErrorStackEntry),
580 {
581 for entry in &self.entries {
582 callback(entry);
583 }
584 }
585
586 pub fn walk1<F>(&self, callback: F)
588 where
589 F: FnMut(&ErrorStackEntry),
590 {
591 self.walk(callback);
592 }
593
594 pub fn walk_internal<F>(&self, callback: F)
596 where
597 F: FnMut(&ErrorStackEntry),
598 {
599 self.walk(callback);
600 }
601
602 pub fn walk1_cb<F>(&self, callback: F)
604 where
605 F: FnMut(&ErrorStackEntry),
606 {
607 self.walk(callback);
608 }
609
610 pub fn walk2_cb<F>(&self, callback: F)
612 where
613 F: FnMut(&ErrorStackEntry),
614 {
615 self.walk(callback);
616 }
617
618 pub fn set_default_auto(&mut self, enabled: bool) {
620 self.auto_enabled = enabled;
621 }
622
623 pub fn set_auto(&mut self, enabled: bool) {
625 self.auto_enabled = enabled;
626 }
627
628 pub fn set_auto1(&mut self, enabled: bool) {
630 self.set_auto(enabled);
631 }
632
633 pub fn get_auto(&self) -> bool {
635 self.auto_enabled
636 }
637
638 pub fn get_default_auto_func(&self) -> bool {
640 self.auto_enabled
641 }
642
643 pub fn get_auto1(&self) -> bool {
645 self.auto_enabled
646 }
647
648 pub fn pause_stack(&mut self) {
650 self.auto_enabled = false;
651 }
652
653 pub fn resume_stack(&mut self) {
655 self.auto_enabled = true;
656 }
657
658 pub fn get_major(&self) -> Option<&str> {
660 self.entries.last().map(|entry| entry.major.as_str())
661 }
662
663 pub fn get_minor(&self) -> Option<&str> {
665 self.entries.last().map(|entry| entry.minor.as_str())
666 }
667}
668
669#[cfg(test)]
670mod error_stack_tests {
671 use super::*;
672
673 #[test]
674 fn error_stack_aliases_roundtrip() {
675 let class = ErrorClass::register_class("hdf5", "major", "1.0");
676 assert_eq!(class.class_name(), "major");
677 let msg = ErrorMessage::create_msg("minor");
678 assert_eq!(msg.get_msg(), "minor");
679 assert_eq!(msg.get_msg_internal(), "minor");
680
681 let mut stack = ErrorStack::init();
682 assert!(stack.user_cb_prepare());
683 stack.push_stack(ErrorStackEntry::new("major", "io", "open", "failed"));
684 assert_eq!(stack.get_num(), 1);
685 assert_eq!(stack.get_major(), Some("io"));
686 assert_eq!(stack.get_minor(), Some("open"));
687 let mut printed = String::new();
688 stack.print_into(&mut printed).unwrap();
689 assert_eq!(printed, "failed");
690
691 let mut walked = Vec::new();
692 stack.print_with(|description| walked.push(description.to_owned()));
693 assert_eq!(walked, vec!["failed"]);
694
695 let copy = stack.get_current_stack();
696 stack.append_stack(©);
697 assert_eq!(stack.get_num_internal(), 2);
698 stack.pop_internal(1);
699 assert_eq!(stack.get_num(), 1);
700 stack.set_auto1(true);
701 assert!(stack.get_auto1());
702 stack.pause_stack();
703 assert!(!stack.get_auto());
704 stack.resume_stack();
705 assert!(stack.get_default_auto_func());
706 stack.clear_stack();
707 assert_eq!(stack.get_num(), 0);
708 }
709
710 #[test]
711 #[allow(deprecated)]
712 fn error_stack_print_helpers_pin_streaming_and_allocating_output() {
713 let mut stack = ErrorStack::init();
714 let mut printed = String::from("prefix:");
715 stack.print_into(&mut printed).unwrap();
716 assert_eq!(printed, "prefix:");
717
718 stack.push_stack(ErrorStackEntry::new("hdf5", "major", "minor", "first"));
719 stack.printf_stack(ErrorStackEntry::new("hdf5", "major", "minor", "second"));
720
721 stack.print_into(&mut printed).unwrap();
722 assert_eq!(printed, "prefix:first\nsecond");
723
724 let mut descriptions = vec!["stale".to_string()];
725 stack.print_with(|description| descriptions.push(description.to_owned()));
726 assert_eq!(descriptions, vec!["stale", "first", "second"]);
727
728 assert_eq!(stack.print(), "first\nsecond");
729 assert_eq!(stack.print2(), "first\nsecond");
730 }
731
732 #[test]
733 fn error_event_set_aliases_roundtrip() {
734 let mut event = ErrorEvent::event_new("read");
735 assert!(!event.completed);
736 event.event_completed();
737 assert!(event.completed);
738
739 let mut failed = ErrorEvent::event_new("write");
740 failed.handle_fail("disk");
741
742 let mut set = ErrorEventSet::create();
743 set.list_append(event);
744 set.list_append(failed);
745 set.insert_request("flush");
746 assert_eq!(set.list_count(), 3);
747 assert_eq!(set.get_count(), 3);
748 assert_eq!(set.get_op_counter(), 3);
749 assert_eq!(
750 set.requests().collect::<Vec<_>>(),
751 vec!["read", "write", "flush"]
752 );
753 assert!(set.get_err_status());
754 assert_eq!(set.get_err_count(), 1);
755 assert_eq!(set.err_info().collect::<Vec<_>>(), vec!["disk"]);
756
757 let mut visited = Vec::new();
758 set.list_iterate(|event| visited.push(event.request.clone()));
759 assert_eq!(visited, vec!["read", "write", "flush"]);
760
761 assert_eq!(set.wait(), 1);
762 set.close_failed_cb();
763 let mut requests = Vec::new();
764 set.get_requests_with(|request| requests.push(request.to_owned()));
765 assert_eq!(requests, vec!["read", "flush"]);
766 assert_eq!(set.cancel(), 0);
767 assert_eq!(
768 set.list_remove(1).map(|event| event.request),
769 Some("flush".into())
770 );
771 set.term_package();
772 assert_eq!(set.requests().count(), 0);
773 }
774
775 #[test]
776 #[allow(deprecated)]
777 fn deprecated_allocating_error_wrappers_remain_callable() {
778 let mut set = ErrorEventSet::create();
779 set.insert_request("read");
780 assert_eq!(set.get_requests(), vec!["read"]);
781
782 let mut failed = ErrorEvent::event_new("write");
783 failed.handle_fail("disk");
784 set.list_append(failed);
785 assert_eq!(set.get_err_info(), vec!["disk"]);
786
787 let mut stack = ErrorStack::init();
788 stack.push_stack(ErrorStackEntry::new("major", "io", "open", "failed"));
789 assert_eq!(stack.print(), "failed");
790 assert_eq!(stack.print2(), "failed");
791 }
792}