From d4740ed72cd5b92b43854f430ba3658ddef8a463 Mon Sep 17 00:00:00 2001 From: David Barsky Date: Mon, 2 Dec 2024 14:14:32 +0000 Subject: [PATCH] feature: add id paramater to interned structs --- .../setup_interned_struct_sans_lifetime.rs | 15 ++++++++---- components/salsa-macros/src/accumulator.rs | 1 + components/salsa-macros/src/input.rs | 2 ++ components/salsa-macros/src/interned.rs | 2 ++ .../src/interned_sans_lifetime.rs | 5 ++++ components/salsa-macros/src/options.rs | 22 +++++++++++++++++- components/salsa-macros/src/salsa_struct.rs | 7 ++++++ components/salsa-macros/src/tracked_fn.rs | 2 ++ components/salsa-macros/src/tracked_struct.rs | 2 ++ tests/interned-sans-lifetime.rs | 23 +++++++++++++++---- 10 files changed, 71 insertions(+), 10 deletions(-) diff --git a/components/salsa-macro-rules/src/setup_interned_struct_sans_lifetime.rs b/components/salsa-macro-rules/src/setup_interned_struct_sans_lifetime.rs index aa9e4ef5..bcb254d0 100644 --- a/components/salsa-macro-rules/src/setup_interned_struct_sans_lifetime.rs +++ b/components/salsa-macro-rules/src/setup_interned_struct_sans_lifetime.rs @@ -14,6 +14,9 @@ macro_rules! setup_interned_struct_sans_lifetime { // Name of the `'db` lifetime that the user gave db_lt: $db_lt:lifetime, + // the salsa ID + id: $Id:path, + // Name user gave for `new` new_fn: $new_fn:ident, @@ -55,7 +58,7 @@ macro_rules! setup_interned_struct_sans_lifetime { $(#[$attr])* #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] $vis struct $Struct( - salsa::Id, + $Id, std::marker::PhantomData < &'static salsa::plumbing::interned::Value < $Struct > > ); @@ -96,10 +99,12 @@ macro_rules! setup_interned_struct_sans_lifetime { type Data<'a> = StructData<'a>; type Struct<'a> = $Struct; fn struct_from_id<'db>(id: salsa::Id) -> Self::Struct<'db> { - $Struct(id, std::marker::PhantomData) + use $zalsa::FromId; + $Struct(<$Id>::from_id(id), std::marker::PhantomData) } fn deref_struct(s: Self::Struct<'_>) -> salsa::Id { - s.0 + use $zalsa::AsId; + s.0.as_id() } } @@ -118,13 +123,13 @@ macro_rules! setup_interned_struct_sans_lifetime { impl $zalsa::AsId for $Struct { fn as_id(&self) -> salsa::Id { - self.0 + self.0.as_id() } } impl $zalsa::FromId for $Struct { fn from_id(id: salsa::Id) -> Self { - Self(id, std::marker::PhantomData) + Self(<$Id>::from_id(id), std::marker::PhantomData) } } diff --git a/components/salsa-macros/src/accumulator.rs b/components/salsa-macros/src/accumulator.rs index 1e09cb08..f48a1c25 100644 --- a/components/salsa-macros/src/accumulator.rs +++ b/components/salsa-macros/src/accumulator.rs @@ -42,6 +42,7 @@ impl AllowedOptions for Accumulator { const RECOVERY_FN: bool = false; const LRU: bool = false; const CONSTRUCTOR_NAME: bool = false; + const ID: bool = true; } struct StructMacro { diff --git a/components/salsa-macros/src/input.rs b/components/salsa-macros/src/input.rs index 9ad44491..3c71b7f1 100644 --- a/components/salsa-macros/src/input.rs +++ b/components/salsa-macros/src/input.rs @@ -55,6 +55,8 @@ impl crate::options::AllowedOptions for InputStruct { const LRU: bool = false; const CONSTRUCTOR_NAME: bool = true; + + const ID: bool = true; } impl SalsaStructAllowedOptions for InputStruct { diff --git a/components/salsa-macros/src/interned.rs b/components/salsa-macros/src/interned.rs index 8caba77e..92c278a0 100644 --- a/components/salsa-macros/src/interned.rs +++ b/components/salsa-macros/src/interned.rs @@ -56,6 +56,8 @@ impl crate::options::AllowedOptions for InternedStruct { const LRU: bool = false; const CONSTRUCTOR_NAME: bool = true; + + const ID: bool = true; } impl SalsaStructAllowedOptions for InternedStruct { diff --git a/components/salsa-macros/src/interned_sans_lifetime.rs b/components/salsa-macros/src/interned_sans_lifetime.rs index 215e05fd..384c02c5 100644 --- a/components/salsa-macros/src/interned_sans_lifetime.rs +++ b/components/salsa-macros/src/interned_sans_lifetime.rs @@ -32,6 +32,7 @@ pub(crate) fn interned_sans_lifetime( type InternedArgs = Options; +#[derive(Debug)] struct InternedStruct; impl crate::options::AllowedOptions for InternedStruct { @@ -56,6 +57,8 @@ impl crate::options::AllowedOptions for InternedStruct { const LRU: bool = false; const CONSTRUCTOR_NAME: bool = true; + + const ID: bool = true; } impl SalsaStructAllowedOptions for InternedStruct { @@ -93,6 +96,7 @@ impl Macro { let field_tys = salsa_struct.field_tys(); let field_indexed_tys = salsa_struct.field_indexed_tys(); let generate_debug_impl = salsa_struct.generate_debug_impl(); + let id = salsa_struct.id(); let zalsa = self.hygiene.ident("zalsa"); let zalsa_struct = self.hygiene.ident("zalsa_struct"); @@ -108,6 +112,7 @@ impl Macro { vis: #vis, Struct: #struct_ident, db_lt: #db_lt, + id: #id, new_fn: #new_fn, field_options: [#(#field_options),*], field_ids: [#(#field_ids),*], diff --git a/components/salsa-macros/src/options.rs b/components/salsa-macros/src/options.rs index 6f30bb3e..f1646630 100644 --- a/components/salsa-macros/src/options.rs +++ b/components/salsa-macros/src/options.rs @@ -7,6 +7,7 @@ use syn::{ext::IdentExt, spanned::Spanned}; /// are required and trailing commas are permitted. The options accepted /// for any particular location are configured via the `AllowedOptions` /// trait. +#[derive(Debug)] pub(crate) struct Options { /// The `return_ref` option is used to signal that field/return type is "by ref" /// @@ -66,6 +67,12 @@ pub(crate) struct Options { /// If this is `Some`, the value is the ``. pub constructor_name: Option, + /// The `id = ` option is used to set a custom ID for interrned structs. + /// + /// The custom ID needs to handle + /// If this is `Some`, the value is the ``. + pub id: Option, + /// Remember the `A` parameter, which plays no role after parsing. phantom: PhantomData, } @@ -85,6 +92,7 @@ impl Default for Options { phantom: Default::default(), lru: Default::default(), singleton: Default::default(), + id: Default::default(), } } } @@ -102,6 +110,7 @@ pub(crate) trait AllowedOptions { const RECOVERY_FN: bool; const LRU: bool; const CONSTRUCTOR_NAME: bool; + const ID: bool; } type Equals = syn::Token![=]; @@ -252,7 +261,7 @@ impl syn::parse::Parse for Options { } } else if ident == "constructor" { if A::CONSTRUCTOR_NAME { - let _eq = Equals::parse(input)?; + let _eq: syn::token::Eq = Equals::parse(input)?; let ident = syn::Ident::parse(input)?; if let Some(old) = std::mem::replace(&mut options.constructor_name, Some(ident)) { @@ -267,6 +276,17 @@ impl syn::parse::Parse for Options { "`constructor` option not allowed here", )); } + } else if ident == "id" { + if A::ID { + let _eq = Equals::parse(input)?; + let path = syn::Path::parse(input)?; + options.id = Some(path); + } else { + return Err(syn::Error::new( + ident.span(), + "`id` option not allowed here", + )); + } } else { return Err(syn::Error::new( ident.span(), diff --git a/components/salsa-macros/src/salsa_struct.rs b/components/salsa-macros/src/salsa_struct.rs index 1a24fdc4..6e0759e1 100644 --- a/components/salsa-macros/src/salsa_struct.rs +++ b/components/salsa-macros/src/salsa_struct.rs @@ -118,6 +118,13 @@ where } } + pub(crate) fn id(&self) -> syn::Path { + match &self.args.id { + Some(id) => id.clone(), + None => parse_quote!(salsa::Id), + } + } + /// Disallow `#[id]` attributes on the fields of this struct. /// /// If an `#[id]` field is found, return an error. diff --git a/components/salsa-macros/src/tracked_fn.rs b/components/salsa-macros/src/tracked_fn.rs index 57023ef2..3e9d2f35 100644 --- a/components/salsa-macros/src/tracked_fn.rs +++ b/components/salsa-macros/src/tracked_fn.rs @@ -44,6 +44,8 @@ impl crate::options::AllowedOptions for TrackedFn { const LRU: bool = true; const CONSTRUCTOR_NAME: bool = false; + + const ID: bool = true; } struct Macro { diff --git a/components/salsa-macros/src/tracked_struct.rs b/components/salsa-macros/src/tracked_struct.rs index 1730b340..4904d365 100644 --- a/components/salsa-macros/src/tracked_struct.rs +++ b/components/salsa-macros/src/tracked_struct.rs @@ -50,6 +50,8 @@ impl crate::options::AllowedOptions for TrackedStruct { const LRU: bool = false; const CONSTRUCTOR_NAME: bool = true; + + const ID: bool = true; } impl SalsaStructAllowedOptions for TrackedStruct { diff --git a/tests/interned-sans-lifetime.rs b/tests/interned-sans-lifetime.rs index 08224712..6ab50026 100644 --- a/tests/interned-sans-lifetime.rs +++ b/tests/interned-sans-lifetime.rs @@ -2,23 +2,38 @@ use expect_test::expect; use std::path::{Path, PathBuf}; use test_log::test; -#[salsa::interned_sans_lifetime] +#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, PartialOrd, Ord)] +struct CustomSalsaIdWrapper(salsa::Id); + +impl salsa::plumbing::AsId for CustomSalsaIdWrapper { + fn as_id(&self) -> salsa::Id { + self.0 + } +} + +impl salsa::plumbing::FromId for CustomSalsaIdWrapper { + fn from_id(id: salsa::Id) -> Self { + CustomSalsaIdWrapper(id) + } +} + +#[salsa::interned_sans_lifetime(id = CustomSalsaIdWrapper)] struct InternedString { data: String, } -#[salsa::interned_sans_lifetime] +#[salsa::interned_sans_lifetime(id = CustomSalsaIdWrapper)] struct InternedPair { data: (InternedString, InternedString), } -#[salsa::interned_sans_lifetime] +#[salsa::interned_sans_lifetime(id = CustomSalsaIdWrapper)] struct InternedTwoFields { data1: String, data2: String, } -#[salsa::interned_sans_lifetime] +#[salsa::interned_sans_lifetime(id = CustomSalsaIdWrapper)] struct InternedVec { data1: Vec, }