use crate::options::localization::MonthFormat;
#[cfg(feature = "schema")]
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "kebab-case")]
pub enum TimeFormat {
Hour12,
Hour24,
}
#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "kebab-case")]
pub enum EraLabels {
#[default]
Default,
BcAd,
BceCe,
}
#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "kebab-case")]
pub enum NegativeUnspecifiedYears {
#[default]
Range,
Fuzzy,
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(untagged)]
pub enum DateConfigEntry {
Preset(crate::presets::DatePreset),
Explicit(DateConfig),
}
impl Default for DateConfigEntry {
fn default() -> Self {
DateConfigEntry::Explicit(DateConfig::default())
}
}
impl DateConfigEntry {
pub fn resolve(&self) -> DateConfig {
match self {
DateConfigEntry::Preset(preset) => preset.config(),
DateConfigEntry::Explicit(config) => config.clone(),
}
}
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "kebab-case")]
pub struct DateConfig {
pub month: MonthFormat,
#[serde(skip_serializing_if = "Option::is_none")]
pub uncertainty_marker: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub approximation_marker: Option<String>,
#[serde(default = "default_range_delimiter")]
pub range_delimiter: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub open_range_marker: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom: Option<HashMap<String, serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub time_format: Option<TimeFormat>,
#[serde(default)]
pub show_seconds: bool,
#[serde(default)]
pub show_timezone: bool,
#[serde(default)]
pub era_labels: EraLabels,
#[serde(default)]
pub negative_unspecified_years: NegativeUnspecifiedYears,
#[serde(
flatten,
default,
skip_serializing_if = "std::collections::BTreeMap::is_empty"
)]
#[cfg_attr(feature = "schema", schemars(skip))]
pub unknown_fields: std::collections::BTreeMap<String, serde_yaml::Value>,
}
fn default_range_delimiter() -> String {
"–".to_string() }
impl Default for DateConfig {
fn default() -> Self {
Self {
month: MonthFormat::Long,
uncertainty_marker: Some("?".to_string()),
approximation_marker: Some("ca. ".to_string()),
range_delimiter: default_range_delimiter(),
open_range_marker: None,
custom: None,
time_format: None,
show_seconds: false,
show_timezone: false,
era_labels: EraLabels::default(),
negative_unspecified_years: NegativeUnspecifiedYears::default(),
unknown_fields: std::collections::BTreeMap::new(),
}
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, reason = "Panicking is acceptable in tests.")]
mod tests {
use super::*;
#[test]
fn captures_unknown_fields_for_forward_compat() {
let yaml = r#"
month: long
future-key: true
"#;
let cfg: DateConfig = serde_yaml::from_str(yaml).unwrap();
assert!(cfg.unknown_fields.contains_key("future-key"));
assert_eq!(cfg.month, MonthFormat::Long);
}
}