lib.rs

  1// FluentBuilder
  2// pub use gpui_util::{FutureExt, Timeout, arc_cow::ArcCow};
  3
  4use std::{
  5    env,
  6    future::Future,
  7    ops::AddAssign,
  8    panic::Location,
  9    pin::Pin,
 10    sync::OnceLock,
 11    task::{Context, Poll},
 12    time::Instant,
 13};
 14
 15pub mod arc_cow;
 16
 17pub fn post_inc<T: From<u8> + AddAssign<T> + Copy>(value: &mut T) -> T {
 18    let prev = *value;
 19    *value += T::from(1);
 20    prev
 21}
 22
 23pub fn measure<R>(label: &str, f: impl FnOnce() -> R) -> R {
 24    static ZED_MEASUREMENTS: OnceLock<bool> = OnceLock::new();
 25    let zed_measurements = ZED_MEASUREMENTS.get_or_init(|| {
 26        env::var("ZED_MEASUREMENTS")
 27            .map(|measurements| measurements == "1" || measurements == "true")
 28            .unwrap_or(false)
 29    });
 30
 31    if *zed_measurements {
 32        let start = Instant::now();
 33        let result = f();
 34        let elapsed = start.elapsed();
 35        eprintln!("{}: {:?}", label, elapsed);
 36        result
 37    } else {
 38        f()
 39    }
 40}
 41
 42#[macro_export]
 43macro_rules! debug_panic {
 44    ( $($fmt_arg:tt)* ) => {
 45        if cfg!(debug_assertions) {
 46            panic!( $($fmt_arg)* );
 47        } else {
 48            let backtrace = std::backtrace::Backtrace::capture();
 49            log::error!("{}\n{:?}", format_args!($($fmt_arg)*), backtrace);
 50        }
 51    };
 52}
 53
 54#[track_caller]
 55pub fn some_or_debug_panic<T>(option: Option<T>) -> Option<T> {
 56    #[cfg(debug_assertions)]
 57    if option.is_none() {
 58        panic!("Unexpected None");
 59    }
 60    option
 61}
 62
 63/// Expands to an immediately-invoked function expression. Good for using the ? operator
 64/// in functions which do not return an Option or Result.
 65///
 66/// Accepts a normal block, an async block, or an async move block.
 67#[macro_export]
 68macro_rules! maybe {
 69    ($block:block) => {
 70        (|| $block)()
 71    };
 72    (async $block:block) => {
 73        (async || $block)()
 74    };
 75    (async move $block:block) => {
 76        (async move || $block)()
 77    };
 78}
 79pub trait ResultExt<E> {
 80    type Ok;
 81
 82    fn log_err(self) -> Option<Self::Ok>;
 83    /// Assert that this result should never be an error in development or tests.
 84    fn debug_assert_ok(self, reason: &str) -> Self;
 85    fn warn_on_err(self) -> Option<Self::Ok>;
 86    fn log_with_level(self, level: log::Level) -> Option<Self::Ok>;
 87    fn anyhow(self) -> anyhow::Result<Self::Ok>
 88    where
 89        E: Into<anyhow::Error>;
 90}
 91
 92impl<T, E> ResultExt<E> for Result<T, E>
 93where
 94    E: std::fmt::Debug,
 95{
 96    type Ok = T;
 97
 98    #[track_caller]
 99    fn log_err(self) -> Option<T> {
100        self.log_with_level(log::Level::Error)
101    }
102
103    #[track_caller]
104    fn debug_assert_ok(self, reason: &str) -> Self {
105        if let Err(error) = &self {
106            debug_panic!("{reason} - {error:?}");
107        }
108        self
109    }
110
111    #[track_caller]
112    fn warn_on_err(self) -> Option<T> {
113        self.log_with_level(log::Level::Warn)
114    }
115
116    #[track_caller]
117    fn log_with_level(self, level: log::Level) -> Option<T> {
118        match self {
119            Ok(value) => Some(value),
120            Err(error) => {
121                log_error_with_caller(*Location::caller(), error, level);
122                None
123            }
124        }
125    }
126
127    fn anyhow(self) -> anyhow::Result<T>
128    where
129        E: Into<anyhow::Error>,
130    {
131        self.map_err(Into::into)
132    }
133}
134
135fn log_error_with_caller<E>(caller: core::panic::Location<'_>, error: E, level: log::Level)
136where
137    E: std::fmt::Debug,
138{
139    #[cfg(not(windows))]
140    let file = caller.file();
141    #[cfg(windows)]
142    let file = caller.file().replace('\\', "/");
143    // In this codebase all crates reside in a `crates` directory,
144    // so discard the prefix up to that segment to find the crate name
145    let file = file.split_once("crates/");
146    let target = file.as_ref().and_then(|(_, s)| s.split_once("/src/"));
147
148    let module_path = target.map(|(krate, module)| {
149        if module.starts_with(krate) {
150            module.trim_end_matches(".rs").replace('/', "::")
151        } else {
152            krate.to_owned() + "::" + &module.trim_end_matches(".rs").replace('/', "::")
153        }
154    });
155    let file = file.map(|(_, file)| format!("crates/{file}"));
156    log::logger().log(
157        &log::Record::builder()
158            .target(module_path.as_deref().unwrap_or(""))
159            .module_path(file.as_deref())
160            .args(format_args!("{:?}", error))
161            .file(Some(caller.file()))
162            .line(Some(caller.line()))
163            .level(level)
164            .build(),
165    );
166}
167
168pub fn log_err<E: std::fmt::Debug>(error: &E) {
169    log_error_with_caller(*Location::caller(), error, log::Level::Error);
170}
171
172pub trait TryFutureExt {
173    fn log_err(self) -> LogErrorFuture<Self>
174    where
175        Self: Sized;
176
177    fn log_tracked_err(self, location: core::panic::Location<'static>) -> LogErrorFuture<Self>
178    where
179        Self: Sized;
180
181    fn warn_on_err(self) -> LogErrorFuture<Self>
182    where
183        Self: Sized;
184    fn unwrap(self) -> UnwrapFuture<Self>
185    where
186        Self: Sized;
187}
188
189impl<F, T, E> TryFutureExt for F
190where
191    F: Future<Output = Result<T, E>>,
192    E: std::fmt::Debug,
193{
194    #[track_caller]
195    fn log_err(self) -> LogErrorFuture<Self>
196    where
197        Self: Sized,
198    {
199        let location = Location::caller();
200        LogErrorFuture(self, log::Level::Error, *location)
201    }
202
203    fn log_tracked_err(self, location: core::panic::Location<'static>) -> LogErrorFuture<Self>
204    where
205        Self: Sized,
206    {
207        LogErrorFuture(self, log::Level::Error, location)
208    }
209
210    #[track_caller]
211    fn warn_on_err(self) -> LogErrorFuture<Self>
212    where
213        Self: Sized,
214    {
215        let location = Location::caller();
216        LogErrorFuture(self, log::Level::Warn, *location)
217    }
218
219    fn unwrap(self) -> UnwrapFuture<Self>
220    where
221        Self: Sized,
222    {
223        UnwrapFuture(self)
224    }
225}
226
227#[must_use]
228pub struct LogErrorFuture<F>(F, log::Level, core::panic::Location<'static>);
229
230impl<F, T, E> Future for LogErrorFuture<F>
231where
232    F: Future<Output = Result<T, E>>,
233    E: std::fmt::Debug,
234{
235    type Output = Option<T>;
236
237    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
238        let level = self.1;
239        let location = self.2;
240        let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) };
241        match inner.poll(cx) {
242            Poll::Ready(output) => Poll::Ready(match output {
243                Ok(output) => Some(output),
244                Err(error) => {
245                    log_error_with_caller(location, error, level);
246                    None
247                }
248            }),
249            Poll::Pending => Poll::Pending,
250        }
251    }
252}
253
254pub struct UnwrapFuture<F>(F);
255
256impl<F, T, E> Future for UnwrapFuture<F>
257where
258    F: Future<Output = Result<T, E>>,
259    E: std::fmt::Debug,
260{
261    type Output = T;
262
263    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
264        let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) };
265        match inner.poll(cx) {
266            Poll::Ready(result) => Poll::Ready(result.unwrap()),
267            Poll::Pending => Poll::Pending,
268        }
269    }
270}
271
272pub struct Deferred<F: FnOnce()>(Option<F>);
273
274impl<F: FnOnce()> Deferred<F> {
275    /// Drop without running the deferred function.
276    pub fn abort(mut self) {
277        self.0.take();
278    }
279}
280
281impl<F: FnOnce()> Drop for Deferred<F> {
282    fn drop(&mut self) {
283        if let Some(f) = self.0.take() {
284            f()
285        }
286    }
287}
288
289/// Run the given function when the returned value is dropped (unless it's cancelled).
290#[must_use]
291pub fn defer<F: FnOnce()>(f: F) -> Deferred<F> {
292    Deferred(Some(f))
293}