Skip to content

Commit ddbdecf

Browse files
authored
Merge pull request #2 from cormacrelf/apply_input
Option<T> version of all the *ConfigDatas, named *ConfigInput
2 parents 33a4fe8 + 10c1db6 commit ddbdecf

File tree

1 file changed

+121
-65
lines changed

1 file changed

+121
-65
lines changed

crates/rust-analyzer/src/config.rs

Lines changed: 121 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ mod patch_old_style;
6060
// To deprecate an option by replacing it with another name use `new_name | `old_name` so that we keep
6161
// parsing the old name.
6262
config_data! {
63-
global: struct GlobalConfigData {
63+
global: struct GlobalConfigData <- GlobalConfigInput -> RootGlobalConfigData {
6464
/// Whether to insert #[must_use] when generating `as_` methods
6565
/// for enum variants.
6666
assist_emitMustUse: bool = false,
@@ -366,7 +366,7 @@ config_data! {
366366
}
367367

368368
config_data! {
369-
local: struct LocalConfigData {
369+
local: struct LocalConfigData <- LocalConfigInput -> RootLocalConfigData {
370370
/// Toggles the additional completions that automatically add imports when completed.
371371
/// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
372372
completion_autoimport_enable: bool = true,
@@ -583,44 +583,25 @@ config_data! {
583583
}
584584

585585
config_data! {
586-
client: struct ClientConfigData {}
586+
client: struct ClientConfigData <- ClientConfigInput -> RootClientConfigData {}
587587
}
588588

589-
impl Default for ConfigData {
590-
fn default() -> Self {
591-
ConfigData::from_json(serde_json::Value::Null, &mut Vec::new())
592-
}
593-
}
594-
595-
#[derive(Debug, Clone)]
596-
struct RootLocalConfigData(LocalConfigData);
597-
#[derive(Debug, Clone)]
598-
struct RootGlobalConfigData(GlobalConfigData);
599-
#[derive(Debug, Clone)]
600-
struct RootClientConfigData(ClientConfigData);
601-
602-
#[derive(Debug, Clone)]
589+
#[derive(Debug, Clone, Default)]
603590
struct RootConfigData {
604591
local: RootLocalConfigData,
605592
global: RootGlobalConfigData,
606593
client: RootClientConfigData,
607594
}
608595

609-
impl Default for RootConfigData {
610-
fn default() -> Self {
611-
RootConfigData {
612-
local: RootLocalConfigData(LocalConfigData::from_json(
613-
&mut serde_json::Value::Null,
614-
&mut Vec::new(),
615-
)),
616-
global: RootGlobalConfigData(GlobalConfigData::from_json(
617-
&mut serde_json::Value::Null,
618-
&mut Vec::new(),
619-
)),
620-
client: RootClientConfigData(ClientConfigData::from_json(
621-
&mut serde_json::Value::Null,
622-
&mut Vec::new(),
623-
)),
596+
impl RootConfigData {
597+
/// Reads a single root config blob. All fields are either set by the config blob, or to the
598+
/// default value.
599+
fn from_root_input(input: ConfigInput) -> Self {
600+
let ConfigInput { global, local, client } = input;
601+
Self {
602+
global: RootGlobalConfigData::from_root_input(global),
603+
local: RootLocalConfigData::from_root_input(local),
604+
client: RootClientConfigData::from_root_input(client),
624605
}
625606
}
626607
}
@@ -1188,13 +1169,14 @@ impl Config {
11881169
}
11891170
let mut errors = Vec::new();
11901171
self.detached_files =
1191-
get_field::<Vec<PathBuf>>(&mut json, &mut errors, "detachedFiles", None, vec![])
1172+
get_field::<Vec<PathBuf>>(&mut json, &mut errors, "detachedFiles", None)
1173+
.unwrap_or_default()
11921174
.into_iter()
11931175
.map(AbsPathBuf::assert)
11941176
.collect();
11951177
patch_old_style::patch_json_for_outdated_configs(&mut json);
1196-
self.root_config.global =
1197-
RootGlobalConfigData(GlobalConfigData::from_json(&mut json, &mut errors));
1178+
let input = ConfigInput::from_json(json, &mut errors);
1179+
self.root_config = RootConfigData::from_root_input(input);
11981180
tracing::debug!("deserialized config data: {:#?}", self.root_config.global);
11991181
self.snippets.clear();
12001182
for (name, def) in self.root_config.local.0.completion_snippets_custom.iter() {
@@ -1244,7 +1226,7 @@ impl Config {
12441226
}
12451227

12461228
pub fn json_schema() -> serde_json::Value {
1247-
ConfigData::json_schema()
1229+
ConfigInput::json_schema()
12481230
}
12491231

12501232
pub fn root_path(&self) -> &AbsPathBuf {
@@ -2325,38 +2307,102 @@ macro_rules! _default_str {
23252307

23262308
macro_rules! _config_data {
23272309
// modname is for the tests
2328-
($modname:ident: struct $name:ident {
2310+
($modname:ident: struct $name:ident <- $input:ident -> $root:ident {
23292311
$(
23302312
$(#[doc=$doc:literal])*
23312313
$field:ident $(| $alias:ident)*: $ty:ty = $(@$marker:ident: )? $default:expr,
23322314
)*
23332315
}) => {
2316+
/// All fields raw `T`, representing either a root config, or a root config + overrides from
2317+
/// some distal configuration blob(s).
23342318
#[allow(non_snake_case)]
23352319
#[derive(Debug, Clone, Serialize)]
23362320
struct $name { $($field: $ty,)* }
2321+
2322+
/// All fields `Option<T>`, `None` representing fields not set in a particular JSON/TOML blob.
2323+
#[allow(non_snake_case)]
2324+
#[derive(Clone, Serialize, Default)]
2325+
struct $input { $(
2326+
#[serde(skip_serializing_if = "Option::is_none")]
2327+
$field: Option<$ty>,
2328+
)* }
2329+
2330+
impl std::fmt::Debug for $input {
2331+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2332+
let mut s = f.debug_struct(stringify!($input));
2333+
$(
2334+
if let Some(val) = self.$field.as_ref() {
2335+
s.field(stringify!($field), val);
2336+
}
2337+
)*
2338+
s.finish()
2339+
}
2340+
}
2341+
2342+
/// Newtype of
2343+
#[doc = stringify!($name)]
2344+
/// expressing that this was read directly from a single, root config blob.
2345+
#[derive(Debug, Clone, Default)]
2346+
struct $root($name);
2347+
2348+
impl $root {
2349+
/// Reads a single root config blob. All fields are either set by the config blob, or to the
2350+
/// default value.
2351+
fn from_root_input(input: $input) -> Self {
2352+
let mut data = $name::default();
2353+
data.apply_input(input);
2354+
Self(data)
2355+
}
2356+
}
2357+
2358+
impl Default for $name {
2359+
fn default() -> Self {
2360+
$name {$(
2361+
$field: default_val!($(@$marker:)? $default, $ty),
2362+
)*}
2363+
}
2364+
}
2365+
23372366
impl $name {
2367+
/// Applies overrides from some more local config blob, to self.
23382368
#[allow(unused)]
2339-
fn from_json(json: &mut serde_json::Value, error_sink: &mut Vec<(String, serde_json::Error)>) -> $name {
2340-
$name {$(
2369+
fn apply_input(&mut self, input: $input) {
2370+
$(
2371+
if let Some(value) = input.$field {
2372+
self.$field = value;
2373+
}
2374+
)*
2375+
}
2376+
2377+
#[allow(unused)]
2378+
fn clone_with_overrides(&self, input: $input) -> Self {
2379+
Self {$(
2380+
$field: input.$field.unwrap_or_else(|| self.$field.clone()),
2381+
)*}
2382+
}
2383+
}
2384+
2385+
impl $input {
2386+
#[allow(unused)]
2387+
fn from_json(json: &mut serde_json::Value, error_sink: &mut Vec<(String, serde_json::Error)>) -> Self {
2388+
Self {$(
23412389
$field: get_field(
23422390
json,
23432391
error_sink,
23442392
stringify!($field),
23452393
None$(.or(Some(stringify!($alias))))*,
2346-
default_val!($(@$marker:)? $default, $ty),
23472394
),
23482395
)*}
23492396
}
23502397

23512398
#[allow(unused)]
2352-
fn from_toml(toml: &mut toml::Table , error_sink: &mut Vec<(String, toml::de::Error)>) -> $name {
2353-
$name {$(
2399+
fn from_toml(toml: &mut toml::Table , error_sink: &mut Vec<(String, toml::de::Error)>) -> Self {
2400+
Self {$(
23542401
$field: get_field_toml::<$ty>(
23552402
toml,
23562403
error_sink,
23572404
stringify!($field),
23582405
None$(.or(Some(stringify!($alias))))*,
2359-
default_val!($(@$marker:)? $default, $ty),
23602406
),
23612407
)*}
23622408
}
@@ -2387,7 +2433,8 @@ use _config_data as config_data;
23872433
use _default_str as default_str;
23882434
use _default_val as default_val;
23892435

2390-
#[derive(Debug, Clone, Serialize)]
2436+
/// All of the config levels, all fields raw `T`. Represents a root configuration, or a config set
2437+
#[derive(Debug, Clone, Serialize, Default)]
23912438
struct ConfigData {
23922439
#[serde(flatten)]
23932440
global: GlobalConfigData,
@@ -2397,34 +2444,47 @@ struct ConfigData {
23972444
client: ClientConfigData,
23982445
}
23992446

2400-
impl ConfigData {
2447+
/// All of the config levels, all fields `Option<T>`, to describe fields that are actually set by
2448+
/// some rust-analyzer.toml file or JSON blob. An empty rust-analyzer.toml corresponds to
2449+
/// all fields being None.
2450+
#[derive(Debug, Clone, Serialize, Default)]
2451+
struct ConfigInput {
2452+
#[serde(flatten)]
2453+
global: GlobalConfigInput,
2454+
#[serde(flatten)]
2455+
local: LocalConfigInput,
2456+
#[serde(flatten)]
2457+
client: ClientConfigInput,
2458+
}
2459+
2460+
impl ConfigInput {
24012461
fn from_json(
24022462
mut json: serde_json::Value,
24032463
error_sink: &mut Vec<(String, serde_json::Error)>,
2404-
) -> ConfigData {
2405-
ConfigData {
2406-
global: GlobalConfigData::from_json(&mut json, error_sink),
2407-
local: LocalConfigData::from_json(&mut json, error_sink),
2408-
client: ClientConfigData::from_json(&mut json, error_sink),
2464+
) -> ConfigInput {
2465+
ConfigInput {
2466+
global: GlobalConfigInput::from_json(&mut json, error_sink),
2467+
local: LocalConfigInput::from_json(&mut json, error_sink),
2468+
client: ClientConfigInput::from_json(&mut json, error_sink),
24092469
}
24102470
}
24112471

24122472
fn from_toml(
24132473
mut toml: toml::Table,
24142474
error_sink: &mut Vec<(String, toml::de::Error)>,
2415-
) -> ConfigData {
2416-
ConfigData {
2417-
global: GlobalConfigData::from_toml(&mut toml, error_sink),
2418-
local: LocalConfigData::from_toml(&mut toml, error_sink),
2419-
client: ClientConfigData::from_toml(&mut toml, error_sink),
2475+
) -> ConfigInput {
2476+
ConfigInput {
2477+
global: GlobalConfigInput::from_toml(&mut toml, error_sink),
2478+
local: LocalConfigInput::from_toml(&mut toml, error_sink),
2479+
client: ClientConfigInput::from_toml(&mut toml, error_sink),
24202480
}
24212481
}
24222482

24232483
fn schema_fields() -> Vec<SchemaField> {
24242484
let mut fields = Vec::new();
2425-
GlobalConfigData::schema_fields(&mut fields);
2426-
LocalConfigData::schema_fields(&mut fields);
2427-
ClientConfigData::schema_fields(&mut fields);
2485+
GlobalConfigInput::schema_fields(&mut fields);
2486+
LocalConfigInput::schema_fields(&mut fields);
2487+
ClientConfigInput::schema_fields(&mut fields);
24282488
// HACK: sort the fields, so the diffs on the generated docs/schema are smaller
24292489
fields.sort_by_key(|&(x, ..)| x);
24302490
fields
@@ -2445,8 +2505,7 @@ fn get_field_toml<T: DeserializeOwned>(
24452505
error_sink: &mut Vec<(String, toml::de::Error)>,
24462506
field: &'static str,
24472507
alias: Option<&'static str>,
2448-
default: T,
2449-
) -> T {
2508+
) -> Option<T> {
24502509
alias
24512510
.into_iter()
24522511
.chain(iter::once(field))
@@ -2474,16 +2533,14 @@ fn get_field_toml<T: DeserializeOwned>(
24742533
None
24752534
}
24762535
})
2477-
.unwrap_or(default)
24782536
}
24792537

24802538
fn get_field<T: DeserializeOwned>(
24812539
json: &mut serde_json::Value,
24822540
error_sink: &mut Vec<(String, serde_json::Error)>,
24832541
field: &'static str,
24842542
alias: Option<&'static str>,
2485-
default: T,
2486-
) -> T {
2543+
) -> Option<T> {
24872544
// XXX: check alias first, to work around the VS Code where it pre-fills the
24882545
// defaults instead of sending an empty object.
24892546
alias
@@ -2504,7 +2561,6 @@ fn get_field<T: DeserializeOwned>(
25042561
None
25052562
}
25062563
})
2507-
.unwrap_or(default)
25082564
}
25092565

25102566
type SchemaField = (&'static str, &'static str, &'static [&'static str], String);
@@ -2965,7 +3021,7 @@ mod tests {
29653021
#[test]
29663022
fn generate_config_documentation() {
29673023
let docs_path = project_root().join("docs/user/generated_config.adoc");
2968-
let expected = ConfigData::manual();
3024+
let expected = ConfigInput::manual();
29693025
ensure_file_contents(&docs_path, &expected);
29703026
}
29713027

0 commit comments

Comments
 (0)