Skip to main content

ntex_util/
lib.rs

1//! Utilities shared by the ntex ecosystem.
2//!
3//! This crate provides:
4//!
5//! - [`channel`] for local asynchronous communication primitives
6//! - [`future`] for future and stream combinators
7//! - [`services`] for reusable service middleware
8//! - [`task`] for task wake-up and cooperative yielding
9//! - [`time`] for timers, intervals, deadlines, and timeouts
10//!
11//! Most types in this crate are designed for ntex's single-threaded execution
12//! model and therefore do not necessarily implement `Send` or `Sync`.
13#![deny(clippy::pedantic)]
14#![allow(
15    async_fn_in_trait,
16    clippy::missing_fields_in_debug,
17    clippy::must_use_candidate,
18    clippy::missing_errors_doc,
19    clippy::missing_panics_doc,
20    clippy::unused_async_trait_impl
21)]
22use std::{error::Error, io, rc::Rc};
23
24pub mod channel;
25pub mod future;
26pub mod services;
27pub mod task;
28pub mod time;
29
30pub use futures_core::Stream;
31pub use ntex_rt::spawn;
32
33#[doc(hidden)]
34pub use hashbrown::{Equivalent, hash_map, hash_set};
35
36/// A hash map using ntex's fast, randomly seeded hash state.
37pub type HashMap<K, V> = hash_map::HashMap<K, V, foldhash::fast::RandomState>;
38/// A hash set using ntex's fast, randomly seeded hash state.
39pub type HashSet<V> = hash_set::HashSet<V, foldhash::fast::RandomState>;
40/// The hash state used by [`HashMap`] and [`HashSet`].
41pub type HashRandomState = foldhash::fast::RandomState;
42
43/// Boxes an error as a dynamically dispatched error.
44pub fn dyn_err<E: Error + 'static>(e: E) -> Box<dyn Error> {
45    let e: Box<dyn Error> = Box::new(e);
46    e
47}
48
49/// Wraps an error in a reference-counted, dynamically dispatched error.
50pub fn dyn_rc_err<T: Error + 'static>(err: T) -> Rc<dyn Error> {
51    Rc::new(err)
52}
53
54/// Converts a string into a reference-counted error.
55pub fn str_rc_err(s: String) -> Rc<dyn Error> {
56    #[derive(thiserror::Error, Debug)]
57    #[error("{_0}")]
58    struct StringError(String);
59
60    Rc::new(StringError(s))
61}
62
63/// Clones an I/O error's kind and message.
64///
65/// `std::io::Error` is not generally cloneable. The returned error preserves
66/// the original [`io::ErrorKind`] and uses the original error's display output
67/// as its message.
68pub fn clone_io_error(err: &io::Error) -> io::Error {
69    io::Error::new(err.kind(), err.to_string())
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_clone_io_error() {
78        let err = io::Error::new(io::ErrorKind::TimedOut, "timed out");
79        let cloned = clone_io_error(&err);
80        assert_eq!(cloned.kind(), io::ErrorKind::TimedOut);
81        assert_eq!(cloned.to_string(), err.to_string());
82        assert_eq!(clone_io_error(&cloned).to_string(), "timed out");
83    }
84
85    #[test]
86    fn test_dyn_errors() {
87        let err = io::Error::other("boxed");
88        assert_eq!(dyn_err(err).to_string(), "boxed");
89        assert_eq!(dyn_rc_err(io::Error::other("rc")).to_string(), "rc");
90
91        let err = str_rc_err("string error".to_string());
92        assert_eq!(err.to_string(), "string error");
93        assert!(format!("{err:?}").contains("StringError"));
94    }
95}