Skip to content

Commit 8377ee5

Browse files
author
Paolo Tranquilli
committed
Rust: fix reading lists from options.yml
1 parent 0943389 commit 8377ee5

File tree

2 files changed

+53
-9
lines changed

2 files changed

+53
-9
lines changed

rust/extractor/src/config.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
mod deserialize_vec;
2+
13
use anyhow::Context;
24
use clap::Parser;
35
use codeql_extractor::trap;
6+
use deserialize_vec::deserialize_newline_or_comma_separated;
47
use figment::{
58
providers::{Env, Format, Serialized, Yaml},
69
value::Value,
@@ -14,7 +17,7 @@ use ra_ap_intern::Symbol;
1417
use ra_ap_paths::Utf8PathBuf;
1518
use ra_ap_project_model::{CargoConfig, CargoFeatures, CfgOverrides, RustLibSource};
1619
use rust_extractor_macros::extractor_cli_config;
17-
use serde::{Deserialize, Deserializer, Serialize};
20+
use serde::{Deserialize, Serialize};
1821
use std::fmt::Debug;
1922
use std::ops::Not;
2023
use std::path::PathBuf;
@@ -37,14 +40,6 @@ impl From<Compression> for trap::Compression {
3740
}
3841
}
3942

40-
// required by the extractor_cli_config macro.
41-
fn deserialize_newline_or_comma_separated<'a, D: Deserializer<'a>, T: for<'b> From<&'b str>>(
42-
deserializer: D,
43-
) -> Result<Vec<T>, D::Error> {
44-
let value = String::deserialize(deserializer)?;
45-
Ok(value.split(['\n', ',']).map(T::from).collect())
46-
}
47-
4843
#[extractor_cli_config]
4944
pub struct Config {
5045
pub scratch_dir: PathBuf,
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use serde::de::Visitor;
2+
use serde::Deserializer;
3+
use std::fmt::Formatter;
4+
use std::marker::PhantomData;
5+
6+
// phantom data ise required to allow parametrizing on `T` without actual `T` data
7+
struct VectorVisitor<T: From<String>>(PhantomData<T>);
8+
9+
impl<T: From<String>> VectorVisitor<T> {
10+
fn new() -> Self {
11+
VectorVisitor(PhantomData)
12+
}
13+
}
14+
15+
impl<'de, T: From<String>> Visitor<'de> for VectorVisitor<T> {
16+
type Value = Vec<T>;
17+
18+
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
19+
formatter.write_str("either a sequence, or a comma or newline separated string")
20+
}
21+
22+
fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Vec<T>, E> {
23+
Ok(value
24+
.split(['\n', ','])
25+
.map(|s| T::from(s.to_owned()))
26+
.collect())
27+
}
28+
29+
fn visit_seq<A>(self, mut seq: A) -> Result<Vec<T>, A::Error>
30+
where
31+
A: serde::de::SeqAccess<'de>,
32+
{
33+
let mut ret = Vec::new();
34+
while let Some(el) = seq.next_element::<String>()? {
35+
ret.push(T::from(el));
36+
}
37+
Ok(ret)
38+
}
39+
}
40+
41+
/// deserialize into a vector of `T` either of:
42+
/// * a sequence of elements serializable into `String`s, or
43+
/// * a single element serializable into `String`, then split on `,` and `\n`
44+
/// This is required to be in scope when the `extractor_cli_config` macro is used.
45+
pub(crate) fn deserialize_newline_or_comma_separated<'a, D: Deserializer<'a>, T: From<String>>(
46+
deserializer: D,
47+
) -> Result<Vec<T>, D::Error> {
48+
deserializer.deserialize_seq(VectorVisitor::new())
49+
}

0 commit comments

Comments
 (0)