Rust: fix reading lists from options.yml

This commit is contained in:
Paolo Tranquilli
2024-11-18 17:22:23 +01:00
parent 0943389ca1
commit 8377ee545f
2 changed files with 53 additions and 9 deletions

View File

@@ -1,6 +1,9 @@
mod deserialize_vec;
use anyhow::Context;
use clap::Parser;
use codeql_extractor::trap;
use deserialize_vec::deserialize_newline_or_comma_separated;
use figment::{
providers::{Env, Format, Serialized, Yaml},
value::Value,
@@ -14,7 +17,7 @@ use ra_ap_intern::Symbol;
use ra_ap_paths::Utf8PathBuf;
use ra_ap_project_model::{CargoConfig, CargoFeatures, CfgOverrides, RustLibSource};
use rust_extractor_macros::extractor_cli_config;
use serde::{Deserialize, Deserializer, Serialize};
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::ops::Not;
use std::path::PathBuf;
@@ -37,14 +40,6 @@ impl From<Compression> for trap::Compression {
}
}
// required by the extractor_cli_config macro.
fn deserialize_newline_or_comma_separated<'a, D: Deserializer<'a>, T: for<'b> From<&'b str>>(
deserializer: D,
) -> Result<Vec<T>, D::Error> {
let value = String::deserialize(deserializer)?;
Ok(value.split(['\n', ',']).map(T::from).collect())
}
#[extractor_cli_config]
pub struct Config {
pub scratch_dir: PathBuf,

View File

@@ -0,0 +1,49 @@
use serde::de::Visitor;
use serde::Deserializer;
use std::fmt::Formatter;
use std::marker::PhantomData;
// phantom data ise required to allow parametrizing on `T` without actual `T` data
struct VectorVisitor<T: From<String>>(PhantomData<T>);
impl<T: From<String>> VectorVisitor<T> {
fn new() -> Self {
VectorVisitor(PhantomData)
}
}
impl<'de, T: From<String>> Visitor<'de> for VectorVisitor<T> {
type Value = Vec<T>;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("either a sequence, or a comma or newline separated string")
}
fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Vec<T>, E> {
Ok(value
.split(['\n', ','])
.map(|s| T::from(s.to_owned()))
.collect())
}
fn visit_seq<A>(self, mut seq: A) -> Result<Vec<T>, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut ret = Vec::new();
while let Some(el) = seq.next_element::<String>()? {
ret.push(T::from(el));
}
Ok(ret)
}
}
/// deserialize into a vector of `T` either of:
/// * a sequence of elements serializable into `String`s, or
/// * a single element serializable into `String`, then split on `,` and `\n`
/// This is required to be in scope when the `extractor_cli_config` macro is used.
pub(crate) fn deserialize_newline_or_comma_separated<'a, D: Deserializer<'a>, T: From<String>>(
deserializer: D,
) -> Result<Vec<T>, D::Error> {
deserializer.deserialize_seq(VectorVisitor::new())
}