use std::any::Any;
use std::fmt::Debug;
use std::ops::RangeInclusive;
use typed_builder::TypedBuilder;
pub use crate::{ExtcapFormatter, PrintSentence};
macro_rules! generate_config_ext {
($config_type:ty) => {
impl ConfigTrait for $config_type {
fn call(&self) -> &str {
&self.call
}
fn as_any(&self) -> &dyn Any {
self
}
}
};
}
pub struct Reload {
pub label: String,
pub reload_fn: fn() -> Vec<ConfigOptionValue>,
}
impl std::fmt::Debug for Reload {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Reload(label={})", self.label)
}
}
#[derive(Debug, TypedBuilder)]
pub struct SelectorConfig {
pub config_number: u8,
#[builder(setter(into))]
pub call: String,
#[builder(setter(into))]
pub display: String,
#[builder(default, setter(strip_option, into))]
pub tooltip: Option<String>,
#[builder(default, setter(strip_option))]
pub reload: Option<Reload>,
#[builder(default, setter(strip_option, into))]
pub group: Option<String>,
#[builder(setter(into))]
pub default_options: Vec<ConfigOptionValue>,
}
impl PrintSentence for SelectorConfig {
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "arg {{number={}}}", self.config_number)?;
write!(f, "{{call=--{}}}", self.call)?;
write!(f, "{{display={}}}", self.display)?;
if let Some(tooltip) = &self.tooltip {
write!(f, "{{tooltip={tooltip}}}")?;
}
write!(f, "{{type=selector}}")?;
if let Some(Reload { label, .. }) = &self.reload {
write!(f, "{{reload=true}}")?;
write!(f, "{{placeholder={label}}}")?;
}
if let Some(group) = &self.group {
write!(f, "{{group={group}}}")?;
}
writeln!(f)?;
for opt in self.default_options.iter() {
write!(f, "{}", ExtcapFormatter(&(opt, self.config_number)))?;
}
Ok(())
}
}
generate_config_ext!(SelectorConfig);
#[derive(Debug, TypedBuilder)]
pub struct RadioConfig {
pub config_number: u8,
#[builder(setter(into))]
pub call: String,
#[builder(setter(into))]
pub display: String,
#[builder(default, setter(strip_option, into))]
pub tooltip: Option<String>,
#[builder(default, setter(strip_option, into))]
pub group: Option<String>,
#[builder(setter(into))]
pub options: Vec<ConfigOptionValue>,
}
impl PrintSentence for RadioConfig {
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "arg {{number={}}}", self.config_number)?;
write!(f, "{{call=--{}}}", self.call)?;
write!(f, "{{display={}}}", self.display)?;
if let Some(tooltip) = &self.tooltip {
write!(f, "{{tooltip={tooltip}}}")?;
}
if let Some(group) = &self.group {
write!(f, "{{group={}}}", group)?;
}
write!(f, "{{type=radio}}")?;
writeln!(f)?;
for opt in self.options.iter() {
write!(f, "{}", ExtcapFormatter(&(opt, self.config_number)))?;
}
Ok(())
}
}
generate_config_ext!(RadioConfig);
#[derive(Debug, TypedBuilder)]
pub struct MultiCheckConfig {
pub config_number: u8,
#[builder(setter(into))]
pub call: String,
#[builder(setter(into))]
pub display: String,
#[builder(default, setter(strip_option, into))]
pub tooltip: Option<String>,
#[builder(default, setter(strip_option, into))]
pub group: Option<String>,
#[builder(setter(into))]
pub options: Vec<MultiCheckValue>,
}
impl PrintSentence for MultiCheckConfig {
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "arg {{number={}}}", self.config_number)?;
write!(f, "{{call=--{}}}", self.call)?;
write!(f, "{{display={}}}", self.display)?;
if let Some(tooltip) = &self.tooltip {
write!(f, "{{tooltip={tooltip}}}")?;
}
if let Some(group) = &self.group {
write!(f, "{{group={}}}", group)?;
}
write!(f, "{{type=multicheck}}")?;
writeln!(f)?;
for opt in self.options.iter() {
write!(f, "{}", ExtcapFormatter(&(opt, self.config_number, None)))?;
}
Ok(())
}
}
generate_config_ext!(MultiCheckConfig);
#[derive(Debug, Clone, TypedBuilder)]
pub struct MultiCheckValue {
#[builder(setter(into))]
pub value: String,
#[builder(setter(into))]
pub display: String,
#[builder(default = false)]
pub default_value: bool,
#[builder(default = true)]
pub enabled: bool,
#[builder(default, setter(into))]
pub children: Vec<MultiCheckValue>,
}
impl PrintSentence for (&MultiCheckValue, u8, Option<&MultiCheckValue>) {
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let (config, config_number, parent) = self;
write!(f, "value {{arg={}}}", config_number)?;
write!(f, "{{value={}}}", config.value)?;
write!(f, "{{display={}}}", config.display)?;
write!(f, "{{default={}}}", config.default_value)?;
write!(f, "{{enabled={}}}", config.enabled)?;
if let Some(parent) = parent {
write!(f, "{{parent={}}}", parent.value)?;
}
writeln!(f)?;
for c in config.children.iter() {
write!(
f,
"{}",
ExtcapFormatter(&(c, *config_number, Some(*config)))
)?;
}
Ok(())
}
}
#[derive(Debug, TypedBuilder)]
pub struct LongConfig {
pub config_number: u8,
#[builder(setter(into))]
pub call: String,
#[builder(setter(into))]
pub display: String,
#[builder(default, setter(strip_option, into))]
pub tooltip: Option<String>,
#[builder(default, setter(strip_option))]
pub range: Option<RangeInclusive<i64>>,
pub default_value: i64,
#[builder(default, setter(strip_option, into))]
pub group: Option<String>,
}
impl PrintSentence for LongConfig {
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "arg {{number={}}}", self.config_number)?;
write!(f, "{{call=--{}}}", self.call)?;
write!(f, "{{display={}}}", self.display)?;
if let Some(tooltip) = &self.tooltip {
write!(f, "{{tooltip={tooltip}}}")?;
}
if let Some(range) = &self.range {
write!(f, "{{range={},{}}}", range.start(), range.end())?;
}
write!(f, "{{default={}}}", self.default_value)?;
write!(f, "{{type=long}}")?;
if let Some(group) = &self.group {
write!(f, "{{group={group}}}")?;
}
writeln!(f)?;
Ok(())
}
}
generate_config_ext!(LongConfig);
#[derive(Debug, TypedBuilder)]
pub struct IntegerConfig {
pub config_number: u8,
#[builder(setter(into))]
pub call: String,
#[builder(setter(into))]
pub display: String,
#[builder(default, setter(strip_option, into))]
pub tooltip: Option<String>,
#[builder(default, setter(strip_option))]
pub range: Option<RangeInclusive<i32>>,
pub default_value: i32,
#[builder(default, setter(strip_option, into))]
pub group: Option<String>,
}
impl PrintSentence for IntegerConfig {
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "arg {{number={}}}", self.config_number)?;
write!(f, "{{call=--{}}}", self.call)?;
write!(f, "{{display={}}}", self.display)?;
if let Some(tooltip) = &self.tooltip {
write!(f, "{{tooltip={tooltip}}}")?;
}
if let Some(range) = &self.range {
write!(f, "{{range={},{}}}", range.start(), range.end())?;
}
write!(f, "{{default={}}}", self.default_value)?;
write!(f, "{{type=integer}}")?;
if let Some(group) = &self.group {
write!(f, "{{group={group}}}")?;
}
writeln!(f)?;
Ok(())
}
}
generate_config_ext!(IntegerConfig);
#[derive(Debug, TypedBuilder)]
pub struct UnsignedConfig {
pub config_number: u8,
#[builder(setter(into))]
pub call: String,
#[builder(setter(into))]
pub display: String,
#[builder(default, setter(strip_option, into))]
pub tooltip: Option<String>,
#[builder(default, setter(strip_option, into))]
pub range: Option<RangeInclusive<u32>>,
pub default_value: u32,
#[builder(default, setter(strip_option, into))]
pub group: Option<String>,
}
impl PrintSentence for UnsignedConfig {
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "arg {{number={}}}", self.config_number)?;
write!(f, "{{call=--{}}}", self.call)?;
write!(f, "{{display={}}}", self.display)?;
if let Some(tooltip) = &self.tooltip {
write!(f, "{{tooltip={tooltip}}}")?;
}
if let Some(range) = &self.range {
write!(f, "{{range={},{}}}", range.start(), range.end())?;
}
write!(f, "{{default={}}}", self.default_value)?;
write!(f, "{{type=unsigned}}")?;
if let Some(group) = &self.group {
write!(f, "{{group={group}}}")?;
}
writeln!(f)?;
Ok(())
}
}
generate_config_ext!(UnsignedConfig);
#[derive(Debug, TypedBuilder)]
pub struct DoubleConfig {
pub config_number: u8,
#[builder(setter(into))]
pub call: String,
#[builder(setter(into))]
pub display: String,
#[builder(default, setter(strip_option, into))]
pub tooltip: Option<String>,
#[builder(default, setter(strip_option))]
pub range: Option<RangeInclusive<f64>>,
pub default_value: f64,
#[builder(default, setter(strip_option, into))]
pub group: Option<String>,
}
impl PrintSentence for DoubleConfig {
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "arg {{number={}}}", self.config_number)?;
write!(f, "{{call=--{}}}", self.call)?;
write!(f, "{{display={}}}", self.display)?;
if let Some(tooltip) = &self.tooltip {
write!(f, "{{tooltip={tooltip}}}")?;
}
if let Some(range) = &self.range {
write!(f, "{{range={},{}}}", range.start(), range.end())?;
}
write!(f, "{{default={}}}", self.default_value)?;
write!(f, "{{type=double}}")?;
if let Some(group) = &self.group {
write!(f, "{{group={group}}}")?;
}
writeln!(f)?;
Ok(())
}
}
generate_config_ext!(DoubleConfig);
#[allow(deprecated)]
#[derive(Debug, TypedBuilder)]
pub struct StringConfig {
pub config_number: u8,
#[builder(setter(into))]
pub call: String,
#[builder(setter(into))]
pub display: String,
#[builder(default, setter(strip_option, into))]
pub tooltip: Option<String>,
#[builder(default, setter(strip_option, into))]
pub placeholder: Option<String>,
#[builder(default = false)]
pub required: bool,
#[builder(default, setter(strip_option, into))]
pub group: Option<String>,
#[builder(default, setter(strip_option, into))]
pub validation: Option<String>,
#[builder(default = true)]
pub save: bool,
}
impl PrintSentence for StringConfig {
#[allow(deprecated)]
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "arg {{number={}}}", self.config_number)?;
write!(f, "{{call=--{}}}", self.call)?;
write!(f, "{{display={}}}", self.display)?;
if let Some(tooltip) = &self.tooltip {
write!(f, "{{tooltip={tooltip}}}")?;
}
if let Some(placeholder) = &self.placeholder {
write!(f, "{{placeholder={}}}", placeholder)?;
}
if self.required {
write!(f, "{{required=true}}")?;
}
if let Some(validation) = &self.validation {
write!(f, "{{validation={}}}", validation)?;
}
if let Some(group) = &self.group {
write!(f, "{{group={group}}}")?;
}
if !self.save {
write!(f, "{{save=false}}")?;
}
write!(f, "{{type=string}}")?;
writeln!(f)?;
Ok(())
}
}
generate_config_ext!(StringConfig);
#[derive(Debug, TypedBuilder)]
pub struct PasswordConfig {
pub config_number: u8,
#[builder(setter(into))]
pub call: String,
#[builder(setter(into))]
pub display: String,
#[builder(default, setter(strip_option, into))]
pub tooltip: Option<String>,
#[builder(default, setter(strip_option, into))]
pub placeholder: Option<String>,
#[builder(default = false)]
pub required: bool,
#[builder(default, setter(strip_option, into))]
pub validation: Option<String>,
#[builder(default, setter(strip_option, into))]
pub group: Option<String>,
}
impl PrintSentence for PasswordConfig {
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "arg {{number={}}}", self.config_number)?;
write!(f, "{{call=--{}}}", self.call)?;
write!(f, "{{display={}}}", self.display)?;
if let Some(tooltip) = &self.tooltip {
write!(f, "{{tooltip={tooltip}}}")?;
}
if let Some(placeholder) = &self.placeholder {
write!(f, "{{placeholder={}}}", placeholder)?;
}
if self.required {
write!(f, "{{required=true}}")?;
}
if let Some(validation) = &self.validation {
write!(f, "{{validation={}}}", validation)?;
}
if let Some(group) = &self.group {
write!(f, "{{group={group}}}")?;
}
write!(f, "{{type=password}}")?;
writeln!(f)?;
Ok(())
}
}
generate_config_ext!(PasswordConfig);
#[derive(Debug, TypedBuilder)]
pub struct TimestampConfig {
pub config_number: u8,
#[builder(setter(into))]
pub call: String,
#[builder(setter(into))]
pub display: String,
#[builder(default, setter(strip_option, into))]
pub tooltip: Option<String>,
#[builder(default, setter(strip_option, into))]
pub group: Option<String>,
}
impl PrintSentence for TimestampConfig {
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "arg {{number={}}}", self.config_number)?;
write!(f, "{{call=--{}}}", self.call)?;
write!(f, "{{display={}}}", self.display)?;
if let Some(tooltip) = &self.tooltip {
write!(f, "{{tooltip={tooltip}}}")?;
}
if let Some(group) = &self.group {
write!(f, "{{group={group}}}")?;
}
write!(f, "{{type=timestamp}}")?;
writeln!(f)?;
Ok(())
}
}
generate_config_ext!(TimestampConfig);
#[derive(Debug, TypedBuilder)]
pub struct FileSelectConfig {
pub config_number: u8,
#[builder(setter(into))]
pub call: String,
#[builder(setter(into))]
pub display: String,
#[builder(default, setter(strip_option, into))]
pub tooltip: Option<String>,
#[builder(default, setter(strip_option, into))]
pub group: Option<String>,
#[builder(default = true)]
pub must_exist: bool,
#[builder(default, setter(into, strip_option))]
pub file_extension_filter: Option<String>,
}
impl PrintSentence for FileSelectConfig {
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "arg {{number={}}}", self.config_number)?;
write!(f, "{{call=--{}}}", self.call)?;
write!(f, "{{display={}}}", self.display)?;
if let Some(tooltip) = &self.tooltip {
write!(f, "{{tooltip={tooltip}}}")?;
}
if let Some(group) = &self.group {
write!(f, "{{group={group}}}")?;
}
write!(f, "{{type=fileselect}}")?;
write!(f, "{{mustexist={}}}", self.must_exist)?;
if let Some(file_extension_filter) = &self.file_extension_filter {
write!(f, "{{fileext={}}}", file_extension_filter)?;
}
writeln!(f)?;
Ok(())
}
}
generate_config_ext!(FileSelectConfig);
#[derive(Debug, TypedBuilder)]
pub struct BooleanConfig {
pub config_number: u8,
#[builder(setter(into))]
pub call: String,
#[builder(setter(into))]
pub display: String,
#[builder(default, setter(strip_option, into))]
pub tooltip: Option<String>,
#[builder(default = false)]
pub default_value: bool,
#[builder(default, setter(strip_option, into))]
pub group: Option<String>,
#[builder(default = false)]
pub always_include_option: bool,
}
impl PrintSentence for BooleanConfig {
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "arg {{number={}}}", self.config_number)?;
write!(f, "{{call=--{}}}", self.call)?;
write!(f, "{{display={}}}", self.display)?;
if let Some(tooltip) = &self.tooltip {
write!(f, "{{tooltip={tooltip}}}")?;
}
if self.default_value {
write!(f, "{{default=true}}")?;
}
if self.always_include_option {
write!(f, "{{type=boolean}}")?;
} else {
write!(f, "{{type=boolflag}}")?;
}
if let Some(group) = &self.group {
write!(f, "{{group={group}}}")?;
}
writeln!(f)?;
Ok(())
}
}
generate_config_ext!(BooleanConfig);
#[derive(Clone, Debug, TypedBuilder)]
pub struct ConfigOptionValue {
#[builder(setter(into))]
value: String,
#[builder(setter(into))]
display: String,
#[builder(default = false)]
default: bool,
}
impl ConfigOptionValue {
pub fn print_sentence(&self, number: u8) {
(self, number).print_sentence()
}
}
impl PrintSentence for (&ConfigOptionValue, u8) {
fn format_sentence(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let (config, arg_number) = self;
write!(f, "value {{arg={}}}", arg_number)?;
write!(f, "{{value={}}}", config.value)?;
write!(f, "{{display={}}}", config.display)?;
write!(f, "{{default={}}}", config.default)?;
writeln!(f)?;
Ok(())
}
}
pub trait ConfigTrait: PrintSentence + Any {
fn call(&self) -> &str;
fn as_any(&self) -> &dyn Any;
}