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