Skip to main content

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