stem_rs/
lib.rs

1//! # stem-rs
2//!
3//! A Rust implementation of the Stem library for Tor control protocol interaction.
4//!
5//! # Overview
6//!
7//! stem-rs provides idiomatic Rust APIs for interacting with Tor's control protocol,
8//! maintaining functional parity with Python Stem. The library enables:
9//!
10//! - Control socket communication (TCP and Unix domain sockets)
11//! - All authentication methods (NONE, PASSWORD, COOKIE, SAFECOOKIE)
12//! - High-level Controller API for Tor interaction
13//! - Complete descriptor parsing (server, micro, consensus, extra-info, hidden service)
14//! - Event subscription and handling
15//! - Exit policy parsing and evaluation
16//! - ORPort relay communication
17//! - Version parsing and comparison
18//!
19//! # Architecture
20//!
21//! The library is organized into these primary modules:
22//!
23//! - [`socket`]: Low-level control socket communication
24//! - [`auth`]: Authentication methods and protocol info
25//! - [`controller`]: High-level Controller API
26//! - [`descriptor`]: Tor descriptor parsing
27//! - [`events`]: Event types and handling
28//! - [`exit_policy`]: Exit policy evaluation
29//! - [`client`]: Direct ORPort relay communication
30//! - [`response`]: Control protocol response parsing
31//! - [`interpreter`]: Interactive Tor control interpreter
32//! - [`version`]: Tor version parsing and comparison
33//! - [`util`]: Validation utilities for fingerprints, nicknames, etc.
34//!
35//! # Quick Start
36//!
37//! ```rust,no_run
38//! use stem_rs::{controller::Controller, Error};
39//!
40//! #[tokio::main]
41//! async fn main() -> Result<(), Error> {
42//!     // Connect to Tor's control port
43//!     let mut controller = Controller::from_port("127.0.0.1:9051".parse().unwrap()).await?;
44//!     
45//!     // Authenticate (auto-detects method)
46//!     controller.authenticate(None).await?;
47//!     
48//!     // Query Tor version
49//!     let version = controller.get_version().await?;
50//!     println!("Connected to Tor {}", version);
51//!     
52//!     Ok(())
53//! }
54//! ```
55//!
56//! # Thread Safety
57//!
58//! The [`controller::Controller`] type is `Send` but not `Sync`. For concurrent access,
59//! wrap it in `Arc<Mutex<Controller>>` or use separate connections.
60//!
61//! # Security Considerations
62//!
63//! - Authentication tokens are cleared from memory after use
64//! - Constant-time comparison is used for sensitive data (see [`util::secure_compare`])
65//! - Input validation prevents protocol injection attacks
66//!
67//! # Error Handling
68//!
69//! All fallible operations return [`Result<T, Error>`]. The [`Error`] enum provides
70//! specific error variants for different failure modes:
71//!
72//! - [`Error::Socket`] - I/O and connection failures
73//! - [`Error::Authentication`] - Authentication failures (see [`AuthError`])
74//! - [`Error::OperationFailed`] - Tor rejected the operation
75//! - [`Error::Parse`] - Descriptor parsing failures
76//!
77//! See the [`Error`] documentation for recovery guidance.
78
79#![warn(missing_docs)]
80#![warn(rustdoc::broken_intra_doc_links)]
81
82pub mod auth;
83pub mod client;
84pub mod controller;
85pub mod descriptor;
86pub mod events;
87pub mod exit_policy;
88pub mod interpreter;
89pub mod protocol;
90pub mod response;
91pub mod socket;
92pub mod util;
93pub mod version;
94
95// Re-export commonly used types at crate root
96pub use controller::Controller;
97pub use socket::ControlSocket;
98pub use version::Version;
99
100use std::fmt;
101use thiserror::Error;
102
103/// Errors that can occur during stem-rs operations.
104///
105/// This enum represents all possible error conditions in the library.
106/// Each variant provides specific information about the failure.
107///
108/// # Error Categories
109///
110/// - **I/O Errors**: [`Socket`](Error::Socket) - Connection and communication failures
111/// - **Protocol Errors**: [`Protocol`](Error::Protocol) - Malformed control protocol data
112/// - **Auth Errors**: [`Authentication`](Error::Authentication) - Authentication failures
113/// - **Operation Errors**: [`OperationFailed`](Error::OperationFailed) - Tor rejected the request
114/// - **Parse Errors**: [`Parse`](Error::Parse) - Descriptor parsing failures
115///
116/// # Recovery Guide
117///
118/// | Error | Recoverable | Retry Meaningful |
119/// |-------|-------------|------------------|
120/// | [`Socket`](Error::Socket) | Sometimes | Yes, with backoff |
121/// | [`Protocol`](Error::Protocol) | No | No |
122/// | [`Authentication`](Error::Authentication) | Sometimes | Yes, with different credentials |
123/// | [`OperationFailed`](Error::OperationFailed) | Depends on code | Check error code |
124/// | [`Parse`](Error::Parse) | No | No |
125/// | [`Timeout`](Error::Timeout) | Yes | Yes, with longer timeout |
126/// | [`SocketClosed`](Error::SocketClosed) | Yes | Yes, reconnect first |
127/// | [`Download`](Error::Download) | Sometimes | Yes, with backoff |
128/// | [`DownloadTimeout`](Error::DownloadTimeout) | Yes | Yes, with longer timeout |
129///
130/// # Example
131///
132/// ```rust
133/// use stem_rs::Error;
134///
135/// fn handle_error(err: Error) {
136///     match err {
137///         Error::Socket(io_err) => {
138///             eprintln!("Connection failed: {}", io_err);
139///             // Retry with exponential backoff
140///         }
141///         Error::Authentication(auth_err) => {
142///             eprintln!("Auth failed: {}", auth_err);
143///             // Check credentials or try different auth method
144///         }
145///         Error::Parse { location, reason } => {
146///             eprintln!("Parse error at {}: {}", location, reason);
147///             // Log and skip this descriptor
148///         }
149///         Error::OperationFailed { code, message } => {
150///             eprintln!("Tor rejected request: {} - {}", code, message);
151///             // Check if operation can be retried
152///         }
153///         _ => eprintln!("Error: {}", err),
154///     }
155/// }
156/// ```
157#[derive(Debug, Error)]
158pub enum Error {
159    /// I/O error during socket communication.
160    ///
161    /// This error wraps standard I/O errors that occur during socket operations.
162    /// Common causes include connection refused, connection reset, and network
163    /// unreachable errors.
164    ///
165    /// # Recovery
166    ///
167    /// - Check if Tor is running and the control port is accessible
168    /// - Retry with exponential backoff for transient network issues
169    /// - Verify firewall rules allow the connection
170    #[error("socket error: {0}")]
171    Socket(#[from] std::io::Error),
172
173    /// Malformed data received from the control protocol.
174    ///
175    /// This indicates the data received from Tor doesn't conform to the
176    /// expected control protocol format. This typically indicates a bug
177    /// in either Tor or this library.
178    ///
179    /// # Recovery
180    ///
181    /// This error is not recoverable. Report the issue with the malformed data.
182    #[error("protocol error: {0}")]
183    Protocol(String),
184
185    /// Authentication with Tor failed.
186    ///
187    /// See [`AuthError`] for specific authentication failure reasons.
188    ///
189    /// # Recovery
190    ///
191    /// - Check credentials (password, cookie file path)
192    /// - Verify Tor's authentication configuration
193    /// - Try a different authentication method
194    #[error("authentication failed: {0}")]
195    Authentication(#[from] AuthError),
196
197    /// Tor was unable to complete the requested operation.
198    ///
199    /// This error is returned when Tor understands the request but cannot
200    /// fulfill it. The error code and message provide details about why.
201    ///
202    /// # Fields
203    ///
204    /// - `code`: The numeric error code from Tor (e.g., "552")
205    /// - `message`: Human-readable error description from Tor
206    ///
207    /// # Recovery
208    ///
209    /// Check the error code to determine if retry is meaningful:
210    /// - 4xx codes: Client error, fix the request
211    /// - 5xx codes: Server error, may be transient
212    #[error("operation failed: {code} {message}")]
213    OperationFailed {
214        /// The error code returned by Tor.
215        code: String,
216        /// The error message returned by Tor.
217        message: String,
218    },
219
220    /// The request cannot be satisfied with current Tor state.
221    ///
222    /// This error indicates a valid request that Tor cannot fulfill due to
223    /// its current state (e.g., requesting a circuit when Tor is not connected).
224    ///
225    /// # Recovery
226    ///
227    /// Wait for Tor to reach the required state, then retry.
228    #[error("unsatisfiable request: {0}")]
229    UnsatisfiableRequest(String),
230
231    /// The request was malformed or invalid.
232    ///
233    /// This indicates a programming error - the request doesn't conform
234    /// to the control protocol specification.
235    ///
236    /// # Recovery
237    ///
238    /// Fix the request format. This is not a transient error.
239    #[error("invalid request: {0}")]
240    InvalidRequest(String),
241
242    /// The request contained invalid arguments.
243    ///
244    /// Similar to [`InvalidRequest`](Error::InvalidRequest), but specifically
245    /// for argument validation failures.
246    ///
247    /// # Recovery
248    ///
249    /// Fix the arguments. This is not a transient error.
250    #[error("invalid arguments: {0}")]
251    InvalidArguments(String),
252
253    /// Failed to parse a descriptor or other structured data.
254    ///
255    /// This error occurs when parsing Tor descriptors (server descriptors,
256    /// consensus documents, etc.) and the data doesn't match the expected format.
257    ///
258    /// # Fields
259    ///
260    /// - `location`: Where in the data the parse error occurred
261    /// - `reason`: Description of what was expected vs. found
262    ///
263    /// # Recovery
264    ///
265    /// This error is not recoverable for the specific descriptor. Log the
266    /// error and skip to the next descriptor if processing multiple.
267    #[error("parse error at {location}: {reason}")]
268    Parse {
269        /// Location in the data where parsing failed.
270        location: String,
271        /// Description of the parse failure.
272        reason: String,
273    },
274
275    /// Failed to download a resource from the network.
276    ///
277    /// This error occurs when downloading descriptors or other data from
278    /// directory authorities or mirrors.
279    ///
280    /// # Fields
281    ///
282    /// - `url`: The URL that failed to download
283    /// - `reason`: Description of the failure
284    ///
285    /// # Recovery
286    ///
287    /// - Retry with exponential backoff
288    /// - Try a different directory authority or mirror
289    #[error("download failed: {url} - {reason}")]
290    Download {
291        /// The URL that failed to download.
292        url: String,
293        /// The reason for the download failure.
294        reason: String,
295    },
296
297    /// Download timed out before completing.
298    ///
299    /// The configured timeout was reached before the download completed.
300    ///
301    /// # Recovery
302    ///
303    /// - Increase the timeout value
304    /// - Try a different server
305    /// - Check network connectivity
306    #[error("download timeout: {url}")]
307    DownloadTimeout {
308        /// The URL that timed out.
309        url: String,
310    },
311
312    /// A general operation timeout occurred.
313    ///
314    /// The operation did not complete within the expected time.
315    ///
316    /// # Recovery
317    ///
318    /// - Increase timeout if configurable
319    /// - Check if Tor is responsive
320    /// - Retry the operation
321    #[error("timeout")]
322    Timeout,
323
324    /// The control socket was closed unexpectedly.
325    ///
326    /// This indicates the connection to Tor was lost. This can happen if
327    /// Tor exits, the network connection is interrupted, or the socket
328    /// is closed from the other end.
329    ///
330    /// # Recovery
331    ///
332    /// Reconnect to Tor and re-authenticate.
333    #[error("socket closed")]
334    SocketClosed,
335
336    /// The requested descriptor is not available.
337    ///
338    /// Tor doesn't have the requested descriptor cached and cannot
339    /// retrieve it.
340    ///
341    /// # Recovery
342    ///
343    /// - Wait and retry (descriptor may become available)
344    /// - Try downloading from a different source
345    #[error("descriptor unavailable: {0}")]
346    DescriptorUnavailable(String),
347
348    /// Failed to extend or create a circuit.
349    ///
350    /// The circuit could not be built through the requested relays.
351    ///
352    /// # Recovery
353    ///
354    /// - Try different relays
355    /// - Wait for network conditions to improve
356    /// - Check if the target relay is online
357    #[error("circuit extension failed: {0}")]
358    CircuitExtensionFailed(String),
359
360    /// Failed to parse a socket address.
361    ///
362    /// This error occurs when parsing a string into a socket address fails.
363    ///
364    /// # Recovery
365    ///
366    /// Verify the address format is correct (e.g., "127.0.0.1:9051").
367    #[error("address parse error: {0}")]
368    AddrParse(#[from] std::net::AddrParseError),
369}
370
371/// Authentication-specific errors.
372///
373/// These errors provide detailed information about why authentication
374/// with Tor's control port failed.
375///
376/// # Authentication Methods
377///
378/// Tor supports several authentication methods:
379///
380/// - **NONE**: No authentication required (open control port)
381/// - **PASSWORD**: Password-based authentication (HashedControlPassword)
382/// - **COOKIE**: Cookie file authentication (CookieAuthentication)
383/// - **SAFECOOKIE**: Challenge-response cookie authentication (recommended)
384///
385/// # Recovery Guide
386///
387/// | Error | Recovery Action |
388/// |-------|-----------------|
389/// | [`NoMethods`](AuthError::NoMethods) | Configure authentication in torrc |
390/// | [`IncorrectPassword`](AuthError::IncorrectPassword) | Verify password matches HashedControlPassword |
391/// | [`CookieUnreadable`](AuthError::CookieUnreadable) | Check file permissions and path |
392/// | [`IncorrectCookie`](AuthError::IncorrectCookie) | Cookie file may be stale; restart Tor |
393/// | [`ChallengeFailed`](AuthError::ChallengeFailed) | SAFECOOKIE protocol error; try COOKIE |
394/// | [`MissingPassword`](AuthError::MissingPassword) | Provide password for PASSWORD auth |
395///
396/// # Example
397///
398/// ```rust
399/// use stem_rs::AuthError;
400///
401/// fn handle_auth_error(err: AuthError) {
402///     match err {
403///         AuthError::IncorrectPassword => {
404///             eprintln!("Wrong password - check your torrc HashedControlPassword");
405///         }
406///         AuthError::CookieUnreadable(path) => {
407///             eprintln!("Cannot read cookie file: {}", path);
408///             eprintln!("Check file permissions and that Tor is running");
409///         }
410///         AuthError::NoMethods => {
411///             eprintln!("No compatible auth methods - configure torrc");
412///         }
413///         _ => eprintln!("Authentication error: {}", err),
414///     }
415/// }
416/// ```
417#[derive(Debug, Error)]
418pub enum AuthError {
419    /// No compatible authentication methods are available.
420    ///
421    /// Tor's PROTOCOLINFO response didn't include any authentication
422    /// methods that this library supports.
423    ///
424    /// # Recovery
425    ///
426    /// Configure at least one of: CookieAuthentication, HashedControlPassword,
427    /// or disable authentication entirely in torrc.
428    #[error("no authentication methods available")]
429    NoMethods,
430
431    /// The provided password was incorrect.
432    ///
433    /// PASSWORD authentication failed because the password doesn't match
434    /// the HashedControlPassword in torrc.
435    ///
436    /// # Recovery
437    ///
438    /// Verify the password matches what was used to generate HashedControlPassword.
439    /// Use `tor --hash-password` to generate a new hash if needed.
440    #[error("incorrect password")]
441    IncorrectPassword,
442
443    /// The cookie file could not be read.
444    ///
445    /// COOKIE or SAFECOOKIE authentication requires reading a cookie file,
446    /// but the file couldn't be accessed.
447    ///
448    /// # Recovery
449    ///
450    /// - Verify the cookie file path is correct
451    /// - Check file permissions (must be readable by your process)
452    /// - Ensure Tor is running (cookie file is created on startup)
453    #[error("cookie file unreadable: {0}")]
454    CookieUnreadable(String),
455
456    /// The cookie value was incorrect.
457    ///
458    /// The cookie file was read successfully, but Tor rejected the value.
459    /// This can happen if the cookie file is stale (from a previous Tor run).
460    ///
461    /// # Recovery
462    ///
463    /// Restart Tor to generate a fresh cookie file, then retry authentication.
464    #[error("incorrect cookie value")]
465    IncorrectCookie,
466
467    /// The cookie file has an incorrect size.
468    ///
469    /// Tor's cookie file should be exactly 32 bytes. A different size
470    /// indicates file corruption or an incorrect file.
471    ///
472    /// # Recovery
473    ///
474    /// Verify you're reading the correct cookie file. Restart Tor if needed.
475    #[error("incorrect cookie size")]
476    IncorrectCookieSize,
477
478    /// SAFECOOKIE challenge-response failed.
479    ///
480    /// The SAFECOOKIE authentication protocol failed during the
481    /// challenge-response exchange.
482    ///
483    /// # Recovery
484    ///
485    /// - Fall back to COOKIE authentication if available
486    /// - Verify the cookie file is current
487    /// - Check for network issues between client and Tor
488    #[error("safecookie challenge failed")]
489    ChallengeFailed,
490
491    /// SAFECOOKIE authentication is not supported.
492    ///
493    /// The Tor version doesn't support SAFECOOKIE, or it's disabled.
494    ///
495    /// # Recovery
496    ///
497    /// Use COOKIE or PASSWORD authentication instead.
498    #[error("safecookie challenge unsupported")]
499    ChallengeUnsupported,
500
501    /// A security check failed during authentication.
502    ///
503    /// This indicates a potential security issue, such as a mismatch
504    /// in expected vs. received authentication data.
505    ///
506    /// # Recovery
507    ///
508    /// This may indicate a man-in-the-middle attack. Verify your
509    /// connection to Tor is secure.
510    #[error("auth security failure")]
511    SecurityFailure,
512
513    /// PASSWORD authentication was requested but no password provided.
514    ///
515    /// The authenticate method was called without a password, but
516    /// PASSWORD is the only available authentication method.
517    ///
518    /// # Recovery
519    ///
520    /// Provide a password to the authenticate method.
521    #[error("missing password")]
522    MissingPassword,
523
524    /// Tor advertised unrecognized authentication methods.
525    ///
526    /// PROTOCOLINFO returned authentication methods this library
527    /// doesn't recognize. This may indicate a newer Tor version.
528    ///
529    /// # Recovery
530    ///
531    /// Update stem-rs to a newer version that supports these methods.
532    #[error("unrecognized auth methods: {0:?}")]
533    UnrecognizedMethods(Vec<String>),
534
535    /// Wrong socket type for the requested authentication.
536    ///
537    /// Some authentication methods are only valid for certain socket types
538    /// (e.g., Unix domain sockets vs. TCP sockets).
539    ///
540    /// # Recovery
541    ///
542    /// Use a different authentication method appropriate for your socket type.
543    #[error("incorrect socket type")]
544    IncorrectSocketType,
545}
546
547/// Logging severity levels for Tor events.
548///
549/// These levels correspond to Tor's internal logging runlevels and are used
550/// in log events received via the control protocol.
551///
552/// # Severity Order
553///
554/// From most to least severe: [`Err`](Runlevel::Err) > [`Warn`](Runlevel::Warn) >
555/// [`Notice`](Runlevel::Notice) > [`Info`](Runlevel::Info) > [`Debug`](Runlevel::Debug)
556///
557/// # Example
558///
559/// ```rust
560/// use stem_rs::Runlevel;
561///
562/// let level = Runlevel::Notice;
563/// println!("Log level: {}", level); // Prints "NOTICE"
564/// ```
565#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
566pub enum Runlevel {
567    /// Low-level runtime information for debugging.
568    ///
569    /// Very verbose output useful for development and troubleshooting.
570    Debug,
571    /// High-level runtime information.
572    ///
573    /// General operational information about Tor's activities.
574    Info,
575    /// Information that may be helpful to the user.
576    ///
577    /// Normal operational messages that users might want to see.
578    Notice,
579    /// Non-critical issues the user should be aware of.
580    ///
581    /// Problems that don't prevent operation but may need attention.
582    Warn,
583    /// Critical issues that impair Tor's ability to function.
584    ///
585    /// Serious errors that may prevent normal operation.
586    Err,
587}
588
589impl fmt::Display for Runlevel {
590    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
591        match self {
592            Runlevel::Debug => write!(f, "DEBUG"),
593            Runlevel::Info => write!(f, "INFO"),
594            Runlevel::Notice => write!(f, "NOTICE"),
595            Runlevel::Warn => write!(f, "WARN"),
596            Runlevel::Err => write!(f, "ERR"),
597        }
598    }
599}
600
601/// Signals that can be sent to the Tor process.
602///
603/// These signals control Tor's behavior and can be sent via
604/// [`controller::Controller::signal`].
605///
606/// # Signal Pairs
607///
608/// Some signals have Unix signal equivalents:
609/// - [`Reload`](Signal::Reload) / [`Hup`](Signal::Hup) - Reload configuration (SIGHUP)
610/// - [`Shutdown`](Signal::Shutdown) / [`Int`](Signal::Int) - Graceful shutdown (SIGINT)
611/// - [`Dump`](Signal::Dump) / [`Usr1`](Signal::Usr1) - Dump stats (SIGUSR1)
612/// - [`Debug`](Signal::Debug) / [`Usr2`](Signal::Usr2) - Debug logging (SIGUSR2)
613/// - [`Halt`](Signal::Halt) / [`Term`](Signal::Term) - Immediate exit (SIGTERM)
614///
615/// # Example
616///
617/// ```rust,no_run
618/// use stem_rs::{controller::Controller, Signal};
619///
620/// # async fn example() -> Result<(), stem_rs::Error> {
621/// # let mut controller = Controller::from_port("127.0.0.1:9051".parse().unwrap()).await?;
622/// // Request new circuits for privacy
623/// controller.signal(Signal::Newnym).await?;
624///
625/// // Clear DNS cache
626/// controller.signal(Signal::ClearDnsCache).await?;
627/// # Ok(())
628/// # }
629/// ```
630#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
631pub enum Signal {
632    /// Reload configuration files.
633    ///
634    /// Tor will reload torrc and apply changes that can be changed at runtime.
635    /// Equivalent to sending SIGHUP.
636    Reload,
637    /// Alias for [`Reload`](Signal::Reload).
638    ///
639    /// Unix SIGHUP signal equivalent.
640    Hup,
641    /// Controlled shutdown.
642    ///
643    /// Tor will close listeners and exit cleanly after current connections
644    /// complete, waiting ShutdownWaitLength if configured as a relay.
645    Shutdown,
646    /// Alias for [`Shutdown`](Signal::Shutdown).
647    ///
648    /// Unix SIGINT signal equivalent.
649    Int,
650    /// Dump information about open connections and circuits to the log.
651    ///
652    /// Useful for debugging connection issues.
653    Dump,
654    /// Alias for [`Dump`](Signal::Dump).
655    ///
656    /// Unix SIGUSR1 signal equivalent.
657    Usr1,
658    /// Switch logging to DEBUG level.
659    ///
660    /// Temporarily enables debug-level logging until the next RELOAD.
661    Debug,
662    /// Alias for [`Debug`](Signal::Debug).
663    ///
664    /// Unix SIGUSR2 signal equivalent.
665    Usr2,
666    /// Immediate shutdown.
667    ///
668    /// Tor exits immediately without waiting for connections to close.
669    Halt,
670    /// Alias for [`Halt`](Signal::Halt).
671    ///
672    /// Unix SIGTERM signal equivalent.
673    Term,
674    /// Request new circuits for future connections.
675    ///
676    /// Clears the current circuit cache and builds new circuits.
677    /// Also clears the DNS cache. Rate-limited to prevent abuse.
678    /// Use this for privacy when you want to appear as a "new" user.
679    Newnym,
680    /// Clear cached DNS results.
681    ///
682    /// Forces Tor to re-resolve all hostnames on subsequent requests.
683    ClearDnsCache,
684    /// Trigger a heartbeat log message.
685    ///
686    /// Useful for monitoring that Tor is responsive.
687    Heartbeat,
688    /// Wake from dormant mode.
689    ///
690    /// Resumes normal operation if Tor was in dormant mode.
691    /// Disables dormant mode.
692    Active,
693    /// Enter dormant mode.
694    ///
695    /// Reduces resource usage (CPU and network) when Tor is not actively needed.
696    /// Tor will avoid building circuits and making network connections.
697    Dormant,
698}
699
700impl fmt::Display for Signal {
701    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
702        match self {
703            Signal::Reload => write!(f, "RELOAD"),
704            Signal::Hup => write!(f, "HUP"),
705            Signal::Shutdown => write!(f, "SHUTDOWN"),
706            Signal::Int => write!(f, "INT"),
707            Signal::Dump => write!(f, "DUMP"),
708            Signal::Usr1 => write!(f, "USR1"),
709            Signal::Debug => write!(f, "DEBUG"),
710            Signal::Usr2 => write!(f, "USR2"),
711            Signal::Halt => write!(f, "HALT"),
712            Signal::Term => write!(f, "TERM"),
713            Signal::Newnym => write!(f, "NEWNYM"),
714            Signal::ClearDnsCache => write!(f, "CLEARDNSCACHE"),
715            Signal::Heartbeat => write!(f, "HEARTBEAT"),
716            Signal::Active => write!(f, "ACTIVE"),
717            Signal::Dormant => write!(f, "DORMANT"),
718        }
719    }
720}
721
722/// Flags assigned to Tor relays by directory authorities.
723///
724/// These flags indicate various characteristics of relays and are used
725/// for path selection and relay classification.
726///
727/// # Flag Meanings
728///
729/// Flags are assigned based on relay behavior and capabilities:
730/// - Performance flags: [`Fast`](Flag::Fast), [`Stable`](Flag::Stable)
731/// - Role flags: [`Guard`](Flag::Guard), [`Exit`](Flag::Exit), [`Authority`](Flag::Authority)
732/// - Status flags: [`Running`](Flag::Running), [`Valid`](Flag::Valid)
733/// - Warning flags: [`BadExit`](Flag::BadExit), [`BadDirectory`](Flag::BadDirectory)
734///
735/// # Example
736///
737/// ```rust
738/// use stem_rs::Flag;
739///
740/// let flag = Flag::Guard;
741/// println!("Relay flag: {}", flag); // Prints "Guard"
742/// ```
743#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
744pub enum Flag {
745    /// Relay is a directory authority.
746    ///
747    /// This relay is one of the trusted directory authorities that
748    /// vote on the network consensus.
749    Authority,
750    /// Relay shouldn't be used as an exit due to being problematic or malicious.
751    ///
752    /// The relay has been flagged for bad behavior when used as an exit node.
753    BadExit,
754    /// Relay shouldn't be used for directory information.
755    ///
756    /// Note: This flag was removed from Tor but may appear in older descriptors.
757    BadDirectory,
758    /// Relay's exit policy makes it useful as an exit node.
759    ///
760    /// The relay allows exiting to a reasonable number of ports.
761    Exit,
762    /// Relay is suitable for high-bandwidth circuits.
763    ///
764    /// The relay has sufficient bandwidth for performance-sensitive traffic.
765    Fast,
766    /// Relay is suitable for being an entry guard (first hop).
767    ///
768    /// The relay is stable and fast enough to be used as a guard node.
769    Guard,
770    /// Relay is being used as a hidden service directory.
771    ///
772    /// The relay stores and serves hidden service descriptors.
773    HsDir,
774    /// Relay can be referred to by its nickname.
775    ///
776    /// The nickname is unique and verified.
777    Named,
778    /// Relay's Ed25519 key doesn't match the consensus.
779    ///
780    /// There's a mismatch in the relay's Ed25519 identity.
781    NoEdConsensus,
782    /// Relay is currently usable.
783    ///
784    /// The relay is online and responding to connections.
785    Running,
786    /// Relay is suitable for long-lived circuits.
787    ///
788    /// The relay has good uptime and is reliable for persistent connections.
789    Stable,
790    /// Relay descriptor is outdated and should be re-uploaded.
791    ///
792    /// The relay's descriptor is stale and needs to be refreshed.
793    StaleDesc,
794    /// Relay isn't currently bound to a nickname.
795    ///
796    /// The nickname is not verified or is shared with other relays.
797    Unnamed,
798    /// Relay supports the v2 directory protocol.
799    ///
800    /// The relay can serve directory information via the v2 protocol.
801    V2Dir,
802    /// Relay supports the v3 directory protocol.
803    ///
804    /// The relay can serve directory information via the v3 protocol.
805    V3Dir,
806    /// Relay has been validated.
807    ///
808    /// The relay's identity has been verified by the directory authorities.
809    Valid,
810}
811
812impl fmt::Display for Flag {
813    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
814        match self {
815            Flag::Authority => write!(f, "Authority"),
816            Flag::BadExit => write!(f, "BadExit"),
817            Flag::BadDirectory => write!(f, "BadDirectory"),
818            Flag::Exit => write!(f, "Exit"),
819            Flag::Fast => write!(f, "Fast"),
820            Flag::Guard => write!(f, "Guard"),
821            Flag::HsDir => write!(f, "HSDir"),
822            Flag::Named => write!(f, "Named"),
823            Flag::NoEdConsensus => write!(f, "NoEdConsensus"),
824            Flag::Running => write!(f, "Running"),
825            Flag::Stable => write!(f, "Stable"),
826            Flag::StaleDesc => write!(f, "StaleDesc"),
827            Flag::Unnamed => write!(f, "Unnamed"),
828            Flag::V2Dir => write!(f, "V2Dir"),
829            Flag::V3Dir => write!(f, "V3Dir"),
830            Flag::Valid => write!(f, "Valid"),
831        }
832    }
833}
834
835/// Status of a circuit in the Tor network.
836///
837/// Circuits progress through these states during their lifecycle.
838/// Tor may provide statuses not in this enum.
839///
840/// # Circuit Lifecycle
841///
842/// ```text
843/// LAUNCHED -> EXTENDED -> BUILT -> CLOSED
844///     |          |
845///     v          v
846///   FAILED    FAILED
847/// ```
848///
849/// # Example
850///
851/// ```rust
852/// use stem_rs::CircStatus;
853///
854/// let status = CircStatus::Built;
855/// println!("Circuit status: {}", status); // Prints "BUILT"
856/// ```
857#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
858pub enum CircStatus {
859    /// New circuit was created.
860    ///
861    /// The circuit has been initiated but not yet extended to any relays.
862    Launched,
863    /// Circuit finished being created and can accept traffic.
864    ///
865    /// The circuit is fully built and ready for use.
866    Built,
867    /// Waiting to see if there's a circuit with a better guard.
868    ///
869    /// Tor is evaluating whether to use this circuit or wait for a better one.
870    GuardWait,
871    /// Circuit has been extended by a hop.
872    ///
873    /// The circuit is being built and has added another relay.
874    Extended,
875    /// Circuit construction failed.
876    ///
877    /// The circuit could not be completed. See [`CircClosureReason`] for details.
878    Failed,
879    /// Circuit has been closed.
880    ///
881    /// The circuit is no longer usable. See [`CircClosureReason`] for details.
882    Closed,
883}
884
885impl fmt::Display for CircStatus {
886    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
887        match self {
888            CircStatus::Launched => write!(f, "LAUNCHED"),
889            CircStatus::Built => write!(f, "BUILT"),
890            CircStatus::GuardWait => write!(f, "GUARD_WAIT"),
891            CircStatus::Extended => write!(f, "EXTENDED"),
892            CircStatus::Failed => write!(f, "FAILED"),
893            CircStatus::Closed => write!(f, "CLOSED"),
894        }
895    }
896}
897
898/// Attributes about how a circuit is built.
899///
900/// These flags describe special properties of circuit construction.
901/// Introduced in Tor version 0.2.3.11.
902///
903/// # Example
904///
905/// ```rust
906/// use stem_rs::CircBuildFlag;
907///
908/// let flag = CircBuildFlag::IsInternal;
909/// println!("Build flag: {}", flag); // Prints "IS_INTERNAL"
910/// ```
911#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
912pub enum CircBuildFlag {
913    /// Single hop circuit to fetch directory information.
914    ///
915    /// A one-hop tunnel used for directory fetches, not for user traffic.
916    OneHopTunnel,
917    /// Circuit that won't be used for client traffic.
918    ///
919    /// Internal circuits are used for Tor's own operations.
920    IsInternal,
921    /// Circuit only includes high capacity relays.
922    ///
923    /// Built for bandwidth-intensive operations.
924    NeedCapacity,
925    /// Circuit only includes relays with high uptime.
926    ///
927    /// Built for long-lived connections that need stability.
928    NeedUptime,
929}
930
931impl fmt::Display for CircBuildFlag {
932    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
933        match self {
934            CircBuildFlag::OneHopTunnel => write!(f, "ONEHOP_TUNNEL"),
935            CircBuildFlag::IsInternal => write!(f, "IS_INTERNAL"),
936            CircBuildFlag::NeedCapacity => write!(f, "NEED_CAPACITY"),
937            CircBuildFlag::NeedUptime => write!(f, "NEED_UPTIME"),
938        }
939    }
940}
941
942/// Purpose of a circuit.
943///
944/// Describes what a circuit is intended for. Introduced in Tor version 0.2.1.6.
945///
946/// # Example
947///
948/// ```rust
949/// use stem_rs::CircPurpose;
950///
951/// let purpose = CircPurpose::General;
952/// println!("Circuit purpose: {}", purpose); // Prints "GENERAL"
953/// ```
954#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
955pub enum CircPurpose {
956    /// General client traffic or fetching directory information.
957    ///
958    /// Standard circuits used for normal Tor operations.
959    General,
960    /// Client-side introduction point for a hidden service circuit.
961    ///
962    /// Used when connecting to a hidden service's introduction point.
963    HsClientIntro,
964    /// Client-side hidden service rendezvous circuit.
965    ///
966    /// Used for the rendezvous connection when accessing a hidden service.
967    HsClientRend,
968    /// Server-side introduction point for a hidden service circuit.
969    ///
970    /// Used by hidden services to establish introduction points.
971    HsServiceIntro,
972    /// Server-side hidden service rendezvous circuit.
973    ///
974    /// Used by hidden services for rendezvous connections.
975    HsServiceRend,
976    /// Testing to see if we're reachable as a relay.
977    ///
978    /// Self-test circuits to verify relay reachability.
979    Testing,
980    /// Circuit that was built by a controller.
981    ///
982    /// Explicitly created via the control protocol.
983    Controller,
984    /// Circuit being kept around to measure timeout.
985    ///
986    /// Used for circuit build time measurement.
987    MeasureTimeout,
988    /// Constructed in advance for hidden service vanguards.
989    ///
990    /// Pre-built circuits for vanguard protection.
991    HsVanguards,
992    /// Probing if circuits are being maliciously closed.
993    ///
994    /// Used to detect path bias attacks.
995    PathBiasTesting,
996    /// Circuit is unused but remains open to disguise closure time.
997    ///
998    /// Padding circuits to prevent traffic analysis.
999    CircuitPadding,
1000}
1001
1002impl fmt::Display for CircPurpose {
1003    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1004        match self {
1005            CircPurpose::General => write!(f, "GENERAL"),
1006            CircPurpose::HsClientIntro => write!(f, "HS_CLIENT_INTRO"),
1007            CircPurpose::HsClientRend => write!(f, "HS_CLIENT_REND"),
1008            CircPurpose::HsServiceIntro => write!(f, "HS_SERVICE_INTRO"),
1009            CircPurpose::HsServiceRend => write!(f, "HS_SERVICE_REND"),
1010            CircPurpose::Testing => write!(f, "TESTING"),
1011            CircPurpose::Controller => write!(f, "CONTROLLER"),
1012            CircPurpose::MeasureTimeout => write!(f, "MEASURE_TIMEOUT"),
1013            CircPurpose::HsVanguards => write!(f, "HS_VANGUARDS"),
1014            CircPurpose::PathBiasTesting => write!(f, "PATH_BIAS_TESTING"),
1015            CircPurpose::CircuitPadding => write!(f, "CIRCUIT_PADDING"),
1016        }
1017    }
1018}
1019
1020/// Reason that a circuit is being closed or failed to be established.
1021///
1022/// Provides detailed information about why a circuit ended.
1023///
1024/// # Example
1025///
1026/// ```rust
1027/// use stem_rs::CircClosureReason;
1028///
1029/// let reason = CircClosureReason::Timeout;
1030/// println!("Closure reason: {}", reason); // Prints "TIMEOUT"
1031/// ```
1032#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1033pub enum CircClosureReason {
1034    /// No reason given.
1035    None,
1036    /// Violation in the Tor protocol.
1037    ///
1038    /// A relay sent malformed or unexpected data.
1039    TorProtocol,
1040    /// Internal error.
1041    ///
1042    /// An internal error occurred in Tor.
1043    Internal,
1044    /// Requested by the client via a TRUNCATE command.
1045    ///
1046    /// The circuit was explicitly closed by the client.
1047    Requested,
1048    /// Relay is currently hibernating.
1049    ///
1050    /// The relay is in low-power mode and not accepting circuits.
1051    Hibernating,
1052    /// Relay is out of memory, sockets, or circuit IDs.
1053    ///
1054    /// The relay has exhausted resources.
1055    ResourceLimit,
1056    /// Unable to contact the relay.
1057    ///
1058    /// Network connectivity issue to the next hop.
1059    ConnectFailed,
1060    /// Relay had the wrong OR identification.
1061    ///
1062    /// The relay's identity key didn't match what was expected.
1063    OrIdentity,
1064    /// Connection failed after being established.
1065    ///
1066    /// The OR connection was closed unexpectedly.
1067    OrConnClosed,
1068    /// Circuit has expired.
1069    ///
1070    /// The circuit exceeded MaxCircuitDirtiness lifetime.
1071    Finished,
1072    /// Circuit construction timed out.
1073    ///
1074    /// The circuit took too long to build.
1075    Timeout,
1076    /// Circuit unexpectedly closed.
1077    ///
1078    /// The circuit was destroyed by a relay.
1079    Destroyed,
1080    /// Not enough relays to make a circuit.
1081    ///
1082    /// Insufficient relays available for path selection.
1083    NoPath,
1084    /// Requested hidden service does not exist.
1085    ///
1086    /// The onion address is invalid or the service is offline.
1087    NoSuchService,
1088    /// Same as Timeout but left open for measurement.
1089    ///
1090    /// Circuit timed out but was kept for build time measurement.
1091    MeasurementExpired,
1092    /// Introduction point is redundant with another circuit.
1093    ///
1094    /// Another circuit already serves this introduction point.
1095    IpNowRedundant,
1096}
1097
1098impl fmt::Display for CircClosureReason {
1099    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1100        match self {
1101            CircClosureReason::None => write!(f, "NONE"),
1102            CircClosureReason::TorProtocol => write!(f, "TORPROTOCOL"),
1103            CircClosureReason::Internal => write!(f, "INTERNAL"),
1104            CircClosureReason::Requested => write!(f, "REQUESTED"),
1105            CircClosureReason::Hibernating => write!(f, "HIBERNATING"),
1106            CircClosureReason::ResourceLimit => write!(f, "RESOURCELIMIT"),
1107            CircClosureReason::ConnectFailed => write!(f, "CONNECTFAILED"),
1108            CircClosureReason::OrIdentity => write!(f, "OR_IDENTITY"),
1109            CircClosureReason::OrConnClosed => write!(f, "OR_CONN_CLOSED"),
1110            CircClosureReason::Finished => write!(f, "FINISHED"),
1111            CircClosureReason::Timeout => write!(f, "TIMEOUT"),
1112            CircClosureReason::Destroyed => write!(f, "DESTROYED"),
1113            CircClosureReason::NoPath => write!(f, "NOPATH"),
1114            CircClosureReason::NoSuchService => write!(f, "NOSUCHSERVICE"),
1115            CircClosureReason::MeasurementExpired => write!(f, "MEASUREMENT_EXPIRED"),
1116            CircClosureReason::IpNowRedundant => write!(f, "IP_NOW_REDUNDANT"),
1117        }
1118    }
1119}
1120
1121/// Type of change reflected in a circuit by a CIRC_MINOR event.
1122///
1123/// These events indicate minor changes to circuits that don't affect
1124/// their overall status.
1125///
1126/// # Example
1127///
1128/// ```rust
1129/// use stem_rs::CircEvent;
1130///
1131/// let event = CircEvent::PurposeChanged;
1132/// println!("Circuit event: {}", event); // Prints "PURPOSE_CHANGED"
1133/// ```
1134#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1135pub enum CircEvent {
1136    /// Circuit purpose or hidden service state has changed.
1137    ///
1138    /// The circuit's intended use has been modified.
1139    PurposeChanged,
1140    /// Circuit connections are being reused for a different circuit.
1141    ///
1142    /// An existing circuit is being repurposed.
1143    Cannibalized,
1144}
1145
1146impl fmt::Display for CircEvent {
1147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1148        match self {
1149            CircEvent::PurposeChanged => write!(f, "PURPOSE_CHANGED"),
1150            CircEvent::Cannibalized => write!(f, "CANNIBALIZED"),
1151        }
1152    }
1153}
1154
1155/// State of a hidden service circuit.
1156///
1157/// These states track the progress of hidden service connections.
1158/// Introduced in Tor version 0.2.3.11.
1159///
1160/// # State Prefixes
1161///
1162/// - `HSCI_*` - Client-side introduction point
1163/// - `HSCR_*` - Client-side rendezvous point
1164/// - `HSSI_*` - Service-side introduction point
1165/// - `HSSR_*` - Service-side rendezvous point
1166///
1167/// # Example
1168///
1169/// ```rust
1170/// use stem_rs::HiddenServiceState;
1171///
1172/// let state = HiddenServiceState::HscrJoined;
1173/// println!("HS state: {}", state); // Prints "HSCR_JOINED"
1174/// ```
1175#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1176pub enum HiddenServiceState {
1177    /// Client connecting to the introduction point.
1178    HsciConnecting,
1179    /// Client sent INTRODUCE1 and awaiting reply.
1180    HsciIntroSent,
1181    /// Client received reply, circuit is closing.
1182    HsciDone,
1183    /// Client connecting to rendezvous point.
1184    HscrConnecting,
1185    /// Rendezvous point established, awaiting introduction.
1186    HscrEstablishedIdle,
1187    /// Introduction received, awaiting rendezvous.
1188    HscrEstablishedWaiting,
1189    /// Client connected to the hidden service.
1190    HscrJoined,
1191    /// Service connecting to introduction point.
1192    HssiConnecting,
1193    /// Service established introduction point.
1194    HssiEstablished,
1195    /// Service connecting to rendezvous point.
1196    HssrConnecting,
1197    /// Service connected to rendezvous point.
1198    HssrJoined,
1199}
1200
1201impl fmt::Display for HiddenServiceState {
1202    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1203        match self {
1204            HiddenServiceState::HsciConnecting => write!(f, "HSCI_CONNECTING"),
1205            HiddenServiceState::HsciIntroSent => write!(f, "HSCI_INTRO_SENT"),
1206            HiddenServiceState::HsciDone => write!(f, "HSCI_DONE"),
1207            HiddenServiceState::HscrConnecting => write!(f, "HSCR_CONNECTING"),
1208            HiddenServiceState::HscrEstablishedIdle => write!(f, "HSCR_ESTABLISHED_IDLE"),
1209            HiddenServiceState::HscrEstablishedWaiting => write!(f, "HSCR_ESTABLISHED_WAITING"),
1210            HiddenServiceState::HscrJoined => write!(f, "HSCR_JOINED"),
1211            HiddenServiceState::HssiConnecting => write!(f, "HSSI_CONNECTING"),
1212            HiddenServiceState::HssiEstablished => write!(f, "HSSI_ESTABLISHED"),
1213            HiddenServiceState::HssrConnecting => write!(f, "HSSR_CONNECTING"),
1214            HiddenServiceState::HssrJoined => write!(f, "HSSR_JOINED"),
1215        }
1216    }
1217}
1218
1219/// Status of a stream going through Tor.
1220///
1221/// Streams represent individual TCP connections tunneled through circuits.
1222///
1223/// # Example
1224///
1225/// ```rust
1226/// use stem_rs::StreamStatus;
1227///
1228/// let status = StreamStatus::Succeeded;
1229/// println!("Stream status: {}", status); // Prints "SUCCEEDED"
1230/// ```
1231#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1232pub enum StreamStatus {
1233    /// Request for a new connection.
1234    New,
1235    /// Request to resolve an address.
1236    NewResolve,
1237    /// Address is being re-mapped to another.
1238    Remap,
1239    /// Sent a connect cell along a circuit.
1240    SentConnect,
1241    /// Sent a resolve cell along a circuit.
1242    SentResolve,
1243    /// Stream has been established.
1244    Succeeded,
1245    /// Stream is detached and won't be re-established.
1246    Failed,
1247    /// Stream is detached but might be re-established.
1248    Detached,
1249    /// Awaiting a controller's ATTACHSTREAM request.
1250    ControllerWait,
1251    /// Stream has closed.
1252    Closed,
1253}
1254
1255impl fmt::Display for StreamStatus {
1256    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1257        match self {
1258            StreamStatus::New => write!(f, "NEW"),
1259            StreamStatus::NewResolve => write!(f, "NEWRESOLVE"),
1260            StreamStatus::Remap => write!(f, "REMAP"),
1261            StreamStatus::SentConnect => write!(f, "SENTCONNECT"),
1262            StreamStatus::SentResolve => write!(f, "SENTRESOLVE"),
1263            StreamStatus::Succeeded => write!(f, "SUCCEEDED"),
1264            StreamStatus::Failed => write!(f, "FAILED"),
1265            StreamStatus::Detached => write!(f, "DETACHED"),
1266            StreamStatus::ControllerWait => write!(f, "CONTROLLER_WAIT"),
1267            StreamStatus::Closed => write!(f, "CLOSED"),
1268        }
1269    }
1270}
1271
1272/// Reason that a stream is being closed or failed to be established.
1273///
1274/// Provides detailed information about why a stream ended.
1275///
1276/// # Example
1277///
1278/// ```rust
1279/// use stem_rs::StreamClosureReason;
1280///
1281/// let reason = StreamClosureReason::Done;
1282/// println!("Closure reason: {}", reason); // Prints "DONE"
1283/// ```
1284#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1285pub enum StreamClosureReason {
1286    /// None of the other reasons apply.
1287    Misc,
1288    /// Unable to resolve the hostname.
1289    ResolveFailed,
1290    /// Remote host refused the connection.
1291    ConnectRefused,
1292    /// OR refuses to connect due to exit policy.
1293    ExitPolicy,
1294    /// Circuit is being shut down.
1295    Destroy,
1296    /// Connection has been closed normally.
1297    Done,
1298    /// Connection timed out.
1299    Timeout,
1300    /// Routing error while contacting the destination.
1301    NoRoute,
1302    /// Relay is temporarily hibernating.
1303    Hibernating,
1304    /// Internal error at the relay.
1305    Internal,
1306    /// Relay has insufficient resources.
1307    ResourceLimit,
1308    /// Connection was unexpectedly reset.
1309    ConnReset,
1310    /// Violation in the Tor protocol.
1311    TorProtocol,
1312    /// Directory info requested from non-directory relay.
1313    NotDirectory,
1314    /// Endpoint has sent a RELAY_END cell.
1315    End,
1316    /// Endpoint was a private address (127.0.0.1, 10.0.0.1, etc).
1317    PrivateAddr,
1318}
1319
1320impl fmt::Display for StreamClosureReason {
1321    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1322        match self {
1323            StreamClosureReason::Misc => write!(f, "MISC"),
1324            StreamClosureReason::ResolveFailed => write!(f, "RESOLVEFAILED"),
1325            StreamClosureReason::ConnectRefused => write!(f, "CONNECTREFUSED"),
1326            StreamClosureReason::ExitPolicy => write!(f, "EXITPOLICY"),
1327            StreamClosureReason::Destroy => write!(f, "DESTROY"),
1328            StreamClosureReason::Done => write!(f, "DONE"),
1329            StreamClosureReason::Timeout => write!(f, "TIMEOUT"),
1330            StreamClosureReason::NoRoute => write!(f, "NOROUTE"),
1331            StreamClosureReason::Hibernating => write!(f, "HIBERNATING"),
1332            StreamClosureReason::Internal => write!(f, "INTERNAL"),
1333            StreamClosureReason::ResourceLimit => write!(f, "RESOURCELIMIT"),
1334            StreamClosureReason::ConnReset => write!(f, "CONNRESET"),
1335            StreamClosureReason::TorProtocol => write!(f, "TORPROTOCOL"),
1336            StreamClosureReason::NotDirectory => write!(f, "NOTDIRECTORY"),
1337            StreamClosureReason::End => write!(f, "END"),
1338            StreamClosureReason::PrivateAddr => write!(f, "PRIVATE_ADDR"),
1339        }
1340    }
1341}
1342
1343/// Cause of a stream being remapped to another address.
1344///
1345/// # Example
1346///
1347/// ```rust
1348/// use stem_rs::StreamSource;
1349///
1350/// let source = StreamSource::Cache;
1351/// println!("Stream source: {}", source); // Prints "CACHE"
1352/// ```
1353#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1354pub enum StreamSource {
1355    /// Tor is remapping because of a cached answer.
1356    Cache,
1357    /// Exit relay requested the remap.
1358    Exit,
1359}
1360
1361impl fmt::Display for StreamSource {
1362    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1363        match self {
1364            StreamSource::Cache => write!(f, "CACHE"),
1365            StreamSource::Exit => write!(f, "EXIT"),
1366        }
1367    }
1368}
1369
1370/// Purpose of a stream.
1371///
1372/// Describes what the stream is being used for. Only provided with new streams.
1373///
1374/// # Example
1375///
1376/// ```rust
1377/// use stem_rs::StreamPurpose;
1378///
1379/// let purpose = StreamPurpose::User;
1380/// println!("Stream purpose: {}", purpose); // Prints "USER"
1381/// ```
1382#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1383pub enum StreamPurpose {
1384    /// Fetching directory information (descriptors, consensus, etc).
1385    DirFetch,
1386    /// Uploading our descriptor to an authority.
1387    DirUpload,
1388    /// User initiated DNS request.
1389    DnsRequest,
1390    /// Checking that our directory port is reachable externally.
1391    DirportTest,
1392    /// Either relaying user traffic or not one of the above categories.
1393    User,
1394}
1395
1396impl fmt::Display for StreamPurpose {
1397    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1398        match self {
1399            StreamPurpose::DirFetch => write!(f, "DIR_FETCH"),
1400            StreamPurpose::DirUpload => write!(f, "DIR_UPLOAD"),
1401            StreamPurpose::DnsRequest => write!(f, "DNS_REQUEST"),
1402            StreamPurpose::DirportTest => write!(f, "DIRPORT_TEST"),
1403            StreamPurpose::User => write!(f, "USER"),
1404        }
1405    }
1406}
1407
1408/// Status of an OR (Onion Router) connection.
1409///
1410/// OR connections are the TLS connections between Tor relays.
1411///
1412/// # Example
1413///
1414/// ```rust
1415/// use stem_rs::OrStatus;
1416///
1417/// let status = OrStatus::Connected;
1418/// println!("OR status: {}", status); // Prints "CONNECTED"
1419/// ```
1420#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1421pub enum OrStatus {
1422    /// Received OR connection, starting server-side handshake.
1423    New,
1424    /// Launched outbound OR connection, starting client-side handshake.
1425    Launched,
1426    /// OR connection has been established.
1427    Connected,
1428    /// Attempt to establish OR connection failed.
1429    Failed,
1430    /// OR connection has been closed.
1431    Closed,
1432}
1433
1434impl fmt::Display for OrStatus {
1435    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1436        match self {
1437            OrStatus::New => write!(f, "NEW"),
1438            OrStatus::Launched => write!(f, "LAUNCHED"),
1439            OrStatus::Connected => write!(f, "CONNECTED"),
1440            OrStatus::Failed => write!(f, "FAILED"),
1441            OrStatus::Closed => write!(f, "CLOSED"),
1442        }
1443    }
1444}
1445
1446/// Reason that an OR connection is being closed or failed.
1447///
1448/// # Example
1449///
1450/// ```rust
1451/// use stem_rs::OrClosureReason;
1452///
1453/// let reason = OrClosureReason::Done;
1454/// println!("OR closure reason: {}", reason); // Prints "DONE"
1455/// ```
1456#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1457pub enum OrClosureReason {
1458    /// OR connection shut down cleanly.
1459    Done,
1460    /// Got ECONNREFUSED when connecting to the relay.
1461    ConnectRefused,
1462    /// Identity of the relay wasn't what we expected.
1463    Identity,
1464    /// Got ECONNRESET or similar error from relay.
1465    ConnectReset,
1466    /// Got ETIMEOUT or similar error from relay.
1467    Timeout,
1468    /// Got ENOTCONN, ENETUNREACH, ENETDOWN, EHOSTUNREACH, or similar.
1469    NoRoute,
1470    /// Got a different kind of I/O error from relay.
1471    IoError,
1472    /// Relay has insufficient resources.
1473    ResourceLimit,
1474    /// Connection refused for another reason.
1475    Misc,
1476    /// No pluggable transport was available.
1477    PtMissing,
1478}
1479
1480impl fmt::Display for OrClosureReason {
1481    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1482        match self {
1483            OrClosureReason::Done => write!(f, "DONE"),
1484            OrClosureReason::ConnectRefused => write!(f, "CONNECTREFUSED"),
1485            OrClosureReason::Identity => write!(f, "IDENTITY"),
1486            OrClosureReason::ConnectReset => write!(f, "CONNECTRESET"),
1487            OrClosureReason::Timeout => write!(f, "TIMEOUT"),
1488            OrClosureReason::NoRoute => write!(f, "NOROUTE"),
1489            OrClosureReason::IoError => write!(f, "IOERROR"),
1490            OrClosureReason::ResourceLimit => write!(f, "RESOURCELIMIT"),
1491            OrClosureReason::Misc => write!(f, "MISC"),
1492            OrClosureReason::PtMissing => write!(f, "PT_MISSING"),
1493        }
1494    }
1495}
1496
1497/// Type of guard relay usage.
1498///
1499/// # Example
1500///
1501/// ```rust
1502/// use stem_rs::GuardType;
1503///
1504/// let guard_type = GuardType::Entry;
1505/// println!("Guard type: {}", guard_type); // Prints "ENTRY"
1506/// ```
1507#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1508pub enum GuardType {
1509    /// Used to connect to the Tor network (entry guard).
1510    Entry,
1511}
1512
1513impl fmt::Display for GuardType {
1514    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1515        match self {
1516            GuardType::Entry => write!(f, "ENTRY"),
1517        }
1518    }
1519}
1520
1521/// Status of a guard relay.
1522///
1523/// # Example
1524///
1525/// ```rust
1526/// use stem_rs::GuardStatus;
1527///
1528/// let status = GuardStatus::Up;
1529/// println!("Guard status: {}", status); // Prints "UP"
1530/// ```
1531#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1532pub enum GuardStatus {
1533    /// New guard that we weren't previously using.
1534    New,
1535    /// Removed from use as one of our guards.
1536    Dropped,
1537    /// Guard is now reachable.
1538    Up,
1539    /// Guard is now unreachable.
1540    Down,
1541    /// Consensus or relay considers this relay unusable as a guard.
1542    Bad,
1543    /// Consensus or relay considers this relay usable as a guard.
1544    Good,
1545}
1546
1547impl fmt::Display for GuardStatus {
1548    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1549        match self {
1550            GuardStatus::New => write!(f, "NEW"),
1551            GuardStatus::Dropped => write!(f, "DROPPED"),
1552            GuardStatus::Up => write!(f, "UP"),
1553            GuardStatus::Down => write!(f, "DOWN"),
1554            GuardStatus::Bad => write!(f, "BAD"),
1555            GuardStatus::Good => write!(f, "GOOD"),
1556        }
1557    }
1558}
1559
1560/// Way in which the timeout value of a circuit is changing.
1561///
1562/// # Example
1563///
1564/// ```rust
1565/// use stem_rs::TimeoutSetType;
1566///
1567/// let timeout_type = TimeoutSetType::Computed;
1568/// println!("Timeout type: {}", timeout_type); // Prints "COMPUTED"
1569/// ```
1570#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1571pub enum TimeoutSetType {
1572    /// Tor has computed a new timeout based on prior circuits.
1573    Computed,
1574    /// Timeout reverted to its default.
1575    Reset,
1576    /// Timeout reverted to default until network connectivity recovers.
1577    Suspended,
1578    /// Throwing out timeout value from when the network was down.
1579    Discard,
1580    /// Resumed calculations to determine the proper timeout.
1581    Resume,
1582}
1583
1584impl fmt::Display for TimeoutSetType {
1585    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1586        match self {
1587            TimeoutSetType::Computed => write!(f, "COMPUTED"),
1588            TimeoutSetType::Reset => write!(f, "RESET"),
1589            TimeoutSetType::Suspended => write!(f, "SUSPENDED"),
1590            TimeoutSetType::Discard => write!(f, "DISCARD"),
1591            TimeoutSetType::Resume => write!(f, "RESUME"),
1592        }
1593    }
1594}
1595
1596/// Action being taken in a HS_DESC event.
1597///
1598/// # Example
1599///
1600/// ```rust
1601/// use stem_rs::HsDescAction;
1602///
1603/// let action = HsDescAction::Received;
1604/// println!("HS_DESC action: {}", action); // Prints "RECEIVED"
1605/// ```
1606#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1607pub enum HsDescAction {
1608    /// Uncached hidden service descriptor is being requested.
1609    Requested,
1610    /// Descriptor is being uploaded with HSPOST.
1611    Upload,
1612    /// Hidden service descriptor has been retrieved.
1613    Received,
1614    /// Descriptor was uploaded with HSPOST.
1615    Uploaded,
1616    /// Fetched descriptor was ignored (already have v0 descriptor).
1617    Ignore,
1618    /// We were unable to retrieve the descriptor.
1619    Failed,
1620    /// Hidden service descriptor was just created.
1621    Created,
1622}
1623
1624impl fmt::Display for HsDescAction {
1625    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1626        match self {
1627            HsDescAction::Requested => write!(f, "REQUESTED"),
1628            HsDescAction::Upload => write!(f, "UPLOAD"),
1629            HsDescAction::Received => write!(f, "RECEIVED"),
1630            HsDescAction::Uploaded => write!(f, "UPLOADED"),
1631            HsDescAction::Ignore => write!(f, "IGNORE"),
1632            HsDescAction::Failed => write!(f, "FAILED"),
1633            HsDescAction::Created => write!(f, "CREATED"),
1634        }
1635    }
1636}
1637
1638/// Reason for a hidden service descriptor fetch to fail.
1639///
1640/// # Example
1641///
1642/// ```rust
1643/// use stem_rs::HsDescReason;
1644///
1645/// let reason = HsDescReason::NotFound;
1646/// println!("HS_DESC reason: {}", reason); // Prints "NOT_FOUND"
1647/// ```
1648#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1649pub enum HsDescReason {
1650    /// Descriptor was unparseable.
1651    BadDesc,
1652    /// Hidden service directory refused to provide the descriptor.
1653    QueryRejected,
1654    /// Descriptor was rejected by the hidden service directory.
1655    UploadRejected,
1656    /// Descriptor with the given identifier wasn't found.
1657    NotFound,
1658    /// No hidden service directory was found.
1659    QueryNoHsDir,
1660    /// Request was throttled (rate limited).
1661    QueryRateLimited,
1662    /// Failure type is unknown.
1663    Unexpected,
1664}
1665
1666impl fmt::Display for HsDescReason {
1667    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1668        match self {
1669            HsDescReason::BadDesc => write!(f, "BAD_DESC"),
1670            HsDescReason::QueryRejected => write!(f, "QUERY_REJECTED"),
1671            HsDescReason::UploadRejected => write!(f, "UPLOAD_REJECTED"),
1672            HsDescReason::NotFound => write!(f, "NOT_FOUND"),
1673            HsDescReason::QueryNoHsDir => write!(f, "QUERY_NO_HSDIR"),
1674            HsDescReason::QueryRateLimited => write!(f, "QUERY_RATE_LIMITED"),
1675            HsDescReason::Unexpected => write!(f, "UNEXPECTED"),
1676        }
1677    }
1678}
1679
1680/// Type of authentication for a HS_DESC event.
1681///
1682/// # Example
1683///
1684/// ```rust
1685/// use stem_rs::HsAuth;
1686///
1687/// let auth = HsAuth::NoAuth;
1688/// println!("HS auth: {}", auth); // Prints "NO_AUTH"
1689/// ```
1690#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1691pub enum HsAuth {
1692    /// No authentication required.
1693    NoAuth,
1694    /// General hidden service authentication.
1695    BasicAuth,
1696    /// Authentication that hides service activity from unauthorized clients.
1697    StealthAuth,
1698    /// Unrecognized method of authentication.
1699    Unknown,
1700}
1701
1702impl fmt::Display for HsAuth {
1703    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1704        match self {
1705            HsAuth::NoAuth => write!(f, "NO_AUTH"),
1706            HsAuth::BasicAuth => write!(f, "BASIC_AUTH"),
1707            HsAuth::StealthAuth => write!(f, "STEALTH_AUTH"),
1708            HsAuth::Unknown => write!(f, "UNKNOWN"),
1709        }
1710    }
1711}
1712
1713/// Types of events that can be subscribed to via the control protocol.
1714///
1715/// Use with [`controller::Controller::set_events`] to subscribe to events.
1716///
1717/// # Example
1718///
1719/// ```rust
1720/// use stem_rs::EventType;
1721///
1722/// let event = EventType::Circ;
1723/// println!("Event type: {}", event); // Prints "CIRC"
1724/// ```
1725#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1726pub enum EventType {
1727    /// Circuit status changed.
1728    Circ,
1729    /// Stream status changed.
1730    Stream,
1731    /// OR connection status changed.
1732    OrConn,
1733    /// Bandwidth used in the last second.
1734    Bw,
1735    /// Debug-level log message.
1736    Debug,
1737    /// Info-level log message.
1738    Info,
1739    /// Notice-level log message.
1740    Notice,
1741    /// Warning-level log message.
1742    Warn,
1743    /// Error-level log message.
1744    Err,
1745    /// New descriptors available.
1746    NewDesc,
1747    /// Address mapping changed.
1748    AddrMap,
1749    /// New descriptors uploaded to us as an authority.
1750    AuthDir,
1751    /// Our descriptor changed.
1752    DescChanged,
1753    /// General status event.
1754    Status,
1755    /// Guard status changed.
1756    Guard,
1757    /// Network status changed.
1758    Ns,
1759    /// Per-stream bandwidth.
1760    StreamBw,
1761    /// Periodic client summary (bridge/relay only).
1762    ClientsSeen,
1763    /// New consensus available.
1764    NewConsensus,
1765    /// Circuit build timeout changed.
1766    BuildTimeoutSet,
1767    /// Signal received.
1768    Signal,
1769    /// Configuration changed.
1770    ConfChanged,
1771    /// Minor circuit event.
1772    CircMinor,
1773    /// Pluggable transport launched.
1774    TransportLaunched,
1775    /// Per-connection bandwidth.
1776    ConnBw,
1777    /// Per-circuit bandwidth.
1778    CircBw,
1779    /// Cell statistics.
1780    CellStats,
1781    /// Hidden service descriptor event.
1782    HsDesc,
1783    /// Hidden service descriptor content.
1784    HsDescContent,
1785    /// Network liveness changed.
1786    NetworkLiveness,
1787    /// Pluggable transport log message.
1788    PtLog,
1789    /// Pluggable transport status.
1790    PtStatus,
1791}
1792
1793impl fmt::Display for EventType {
1794    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1795        match self {
1796            EventType::Circ => write!(f, "CIRC"),
1797            EventType::Stream => write!(f, "STREAM"),
1798            EventType::OrConn => write!(f, "ORCONN"),
1799            EventType::Bw => write!(f, "BW"),
1800            EventType::Debug => write!(f, "DEBUG"),
1801            EventType::Info => write!(f, "INFO"),
1802            EventType::Notice => write!(f, "NOTICE"),
1803            EventType::Warn => write!(f, "WARN"),
1804            EventType::Err => write!(f, "ERR"),
1805            EventType::NewDesc => write!(f, "NEWDESC"),
1806            EventType::AddrMap => write!(f, "ADDRMAP"),
1807            EventType::AuthDir => write!(f, "AUTHDIR_NEWDESCS"),
1808            EventType::DescChanged => write!(f, "DESCCHANGED"),
1809            EventType::Status => write!(f, "STATUS_GENERAL"),
1810            EventType::Guard => write!(f, "GUARD"),
1811            EventType::Ns => write!(f, "NS"),
1812            EventType::StreamBw => write!(f, "STREAM_BW"),
1813            EventType::ClientsSeen => write!(f, "CLIENTS_SEEN"),
1814            EventType::NewConsensus => write!(f, "NEWCONSENSUS"),
1815            EventType::BuildTimeoutSet => write!(f, "BUILDTIMEOUT_SET"),
1816            EventType::Signal => write!(f, "SIGNAL"),
1817            EventType::ConfChanged => write!(f, "CONF_CHANGED"),
1818            EventType::CircMinor => write!(f, "CIRC_MINOR"),
1819            EventType::TransportLaunched => write!(f, "TRANSPORT_LAUNCHED"),
1820            EventType::ConnBw => write!(f, "CONN_BW"),
1821            EventType::CircBw => write!(f, "CIRC_BW"),
1822            EventType::CellStats => write!(f, "CELL_STATS"),
1823            EventType::HsDesc => write!(f, "HS_DESC"),
1824            EventType::HsDescContent => write!(f, "HS_DESC_CONTENT"),
1825            EventType::NetworkLiveness => write!(f, "NETWORK_LIVENESS"),
1826            EventType::PtLog => write!(f, "PT_LOG"),
1827            EventType::PtStatus => write!(f, "PT_STATUS"),
1828        }
1829    }
1830}
1831
1832/// Source of a status event.
1833///
1834/// # Example
1835///
1836/// ```rust
1837/// use stem_rs::StatusType;
1838///
1839/// let status = StatusType::General;
1840/// println!("Status type: {}", status); // Prints "GENERAL"
1841/// ```
1842#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1843pub enum StatusType {
1844    /// General Tor activity, not specifically as a client or relay.
1845    General,
1846    /// Related to our activity as a Tor client.
1847    Client,
1848    /// Related to our activity as a Tor relay.
1849    Server,
1850}
1851
1852impl fmt::Display for StatusType {
1853    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1854        match self {
1855            StatusType::General => write!(f, "GENERAL"),
1856            StatusType::Client => write!(f, "CLIENT"),
1857            StatusType::Server => write!(f, "SERVER"),
1858        }
1859    }
1860}
1861
1862/// Purpose for a Tor connection.
1863///
1864/// # Example
1865///
1866/// ```rust
1867/// use stem_rs::ConnectionType;
1868///
1869/// let conn_type = ConnectionType::Or;
1870/// println!("Connection type: {}", conn_type); // Prints "OR"
1871/// ```
1872#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1873pub enum ConnectionType {
1874    /// Carrying traffic within the Tor network.
1875    Or,
1876    /// Fetching or sending Tor descriptor data.
1877    Dir,
1878    /// Carrying traffic between Tor network and external destination.
1879    Exit,
1880}
1881
1882impl fmt::Display for ConnectionType {
1883    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1884        match self {
1885            ConnectionType::Or => write!(f, "OR"),
1886            ConnectionType::Dir => write!(f, "DIR"),
1887            ConnectionType::Exit => write!(f, "EXIT"),
1888        }
1889    }
1890}
1891
1892/// Bucket categories for TB_EMPTY events.
1893///
1894/// Token buckets are used for rate limiting in Tor.
1895///
1896/// # Example
1897///
1898/// ```rust
1899/// use stem_rs::TokenBucket;
1900///
1901/// let bucket = TokenBucket::Global;
1902/// println!("Token bucket: {}", bucket); // Prints "GLOBAL"
1903/// ```
1904#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1905pub enum TokenBucket {
1906    /// Global token bucket for overall bandwidth.
1907    Global,
1908    /// Relay token bucket for relay traffic.
1909    Relay,
1910    /// Bucket used for OR connections.
1911    OrConn,
1912}
1913
1914impl fmt::Display for TokenBucket {
1915    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1916        match self {
1917            TokenBucket::Global => write!(f, "GLOBAL"),
1918            TokenBucket::Relay => write!(f, "RELAY"),
1919            TokenBucket::OrConn => write!(f, "ORCONN"),
1920        }
1921    }
1922}
1923
1924/// Actions that directory authorities take with relay descriptors.
1925///
1926/// # Example
1927///
1928/// ```rust
1929/// use stem_rs::AuthDescriptorAction;
1930///
1931/// let action = AuthDescriptorAction::Accepted;
1932/// println!("Auth action: {}", action); // Prints "ACCEPTED"
1933/// ```
1934#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1935pub enum AuthDescriptorAction {
1936    /// Accepting the descriptor as the newest version.
1937    Accepted,
1938    /// Descriptor rejected without notifying the relay.
1939    Dropped,
1940    /// Relay notified that its descriptor has been rejected.
1941    Rejected,
1942}
1943
1944impl fmt::Display for AuthDescriptorAction {
1945    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1946        match self {
1947            AuthDescriptorAction::Accepted => write!(f, "ACCEPTED"),
1948            AuthDescriptorAction::Dropped => write!(f, "DROPPED"),
1949            AuthDescriptorAction::Rejected => write!(f, "REJECTED"),
1950        }
1951    }
1952}
1953
1954/// Bridge distribution methods.
1955///
1956/// Specifies how a bridge relay should be distributed to users.
1957///
1958/// # Example
1959///
1960/// ```rust
1961/// use stem_rs::BridgeDistribution;
1962///
1963/// let dist = BridgeDistribution::Https;
1964/// println!("Distribution: {}", dist); // Prints "https"
1965/// ```
1966#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1967pub enum BridgeDistribution {
1968    /// Distribute via any method.
1969    Any,
1970    /// Distribute via HTTPS (bridges.torproject.org).
1971    Https,
1972    /// Distribute via email.
1973    Email,
1974    /// Distribute via Moat (built into Tor Browser).
1975    Moat,
1976    /// Distribute via Hyphae.
1977    Hyphae,
1978}
1979
1980impl fmt::Display for BridgeDistribution {
1981    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1982        match self {
1983            BridgeDistribution::Any => write!(f, "any"),
1984            BridgeDistribution::Https => write!(f, "https"),
1985            BridgeDistribution::Email => write!(f, "email"),
1986            BridgeDistribution::Moat => write!(f, "moat"),
1987            BridgeDistribution::Hyphae => write!(f, "hyphae"),
1988        }
1989    }
1990}
1991
1992#[cfg(test)]
1993mod tests {
1994    use super::*;
1995
1996    #[test]
1997    fn test_runlevel_display() {
1998        assert_eq!(format!("{}", Runlevel::Debug), "DEBUG");
1999        assert_eq!(format!("{}", Runlevel::Info), "INFO");
2000        assert_eq!(format!("{}", Runlevel::Notice), "NOTICE");
2001        assert_eq!(format!("{}", Runlevel::Warn), "WARN");
2002        assert_eq!(format!("{}", Runlevel::Err), "ERR");
2003    }
2004
2005    #[test]
2006    fn test_signal_display() {
2007        assert_eq!(format!("{}", Signal::Reload), "RELOAD");
2008        assert_eq!(format!("{}", Signal::Hup), "HUP");
2009        assert_eq!(format!("{}", Signal::Shutdown), "SHUTDOWN");
2010        assert_eq!(format!("{}", Signal::Int), "INT");
2011        assert_eq!(format!("{}", Signal::Dump), "DUMP");
2012        assert_eq!(format!("{}", Signal::Usr1), "USR1");
2013        assert_eq!(format!("{}", Signal::Debug), "DEBUG");
2014        assert_eq!(format!("{}", Signal::Usr2), "USR2");
2015        assert_eq!(format!("{}", Signal::Halt), "HALT");
2016        assert_eq!(format!("{}", Signal::Term), "TERM");
2017        assert_eq!(format!("{}", Signal::Newnym), "NEWNYM");
2018        assert_eq!(format!("{}", Signal::ClearDnsCache), "CLEARDNSCACHE");
2019        assert_eq!(format!("{}", Signal::Heartbeat), "HEARTBEAT");
2020        assert_eq!(format!("{}", Signal::Active), "ACTIVE");
2021        assert_eq!(format!("{}", Signal::Dormant), "DORMANT");
2022    }
2023
2024    #[test]
2025    fn test_flag_display() {
2026        assert_eq!(format!("{}", Flag::Authority), "Authority");
2027        assert_eq!(format!("{}", Flag::BadExit), "BadExit");
2028        assert_eq!(format!("{}", Flag::BadDirectory), "BadDirectory");
2029        assert_eq!(format!("{}", Flag::Exit), "Exit");
2030        assert_eq!(format!("{}", Flag::Fast), "Fast");
2031        assert_eq!(format!("{}", Flag::Guard), "Guard");
2032        assert_eq!(format!("{}", Flag::HsDir), "HSDir");
2033        assert_eq!(format!("{}", Flag::Named), "Named");
2034        assert_eq!(format!("{}", Flag::NoEdConsensus), "NoEdConsensus");
2035        assert_eq!(format!("{}", Flag::Running), "Running");
2036        assert_eq!(format!("{}", Flag::Stable), "Stable");
2037        assert_eq!(format!("{}", Flag::StaleDesc), "StaleDesc");
2038        assert_eq!(format!("{}", Flag::Unnamed), "Unnamed");
2039        assert_eq!(format!("{}", Flag::V2Dir), "V2Dir");
2040        assert_eq!(format!("{}", Flag::V3Dir), "V3Dir");
2041        assert_eq!(format!("{}", Flag::Valid), "Valid");
2042    }
2043
2044    #[test]
2045    fn test_circ_status_display() {
2046        assert_eq!(format!("{}", CircStatus::Launched), "LAUNCHED");
2047        assert_eq!(format!("{}", CircStatus::Built), "BUILT");
2048        assert_eq!(format!("{}", CircStatus::GuardWait), "GUARD_WAIT");
2049        assert_eq!(format!("{}", CircStatus::Extended), "EXTENDED");
2050        assert_eq!(format!("{}", CircStatus::Failed), "FAILED");
2051        assert_eq!(format!("{}", CircStatus::Closed), "CLOSED");
2052    }
2053
2054    #[test]
2055    fn test_circ_build_flag_display() {
2056        assert_eq!(format!("{}", CircBuildFlag::OneHopTunnel), "ONEHOP_TUNNEL");
2057        assert_eq!(format!("{}", CircBuildFlag::IsInternal), "IS_INTERNAL");
2058        assert_eq!(format!("{}", CircBuildFlag::NeedCapacity), "NEED_CAPACITY");
2059        assert_eq!(format!("{}", CircBuildFlag::NeedUptime), "NEED_UPTIME");
2060    }
2061
2062    #[test]
2063    fn test_circ_purpose_display() {
2064        assert_eq!(format!("{}", CircPurpose::General), "GENERAL");
2065        assert_eq!(format!("{}", CircPurpose::HsClientIntro), "HS_CLIENT_INTRO");
2066        assert_eq!(format!("{}", CircPurpose::HsClientRend), "HS_CLIENT_REND");
2067        assert_eq!(
2068            format!("{}", CircPurpose::HsServiceIntro),
2069            "HS_SERVICE_INTRO"
2070        );
2071        assert_eq!(format!("{}", CircPurpose::HsServiceRend), "HS_SERVICE_REND");
2072        assert_eq!(format!("{}", CircPurpose::Testing), "TESTING");
2073        assert_eq!(format!("{}", CircPurpose::Controller), "CONTROLLER");
2074        assert_eq!(
2075            format!("{}", CircPurpose::MeasureTimeout),
2076            "MEASURE_TIMEOUT"
2077        );
2078        assert_eq!(format!("{}", CircPurpose::HsVanguards), "HS_VANGUARDS");
2079        assert_eq!(
2080            format!("{}", CircPurpose::PathBiasTesting),
2081            "PATH_BIAS_TESTING"
2082        );
2083        assert_eq!(
2084            format!("{}", CircPurpose::CircuitPadding),
2085            "CIRCUIT_PADDING"
2086        );
2087    }
2088
2089    #[test]
2090    fn test_circ_closure_reason_display() {
2091        assert_eq!(format!("{}", CircClosureReason::None), "NONE");
2092        assert_eq!(format!("{}", CircClosureReason::TorProtocol), "TORPROTOCOL");
2093        assert_eq!(format!("{}", CircClosureReason::Internal), "INTERNAL");
2094        assert_eq!(format!("{}", CircClosureReason::Requested), "REQUESTED");
2095        assert_eq!(format!("{}", CircClosureReason::Hibernating), "HIBERNATING");
2096        assert_eq!(
2097            format!("{}", CircClosureReason::ResourceLimit),
2098            "RESOURCELIMIT"
2099        );
2100        assert_eq!(
2101            format!("{}", CircClosureReason::ConnectFailed),
2102            "CONNECTFAILED"
2103        );
2104        assert_eq!(format!("{}", CircClosureReason::OrIdentity), "OR_IDENTITY");
2105        assert_eq!(
2106            format!("{}", CircClosureReason::OrConnClosed),
2107            "OR_CONN_CLOSED"
2108        );
2109        assert_eq!(format!("{}", CircClosureReason::Finished), "FINISHED");
2110        assert_eq!(format!("{}", CircClosureReason::Timeout), "TIMEOUT");
2111        assert_eq!(format!("{}", CircClosureReason::Destroyed), "DESTROYED");
2112        assert_eq!(format!("{}", CircClosureReason::NoPath), "NOPATH");
2113        assert_eq!(
2114            format!("{}", CircClosureReason::NoSuchService),
2115            "NOSUCHSERVICE"
2116        );
2117        assert_eq!(
2118            format!("{}", CircClosureReason::MeasurementExpired),
2119            "MEASUREMENT_EXPIRED"
2120        );
2121        assert_eq!(
2122            format!("{}", CircClosureReason::IpNowRedundant),
2123            "IP_NOW_REDUNDANT"
2124        );
2125    }
2126
2127    #[test]
2128    fn test_circ_event_display() {
2129        assert_eq!(format!("{}", CircEvent::PurposeChanged), "PURPOSE_CHANGED");
2130        assert_eq!(format!("{}", CircEvent::Cannibalized), "CANNIBALIZED");
2131    }
2132
2133    #[test]
2134    fn test_hidden_service_state_display() {
2135        assert_eq!(
2136            format!("{}", HiddenServiceState::HsciConnecting),
2137            "HSCI_CONNECTING"
2138        );
2139        assert_eq!(
2140            format!("{}", HiddenServiceState::HsciIntroSent),
2141            "HSCI_INTRO_SENT"
2142        );
2143        assert_eq!(format!("{}", HiddenServiceState::HsciDone), "HSCI_DONE");
2144        assert_eq!(
2145            format!("{}", HiddenServiceState::HscrConnecting),
2146            "HSCR_CONNECTING"
2147        );
2148        assert_eq!(
2149            format!("{}", HiddenServiceState::HscrEstablishedIdle),
2150            "HSCR_ESTABLISHED_IDLE"
2151        );
2152        assert_eq!(
2153            format!("{}", HiddenServiceState::HscrEstablishedWaiting),
2154            "HSCR_ESTABLISHED_WAITING"
2155        );
2156        assert_eq!(format!("{}", HiddenServiceState::HscrJoined), "HSCR_JOINED");
2157        assert_eq!(
2158            format!("{}", HiddenServiceState::HssiConnecting),
2159            "HSSI_CONNECTING"
2160        );
2161        assert_eq!(
2162            format!("{}", HiddenServiceState::HssiEstablished),
2163            "HSSI_ESTABLISHED"
2164        );
2165        assert_eq!(
2166            format!("{}", HiddenServiceState::HssrConnecting),
2167            "HSSR_CONNECTING"
2168        );
2169        assert_eq!(format!("{}", HiddenServiceState::HssrJoined), "HSSR_JOINED");
2170    }
2171
2172    #[test]
2173    fn test_stream_status_display() {
2174        assert_eq!(format!("{}", StreamStatus::New), "NEW");
2175        assert_eq!(format!("{}", StreamStatus::NewResolve), "NEWRESOLVE");
2176        assert_eq!(format!("{}", StreamStatus::Remap), "REMAP");
2177        assert_eq!(format!("{}", StreamStatus::SentConnect), "SENTCONNECT");
2178        assert_eq!(format!("{}", StreamStatus::SentResolve), "SENTRESOLVE");
2179        assert_eq!(format!("{}", StreamStatus::Succeeded), "SUCCEEDED");
2180        assert_eq!(format!("{}", StreamStatus::Failed), "FAILED");
2181        assert_eq!(format!("{}", StreamStatus::Detached), "DETACHED");
2182        assert_eq!(
2183            format!("{}", StreamStatus::ControllerWait),
2184            "CONTROLLER_WAIT"
2185        );
2186        assert_eq!(format!("{}", StreamStatus::Closed), "CLOSED");
2187    }
2188
2189    #[test]
2190    fn test_stream_closure_reason_display() {
2191        assert_eq!(format!("{}", StreamClosureReason::Misc), "MISC");
2192        assert_eq!(
2193            format!("{}", StreamClosureReason::ResolveFailed),
2194            "RESOLVEFAILED"
2195        );
2196        assert_eq!(
2197            format!("{}", StreamClosureReason::ConnectRefused),
2198            "CONNECTREFUSED"
2199        );
2200        assert_eq!(format!("{}", StreamClosureReason::ExitPolicy), "EXITPOLICY");
2201        assert_eq!(format!("{}", StreamClosureReason::Destroy), "DESTROY");
2202        assert_eq!(format!("{}", StreamClosureReason::Done), "DONE");
2203        assert_eq!(format!("{}", StreamClosureReason::Timeout), "TIMEOUT");
2204        assert_eq!(format!("{}", StreamClosureReason::NoRoute), "NOROUTE");
2205        assert_eq!(
2206            format!("{}", StreamClosureReason::Hibernating),
2207            "HIBERNATING"
2208        );
2209        assert_eq!(format!("{}", StreamClosureReason::Internal), "INTERNAL");
2210        assert_eq!(
2211            format!("{}", StreamClosureReason::ResourceLimit),
2212            "RESOURCELIMIT"
2213        );
2214        assert_eq!(format!("{}", StreamClosureReason::ConnReset), "CONNRESET");
2215        assert_eq!(
2216            format!("{}", StreamClosureReason::TorProtocol),
2217            "TORPROTOCOL"
2218        );
2219        assert_eq!(
2220            format!("{}", StreamClosureReason::NotDirectory),
2221            "NOTDIRECTORY"
2222        );
2223        assert_eq!(format!("{}", StreamClosureReason::End), "END");
2224        assert_eq!(
2225            format!("{}", StreamClosureReason::PrivateAddr),
2226            "PRIVATE_ADDR"
2227        );
2228    }
2229
2230    #[test]
2231    fn test_stream_source_display() {
2232        assert_eq!(format!("{}", StreamSource::Cache), "CACHE");
2233        assert_eq!(format!("{}", StreamSource::Exit), "EXIT");
2234    }
2235
2236    #[test]
2237    fn test_stream_purpose_display() {
2238        assert_eq!(format!("{}", StreamPurpose::DirFetch), "DIR_FETCH");
2239        assert_eq!(format!("{}", StreamPurpose::DirUpload), "DIR_UPLOAD");
2240        assert_eq!(format!("{}", StreamPurpose::DnsRequest), "DNS_REQUEST");
2241        assert_eq!(format!("{}", StreamPurpose::DirportTest), "DIRPORT_TEST");
2242        assert_eq!(format!("{}", StreamPurpose::User), "USER");
2243    }
2244
2245    #[test]
2246    fn test_or_status_display() {
2247        assert_eq!(format!("{}", OrStatus::New), "NEW");
2248        assert_eq!(format!("{}", OrStatus::Launched), "LAUNCHED");
2249        assert_eq!(format!("{}", OrStatus::Connected), "CONNECTED");
2250        assert_eq!(format!("{}", OrStatus::Failed), "FAILED");
2251        assert_eq!(format!("{}", OrStatus::Closed), "CLOSED");
2252    }
2253
2254    #[test]
2255    fn test_or_closure_reason_display() {
2256        assert_eq!(format!("{}", OrClosureReason::Done), "DONE");
2257        assert_eq!(
2258            format!("{}", OrClosureReason::ConnectRefused),
2259            "CONNECTREFUSED"
2260        );
2261        assert_eq!(format!("{}", OrClosureReason::Identity), "IDENTITY");
2262        assert_eq!(format!("{}", OrClosureReason::ConnectReset), "CONNECTRESET");
2263        assert_eq!(format!("{}", OrClosureReason::Timeout), "TIMEOUT");
2264        assert_eq!(format!("{}", OrClosureReason::NoRoute), "NOROUTE");
2265        assert_eq!(format!("{}", OrClosureReason::IoError), "IOERROR");
2266        assert_eq!(
2267            format!("{}", OrClosureReason::ResourceLimit),
2268            "RESOURCELIMIT"
2269        );
2270        assert_eq!(format!("{}", OrClosureReason::Misc), "MISC");
2271        assert_eq!(format!("{}", OrClosureReason::PtMissing), "PT_MISSING");
2272    }
2273
2274    #[test]
2275    fn test_guard_type_display() {
2276        assert_eq!(format!("{}", GuardType::Entry), "ENTRY");
2277    }
2278
2279    #[test]
2280    fn test_guard_status_display() {
2281        assert_eq!(format!("{}", GuardStatus::New), "NEW");
2282        assert_eq!(format!("{}", GuardStatus::Dropped), "DROPPED");
2283        assert_eq!(format!("{}", GuardStatus::Up), "UP");
2284        assert_eq!(format!("{}", GuardStatus::Down), "DOWN");
2285        assert_eq!(format!("{}", GuardStatus::Bad), "BAD");
2286        assert_eq!(format!("{}", GuardStatus::Good), "GOOD");
2287    }
2288
2289    #[test]
2290    fn test_timeout_set_type_display() {
2291        assert_eq!(format!("{}", TimeoutSetType::Computed), "COMPUTED");
2292        assert_eq!(format!("{}", TimeoutSetType::Reset), "RESET");
2293        assert_eq!(format!("{}", TimeoutSetType::Suspended), "SUSPENDED");
2294        assert_eq!(format!("{}", TimeoutSetType::Discard), "DISCARD");
2295        assert_eq!(format!("{}", TimeoutSetType::Resume), "RESUME");
2296    }
2297
2298    #[test]
2299    fn test_hs_desc_action_display() {
2300        assert_eq!(format!("{}", HsDescAction::Requested), "REQUESTED");
2301        assert_eq!(format!("{}", HsDescAction::Upload), "UPLOAD");
2302        assert_eq!(format!("{}", HsDescAction::Received), "RECEIVED");
2303        assert_eq!(format!("{}", HsDescAction::Uploaded), "UPLOADED");
2304        assert_eq!(format!("{}", HsDescAction::Ignore), "IGNORE");
2305        assert_eq!(format!("{}", HsDescAction::Failed), "FAILED");
2306        assert_eq!(format!("{}", HsDescAction::Created), "CREATED");
2307    }
2308
2309    #[test]
2310    fn test_hs_desc_reason_display() {
2311        assert_eq!(format!("{}", HsDescReason::BadDesc), "BAD_DESC");
2312        assert_eq!(format!("{}", HsDescReason::QueryRejected), "QUERY_REJECTED");
2313        assert_eq!(
2314            format!("{}", HsDescReason::UploadRejected),
2315            "UPLOAD_REJECTED"
2316        );
2317        assert_eq!(format!("{}", HsDescReason::NotFound), "NOT_FOUND");
2318        assert_eq!(format!("{}", HsDescReason::QueryNoHsDir), "QUERY_NO_HSDIR");
2319        assert_eq!(
2320            format!("{}", HsDescReason::QueryRateLimited),
2321            "QUERY_RATE_LIMITED"
2322        );
2323        assert_eq!(format!("{}", HsDescReason::Unexpected), "UNEXPECTED");
2324    }
2325
2326    #[test]
2327    fn test_hs_auth_display() {
2328        assert_eq!(format!("{}", HsAuth::NoAuth), "NO_AUTH");
2329        assert_eq!(format!("{}", HsAuth::BasicAuth), "BASIC_AUTH");
2330        assert_eq!(format!("{}", HsAuth::StealthAuth), "STEALTH_AUTH");
2331        assert_eq!(format!("{}", HsAuth::Unknown), "UNKNOWN");
2332    }
2333
2334    #[test]
2335    fn test_event_type_display() {
2336        assert_eq!(format!("{}", EventType::Circ), "CIRC");
2337        assert_eq!(format!("{}", EventType::Stream), "STREAM");
2338        assert_eq!(format!("{}", EventType::OrConn), "ORCONN");
2339        assert_eq!(format!("{}", EventType::Bw), "BW");
2340        assert_eq!(format!("{}", EventType::Debug), "DEBUG");
2341        assert_eq!(format!("{}", EventType::Info), "INFO");
2342        assert_eq!(format!("{}", EventType::Notice), "NOTICE");
2343        assert_eq!(format!("{}", EventType::Warn), "WARN");
2344        assert_eq!(format!("{}", EventType::Err), "ERR");
2345        assert_eq!(format!("{}", EventType::NewDesc), "NEWDESC");
2346        assert_eq!(format!("{}", EventType::AddrMap), "ADDRMAP");
2347        assert_eq!(format!("{}", EventType::AuthDir), "AUTHDIR_NEWDESCS");
2348        assert_eq!(format!("{}", EventType::DescChanged), "DESCCHANGED");
2349        assert_eq!(format!("{}", EventType::Status), "STATUS_GENERAL");
2350        assert_eq!(format!("{}", EventType::Guard), "GUARD");
2351        assert_eq!(format!("{}", EventType::Ns), "NS");
2352        assert_eq!(format!("{}", EventType::StreamBw), "STREAM_BW");
2353        assert_eq!(format!("{}", EventType::ClientsSeen), "CLIENTS_SEEN");
2354        assert_eq!(format!("{}", EventType::NewConsensus), "NEWCONSENSUS");
2355        assert_eq!(
2356            format!("{}", EventType::BuildTimeoutSet),
2357            "BUILDTIMEOUT_SET"
2358        );
2359        assert_eq!(format!("{}", EventType::Signal), "SIGNAL");
2360        assert_eq!(format!("{}", EventType::ConfChanged), "CONF_CHANGED");
2361        assert_eq!(format!("{}", EventType::CircMinor), "CIRC_MINOR");
2362        assert_eq!(
2363            format!("{}", EventType::TransportLaunched),
2364            "TRANSPORT_LAUNCHED"
2365        );
2366        assert_eq!(format!("{}", EventType::ConnBw), "CONN_BW");
2367        assert_eq!(format!("{}", EventType::CircBw), "CIRC_BW");
2368        assert_eq!(format!("{}", EventType::CellStats), "CELL_STATS");
2369        assert_eq!(format!("{}", EventType::HsDesc), "HS_DESC");
2370        assert_eq!(format!("{}", EventType::HsDescContent), "HS_DESC_CONTENT");
2371        assert_eq!(
2372            format!("{}", EventType::NetworkLiveness),
2373            "NETWORK_LIVENESS"
2374        );
2375        assert_eq!(format!("{}", EventType::PtLog), "PT_LOG");
2376        assert_eq!(format!("{}", EventType::PtStatus), "PT_STATUS");
2377    }
2378
2379    #[test]
2380    fn test_status_type_display() {
2381        assert_eq!(format!("{}", StatusType::General), "GENERAL");
2382        assert_eq!(format!("{}", StatusType::Client), "CLIENT");
2383        assert_eq!(format!("{}", StatusType::Server), "SERVER");
2384    }
2385
2386    #[test]
2387    fn test_connection_type_display() {
2388        assert_eq!(format!("{}", ConnectionType::Or), "OR");
2389        assert_eq!(format!("{}", ConnectionType::Dir), "DIR");
2390        assert_eq!(format!("{}", ConnectionType::Exit), "EXIT");
2391    }
2392
2393    #[test]
2394    fn test_token_bucket_display() {
2395        assert_eq!(format!("{}", TokenBucket::Global), "GLOBAL");
2396        assert_eq!(format!("{}", TokenBucket::Relay), "RELAY");
2397        assert_eq!(format!("{}", TokenBucket::OrConn), "ORCONN");
2398    }
2399
2400    #[test]
2401    fn test_auth_descriptor_action_display() {
2402        assert_eq!(format!("{}", AuthDescriptorAction::Accepted), "ACCEPTED");
2403        assert_eq!(format!("{}", AuthDescriptorAction::Dropped), "DROPPED");
2404        assert_eq!(format!("{}", AuthDescriptorAction::Rejected), "REJECTED");
2405    }
2406
2407    #[test]
2408    fn test_bridge_distribution_display() {
2409        assert_eq!(format!("{}", BridgeDistribution::Any), "any");
2410        assert_eq!(format!("{}", BridgeDistribution::Https), "https");
2411        assert_eq!(format!("{}", BridgeDistribution::Email), "email");
2412        assert_eq!(format!("{}", BridgeDistribution::Moat), "moat");
2413        assert_eq!(format!("{}", BridgeDistribution::Hyphae), "hyphae");
2414    }
2415
2416    #[test]
2417    fn test_error_display() {
2418        let err = Error::Protocol("test error".to_string());
2419        assert!(format!("{}", err).contains("test error"));
2420
2421        let err = Error::OperationFailed {
2422            code: "500".to_string(),
2423            message: "failed".to_string(),
2424        };
2425        assert!(format!("{}", err).contains("500"));
2426        assert!(format!("{}", err).contains("failed"));
2427
2428        let err = Error::Parse {
2429            location: "line 1".to_string(),
2430            reason: "invalid".to_string(),
2431        };
2432        assert!(format!("{}", err).contains("line 1"));
2433        assert!(format!("{}", err).contains("invalid"));
2434
2435        let err = Error::Download {
2436            url: "http://example.com".to_string(),
2437            reason: "timeout".to_string(),
2438        };
2439        assert!(format!("{}", err).contains("example.com"));
2440
2441        let err = Error::DownloadTimeout {
2442            url: "http://example.com".to_string(),
2443        };
2444        assert!(format!("{}", err).contains("example.com"));
2445
2446        let err = Error::Timeout;
2447        assert!(format!("{}", err).contains("timeout"));
2448
2449        let err = Error::SocketClosed;
2450        assert!(format!("{}", err).contains("closed"));
2451
2452        let err = Error::DescriptorUnavailable("test".to_string());
2453        assert!(format!("{}", err).contains("test"));
2454
2455        let err = Error::CircuitExtensionFailed("test".to_string());
2456        assert!(format!("{}", err).contains("test"));
2457
2458        let err = Error::UnsatisfiableRequest("test".to_string());
2459        assert!(format!("{}", err).contains("test"));
2460
2461        let err = Error::InvalidRequest("test".to_string());
2462        assert!(format!("{}", err).contains("test"));
2463
2464        let err = Error::InvalidArguments("test".to_string());
2465        assert!(format!("{}", err).contains("test"));
2466    }
2467
2468    #[test]
2469    fn test_auth_error_display() {
2470        let err = AuthError::NoMethods;
2471        assert!(format!("{}", err).contains("no authentication"));
2472
2473        let err = AuthError::IncorrectPassword;
2474        assert!(format!("{}", err).contains("password"));
2475
2476        let err = AuthError::CookieUnreadable("path".to_string());
2477        assert!(format!("{}", err).contains("path"));
2478
2479        let err = AuthError::IncorrectCookie;
2480        assert!(format!("{}", err).contains("cookie"));
2481
2482        let err = AuthError::IncorrectCookieSize;
2483        assert!(format!("{}", err).contains("cookie"));
2484
2485        let err = AuthError::ChallengeFailed;
2486        assert!(format!("{}", err).contains("challenge"));
2487
2488        let err = AuthError::ChallengeUnsupported;
2489        assert!(format!("{}", err).contains("challenge"));
2490
2491        let err = AuthError::SecurityFailure;
2492        assert!(format!("{}", err).contains("security"));
2493
2494        let err = AuthError::MissingPassword;
2495        assert!(format!("{}", err).contains("password"));
2496
2497        let err = AuthError::UnrecognizedMethods(vec!["test".to_string()]);
2498        assert!(format!("{}", err).contains("test"));
2499
2500        let err = AuthError::IncorrectSocketType;
2501        assert!(format!("{}", err).contains("socket"));
2502    }
2503
2504    #[test]
2505    fn test_enum_equality() {
2506        assert_eq!(Runlevel::Debug, Runlevel::Debug);
2507        assert_ne!(Runlevel::Debug, Runlevel::Info);
2508
2509        assert_eq!(Signal::Reload, Signal::Reload);
2510        assert_ne!(Signal::Reload, Signal::Shutdown);
2511
2512        assert_eq!(Flag::Exit, Flag::Exit);
2513        assert_ne!(Flag::Exit, Flag::Guard);
2514    }
2515
2516    #[test]
2517    fn test_enum_hash() {
2518        use std::collections::HashSet;
2519
2520        let mut set = HashSet::new();
2521        set.insert(Runlevel::Debug);
2522        set.insert(Runlevel::Info);
2523        assert!(set.contains(&Runlevel::Debug));
2524        assert!(!set.contains(&Runlevel::Warn));
2525
2526        let mut set = HashSet::new();
2527        set.insert(Signal::Newnym);
2528        assert!(set.contains(&Signal::Newnym));
2529    }
2530
2531    #[test]
2532    fn test_enum_clone() {
2533        let r = Runlevel::Debug;
2534        let r2 = r;
2535        assert_eq!(r, r2);
2536
2537        let s = Signal::Newnym;
2538        let s2 = s;
2539        assert_eq!(s, s2);
2540    }
2541
2542    #[test]
2543    fn test_enum_debug() {
2544        assert!(format!("{:?}", Runlevel::Debug).contains("Debug"));
2545        assert!(format!("{:?}", Signal::Newnym).contains("Newnym"));
2546        assert!(format!("{:?}", Flag::Exit).contains("Exit"));
2547    }
2548}