libwayshot 0.7.3

Screenshot crate for wlroots based compositors implementing the zwlr_screencopy_v1 protocol.
Documentation
use std::{io, result};

use drm::buffer::UnrecognizedFourcc;
use gbm::InvalidFdError;
use r_egl_wayland::r_egl as egl;
use thiserror::Error;
use wayland_client::{
    ConnectError, DispatchError, WEnum,
    globals::{BindError, GlobalError},
};
use wayland_protocols::ext::image_copy_capture::v1::client::ext_image_copy_capture_frame_v1::FailureReason;

pub type Result<T, E = Error> = result::Result<T, E>;

#[derive(Error, Debug)]
pub enum Error {
    #[error("no outputs supplied")]
    NoOutputs,
    #[error("image buffer is not big enough")]
    BufferTooSmall,
    #[error("image color type not supported")]
    InvalidColor,
    #[error("IO error: {0}")]
    Io(#[from] io::Error),
    #[error("dispatch error: {0}")]
    Dispatch(#[from] DispatchError),
    #[error("bind error: {0}")]
    Bind(#[from] BindError),
    #[error("global error: {0}")]
    Global(#[from] GlobalError),
    #[error("connect error: {0}")]
    Connect(#[from] ConnectError),
    #[error("framecopy failed")]
    FramecopyFailed,
    #[error("framecopy failed with reason {0:?}")]
    FramecopyFailedWithReason(WEnum<FailureReason>),
    #[error("No supported buffer format")]
    NoSupportedBufferFormat,
    #[error("Cannot find required wayland protocol")]
    ProtocolNotFound(String),
    #[error("error occurred in freeze callback")]
    FreezeCallbackError(String),
    #[error(
        "dmabuf configuration not initialized. Did you not use Wayshot::from_connection_with_dmabuf()?"
    )]
    NoDMAStateError,
    #[error("dmabuf color format provided by compositor is invalid")]
    UnrecognizedColorCode(#[from] UnrecognizedFourcc),
    #[error("dmabuf device has been destroyed")]
    EGLError(#[from] egl::Error),
    #[error("No EGLImageTargetTexture2DOES function located, this extension may not be supported")]
    EGLImageToTexProcNotFoundError,
    #[error("Capture failed: {0}")]
    CaptureFailed(String),
    #[error("Unsupported for some reason: {0}")]
    Unsupported(String),
    #[error("Fd does not exist")]
    InvalidFd(#[from] InvalidFdError),
}

#[cfg(test)]
mod tests {
    use super::*;
    use drm::buffer::UnrecognizedFourcc;
    use wayland_client::{
        ConnectError, DispatchError,
        backend::{InvalidId, ObjectId, WaylandError, protocol::ProtocolError},
        globals::{BindError, GlobalError},
    };

    #[test]
    fn test_display_no_outputs() {
        let err = Error::NoOutputs;
        assert_eq!(err.to_string(), "no outputs supplied");
    }

    #[test]
    fn test_display_buffer_too_small() {
        let err = Error::BufferTooSmall;
        assert_eq!(err.to_string(), "image buffer is not big enough");
    }

    #[test]
    fn test_display_invalid_color() {
        let err = Error::InvalidColor;
        assert_eq!(err.to_string(), "image color type not supported");
    }

    #[test]
    fn test_from_io_error() {
        use std::io;
        let io_error = io::Error::other("test error");
        let wayshot_error: Error = io_error.into();

        match wayshot_error {
            Error::Io(_) => {}
            _ => panic!("Expected Error::Io(...)"),
        }
    }

    #[test]
    fn test_from_dispatch_error_bad_message() {
        let dispatch_error = DispatchError::BadMessage {
            sender_id: ObjectId::null(),
            interface: "test_interface",
            opcode: 2,
        };

        let wayshot_error: Error = dispatch_error.into();

        match wayshot_error {
            Error::Dispatch(DispatchError::BadMessage { .. }) => {}
            _ => panic!("Expected Error::Dispatch(DispatchError::BadMessage)"),
        }
    }

    #[test]
    fn test_from_dispatch_error_backend() {
        let protocol_error = ProtocolError {
            code: 1,
            object_id: 10,
            object_interface: "wl_compositor".to_string(),
            message: "Protocol error".to_string(),
        };
        let wayland_error = WaylandError::Protocol(protocol_error);
        let dispatch_error = DispatchError::Backend(wayland_error);

        let wayshot_error: Error = dispatch_error.into();

        match wayshot_error {
            Error::Dispatch(DispatchError::Backend(WaylandError::Protocol(_))) => {}
            _ => panic!("Expected Error::Dispatch(DispatchError::Backend(...))"),
        }
    }

    #[test]
    fn test_from_bind_error_uv() {
        let bind_error = BindError::UnsupportedVersion;
        let wayshot_error: Error = bind_error.into();

        match wayshot_error {
            Error::Bind(BindError::UnsupportedVersion) => {}
            _ => panic!("Expected Error::Bind(BindError::UnsupportedVersion)"),
        }
    }

    #[test]
    fn test_from_bind_error_np() {
        let bind_error = BindError::NotPresent;
        let wayshot_error: Error = bind_error.into();

        match wayshot_error {
            Error::Bind(BindError::NotPresent) => {}
            _ => panic!("Expected Error::Bind(BindError::NotPresent)"),
        }
    }

    #[test]
    fn test_from_global_backend_protocol() {
        let protocol_error = ProtocolError {
            code: 1,
            object_id: 10,
            object_interface: "wl_compositor".to_string(),
            message: "Protocol error".to_string(),
        };

        let wayland_error = WaylandError::Protocol(protocol_error);
        let global_error = GlobalError::Backend(wayland_error);

        let wayshot_error: Error = global_error.into();

        match wayshot_error {
            Error::Global(GlobalError::Backend(WaylandError::Protocol(_))) => {}
            _ => panic!("Expected Error::Global(GlobalError::Backend(...))"),
        }
    }

    #[test]
    fn test_from_global_invalid_id() {
        let invalid_struct = InvalidId;
        let global_error = GlobalError::InvalidId(invalid_struct);

        let wayshot_error: Error = global_error.into();

        match wayshot_error {
            Error::Global(GlobalError::InvalidId(_)) => {}
            _ => panic!("Expected Error::Global(GlobalError::InvalidId(...))"),
        }
    }

    #[test]
    fn test_from_connect_error_nwl() {
        let connect_error = ConnectError::NoWaylandLib;
        let wayshot_error: Error = connect_error.into();

        match wayshot_error {
            Error::Connect(ConnectError::NoWaylandLib) => {}
            _ => panic!("Expected Error::Connect(ConnectError::NoWaylandLib)"),
        }
    }

    #[test]
    fn test_from_connect_error_ncp() {
        let connect_error = ConnectError::NoCompositor;
        let wayshot_error: Error = connect_error.into();

        match wayshot_error {
            Error::Connect(ConnectError::NoCompositor) => {}
            _ => panic!("Expected Error::Connect(ConnectError::NoCompositor)"),
        }
    }

    #[test]
    fn test_from_connect_error_ifd() {
        let connect_error = ConnectError::InvalidFd;
        let wayshot_error: Error = connect_error.into();

        match wayshot_error {
            Error::Connect(ConnectError::InvalidFd) => {}
            _ => panic!("Expected Error::Connect(ConnectError::InvalidFd)"),
        }
    }

    #[test]
    fn test_display_framecopy_failed() {
        let err = Error::FramecopyFailed;
        assert_eq!(err.to_string(), "framecopy failed");
    }

    #[test]
    fn test_display_no_supported_buffer_format() {
        let err = Error::NoSupportedBufferFormat;
        assert_eq!(err.to_string(), "No supported buffer format");
    }

    #[test]
    fn test_display_protocol_not_found() {
        let err = Error::ProtocolNotFound("wl_compositor".to_string());
        assert_eq!(err.to_string(), "Cannot find required wayland protocol");
    }

    #[test]
    fn test_display_freeze_callback_error() {
        let err = Error::FreezeCallbackError("some callback info".to_string());
        assert_eq!(err.to_string(), "error occurred in freeze callback");
    }

    #[test]
    fn test_display_no_dma_state_error() {
        let err = Error::NoDMAStateError;
        let expected_msg = "dmabuf configuration not initialized. Did you not use Wayshot::from_connection_with_dmabuf()?";
        assert_eq!(err.to_string(), expected_msg);
    }

    #[test]
    fn test_from_unrecognised_fourcc() {
        let fourcc_error = UnrecognizedFourcc(42);
        let wayshot_error: Error = fourcc_error.into();

        match wayshot_error {
            Error::UnrecognizedColorCode(UnrecognizedFourcc(42)) => {}
            _ => panic!("Expected Error::UnrecognizedColorCode(UnrecognizedFourcc(42))"),
        }
    }

    #[test]
    fn test_from_egl_error() {
        let egl_error = egl::Error::ContextLost;
        let wayshot_error: Error = egl_error.into();

        match wayshot_error {
            Error::EGLError(egl::Error::ContextLost) => {}
            _ => panic!("Expected Error::EGLError(khronos_egl::Error::ContextLost)"),
        }
    }
}