derive_app_context.rs

  1use proc_macro::TokenStream;
  2use quote::quote;
  3use syn::{DeriveInput, parse_macro_input};
  4
  5use crate::get_simple_attribute_field;
  6
  7pub fn derive_app_context(input: TokenStream) -> TokenStream {
  8    let ast = parse_macro_input!(input as DeriveInput);
  9
 10    let Some(app_variable) = get_simple_attribute_field(&ast, "app") else {
 11        return quote! {
 12            compile_error!("Derive must have an #[app] attribute to detect the &mut App field");
 13        }
 14        .into();
 15    };
 16
 17    let type_name = &ast.ident;
 18    let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl();
 19
 20    let r#gen = quote! {
 21        impl #impl_generics gpui::AppContext for #type_name #type_generics
 22        #where_clause
 23        {
 24            type Result<T> = T;
 25
 26            fn new<T: 'static>(
 27                &mut self,
 28                build_entity: impl FnOnce(&mut gpui::Context<'_, T>) -> T,
 29            ) -> Self::Result<gpui::Entity<T>> {
 30                self.#app_variable.new(build_entity)
 31            }
 32
 33            fn reserve_entity<T: 'static>(&mut self) -> Self::Result<gpui::Reservation<T>> {
 34                self.#app_variable.reserve_entity()
 35            }
 36
 37            fn insert_entity<T: 'static>(
 38                &mut self,
 39                reservation: gpui::Reservation<T>,
 40                build_entity: impl FnOnce(&mut gpui::Context<'_, T>) -> T,
 41            ) -> Self::Result<gpui::Entity<T>> {
 42                self.#app_variable.insert_entity(reservation, build_entity)
 43            }
 44
 45            fn update_entity<T, R>(
 46                &mut self,
 47                handle: &gpui::Entity<T>,
 48                update: impl FnOnce(&mut T, &mut gpui::Context<'_, T>) -> R,
 49            ) -> Self::Result<R>
 50            where
 51                T: 'static,
 52            {
 53                self.#app_variable.update_entity(handle, update)
 54            }
 55
 56            fn as_mut<'y, 'z, T>(
 57                &'y mut self,
 58                handle: &'z gpui::Entity<T>,
 59            ) -> Self::Result<gpui::GpuiBorrow<'y, T>>
 60            where
 61                T: 'static,
 62            {
 63                self.#app_variable.as_mut(handle)
 64            }
 65
 66            fn read_entity<T, R>(
 67                &self,
 68                handle: &gpui::Entity<T>,
 69                read: impl FnOnce(&T, &gpui::App) -> R,
 70            ) -> Self::Result<R>
 71            where
 72                T: 'static,
 73            {
 74                self.#app_variable.read_entity(handle, read)
 75            }
 76
 77            fn update_window<T, F>(&mut self, window: gpui::AnyWindowHandle, f: F) -> gpui::Result<T>
 78            where
 79                F: FnOnce(gpui::AnyView, &mut gpui::Window, &mut gpui::App) -> T,
 80            {
 81                self.#app_variable.update_window(window, f)
 82            }
 83
 84            fn read_window<T, R>(
 85                &self,
 86                window: &gpui::WindowHandle<T>,
 87                read: impl FnOnce(gpui::Entity<T>, &gpui::App) -> R,
 88            ) -> gpui::Result<R>
 89            where
 90                T: 'static,
 91            {
 92                self.#app_variable.read_window(window, read)
 93            }
 94
 95            fn background_spawn<R>(&self, future: impl std::future::Future<Output = R> + Send + 'static) -> gpui::Task<R>
 96            where
 97                R: Send + 'static,
 98            {
 99                self.#app_variable.background_spawn(future)
100            }
101
102            fn read_global<G, R>(&self, callback: impl FnOnce(&G, &gpui::App) -> R) -> Self::Result<R>
103            where
104                G: gpui::Global,
105            {
106                self.#app_variable.read_global(callback)
107            }
108        }
109    };
110
111    r#gen.into()
112}