rust-mc-status 2.0.0

High-performance asynchronous Rust library for querying Minecraft server status (Java & Bedrock)
Documentation
//! Error types for the Minecraft server status library.
//!
//! This module provides comprehensive error handling using [`thiserror`] for
//! all operations that can fail during server status queries.
//!
//! # Example
//!
//! ```no_run
//! use rust_mc_status::{McClient, ServerEdition, McError};
//!
//! #[tokio::main]
//! async fn main() -> Result<(), McError> {
//!     let client = McClient::new();
//!
//!     match client.ping("invalid-server", ServerEdition::Java).await {
//!         Ok(status) => println!("Server is online!"),
//!         Err(McError::Timeout) => println!("Request timed out"),
//!         Err(McError::DnsError(msg)) => println!("DNS error: {}", msg),
//!         Err(e) => println!("Other error: {}", e),
//!     }
//!
//!     Ok(())
//! }
//! ```

use thiserror::Error;

/// Errors that can occur during Minecraft server status queries.
///
/// All errors implement `std::error::Error` and can be easily converted to
/// user-friendly error messages using the `Display` trait.
///
/// # Error Types
///
/// - **DnsError**: DNS resolution failed (e.g., hostname not found)
/// - **ConnectionError**: Failed to establish connection to server
/// - **Timeout**: Request timed out
/// - **InvalidResponse**: Server returned invalid or malformed data
/// - **IoError**: I/O error occurred (wrapped `std::io::Error`)
/// - **JsonError**: Failed to parse JSON response (wrapped `serde_json::Error`)
/// - **Utf8Error**: Invalid UTF-8 in server response
/// - **Base64Error**: Failed to decode base64 data (e.g., favicon)
/// - **InvalidEdition**: Invalid server edition specified
/// - **InvalidPort**: Invalid port number in address
/// - **InvalidAddress**: Invalid address format
#[derive(Error, Debug)]
pub enum McError {
    /// DNS resolution failed.
    ///
    /// This error occurs when the hostname cannot be resolved to an IP address,
    /// or when an SRV record lookup fails.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use rust_mc_status::McError;
    /// # fn example() -> Result<(), McError> {
    /// Err(McError::DnsError("Hostname not found".to_string()))
    /// # }
    /// ```
    #[error("DNS resolution failed: {0}")]
    DnsError(String),

    /// Connection to server failed.
    ///
    /// This error occurs when a TCP/UDP connection cannot be established,
    /// typically due to network issues or the server being unreachable.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use rust_mc_status::McError;
    /// # fn example() -> Result<(), McError> {
    /// Err(McError::ConnectionError("Connection refused".to_string()))
    /// # }
    /// ```
    #[error("Connection failed: {0}")]
    ConnectionError(String),

    /// Request timed out.
    ///
    /// This error occurs when the server does not respond within the configured
    /// timeout duration. You can adjust the timeout using `McClient::with_timeout`.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use rust_mc_status::McClient;
    /// # use std::time::Duration;
    /// # #[tokio::main]
    /// # async fn main() {
    /// let client = McClient::new().with_timeout(Duration::from_secs(2));
    /// // If server doesn't respond within 2 seconds, Timeout error is returned
    /// # }
    /// ```
    #[error("Timeout occurred")]
    Timeout,

    /// Server returned invalid or malformed response.
    ///
    /// This error occurs when the server response does not match the expected
    /// protocol format, or contains invalid data.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use rust_mc_status::McError;
    /// # fn example() -> Result<(), McError> {
    /// Err(McError::InvalidResponse("Response too short".to_string()))
    /// # }
    /// ```
    #[error("Invalid server response: {0}")]
    InvalidResponse(String),

    /// I/O error occurred.
    ///
    /// This is a wrapper around `std::io::Error` for operations like reading
    /// from or writing to network streams.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use rust_mc_status::McError;
    /// # use std::io;
    /// # fn example() -> Result<(), McError> {
    /// let io_error = io::Error::new(io::ErrorKind::NotFound, "File not found");
    /// Err(McError::IoError(io_error))
    /// # }
    /// ```
    #[error("I/O error: {0}")]
    IoError(#[from] std::io::Error),

    /// JSON parsing error.
    ///
    /// This error occurs when the server response contains invalid JSON.
    /// It's a wrapper around `serde_json::Error`.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use rust_mc_status::McError;
    /// # fn example() -> Result<(), McError> {
    /// // Usually occurs when parsing Java server status JSON
    /// # Ok(())
    /// # }
    /// ```
    #[error("JSON parsing error: {0}")]
    JsonError(#[from] serde_json::Error),

    /// UTF-8 conversion error.
    ///
    /// This error occurs when the server response contains invalid UTF-8 sequences.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use rust_mc_status::McError;
    /// # fn example() -> Result<(), McError> {
    /// // Usually occurs when reading server response
    /// # Ok(())
    /// # }
    /// ```
    #[error("UTF-8 conversion error: {0}")]
    Utf8Error(#[from] std::string::FromUtf8Error),

    /// Base64 decoding error.
    ///
    /// This error occurs when decoding base64-encoded data (e.g., server favicon)
    /// fails.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use rust_mc_status::{McClient, ServerEdition};
    /// # #[tokio::main]
    /// # async fn main() {
    /// # let client = McClient::new();
    /// # if let Ok(status) = client.ping("server.com", ServerEdition::Java).await {
    /// # if let rust_mc_status::ServerData::Java(java) = status.data {
    /// // Can occur when saving favicon
    /// java.save_favicon("icon.png").unwrap();
    /// # }
    /// # }
    /// # }
    /// ```
    #[error("Base64 decoding error: {0}")]
    Base64Error(#[from] base64::DecodeError),

    /// Invalid server edition specified.
    ///
    /// This error occurs when an invalid server edition is provided.
    /// Valid editions are `Java` and `Bedrock`.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use rust_mc_status::McError;
    /// # use std::str::FromStr;
    /// # use rust_mc_status::ServerEdition;
    /// # fn example() -> Result<(), McError> {
    /// ServerEdition::from_str("invalid")?;
    /// # Ok(())
    /// # }
    /// ```
    #[error("Invalid edition: {0}")]
    InvalidEdition(String),

    /// Invalid port number in address.
    ///
    /// This error occurs when the port in the address string cannot be parsed
    /// as a valid `u16` value.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use rust_mc_status::McClient;
    /// # use rust_mc_status::ServerEdition;
    /// # #[tokio::main]
    /// # async fn main() {
    /// let client = McClient::new();
    /// // This will return InvalidPort error
    /// let _ = client.ping("server.com:99999", ServerEdition::Java).await;
    /// # }
    /// ```
    #[error("Invalid port: {0}")]
    InvalidPort(String),

    /// Invalid address format.
    ///
    /// This error occurs when the server address has an invalid format.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use rust_mc_status::McError;
    /// # fn example() -> Result<(), McError> {
    /// Err(McError::InvalidAddress("Invalid format".to_string()))
    /// # }
    /// ```
    #[error("Invalid address format: {0}")]
    InvalidAddress(String),
}