tachyon-i2p 0.0.4

Safe async wrapper around i2pd-sys (native I2P `.b32.i2p` eepsite support)
Documentation
//! Error type returned by this crate's fallible operations.

use std::fmt;

/// Errors that can occur while starting the router, creating a destination, or using a stream.
#[derive(Debug)]
#[non_exhaustive]
pub enum I2pError {
    /// Another [`I2pRouter`](crate::I2pRouter) is still running in this process. Once the last
    /// clone of it has been dropped, a fresh `start` succeeds.
    ///
    /// The exception is a router whose start panicked inside libi2pd: the globals are then in an
    /// unknown state, and every later `start` in that process returns this error rather than
    /// re-initializing over them.
    AlreadyRunning,
    /// The application name contained an interior NUL byte and can't cross the C ABI.
    InvalidAppName,
    /// The blocking worker task backing an async call panicked -- a bug in this crate or libi2pd.
    WorkerPanicked,
    /// libi2pd failed to create the destination. Its API reports no further detail.
    DestinationCreationFailed,
    /// libi2pd failed to generate a new destination keypair.
    KeyGenerationFailed,
    /// [`Destination::connect`](crate::Destination::connect) timed out or failed -- most often
    /// because a tunnel had to be built over the live network first, which takes seconds to
    /// minutes.
    ConnectFailed,
    /// The destination was dropped while an [`accept`](crate::Destination::accept) was pending.
    DestinationClosed,
    /// An I/O error occurred reading/writing a persistent keys file.
    Io(std::io::Error),
}

impl fmt::Display for I2pError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::AlreadyRunning => f.write_str("an I2pRouter is already running in this process"),
            Self::InvalidAppName => f.write_str("application name contains an interior NUL byte"),
            Self::WorkerPanicked => f.write_str("internal blocking worker task panicked"),
            Self::DestinationCreationFailed => {
                f.write_str("libi2pd failed to create the destination")
            }
            Self::KeyGenerationFailed => {
                f.write_str("libi2pd failed to generate a destination keypair")
            }
            Self::ConnectFailed => f.write_str("failed to connect to the remote I2P destination"),
            Self::DestinationClosed => f.write_str("the destination was closed"),
            Self::Io(e) => write!(f, "I/O error: {e}"),
        }
    }
}

impl std::error::Error for I2pError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::Io(e) => Some(e),
            _ => None,
        }
    }
}