use std::fmt;
use std::io;
#[derive(Debug)]
pub enum Error {
Io(io::Error),
InvalidFormat(String),
Unsupported(String),
Other(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Io(e) => write!(f, "I/O error: {e}"),
Error::InvalidFormat(msg) => write!(f, "Invalid HDF5 format: {msg}"),
Error::Unsupported(msg) => write!(f, "Unsupported: {msg}"),
Error::Other(msg) => write!(f, "{msg}"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Io(e) => Some(e),
_ => None,
}
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Error::Io(e)
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ErrorClass {
pub library: String,
pub class_name: String,
pub version: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ErrorMessage {
pub message: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ErrorEvent {
pub request: String,
pub completed: bool,
pub error: Option<String>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ErrorEventSet {
events: Vec<ErrorEvent>,
op_counter: u64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ErrorStackEntry {
pub class_name: String,
pub major: String,
pub minor: String,
pub description: String,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct ErrorStack {
entries: Vec<ErrorStackEntry>,
auto_enabled: bool,
}
impl ErrorClass {
pub fn register_class(
library: impl Into<String>,
class_name: impl Into<String>,
version: impl Into<String>,
) -> Self {
Self {
library: library.into(),
class_name: class_name.into(),
version: version.into(),
}
}
pub fn register_class_internal(
library: impl Into<String>,
class_name: impl Into<String>,
version: impl Into<String>,
) -> Self {
Self::register_class(library, class_name, version)
}
pub fn unregister_class(self) {}
pub fn unregister_class_internal(self) {}
pub fn class_name(&self) -> &str {
&self.class_name
}
}
impl ErrorMessage {
pub fn create_msg(message: impl Into<String>) -> Self {
Self {
message: message.into(),
}
}
pub fn create_msg_internal(message: impl Into<String>) -> Self {
Self::create_msg(message)
}
pub fn get_msg(&self) -> &str {
&self.message
}
pub fn get_msg_internal(&self) -> &str {
self.get_msg()
}
pub fn close_msg(self) {}
pub fn close_msg_cb(self) {}
pub fn close_msg_internal(self) {}
pub fn free_msg(self) {}
}
impl ErrorEvent {
pub fn event_new(request: impl Into<String>) -> Self {
Self {
request: request.into(),
completed: false,
error: None,
}
}
pub fn event_free(self) {}
pub fn event_completed(&mut self) {
self.completed = true;
}
pub fn handle_fail(&mut self, error: impl Into<String>) {
self.completed = true;
self.error = Some(error.into());
}
}
impl ErrorEventSet {
pub fn init_package() -> Self {
Self::default()
}
pub fn term_package(&mut self) {
self.events.clear();
}
pub fn create() -> Self {
Self::default()
}
pub fn create_internal() -> Self {
Self::create()
}
pub fn close_cb(self) {}
pub fn close_internal(self) {}
pub fn list_append(&mut self, event: ErrorEvent) {
self.events.push(event);
self.op_counter = self.op_counter.saturating_add(1);
}
pub fn list_count(&self) -> usize {
self.events.len()
}
pub fn list_iterate<F>(&self, mut callback: F)
where
F: FnMut(&ErrorEvent),
{
for event in &self.events {
callback(event);
}
}
pub fn list_remove(&mut self, index: usize) -> Option<ErrorEvent> {
if index < self.events.len() {
Some(self.events.remove(index))
} else {
None
}
}
pub fn insert(&mut self, request: impl Into<String>) {
self.insert_request(request);
}
pub fn insert_request(&mut self, request: impl Into<String>) {
self.insert_request_internal(request);
}
pub fn insert_request_internal(&mut self, request: impl Into<String>) {
self.list_append(ErrorEvent::event_new(request));
}
pub fn get_requests_cb(&self) -> Vec<String> {
self.get_requests()
}
pub fn get_requests_internal(&self) -> Vec<String> {
self.get_requests()
}
pub fn get_requests(&self) -> Vec<String> {
self.events
.iter()
.map(|event| event.request.clone())
.collect()
}
pub fn get_count(&self) -> usize {
self.events.len()
}
pub fn get_op_counter(&self) -> u64 {
self.op_counter
}
pub fn wait(&mut self) -> usize {
let mut completed = 0;
for event in &mut self.events {
if !event.completed {
event.event_completed();
completed += 1;
}
}
completed
}
pub fn cancel(&mut self) -> usize {
let mut canceled = 0;
for event in &mut self.events {
if !event.completed {
event.completed = true;
event.error = Some("canceled".into());
canceled += 1;
}
}
canceled
}
pub fn get_err_status(&self) -> bool {
self.events.iter().any(|event| event.error.is_some())
}
pub fn get_err_count(&self) -> usize {
self.events
.iter()
.filter(|event| event.error.is_some())
.count()
}
pub fn get_err_info_internal(&self) -> Vec<String> {
self.get_err_info()
}
pub fn get_err_info(&self) -> Vec<String> {
self.events
.iter()
.filter_map(|event| event.error.clone())
.collect()
}
pub fn close_failed_cb(&mut self) {
self.events.retain(|event| event.error.is_none());
}
}
impl ErrorStackEntry {
pub fn new(
class_name: impl Into<String>,
major: impl Into<String>,
minor: impl Into<String>,
description: impl Into<String>,
) -> Self {
Self {
class_name: class_name.into(),
major: major.into(),
minor: minor.into(),
description: description.into(),
}
}
pub fn copy_stack_entry(&self) -> Self {
self.clone()
}
pub fn set_stack_entry(
&mut self,
class_name: impl Into<String>,
major: impl Into<String>,
minor: impl Into<String>,
description: impl Into<String>,
) {
*self = Self::new(class_name, major, minor, description);
}
}
impl ErrorStack {
pub fn init() -> Self {
Self::default()
}
pub fn init_package() -> Self {
Self::init()
}
pub fn term_package(&mut self) {
self.entries.clear();
}
pub fn user_cb_prepare(&self) -> bool {
true
}
pub fn get_current_stack(&self) -> Self {
self.clone()
}
pub fn get_current_stack_internal(&self) -> Self {
self.get_current_stack()
}
pub fn set_current_stack(&mut self, other: Self) {
*self = other;
}
pub fn set_current_stack_internal(&mut self, other: Self) {
self.set_current_stack(other);
}
pub fn close_stack(self) {}
pub fn close_stack_internal(self) {}
pub fn get_num(&self) -> usize {
self.entries.len()
}
pub fn get_num_internal(&self) -> usize {
self.get_num()
}
pub fn push_stack(&mut self, entry: ErrorStackEntry) {
self.entries.push(entry);
}
pub fn push1(&mut self, entry: ErrorStackEntry) {
self.push_stack(entry);
}
pub fn printf_stack(&mut self, entry: ErrorStackEntry) {
self.push_stack(entry);
}
pub fn append_stack(&mut self, other: &Self) {
self.entries.extend(other.entries.iter().cloned());
}
pub fn pop(&mut self, count: usize) {
let keep = self.entries.len().saturating_sub(count);
self.entries.truncate(keep);
}
pub fn pop_internal(&mut self, count: usize) {
self.pop(count);
}
pub fn clear2(&mut self) {
self.entries.clear();
}
pub fn clear1(&mut self) {
self.clear2();
}
pub fn clear_stack(&mut self) {
self.clear2();
}
pub fn clear_entries(&mut self) {
self.clear2();
}
pub fn destroy_stack(&mut self) {
self.clear2();
}
pub fn print(&self) -> String {
self.entries
.iter()
.map(|entry| entry.description.as_str())
.collect::<Vec<_>>()
.join("\n")
}
pub fn print_internal(&self) -> String {
self.print()
}
pub fn print2(&self) -> String {
self.print()
}
pub fn dump_api_stack(&self) -> String {
self.print()
}
pub fn walk<F>(&self, mut callback: F)
where
F: FnMut(&ErrorStackEntry),
{
for entry in &self.entries {
callback(entry);
}
}
pub fn walk1<F>(&self, callback: F)
where
F: FnMut(&ErrorStackEntry),
{
self.walk(callback);
}
pub fn walk_internal<F>(&self, callback: F)
where
F: FnMut(&ErrorStackEntry),
{
self.walk(callback);
}
pub fn walk1_cb<F>(&self, callback: F)
where
F: FnMut(&ErrorStackEntry),
{
self.walk(callback);
}
pub fn walk2_cb<F>(&self, callback: F)
where
F: FnMut(&ErrorStackEntry),
{
self.walk(callback);
}
pub fn set_default_auto(&mut self, enabled: bool) {
self.auto_enabled = enabled;
}
pub fn set_auto(&mut self, enabled: bool) {
self.auto_enabled = enabled;
}
pub fn set_auto1(&mut self, enabled: bool) {
self.set_auto(enabled);
}
pub fn get_auto(&self) -> bool {
self.auto_enabled
}
pub fn get_default_auto_func(&self) -> bool {
self.auto_enabled
}
pub fn get_auto1(&self) -> bool {
self.auto_enabled
}
pub fn pause_stack(&mut self) {
self.auto_enabled = false;
}
pub fn resume_stack(&mut self) {
self.auto_enabled = true;
}
pub fn get_major(&self) -> Option<&str> {
self.entries.last().map(|entry| entry.major.as_str())
}
pub fn get_minor(&self) -> Option<&str> {
self.entries.last().map(|entry| entry.minor.as_str())
}
}
#[cfg(test)]
mod error_stack_tests {
use super::*;
#[test]
fn error_stack_aliases_roundtrip() {
let class = ErrorClass::register_class("hdf5", "major", "1.0");
assert_eq!(class.class_name(), "major");
let msg = ErrorMessage::create_msg("minor");
assert_eq!(msg.get_msg(), "minor");
assert_eq!(msg.get_msg_internal(), "minor");
let mut stack = ErrorStack::init();
assert!(stack.user_cb_prepare());
stack.push_stack(ErrorStackEntry::new("major", "io", "open", "failed"));
assert_eq!(stack.get_num(), 1);
assert_eq!(stack.get_major(), Some("io"));
assert_eq!(stack.get_minor(), Some("open"));
assert_eq!(stack.print2(), "failed");
let mut walked = Vec::new();
stack.walk1(|entry| walked.push(entry.description.clone()));
assert_eq!(walked, vec!["failed"]);
let copy = stack.get_current_stack();
stack.append_stack(©);
assert_eq!(stack.get_num_internal(), 2);
stack.pop_internal(1);
assert_eq!(stack.get_num(), 1);
stack.set_auto1(true);
assert!(stack.get_auto1());
stack.pause_stack();
assert!(!stack.get_auto());
stack.resume_stack();
assert!(stack.get_default_auto_func());
stack.clear_stack();
assert_eq!(stack.get_num(), 0);
}
#[test]
fn error_event_set_aliases_roundtrip() {
let mut event = ErrorEvent::event_new("read");
assert!(!event.completed);
event.event_completed();
assert!(event.completed);
let mut failed = ErrorEvent::event_new("write");
failed.handle_fail("disk");
let mut set = ErrorEventSet::create();
set.list_append(event);
set.list_append(failed);
set.insert_request("flush");
assert_eq!(set.list_count(), 3);
assert_eq!(set.get_count(), 3);
assert_eq!(set.get_op_counter(), 3);
assert_eq!(set.get_requests(), vec!["read", "write", "flush"]);
assert!(set.get_err_status());
assert_eq!(set.get_err_count(), 1);
assert_eq!(set.get_err_info(), vec!["disk"]);
let mut visited = Vec::new();
set.list_iterate(|event| visited.push(event.request.clone()));
assert_eq!(visited, vec!["read", "write", "flush"]);
assert_eq!(set.wait(), 1);
set.close_failed_cb();
assert_eq!(set.get_requests_cb(), vec!["read", "flush"]);
assert_eq!(set.cancel(), 0);
assert_eq!(
set.list_remove(1).map(|event| event.request),
Some("flush".into())
);
set.term_package();
assert_eq!(set.get_requests_internal().len(), 0);
}
}