use std::any::Any;
use std::fmt::Display;
use datafusion::common::config::{
ConfigEntry, ConfigExtension, ConfigField, ExtensionOptions, Visit,
};
use datafusion::common::config_err;
use datafusion::error::Result as DfResult;
use exon_bed::{ExonBEDError, ExonBEDResult};
#[derive(Debug, Clone, Default)]
pub struct BEDOptions {
n_fields: Option<String>,
file_extension: Option<String>,
}
impl BEDOptions {
pub fn n_fields(&self) -> ExonBEDResult<usize> {
if let Some(n_fields) = &self.n_fields {
let n_fields = n_fields.parse::<usize>()?;
if !(3..=12).contains(&n_fields) {
return Err(ExonBEDError::InvalidNumberOfFields(n_fields));
}
Ok(n_fields)
} else {
Ok(12)
}
}
pub fn file_extension(&self) -> &str {
self.file_extension.as_deref().unwrap_or("bed")
}
}
impl ExtensionOptions for BEDOptions {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn cloned(&self) -> Box<dyn ExtensionOptions> {
Box::new(self.clone())
}
fn set(&mut self, key: &str, value: &str) -> DfResult<()> {
let (_key, bed_key) = key.split_once('.').unwrap_or((key, ""));
let (key, rem) = bed_key.split_once('.').unwrap_or((bed_key, ""));
match key {
"n_fields" => {
self.n_fields.set(rem, value)?;
}
"file_extension" => {
self.file_extension.set(rem, value)?;
}
_ => {
return config_err!("Config value \"{}\" not found on BEDOptions", rem);
}
}
Ok(())
}
fn entries(&self) -> Vec<ConfigEntry> {
struct Visitor(Vec<ConfigEntry>);
impl Visit for Visitor {
fn some<V: Display>(&mut self, key: &str, value: V, description: &'static str) {
self.0.push(ConfigEntry {
key: key.to_string(),
value: Some(value.to_string()),
description,
})
}
fn none(&mut self, key: &str, description: &'static str) {
self.0.push(ConfigEntry {
key: key.to_string(),
value: None,
description,
})
}
}
let mut v = Visitor(vec![]);
self.n_fields.visit(&mut v, "n_fields", "");
self.file_extension.visit(&mut v, "file_extension", "");
v.0
}
}
impl ConfigExtension for BEDOptions {
const PREFIX: &'static str = "bed";
}