use std::collections::{BTreeMap, BTreeSet}; use std::marker::PhantomData; use std::num::NonZeroUsize; use serde::{Deserialize, Deserializer}; #[cfg(test)] fn serialize_with_wildcard( field: &Setting>, s: S, ) -> std::result::Result where S: serde::Serializer, { use serde::Serialize; let wildcard = vec!["*".to_string()]; match field { Setting::Set(value) => Some(value), Setting::Reset => Some(&wildcard), Setting::NotSet => None, } .serialize(s) } #[derive(Clone, Default, Debug, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize))] pub struct Checked; #[derive(Clone, Default, Debug, Deserialize, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize))] pub struct Unchecked; #[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize))] #[serde(deny_unknown_fields)] #[serde(rename_all = "camelCase")] pub struct MinWordSizeTyposSetting { #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub one_typo: Setting, #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub two_typos: Setting, } #[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize))] #[serde(deny_unknown_fields)] #[serde(rename_all = "camelCase")] pub struct TypoSettings { #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub enabled: Setting, #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub min_word_size_for_typos: Setting, #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub disable_on_words: Setting>, #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub disable_on_attributes: Setting>, } /// Holds all the settings for an index. `T` can either be `Checked` if they represents settings /// whose validity is guaranteed, or `Unchecked` if they need to be validated. In the later case, a /// call to `check` will return a `Settings` from a `Settings`. #[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq)] #[cfg_attr(test, derive(serde::Serialize))] #[serde(deny_unknown_fields)] #[serde(rename_all = "camelCase")] #[serde(bound(serialize = "T: serde::Serialize", deserialize = "T: Deserialize<'static>"))] pub struct Settings { #[serde( default, serialize_with = "serialize_with_wildcard", skip_serializing_if = "Setting::is_not_set" )] pub displayed_attributes: Setting>, #[serde( default, serialize_with = "serialize_with_wildcard", skip_serializing_if = "Setting::is_not_set" )] pub searchable_attributes: Setting>, #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub filterable_attributes: Setting>, #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub sortable_attributes: Setting>, #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub ranking_rules: Setting>, #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub stop_words: Setting>, #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub synonyms: Setting>>, #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub distinct_attribute: Setting, #[serde(default, skip_serializing_if = "Setting::is_not_set")] pub typo_tolerance: Setting, #[serde(skip)] pub _kind: PhantomData, } impl Settings { pub fn cleared() -> Settings { Settings { displayed_attributes: Setting::Reset, searchable_attributes: Setting::Reset, filterable_attributes: Setting::Reset, sortable_attributes: Setting::Reset, ranking_rules: Setting::Reset, stop_words: Setting::Reset, synonyms: Setting::Reset, distinct_attribute: Setting::Reset, typo_tolerance: Setting::Reset, _kind: PhantomData, } } pub fn into_unchecked(self) -> Settings { let Self { displayed_attributes, searchable_attributes, filterable_attributes, sortable_attributes, ranking_rules, stop_words, synonyms, distinct_attribute, typo_tolerance, .. } = self; Settings { displayed_attributes, searchable_attributes, filterable_attributes, sortable_attributes, ranking_rules, stop_words, synonyms, distinct_attribute, typo_tolerance, _kind: PhantomData, } } } impl Settings { pub fn check(self) -> Settings { let displayed_attributes = match self.displayed_attributes { Setting::Set(fields) => { if fields.iter().any(|f| f == "*") { Setting::Reset } else { Setting::Set(fields) } } otherwise => otherwise, }; let searchable_attributes = match self.searchable_attributes { Setting::Set(fields) => { if fields.iter().any(|f| f == "*") { Setting::Reset } else { Setting::Set(fields) } } otherwise => otherwise, }; Settings { displayed_attributes, searchable_attributes, filterable_attributes: self.filterable_attributes, sortable_attributes: self.sortable_attributes, ranking_rules: self.ranking_rules, stop_words: self.stop_words, synonyms: self.synonyms, distinct_attribute: self.distinct_attribute, typo_tolerance: self.typo_tolerance, _kind: PhantomData, } } } #[derive(Debug, Clone, Deserialize)] #[cfg_attr(test, derive(serde::Serialize))] #[serde(deny_unknown_fields)] #[serde(rename_all = "camelCase")] pub struct Facets { pub level_group_size: Option, pub min_level_size: Option, } #[derive(Debug, Clone, PartialEq, Eq, Copy)] pub enum Setting { Set(T), Reset, NotSet, } impl Default for Setting { fn default() -> Self { Self::NotSet } } impl Setting { pub fn set(self) -> Option { match self { Self::Set(value) => Some(value), _ => None, } } pub const fn as_ref(&self) -> Setting<&T> { match *self { Self::Set(ref value) => Setting::Set(value), Self::Reset => Setting::Reset, Self::NotSet => Setting::NotSet, } } pub const fn is_not_set(&self) -> bool { matches!(self, Self::NotSet) } /// If `Self` is `Reset`, then map self to `Set` with the provided `val`. pub fn or_reset(self, val: T) -> Self { match self { Self::Reset => Self::Set(val), otherwise => otherwise, } } } #[cfg(test)] impl serde::Serialize for Setting { fn serialize(&self, serializer: S) -> std::result::Result where S: serde::Serializer, { match self { Self::Set(value) => Some(value), // Usually not_set isn't serialized by setting skip_serializing_if field attribute Self::NotSet | Self::Reset => None, } .serialize(serializer) } } impl<'de, T: Deserialize<'de>> Deserialize<'de> for Setting { fn deserialize(deserializer: D) -> std::result::Result where D: Deserializer<'de>, { Deserialize::deserialize(deserializer).map(|x| match x { Some(x) => Self::Set(x), None => Self::Reset, // Reset is forced by sending null value }) } }