datafusion-distributed 2.0.0

Framework for enhancing Apache DataFusion with distributed capabilities
Documentation
use std::io::ErrorKind;

#[derive(Clone, PartialEq, ::prost::Message)]
pub struct IoErrorProto {
    #[prost(string, tag = "1")]
    pub msg: String,
    #[prost(int32, tag = "2")]
    pub code: i32,
    #[prost(string, tag = "3")]
    pub err: String,
}

impl IoErrorProto {
    pub(crate) fn from_io_error(msg: &str, err: &std::io::Error) -> Self {
        Self {
            msg: msg.to_string(),
            code: match err.kind() {
                ErrorKind::NotFound => 0,
                ErrorKind::PermissionDenied => 1,
                ErrorKind::ConnectionRefused => 2,
                ErrorKind::ConnectionReset => 3,
                ErrorKind::HostUnreachable => 4,
                ErrorKind::NetworkUnreachable => 5,
                ErrorKind::ConnectionAborted => 6,
                ErrorKind::NotConnected => 7,
                ErrorKind::AddrInUse => 8,
                ErrorKind::AddrNotAvailable => 9,
                ErrorKind::NetworkDown => 10,
                ErrorKind::BrokenPipe => 11,
                ErrorKind::AlreadyExists => 12,
                ErrorKind::WouldBlock => 13,
                ErrorKind::NotADirectory => 14,
                ErrorKind::IsADirectory => 15,
                ErrorKind::DirectoryNotEmpty => 16,
                ErrorKind::ReadOnlyFilesystem => 17,
                ErrorKind::StaleNetworkFileHandle => 18,
                ErrorKind::InvalidInput => 19,
                ErrorKind::InvalidData => 20,
                ErrorKind::TimedOut => 21,
                ErrorKind::WriteZero => 22,
                ErrorKind::StorageFull => 23,
                ErrorKind::NotSeekable => 24,
                ErrorKind::FileTooLarge => 25,
                ErrorKind::ResourceBusy => 26,
                ErrorKind::ExecutableFileBusy => 27,
                ErrorKind::Deadlock => 28,
                ErrorKind::TooManyLinks => 29,
                ErrorKind::ArgumentListTooLong => 30,
                ErrorKind::Interrupted => 31,
                ErrorKind::Unsupported => 32,
                ErrorKind::UnexpectedEof => 33,
                ErrorKind::OutOfMemory => 34,
                ErrorKind::Other => 35,
                _ => -1,
            },
            err: err.to_string(),
        }
    }

    pub(crate) fn to_io_error(&self) -> (std::io::Error, String) {
        let kind = match self.code {
            0 => ErrorKind::NotFound,
            1 => ErrorKind::PermissionDenied,
            2 => ErrorKind::ConnectionRefused,
            3 => ErrorKind::ConnectionReset,
            4 => ErrorKind::HostUnreachable,
            5 => ErrorKind::NetworkUnreachable,
            6 => ErrorKind::ConnectionAborted,
            7 => ErrorKind::NotConnected,
            8 => ErrorKind::AddrInUse,
            9 => ErrorKind::AddrNotAvailable,
            10 => ErrorKind::NetworkDown,
            11 => ErrorKind::BrokenPipe,
            12 => ErrorKind::AlreadyExists,
            13 => ErrorKind::WouldBlock,
            14 => ErrorKind::NotADirectory,
            15 => ErrorKind::IsADirectory,
            16 => ErrorKind::DirectoryNotEmpty,
            17 => ErrorKind::ReadOnlyFilesystem,
            18 => ErrorKind::StaleNetworkFileHandle,
            19 => ErrorKind::InvalidInput,
            20 => ErrorKind::InvalidData,
            21 => ErrorKind::TimedOut,
            22 => ErrorKind::WriteZero,
            23 => ErrorKind::StorageFull,
            24 => ErrorKind::NotSeekable,
            25 => ErrorKind::FileTooLarge,
            26 => ErrorKind::ResourceBusy,
            27 => ErrorKind::ExecutableFileBusy,
            28 => ErrorKind::Deadlock,
            29 => ErrorKind::TooManyLinks,
            30 => ErrorKind::ArgumentListTooLong,
            31 => ErrorKind::Interrupted,
            32 => ErrorKind::Unsupported,
            33 => ErrorKind::UnexpectedEof,
            34 => ErrorKind::OutOfMemory,
            35 => ErrorKind::Other,
            _ => ErrorKind::Other,
        };
        (
            std::io::Error::new(kind, self.err.clone()),
            self.msg.clone(),
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use prost::Message;
    use std::io::{Error as IoError, ErrorKind};

    #[test]
    fn test_io_error_roundtrip() {
        let test_cases = vec![
            (ErrorKind::NotFound, "file not found"),
            (ErrorKind::PermissionDenied, "permission denied"),
            (ErrorKind::ConnectionRefused, "connection refused"),
            (ErrorKind::ConnectionReset, "connection reset"),
            (ErrorKind::ConnectionAborted, "connection aborted"),
            (ErrorKind::NotConnected, "not connected"),
            (ErrorKind::AddrInUse, "address in use"),
            (ErrorKind::AddrNotAvailable, "address not available"),
            (ErrorKind::BrokenPipe, "broken pipe"),
            (ErrorKind::AlreadyExists, "already exists"),
            (ErrorKind::WouldBlock, "would block"),
            (ErrorKind::InvalidInput, "invalid input"),
            (ErrorKind::InvalidData, "invalid data"),
            (ErrorKind::TimedOut, "timed out"),
            (ErrorKind::WriteZero, "write zero"),
            (ErrorKind::Interrupted, "interrupted"),
            (ErrorKind::UnexpectedEof, "unexpected eof"),
            (ErrorKind::Other, "other error"),
        ];

        for (kind, msg) in test_cases {
            let original_error = IoError::new(kind, msg);
            let proto = IoErrorProto::from_io_error("test message", &original_error);
            let proto = IoErrorProto::decode(proto.encode_to_vec().as_ref()).unwrap();
            let (recovered_error, recovered_message) = proto.to_io_error();

            assert_eq!(original_error.kind(), recovered_error.kind());
            assert_eq!(original_error.to_string(), recovered_error.to_string());
            assert_eq!(recovered_message, "test message");
        }
    }

    #[test]
    fn test_protobuf_serialization() {
        let original_error = IoError::new(ErrorKind::NotFound, "file not found");
        let proto = IoErrorProto::from_io_error("test message", &original_error);
        let proto = IoErrorProto::decode(proto.encode_to_vec().as_ref()).unwrap();
        let (recovered_error, recovered_message) = proto.to_io_error();

        assert_eq!(original_error.kind(), recovered_error.kind());
        assert_eq!(original_error.to_string(), recovered_error.to_string());
        assert_eq!(recovered_message, "test message");
    }

    #[test]
    fn test_unknown_error_kind() {
        let proto = IoErrorProto {
            msg: "test message".to_string(),
            code: -1,
            err: "unknown error".to_string(),
        };
        let (recovered_error, recovered_message) = proto.to_io_error();

        assert_eq!(recovered_error.kind(), ErrorKind::Other);
        assert_eq!(recovered_message, "test message");
    }
}