393 lines · 10.6 KB · Rust
RawDownload
// FluentBuilder// pub use gpui_util::{FutureExt, Timeout, arc_cow::ArcCow}; use std::{    env,    ops::AddAssign,    panic::Location,    pin::Pin,    sync::OnceLock,    task::{Context, Poll},    time::Instant,}; pub mod arc_cow; pub fn post_inc<T: From<u8> + AddAssign<T> + Copy>(value: &mut T) -> T {    let prev = *value;    *value += T::from(1);    prev} pub fn measure<R>(label: &str, f: impl FnOnce() -> R) -> R {    static ZED_MEASUREMENTS: OnceLock<bool> = OnceLock::new();    let zed_measurements = ZED_MEASUREMENTS.get_or_init(|| {        env::var("ZED_MEASUREMENTS")            .map(|measurements| measurements == "1" || measurements == "true")            .unwrap_or(false)    });     if *zed_measurements {        let start = Instant::now();        let result = f();        let elapsed = start.elapsed();        eprintln!("{}: {:?}", label, elapsed);        result    } else {        f()    }} #[macro_export]macro_rules! debug_panic {    ( $($fmt_arg:tt)* ) => {        if cfg!(debug_assertions) {            panic!( $($fmt_arg)* );        } else {            let backtrace = std::backtrace::Backtrace::capture();            log::error!("{}\n{:?}", format_args!($($fmt_arg)*), backtrace);        }    };} #[track_caller]pub fn some_or_debug_panic<T>(option: Option<T>) -> Option<T> {    #[cfg(debug_assertions)]    if option.is_none() {        panic!("Unexpected None");    }    option} /// Expands to an immediately-invoked function expression. Good for using the ? operator/// in functions which do not return an Option or Result.////// Accepts a normal block, an async block, or an async move block.#[macro_export]macro_rules! maybe {    ($block:block) => {        (|| $block)()    };    (async $block:block) => {        (async || $block)()    };    (async move $block:block) => {        (async move || $block)()    };}pub trait ResultExt<E> {    type Ok;     fn log_err(self) -> Option<Self::Ok>;    /// Like [`ResultExt::log_err`], but uses `{:?}` formatting so `anyhow::Error` values emit their    /// full backtrace. Reach for this only when a backtrace is genuinely wanted — most call sites    /// should stick with `log_err` / `warn_on_err`, whose output is a single chained error message.    fn log_err_with_backtrace(self) -> Option<Self::Ok>    where        E: std::fmt::Debug;    /// Assert that this result should never be an error in development or tests.    fn debug_assert_ok(self, reason: &str) -> Self;    fn warn_on_err(self) -> Option<Self::Ok>;    fn log_with_level(self, level: log::Level) -> Option<Self::Ok>;    fn anyhow(self) -> anyhow::Result<Self::Ok>    where        E: Into<anyhow::Error>;} impl<T, E> ResultExt<E> for Result<T, E>where    E: std::fmt::Display,{    type Ok = T;     #[track_caller]    fn log_err(self) -> Option<T> {        self.log_with_level(log::Level::Error)    }     #[track_caller]    fn log_err_with_backtrace(self) -> Option<T>    where        E: std::fmt::Debug,    {        match self {            Ok(value) => Some(value),            Err(error) => {                log_error_with_caller(                    *Location::caller(),                    DebugAsDisplay(&error),                    log::Level::Error,                );                None            }        }    }     #[track_caller]    fn debug_assert_ok(self, reason: &str) -> Self {        if let Err(error) = &self {            debug_panic!("{reason} - {error:#}");        }        self    }     #[track_caller]    fn warn_on_err(self) -> Option<T> {        self.log_with_level(log::Level::Warn)    }     #[track_caller]    fn log_with_level(self, level: log::Level) -> Option<T> {        match self {            Ok(value) => Some(value),            Err(error) => {                log_error_with_caller(*Location::caller(), error, level);                None            }        }    }     fn anyhow(self) -> anyhow::Result<T>    where        E: Into<anyhow::Error>,    {        self.map_err(Into::into)    }} fn log_error_with_caller<E>(caller: core::panic::Location<'_>, error: E, level: log::Level)where    E: std::fmt::Display,{    #[cfg(not(windows))]    let file = caller.file();    #[cfg(windows)]    let file = caller.file().replace('\\', "/");    // In this codebase all crates reside in a `crates` directory,    // so discard the prefix up to that segment to find the crate name    let file = file.split_once("crates/");    let target = file.as_ref().and_then(|(_, s)| s.split_once("/src/"));     let module_path = target.map(|(krate, module)| {        if module.starts_with(krate) {            module.trim_end_matches(".rs").replace('/', "::")        } else {            krate.to_owned() + "::" + &module.trim_end_matches(".rs").replace('/', "::")        }    });    let file = file.map(|(_, file)| format!("crates/{file}"));    log::logger().log(        &log::Record::builder()            .target(module_path.as_deref().unwrap_or(""))            .module_path(file.as_deref())            .args(format_args!("{:#}", error))            .file(Some(caller.file()))            .line(Some(caller.line()))            .level(level)            .build(),    );} pub fn log_err<E: std::fmt::Display>(error: &E) {    log_error_with_caller(*Location::caller(), error, log::Level::Error);} // Forces `{:?}` formatting through a `Display`-bounded logging helper so `anyhow::Error` emits a// backtrace instead of the single-line chained message produced by its `Display`/`{:#}` forms.struct DebugAsDisplay<'a, E>(&'a E); impl<E: std::fmt::Debug> std::fmt::Display for DebugAsDisplay<'_, E> {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        write!(f, "{:?}", self.0)    }} pub trait TryFutureExt {    fn log_err(self) -> LogErrorFuture<Self>    where        Self: Sized;     fn log_tracked_err(self, location: core::panic::Location<'static>) -> LogErrorFuture<Self>    where        Self: Sized;     fn warn_on_err(self) -> LogErrorFuture<Self>    where        Self: Sized;    fn unwrap(self) -> UnwrapFuture<Self>    where        Self: Sized;} /// `{:?}`-formatting companion to [`TryFutureExt`]; emits a backtrace for `anyhow::Error`. Prefer/// [`TryFutureExt`] unless a backtrace is genuinely wanted.pub trait TryFutureExtBacktrace {    fn log_err_with_backtrace(self) -> LogErrorWithBacktraceFuture<Self>    where        Self: Sized;     fn log_tracked_err_with_backtrace(        self,        location: core::panic::Location<'static>,    ) -> LogErrorWithBacktraceFuture<Self>    where        Self: Sized;} impl<F, T, E> TryFutureExt for Fwhere    F: Future<Output = Result<T, E>>,    E: std::fmt::Display,{    #[track_caller]    fn log_err(self) -> LogErrorFuture<Self>    where        Self: Sized,    {        let location = Location::caller();        LogErrorFuture(self, log::Level::Error, *location)    }     fn log_tracked_err(self, location: core::panic::Location<'static>) -> LogErrorFuture<Self>    where        Self: Sized,    {        LogErrorFuture(self, log::Level::Error, location)    }     #[track_caller]    fn warn_on_err(self) -> LogErrorFuture<Self>    where        Self: Sized,    {        let location = Location::caller();        LogErrorFuture(self, log::Level::Warn, *location)    }     fn unwrap(self) -> UnwrapFuture<Self>    where        Self: Sized,    {        UnwrapFuture(self)    }} impl<F, T, E> TryFutureExtBacktrace for Fwhere    F: Future<Output = Result<T, E>>,    E: std::fmt::Debug,{    #[track_caller]    fn log_err_with_backtrace(self) -> LogErrorWithBacktraceFuture<Self>    where        Self: Sized,    {        let location = Location::caller();        LogErrorWithBacktraceFuture(self, log::Level::Error, *location)    }     fn log_tracked_err_with_backtrace(        self,        location: core::panic::Location<'static>,    ) -> LogErrorWithBacktraceFuture<Self>    where        Self: Sized,    {        LogErrorWithBacktraceFuture(self, log::Level::Error, location)    }} #[must_use]pub struct LogErrorFuture<F>(F, log::Level, core::panic::Location<'static>); impl<F, T, E> Future for LogErrorFuture<F>where    F: Future<Output = Result<T, E>>,    E: std::fmt::Display,{    type Output = Option<T>;     fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {        let level = self.1;        let location = self.2;        let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) };        match inner.poll(cx) {            Poll::Ready(output) => Poll::Ready(match output {                Ok(output) => Some(output),                Err(error) => {                    log_error_with_caller(location, error, level);                    None                }            }),            Poll::Pending => Poll::Pending,        }    }} #[must_use]pub struct LogErrorWithBacktraceFuture<F>(F, log::Level, core::panic::Location<'static>); impl<F, T, E> Future for LogErrorWithBacktraceFuture<F>where    F: Future<Output = Result<T, E>>,    E: std::fmt::Debug,{    type Output = Option<T>;     fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {        let level = self.1;        let location = self.2;        let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) };        match inner.poll(cx) {            Poll::Ready(output) => Poll::Ready(match output {                Ok(output) => Some(output),                Err(error) => {                    log_error_with_caller(location, DebugAsDisplay(&error), level);                    None                }            }),            Poll::Pending => Poll::Pending,        }    }} pub struct UnwrapFuture<F>(F); impl<F, T, E> Future for UnwrapFuture<F>where    F: Future<Output = Result<T, E>>,    E: std::fmt::Debug,{    type Output = T;     fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {        let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) };        match inner.poll(cx) {            Poll::Ready(result) => Poll::Ready(result.unwrap()),            Poll::Pending => Poll::Pending,        }    }} pub struct Deferred<F: FnOnce()>(Option<F>); impl<F: FnOnce()> Deferred<F> {    /// Drop without running the deferred function.    pub fn abort(mut self) {        self.0.take();    }} impl<F: FnOnce()> Drop for Deferred<F> {    fn drop(&mut self) {        if let Some(f) = self.0.take() {            f()        }    }} /// Run the given function when the returned value is dropped (unless it's cancelled).#[must_use]pub fn defer<F: FnOnce()>(f: F) -> Deferred<F> {    Deferred(Some(f))}