// 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 + AddAssign + Copy>(value: &mut T) -> T { let prev = *value; *value += T::from(1); prev } pub fn measure(label: &str, f: impl FnOnce() -> R) -> R { static ZED_MEASUREMENTS: OnceLock = 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(option: Option) -> Option { #[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 { type Ok; fn log_err(self) -> Option; /// 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 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; fn log_with_level(self, level: log::Level) -> Option; fn anyhow(self) -> anyhow::Result where E: Into; } impl ResultExt for Result where E: std::fmt::Display, { type Ok = T; #[track_caller] fn log_err(self) -> Option { self.log_with_level(log::Level::Error) } #[track_caller] fn log_err_with_backtrace(self) -> Option 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 { self.log_with_level(log::Level::Warn) } #[track_caller] fn log_with_level(self, level: log::Level) -> Option { match self { Ok(value) => Some(value), Err(error) => { log_error_with_caller(*Location::caller(), error, level); None } } } fn anyhow(self) -> anyhow::Result where E: Into, { self.map_err(Into::into) } } fn log_error_with_caller(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(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 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 where Self: Sized; fn log_tracked_err(self, location: core::panic::Location<'static>) -> LogErrorFuture where Self: Sized; fn warn_on_err(self) -> LogErrorFuture where Self: Sized; fn unwrap(self) -> UnwrapFuture 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 where Self: Sized; fn log_tracked_err_with_backtrace( self, location: core::panic::Location<'static>, ) -> LogErrorWithBacktraceFuture where Self: Sized; } impl TryFutureExt for F where F: Future>, E: std::fmt::Display, { #[track_caller] fn log_err(self) -> LogErrorFuture where Self: Sized, { let location = Location::caller(); LogErrorFuture(self, log::Level::Error, *location) } fn log_tracked_err(self, location: core::panic::Location<'static>) -> LogErrorFuture where Self: Sized, { LogErrorFuture(self, log::Level::Error, location) } #[track_caller] fn warn_on_err(self) -> LogErrorFuture where Self: Sized, { let location = Location::caller(); LogErrorFuture(self, log::Level::Warn, *location) } fn unwrap(self) -> UnwrapFuture where Self: Sized, { UnwrapFuture(self) } } impl TryFutureExtBacktrace for F where F: Future>, E: std::fmt::Debug, { #[track_caller] fn log_err_with_backtrace(self) -> LogErrorWithBacktraceFuture 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 where Self: Sized, { LogErrorWithBacktraceFuture(self, log::Level::Error, location) } } #[must_use] pub struct LogErrorFuture(F, log::Level, core::panic::Location<'static>); impl Future for LogErrorFuture where F: Future>, E: std::fmt::Display, { type Output = Option; fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { 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, log::Level, core::panic::Location<'static>); impl Future for LogErrorWithBacktraceFuture where F: Future>, E: std::fmt::Debug, { type Output = Option; fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { 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); impl Future for UnwrapFuture where F: Future>, E: std::fmt::Debug, { type Output = T; fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { 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(Option); impl Deferred { /// Drop without running the deferred function. pub fn abort(mut self) { self.0.take(); } } impl Drop for Deferred { 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: F) -> Deferred { Deferred(Some(f)) }