tycho_util/
lib.rs

1// NOTE: Required for using `PartialConfig` macros.
2#[allow(unused_extern_crates)]
3extern crate self as tycho_util;
4
5use std::collections::{HashMap, HashSet};
6use std::path::PathBuf;
7use std::process::Command;
8
9pub mod compression;
10pub mod config;
11pub mod io;
12pub mod progress_bar;
13pub mod serde_helpers;
14pub mod time;
15
16pub mod tl;
17
18#[cfg(feature = "fs")]
19pub mod fs {
20    pub use self::mapped_file::{MappedFile, MappedFileMut};
21    pub use self::target_writer::TargetWriter;
22
23    mod mapped_file;
24    mod target_writer;
25}
26
27pub mod futures {
28    pub use self::await_blocking::AwaitBlocking;
29    pub use self::box_future_or_noop::BoxFutureOrNoop;
30    pub use self::join_task::JoinTask;
31    pub use self::shared::{Shared, WeakShared, WeakSharedHandle};
32
33    mod await_blocking;
34    mod box_future_or_noop;
35    mod join_task;
36    mod shared;
37}
38
39pub mod mem {
40    pub use self::reclaimer::{Reclaimer, ReclaimerError};
41    pub use self::slicer::{
42        AllocatedMemoryConstraints, MemoryConstraint, MemoryConstraints, MemorySlicer,
43        MemorySlicerGuard, MemorySlicerRange,
44    };
45
46    mod reclaimer;
47    mod slicer;
48}
49
50pub mod num {
51    pub use self::median::{StreamingUnsignedMedian, VecOfStreamingUnsignedMedian};
52    pub use self::safe_avg::{SafeSignedAvg, SafeUnsignedAvg, SafeUnsignedVecAvg};
53
54    mod median;
55    mod safe_avg;
56}
57
58pub mod sync {
59    pub use self::once_take::*;
60    pub use self::priority_semaphore::{AcquireError, PrioritySemaphore, TryAcquireError};
61    pub use self::rayon::{rayon_run, rayon_run_fifo};
62    pub use self::task::{CancellationFlag, DebounceCancellationFlag, yield_on_complex};
63
64    mod once_take;
65    mod priority_semaphore;
66    mod rayon;
67    mod task;
68}
69
70#[cfg(any(test, feature = "test"))]
71pub mod test {
72    pub use self::logger::init_logger;
73
74    mod logger;
75}
76
77pub mod metrics {
78    pub use self::fs_usage::{FsUsageBuilder, FsUsageMonitor, Stats, StatsEntry};
79    pub use self::gauge_guard::GaugeGuard;
80    pub use self::histogram_guard::{HistogramGuard, HistogramGuardWithLabels};
81    pub use self::metrics_loop::spawn_metrics_loop;
82
83    mod fs_usage;
84    mod gauge_guard;
85    mod histogram_guard;
86    mod metrics_loop;
87}
88
89mod util {
90    pub(crate) mod linked_list;
91    pub(crate) mod wake_list;
92}
93
94#[cfg(feature = "cli")]
95pub mod cli;
96
97pub use dashmap::mapref::entry::Entry as DashMapEntry;
98
99pub type FastDashMap<K, V> = dashmap::DashMap<K, V, ahash::RandomState>;
100pub type FastDashSet<K> = dashmap::DashSet<K, ahash::RandomState>;
101pub type FastHashMap<K, V> = HashMap<K, V, ahash::RandomState>;
102pub type FastHashSet<K> = HashSet<K, ahash::RandomState>;
103pub type FastHasherState = ahash::RandomState;
104
105/// # Example
106///
107/// ```rust
108/// # use tycho_util::realloc_box_enum;
109/// enum Value {
110///     One(BigValue1),
111///     Two(BigValue2),
112/// }
113///
114/// struct BigValue1([u32; 10]);
115///
116/// struct BigValue2([u32; 7]);
117///
118/// fn convert_to_one(value: Box<Value>) -> Option<Box<BigValue1>> {
119///     realloc_box_enum!(value, {
120///         Value::One(value) => Box::new(value) => Some(value),
121///         _ => None,
122///     })
123/// }
124/// ```
125#[macro_export]
126macro_rules! realloc_box_enum {
127    ($value:expr, {
128        $target_variant:pat => Box::new($extracted:ident) => $target:expr,
129        $other_variant:pat => $other:expr,
130    }) => {{
131        let value: ::std::boxed::Box<_> = $value;
132        match ::core::convert::AsRef::as_ref(&value) {
133            #[allow(unused_variables)]
134            $target_variant => {
135                let $extracted = unsafe {
136                    $crate::__internal::realloc_box(value, |value| match value {
137                        $target_variant => $extracted,
138                        _ => unreachable!(),
139                    })
140                };
141                $target
142            }
143            $other_variant => $other,
144        }
145    }};
146}
147
148#[doc(hidden)]
149pub mod __internal {
150    pub use serde;
151
152    /// # Safety
153    /// The following must be true:
154    /// - `T` must have the same layout as `R`
155    /// - `f` must not panic
156    pub unsafe fn realloc_box<T, F, R>(value: Box<T>, f: F) -> Box<R>
157    where
158        F: FnOnce(T) -> R,
159    {
160        unsafe {
161            assert!(std::mem::align_of::<T>() == std::mem::align_of::<R>());
162
163            let ptr = Box::into_raw(value);
164            let value = std::ptr::read(ptr);
165
166            let ptr = std::alloc::realloc(
167                ptr.cast::<u8>(),
168                std::alloc::Layout::new::<T>(),
169                std::mem::size_of::<R>(),
170            )
171            .cast::<R>();
172
173            if ptr.is_null() {
174                std::alloc::handle_alloc_error(std::alloc::Layout::new::<R>());
175            }
176
177            // NOTE: in case of panic, the memory will be leaked
178            std::ptr::write(ptr, f(value));
179
180            Box::from_raw(ptr)
181        }
182    }
183}
184
185pub fn project_root() -> Result<PathBuf, std::io::Error> {
186    let project_root = Command::new("git")
187        .arg("rev-parse")
188        .arg("--show-toplevel")
189        .output()?
190        .stdout;
191    // won't work on windows but we don't care
192    let project_root = PathBuf::from(
193        String::from_utf8(project_root)
194            .map_err(|e| std::io::Error::other(format!("invalid project root: {e}")))?
195            .trim(),
196    );
197    Ok(project_root)
198}
199
200#[cfg(test)]
201mod tests {
202    #[test]
203    #[allow(dead_code)]
204    fn realloc_enum() {
205        enum Value {
206            One(BigValue1),
207            Two(BigValue2),
208        }
209
210        #[derive(Clone)]
211        struct BigValue1([u32; 10]);
212
213        #[derive(Clone)]
214        struct BigValue2([u32; 7]);
215
216        fn convert_to_one(value: Box<Value>) -> Option<Box<BigValue1>> {
217            realloc_box_enum!(value, {
218                Value::One(value) => Box::new(value) => Some(value),
219                _ => None,
220            })
221        }
222
223        let value = BigValue1([123; 10]);
224        let one = convert_to_one(Box::new(Value::One(value.clone())));
225        assert_eq!(one.unwrap().0, value.0);
226    }
227}