use std::collections::BTreeMap;
use std::hash::{Hash, Hasher};
use std::mem;
use std::sync::OnceLock;
use hashbrown::HashMap;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use super::LintGroup;
use crate::Dialect;
use crate::spell::MutableDictionary;
fn ser_ordered<S>(map: &HashMap<String, Option<bool>>, ser: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let ordered: BTreeMap<_, _> = map.iter().map(|(k, v)| (k.clone(), *v)).collect();
ordered.serialize(ser)
}
fn de_hashbrown<'de, D>(de: D) -> Result<HashMap<String, Option<bool>>, D::Error>
where
D: Deserializer<'de>,
{
let ordered: BTreeMap<String, Option<bool>> = BTreeMap::deserialize(de)?;
Ok(ordered.into_iter().collect())
}
#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq, Eq)]
#[serde(transparent)]
pub struct FlatConfig {
#[serde(serialize_with = "ser_ordered", deserialize_with = "de_hashbrown")]
inner: HashMap<String, Option<bool>>,
}
impl FlatConfig {
fn curated() -> Self {
static CURATED: OnceLock<FlatConfig> = OnceLock::new();
CURATED
.get_or_init(|| {
let group =
LintGroup::new_curated(MutableDictionary::new().into(), Dialect::American);
group.config
})
.clone()
}
pub fn has_rule(&self, key: impl AsRef<str>) -> bool {
self.inner.contains_key(key.as_ref())
}
pub fn set_rule_enabled(&mut self, key: impl ToString, val: bool) {
self.inner.insert(key.to_string(), Some(val));
}
pub fn unset_rule_enabled(&mut self, key: impl AsRef<str>) {
self.inner.remove(key.as_ref());
}
pub fn set_rule_enabled_if_unset(&mut self, key: impl AsRef<str>, val: bool) {
if !self.inner.contains_key(key.as_ref()) {
self.set_rule_enabled(key.as_ref().to_string(), val);
}
}
pub fn is_rule_enabled(&self, key: &str) -> bool {
self.inner.get(key).cloned().flatten().unwrap_or(false)
}
pub fn clear(&mut self) {
for val in self.inner.values_mut() {
*val = None
}
}
pub fn merge_from(&mut self, other: FlatConfig) {
for (key, val) in other.inner {
if val.is_none() {
continue;
}
self.inner.insert(key.to_string(), val);
}
}
pub fn fill_with_curated(&mut self) {
let mut temp = Self::new_curated();
mem::swap(self, &mut temp);
self.merge_from(temp);
}
pub fn new_curated() -> Self {
Self::curated()
}
}
impl Hash for FlatConfig {
fn hash<H: Hasher>(&self, hasher: &mut H) {
for (key, value) in &self.inner {
hasher.write(key.as_bytes());
if let Some(value) = value {
hasher.write_u8(1);
hasher.write_u8(*value as u8);
} else {
hasher.write_u8(0);
hasher.write_u8(0);
}
}
}
}