From a1651c89d98bf2d01b154d9837192a62857663c8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 11 Jul 2024 21:35:37 -0400 Subject: [PATCH] WIP --- components/salsa-macros/src/db.rs | 85 ++++++++++---- components/salsa-macros/src/db_view.rs | 153 ------------------------- components/salsa-macros/src/lib.rs | 1 - src/lib.rs | 1 - src/storage.rs | 9 +- 5 files changed, 67 insertions(+), 182 deletions(-) delete mode 100644 components/salsa-macros/src/db_view.rs diff --git a/components/salsa-macros/src/db.rs b/components/salsa-macros/src/db.rs index 7fb576b3..a7c08e63 100644 --- a/components/salsa-macros/src/db.rs +++ b/components/salsa-macros/src/db.rs @@ -1,11 +1,11 @@ use proc_macro2::TokenStream; -use syn::{parse::Nothing, ItemStruct}; +use syn::parse::Nothing; use crate::hygiene::Hygiene; // Source: // -// #[salsa::db(Jar0, Jar1, Jar2)] +// #[salsa::db] // pub struct Database { // storage: salsa::Storage, // } @@ -15,11 +15,10 @@ pub(crate) fn db( input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { let _nothing = syn::parse_macro_input!(args as Nothing); - let db_macro = DbMacro { - hygiene: Hygiene::from(&input), - input: syn::parse_macro_input!(input as syn::ItemStruct), - }; - match db_macro.try_db() { + let hygiene = Hygiene::from(&input); + let input = syn::parse_macro_input!(input as syn::Item); + let db_macro = DbMacro { hygiene }; + match db_macro.try_db(input) { Ok(v) => v.into(), Err(e) => e.to_compile_error().into(), } @@ -27,22 +26,43 @@ pub(crate) fn db( struct DbMacro { hygiene: Hygiene, - input: ItemStruct, } +#[allow(non_snake_case)] impl DbMacro { - fn try_db(self) -> syn::Result { - let has_storage_impl = self.has_storage_impl()?; - let input = self.input; - Ok(quote! { - #has_storage_impl - #input - }) + fn try_db(self, input: syn::Item) -> syn::Result { + match input { + syn::Item::Struct(input) => { + let has_storage_impl = self.has_storage_impl(&input)?; + Ok(quote! { + #has_storage_impl + #input + }) + } + syn::Item::Trait(mut input) => { + self.add_salsa_view_method(&mut input)?; + Ok(quote! { + #input + }) + } + syn::Item::Impl(mut input) => { + self.add_salsa_view_method_impl(&mut input)?; + Ok(quote! { + #input + }) + } + _ => { + return Err(syn::Error::new_spanned( + input, + "`db` must be applied to a struct, trait, or impl", + )); + } + } } - fn find_storage_field(&self) -> syn::Result { + fn find_storage_field(&self, input: &syn::ItemStruct) -> syn::Result { let storage = "storage"; - for field in self.input.fields.iter() { + for field in input.fields.iter() { if let Some(i) = &field.ident { if i == storage { return Ok(i.clone()); @@ -56,15 +76,14 @@ impl DbMacro { } return Err(syn::Error::new_spanned( - &self.input.ident, + &input.ident, "database struct must be a braced struct (`{}`) with a field named `storage`", )); } - #[allow(non_snake_case)] - fn has_storage_impl(&self) -> syn::Result { - let storage = self.find_storage_field()?; - let db = &self.input.ident; + fn has_storage_impl(&self, input: &syn::ItemStruct) -> syn::Result { + let storage = self.find_storage_field(input)?; + let db = &input.ident; let SalsaHasStorage = self.hygiene.ident("SalsaHasStorage"); let SalsaStorage = self.hygiene.ident("SalsaStorage"); @@ -86,4 +105,26 @@ impl DbMacro { }; }) } + + fn add_salsa_view_method(&self, input: &mut syn::ItemTrait) -> syn::Result<()> { + input.items.push(parse_quote! { + fn __salsa_add_view__(&self); + }); + Ok(()) + } + + fn add_salsa_view_method_impl(&self, input: &mut syn::ItemImpl) -> syn::Result<()> { + let Some((_, TraitPath, _)) = &input.trait_ else { + return Err(syn::Error::new_spanned( + &input.self_ty, + "impl must be on a trait", + )); + }; + input.items.push(parse_quote! { + fn __salsa_add_view__(&self) { + salsa::storage::views(self).add::(|t| t, |t| t); + } + }); + Ok(()) + } } diff --git a/components/salsa-macros/src/db_view.rs b/components/salsa-macros/src/db_view.rs deleted file mode 100644 index 72c345fe..00000000 --- a/components/salsa-macros/src/db_view.rs +++ /dev/null @@ -1,153 +0,0 @@ -use std::fmt::Display; - -use heck::ToSnakeCase; -use proc_macro2::{Span, TokenStream}; - -use crate::hygiene::Hygiene; - -// Source: -// -// ``` -// #[salsa::db_view] -// pub trait $Db: ... { -// ... -// } -// ``` -// -// becomes -// -// ``` -// pub trait $Db: __SalsaViewAs$Db__ { -// ... -// } -// -// pub trait __SalsaViewAs$Db__ { -// fn __salsa_add_view_for_$db__(&self); -// } -// -// impl __SalsaViewAs$Db__ for T { -// ... -// } -// ``` -pub(crate) fn db_view( - args: proc_macro::TokenStream, - input: proc_macro::TokenStream, -) -> proc_macro::TokenStream { - syn::parse_macro_input!(args as syn::parse::Nothing); - let db_view_macro = DbViewMacro::new( - Hygiene::from(&input), - syn::parse_macro_input!(input as syn::ItemTrait), - ); - - match db_view_macro.expand() { - Ok(tokens) => tokens.into(), - Err(err) => err.to_compile_error().into(), - } -} - -#[allow(non_snake_case)] -pub(crate) struct DbViewMacro { - hygiene: Hygiene, - input: syn::ItemTrait, - DbViewTrait: syn::Ident, - db_view_method: syn::Ident, -} - -#[allow(non_snake_case)] -impl DbViewMacro { - // This is a case where our hygiene mechanism is inadequate. - // - // We cannot know whether `DbViewTrait` is defined elsewhere - // in the module. - // - // Therefore we give it a dorky name. - - pub(crate) fn db_view_trait_name(input: &impl Display) -> syn::Ident { - syn::Ident::new(&format!("__SalsaAddView{}__", input), Span::call_site()) - } - - pub(crate) fn db_view_method_name(input: &impl Display) -> syn::Ident { - syn::Ident::new( - &format!("__salsa_add_view_{}__", input.to_string().to_snake_case()), - Span::call_site(), - ) - } - - fn new(hygiene: Hygiene, input: syn::ItemTrait) -> Self { - Self { - DbViewTrait: Self::db_view_trait_name(&input.ident), - db_view_method: Self::db_view_method_name(&input.ident), - hygiene, - input, - } - } - - fn expand(mut self) -> syn::Result { - self.add_supertrait(); - let view_impl = self.view_impl(); - let view_trait = self.view_trait(); - - let input = self.input; - Ok(quote! { - #input - #view_trait - #view_impl - }) - } - - fn add_supertrait(&mut self) { - let Self { DbViewTrait, .. } = self; - self.input.supertraits.push(parse_quote! { #DbViewTrait }) - } - - fn view_trait(&self) -> syn::ItemTrait { - let Self { - DbViewTrait, - db_view_method, - .. - } = self; - - let vis = &self.input.vis; - parse_quote! { - /// Internal salsa method generated by the `salsa::db_view` macro - /// that registers this database view trait with the salsa database. - /// - /// Nothing to see here. - #[doc(hidden)] - #vis trait #DbViewTrait { - fn #db_view_method(&self); - } - } - } - - fn view_impl(&self) -> syn::Item { - let Self { - DbViewTrait, - db_view_method, - .. - } = self; - - let DB = self.hygiene.ident("DB"); - let Database = self.hygiene.ident("Database"); - let views = self.hygiene.ident("views"); - let UserTrait = &self.input.ident; - - parse_quote! { - const _: () = { - use salsa::Database as #Database; - - #[doc(hidden)] - impl<#DB: #Database> #DbViewTrait for #DB { - /// Internal salsa method generated by the `salsa::db_view` macro - /// that registers this database view trait with the salsa database. - /// - /// Nothing to see here. - fn #db_view_method(&self) { - let #views = self.views_of_self(); - #views.add::(|t| t, |t| t); - } - } - }; - } - } -} diff --git a/components/salsa-macros/src/lib.rs b/components/salsa-macros/src/lib.rs index ba1a7d3b..d87412a8 100644 --- a/components/salsa-macros/src/lib.rs +++ b/components/salsa-macros/src/lib.rs @@ -42,7 +42,6 @@ mod accumulator; mod configuration; mod db; mod db_lifetime; -mod db_view; mod debug; mod debug_with_db; mod input; diff --git a/src/lib.rs b/src/lib.rs index b6f812b8..70d0c304 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,7 +41,6 @@ pub use self::runtime::Runtime; pub use self::storage::Storage; pub use salsa_macros::accumulator; pub use salsa_macros::db; -pub use salsa_macros::db_view; pub use salsa_macros::input; pub use salsa_macros::interned; pub use salsa_macros::jar; diff --git a/src/storage.rs b/src/storage.rs index 1b098f25..3edb3088 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -14,6 +14,10 @@ use crate::Database; use super::ParallelDatabase; +pub fn views(db: &Db) -> &Views { + DatabaseGen::views(db) +} + /// Salsa database methods whose implementation is generated by /// the `#[salsa::database]` procedural macro. /// @@ -43,11 +47,6 @@ pub unsafe trait DatabaseGen: Any + Send + Sync { /// Returns a reference to the underlying. fn views(&self) -> &Views; - /// Returns the upcasts database, tied to the type of `Self`; cannot be used from `dyn DatabaseGen` objects. - fn views_of_self(&self) -> &ViewsOf - where - Self: Sized + Database; - /// Returns the nonce for the underyling storage. /// /// # Safety