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            fn new<T: 'static>(
 25                &mut self,
 26                build_entity: impl FnOnce(&mut gpui::Context<'_, T>) -> T,
 27            ) -> gpui::Entity<T> {
 28                self.#app_variable.new(build_entity)
 29            }
 30
 31            fn reserve_entity<T: 'static>(&mut self) -> gpui::Reservation<T> {
 32                self.#app_variable.reserve_entity()
 33            }
 34
 35            fn insert_entity<T: 'static>(
 36                &mut self,
 37                reservation: gpui::Reservation<T>,
 38                build_entity: impl FnOnce(&mut gpui::Context<'_, T>) -> T,
 39            ) -> gpui::Entity<T> {
 40                self.#app_variable.insert_entity(reservation, build_entity)
 41            }
 42
 43            fn update_entity<T, R>(
 44                &mut self,
 45                handle: &gpui::Entity<T>,
 46                update: impl FnOnce(&mut T, &mut gpui::Context<'_, T>) -> R,
 47            ) -> R
 48            where
 49                T: 'static,
 50            {
 51                self.#app_variable.update_entity(handle, update)
 52            }
 53
 54            fn as_mut<'y, 'z, T>(
 55                &'y mut self,
 56                handle: &'z gpui::Entity<T>,
 57            ) -> gpui::GpuiBorrow<'y, T>
 58            where
 59                T: 'static,
 60            {
 61                self.#app_variable.as_mut(handle)
 62            }
 63
 64            fn read_entity<T, R>(
 65                &self,
 66                handle: &gpui::Entity<T>,
 67                read: impl FnOnce(&T, &gpui::App) -> R,
 68            ) -> R
 69            where
 70                T: 'static,
 71            {
 72                self.#app_variable.read_entity(handle, read)
 73            }
 74
 75            fn update_window<T, F>(&mut self, window: gpui::AnyWindowHandle, f: F) -> gpui::Result<T>
 76            where
 77                F: FnOnce(gpui::AnyView, &mut gpui::Window, &mut gpui::App) -> T,
 78            {
 79                self.#app_variable.update_window(window, f)
 80            }
 81
 82            fn read_window<T, R>(
 83                &self,
 84                window: &gpui::WindowHandle<T>,
 85                read: impl FnOnce(gpui::Entity<T>, &gpui::App) -> R,
 86            ) -> gpui::Result<R>
 87            where
 88                T: 'static,
 89            {
 90                self.#app_variable.read_window(window, read)
 91            }
 92
 93            fn background_spawn<R>(&self, future: impl std::future::Future<Output = R> + Send + 'static) -> gpui::Task<R>
 94            where
 95                R: Send + 'static,
 96            {
 97                self.#app_variable.background_spawn(future)
 98            }
 99
100            fn read_global<G, R>(&self, callback: impl FnOnce(&G, &gpui::App) -> R) -> R
101            where
102                G: gpui::Global,
103            {
104                self.#app_variable.read_global(callback)
105            }
106        }
107    };
108
109    r#gen.into()
110}