Skip to content

Commit

Permalink
Rust: fix reading lists from options.yml
Browse files Browse the repository at this point in the history
  • Loading branch information
Paolo Tranquilli committed Nov 18, 2024
1 parent 0943389 commit 8377ee5
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 9 deletions.
13 changes: 4 additions & 9 deletions rust/extractor/src/config.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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;
Expand All @@ -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,
Expand Down
49 changes: 49 additions & 0 deletions rust/extractor/src/config/deserialize_vec.rs
Original file line number Diff line number Diff line change
@@ -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())
}

0 comments on commit 8377ee5

Please sign in to comment.