Skip to content

Commit 4c8e52a

Browse files
authored
Merge pull request #543 from MichaReiser/input-builder
Introduce `Input::builder` API
2 parents d6df21f + 547663f commit 4c8e52a

15 files changed

+353
-12
lines changed

components/salsa-macro-rules/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
mod macro_if;
1616
mod maybe_backdate;
1717
mod maybe_clone;
18+
mod maybe_default;
1819
mod setup_accumulator_impl;
1920
mod setup_input_struct;
2021
mod setup_interned_struct;

components/salsa-macro-rules/src/maybe_backdate.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#[macro_export]
33
macro_rules! maybe_backdate {
44
(
5-
($maybe_clone:ident, no_backdate),
5+
($maybe_clone:ident, no_backdate, $maybe_default:ident),
66
$field_ty:ty,
77
$old_field_place:expr,
88
$new_field_place:expr,
@@ -20,7 +20,7 @@ macro_rules! maybe_backdate {
2020
};
2121

2222
(
23-
($maybe_clone:ident, backdate),
23+
($maybe_clone:ident, backdate, $maybe_default:ident),
2424
$field_ty:ty,
2525
$old_field_place:expr,
2626
$new_field_place:expr,

components/salsa-macro-rules/src/maybe_clone.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
#[macro_export]
55
macro_rules! maybe_clone {
66
(
7-
(no_clone, $maybe_backdate:ident),
7+
(no_clone, $maybe_backdate:ident, $maybe_default:ident),
88
$field_ty:ty,
99
$field_ref_expr:expr,
1010
) => {
1111
$field_ref_expr
1212
};
1313

1414
(
15-
(clone, $maybe_backdate:ident),
15+
(clone, $maybe_backdate:ident, $maybe_default:ident),
1616
$field_ty:ty,
1717
$field_ref_expr:expr,
1818
) => {
@@ -23,15 +23,15 @@ macro_rules! maybe_clone {
2323
#[macro_export]
2424
macro_rules! maybe_cloned_ty {
2525
(
26-
(no_clone, $maybe_backdate:ident),
26+
(no_clone, $maybe_backdate:ident, $maybe_default:ident),
2727
$db_lt:lifetime,
2828
$field_ty:ty
2929
) => {
3030
& $db_lt $field_ty
3131
};
3232

3333
(
34-
(clone, $maybe_backdate:ident),
34+
(clone, $maybe_backdate:ident, $maybe_default:ident),
3535
$db_lt:lifetime,
3636
$field_ty:ty
3737
) => {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/// Generate either `field_ref_expr` or `field_ty::default`
2+
///
3+
/// Used when generating an input's builder.
4+
#[macro_export]
5+
macro_rules! maybe_default {
6+
(
7+
($maybe_clone:ident, $maybe_backdate:ident, default),
8+
$field_ty:ty,
9+
$field_ref_expr:expr,
10+
) => {
11+
<$field_ty>::default()
12+
};
13+
14+
(
15+
($maybe_clone:ident, $maybe_backdate:ident, required),
16+
$field_ty:ty,
17+
$field_ref_expr:expr,
18+
) => {
19+
$field_ref_expr
20+
};
21+
}
22+
23+
#[macro_export]
24+
macro_rules! maybe_default_tt {
25+
(($maybe_clone:ident, $maybe_backdate:ident, default) => $($t:tt)*) => {
26+
$($t)*
27+
};
28+
29+
(($maybe_clone:ident, $maybe_backdate:ident, required) => $($t:tt)*) => {
30+
31+
};
32+
}

components/salsa-macro-rules/src/setup_input_struct.rs

Lines changed: 99 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ macro_rules! setup_input_struct {
3232
// Indices for each field from 0..N -- must be unsuffixed (e.g., `0`, `1`).
3333
field_indices: [$($field_index:tt),*],
3434

35+
// Fields that are required (have no default value). Each item is the fields name and type.
36+
required_fields: [$($required_field_id:ident $required_field_ty:ty),*],
37+
38+
// Names for the field durability methods on the builder (typically `foo_durability`)
39+
field_durability_ids: [$($field_durability_id:ident),*],
40+
3541
// Number of fields
3642
num_fields: $N:literal,
3743

@@ -48,6 +54,7 @@ macro_rules! setup_input_struct {
4854
$zalsa:ident,
4955
$zalsa_struct:ident,
5056
$Configuration:ident,
57+
$Builder:ident,
5158
$CACHE:ident,
5259
$Db:ident,
5360
]
@@ -123,14 +130,18 @@ macro_rules! setup_input_struct {
123130
}
124131

125132
impl $Struct {
126-
pub fn $new_fn<$Db>(db: &$Db, $($field_id: $field_ty),*) -> Self
133+
#[inline]
134+
pub fn $new_fn<$Db>(db: &$Db, $($required_field_id: $required_field_ty),*) -> Self
127135
where
128136
// FIXME(rust-lang/rust#65991): The `db` argument *should* have the type `dyn Database`
129137
$Db: ?Sized + salsa::Database,
130138
{
131-
let current_revision = $zalsa::current_revision(db);
132-
let stamps = $zalsa::Array::new([$zalsa::stamp(current_revision, Default::default()); $N]);
133-
$Configuration::ingredient(db.as_dyn_database()).new_input(($($field_id,)*), stamps)
139+
Self::builder($($required_field_id,)*).new(db)
140+
}
141+
142+
pub fn builder($($required_field_id: $required_field_ty),*) -> <Self as $zalsa_struct::HasBuilder>::Builder
143+
{
144+
builder::new_builder($($zalsa::maybe_default!($field_option, $field_ty, $field_id,)),*)
134145
}
135146

136147
$(
@@ -206,6 +217,90 @@ macro_rules! setup_input_struct {
206217
})
207218
}
208219
}
220+
221+
impl $zalsa_struct::HasBuilder for $Struct {
222+
type Builder = builder::$Builder;
223+
}
224+
225+
// Implement `new` here instead of inside the builder module
226+
// because $Configuration can't be named in `builder`.
227+
impl builder::$Builder {
228+
/// Creates the new input with the set values.
229+
#[must_use]
230+
pub fn new<$Db>(self, db: &$Db) -> $Struct
231+
where
232+
// FIXME(rust-lang/rust#65991): The `db` argument *should* have the type `dyn Database`
233+
$Db: ?Sized + salsa::Database
234+
{
235+
let current_revision = $zalsa::current_revision(db);
236+
let ingredient = $Configuration::ingredient(db.as_dyn_database());
237+
let (fields, stamps) = builder::builder_into_inner(self, current_revision);
238+
ingredient.new_input(fields, stamps)
239+
}
240+
}
241+
242+
mod builder {
243+
use super::*;
244+
245+
use salsa::plumbing as $zalsa;
246+
use $zalsa::input as $zalsa_struct;
247+
248+
// These are standalone functions instead of methods on `Builder` to prevent
249+
// that the enclosing module can call them.
250+
pub(super) fn new_builder($($field_id: $field_ty),*) -> $Builder {
251+
$Builder {
252+
fields: ($($field_id,)*),
253+
durabilities: [salsa::Durability::default(); $N],
254+
}
255+
}
256+
257+
pub(super) fn builder_into_inner(builder: $Builder, revision: $zalsa::Revision) -> (($($field_ty,)*), $zalsa::Array<$zalsa::Stamp, $N>) {
258+
let stamps = $zalsa::Array::new([
259+
$($zalsa::stamp(revision, builder.durabilities[$field_index])),*
260+
]);
261+
262+
(builder.fields, stamps)
263+
}
264+
265+
#[must_use]
266+
pub struct $Builder {
267+
/// The field values.
268+
fields: ($($field_ty,)*),
269+
270+
/// The durabilities per field.
271+
durabilities: [salsa::Durability; $N],
272+
}
273+
274+
impl $Builder {
275+
/// Sets the durability of all fields.
276+
///
277+
/// Overrides any previously set durabilities.
278+
pub fn durability(mut self, durability: salsa::Durability) -> Self {
279+
self.durabilities = [durability; $N];
280+
self
281+
}
282+
283+
$($zalsa::maybe_default_tt! { $field_option =>
284+
/// Sets the value of the field `$field_id`.
285+
#[must_use]
286+
pub fn $field_id(mut self, value: $field_ty) -> Self
287+
{
288+
self.fields.$field_index = value;
289+
self
290+
}
291+
})*
292+
293+
$(
294+
/// Sets the durability for the field `$field_id`.
295+
#[must_use]
296+
pub fn $field_durability_id(mut self, durability: salsa::Durability) -> Self
297+
{
298+
self.durabilities[$field_index] = durability;
299+
self
300+
}
301+
)*
302+
}
303+
}
209304
};
210305
};
211306
}

components/salsa-macro-rules/src/setup_struct_fn.rs

Lines changed: 0 additions & 1 deletion
This file was deleted.

components/salsa-macros/src/input.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ impl SalsaStructAllowedOptions for InputStruct {
6262
const ALLOW_ID: bool = false;
6363

6464
const HAS_LIFETIME: bool = false;
65+
66+
const ALLOW_DEFAULT: bool = true;
6567
}
6668

6769
struct Macro {
@@ -85,14 +87,17 @@ impl Macro {
8587
let field_vis = salsa_struct.field_vis();
8688
let field_getter_ids = salsa_struct.field_getter_ids();
8789
let field_setter_ids = salsa_struct.field_setter_ids();
90+
let required_fields = salsa_struct.required_fields();
8891
let field_options = salsa_struct.field_options();
8992
let field_tys = salsa_struct.field_tys();
93+
let field_durability_ids = salsa_struct.field_durability_ids();
9094
let is_singleton = self.args.singleton.is_some();
9195
let generate_debug_impl = salsa_struct.generate_debug_impl();
9296

9397
let zalsa = self.hygiene.ident("zalsa");
9498
let zalsa_struct = self.hygiene.ident("zalsa_struct");
9599
let Configuration = self.hygiene.ident("Configuration");
100+
let Builder = self.hygiene.ident("Builder");
96101
let CACHE = self.hygiene.ident("CACHE");
97102
let Db = self.hygiene.ident("Db");
98103

@@ -110,13 +115,16 @@ impl Macro {
110115
field_setters: [#(#field_vis #field_setter_ids),*],
111116
field_tys: [#(#field_tys),*],
112117
field_indices: [#(#field_indices),*],
118+
required_fields: [#(#required_fields),*],
119+
field_durability_ids: [#(#field_durability_ids),*],
113120
num_fields: #num_fields,
114121
is_singleton: #is_singleton,
115122
generate_debug_impl: #generate_debug_impl,
116123
unused_names: [
117124
#zalsa,
118125
#zalsa_struct,
119126
#Configuration,
127+
#Builder,
120128
#CACHE,
121129
#Db,
122130
]

components/salsa-macros/src/interned.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ impl SalsaStructAllowedOptions for InternedStruct {
6363
const ALLOW_ID: bool = false;
6464

6565
const HAS_LIFETIME: bool = true;
66+
67+
const ALLOW_DEFAULT: bool = false;
6668
}
6769

6870
struct Macro {

0 commit comments

Comments
 (0)