From 75969f9f68cb25716836c362a7d54fa690a4f9a4 Mon Sep 17 00:00:00 2001 From: "F. Levi" <55688616+flevi29@users.noreply.github.com> Date: Mon, 16 Sep 2024 21:14:47 +0300 Subject: [PATCH] Add manual serde Deserialize impl --- meilisearch-types/src/keys.rs | 371 ++++++++++++---------------------- 1 file changed, 132 insertions(+), 239 deletions(-) diff --git a/meilisearch-types/src/keys.rs b/meilisearch-types/src/keys.rs index 483289b7d..459fdf8ca 100644 --- a/meilisearch-types/src/keys.rs +++ b/meilisearch-types/src/keys.rs @@ -4,9 +4,8 @@ use std::str::FromStr; use bitflags::bitflags; use deserr::{take_cf_content, DeserializeError, Deserr, MergeWithError, ValuePointerRef}; -use enum_iterator::Sequence; use milli::update::Setting; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; use time::format_description::well_known::Rfc3339; use time::macros::{format_description, time}; use time::{Date, OffsetDateTime, PrimitiveDateTime}; @@ -181,248 +180,84 @@ fn parse_expiration_date( } bitflags! { - #[derive(Copy, Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] + #[derive(Copy, Clone, Serialize, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] #[repr(transparent)] pub struct Action: u8 { - #[serde(rename = "*")] const All = 0; - #[serde(rename = "search")] const Search = 1; - #[serde(rename = "documents.*")] const DocumentsAll = 2; - #[serde(rename = "documents.add")] const DocumentsAdd = 3; - #[serde(rename = "documents.get")] const DocumentsGet = 4; - #[serde(rename = "documents.delete")] const DocumentsDelete = 5; - #[serde(rename = "indexes.*")] const IndexesAll = 6; - #[serde(rename = "indexes.create")] const IndexesAdd = 7; - #[serde(rename = "indexes.get")] const IndexesGet = 8; - #[serde(rename = "indexes.update")] const IndexesUpdate = 9; - #[serde(rename = "indexes.delete")] const IndexesDelete = 10; - #[serde(rename = "indexes.swap")] const IndexesSwap = 11; - #[serde(rename = "tasks.*")] const TasksAll = 12; - #[serde(rename = "tasks.cancel")] const TasksCancel = 13; - #[serde(rename = "tasks.delete")] const TasksDelete = 14; - #[serde(rename = "tasks.get")] const TasksGet = 15; - #[serde(rename = "settings.*")] const SettingsAll = 16; - #[serde(rename = "settings.get")] const SettingsGet = 17; - #[serde(rename = "settings.update")] const SettingsUpdate = 18; - #[serde(rename = "stats.*")] const StatsAll = 19; - #[serde(rename = "stats.get")] const StatsGet = 20; - #[serde(rename = "metrics.*")] const MetricsAll = 21; - #[serde(rename = "metrics.get")] const MetricsGet = 22; - #[serde(rename = "dumps.*")] const DumpsAll = 23; - #[serde(rename = "dumps.create")] const DumpsCreate = 24; - #[serde(rename = "snapshots.*")] const SnapshotsAll = 25; - #[serde(rename = "snapshots.create")] const SnapshotsCreate = 26; - #[serde(rename = "version")] const Version = 27; - #[serde(rename = "keys.create")] const KeysAdd = 28; - #[serde(rename = "keys.get")] const KeysGet = 29; - #[serde(rename = "keys.update")] const KeysUpdate = 30; - #[serde(rename = "keys.delete")] const KeysDelete = 31; - #[serde(rename = "experimental.get")] const ExperimentalFeaturesGet = 32; - #[serde(rename = "experimental.update")] const ExperimentalFeaturesUpdate = 33; } } -impl Deserr for Action { - fn deserialize_from_value( - value: deserr::Value, - location: deserr::ValuePointerRef<'_>, - ) -> Result { - match value { - deserr::Value::String(s) => match s.as_str() { - "*" => Ok(Action::All), - "search" => Ok(Action::Search), - "documents.*" => Ok(Action::DocumentsAll), - "documents.add" => Ok(Action::DocumentsAdd), - "documents.get" => Ok(Action::DocumentsGet), - "documents.delete" => Ok(Action::DocumentsDelete), - "indexes.*" => Ok(Action::IndexesAll), - "indexes.create" => Ok(Action::IndexesAdd), - "indexes.get" => Ok(Action::IndexesGet), - "indexes.update" => Ok(Action::IndexesUpdate), - "indexes.delete" => Ok(Action::IndexesDelete), - "indexes.swap" => Ok(Action::IndexesSwap), - "tasks.*" => Ok(Action::TasksAll), - "tasks.cancel" => Ok(Action::TasksCancel), - "tasks.delete" => Ok(Action::TasksDelete), - "tasks.get" => Ok(Action::TasksGet), - "settings.*" => Ok(Action::SettingsAll), - "settings.get" => Ok(Action::SettingsGet), - "settings.update" => Ok(Action::SettingsUpdate), - "stats.*" => Ok(Action::StatsAll), - "stats.get" => Ok(Action::StatsGet), - "metrics.*" => Ok(Action::MetricsAll), - "metrics.get" => Ok(Action::MetricsGet), - "dumps.*" => Ok(Action::DumpsAll), - "dumps.create" => Ok(Action::DumpsCreate), - "snapshots.*" => Ok(Action::SnapshotsAll), - "snapshots.create" => Ok(Action::SnapshotsCreate), - "version" => Ok(Action::Version), - "keys.create" => Ok(Action::KeysAdd), - "keys.get" => Ok(Action::KeysGet), - "keys.update" => Ok(Action::KeysUpdate), - "keys.delete" => Ok(Action::KeysDelete), - "experimental.get" => Ok(Action::ExperimentalFeaturesGet), - "experimental.update" => Ok(Action::ExperimentalFeaturesUpdate), - _ => Err(deserr::take_cf_content(E::error::( - None, - deserr::ErrorKind::Unexpected { msg: format!("TODO {}", s) }, - location, - ))), - }, - - value => Err(take_cf_content(E::error( - None, - deserr::ErrorKind::IncorrectValueKind { - actual: value, - accepted: &[deserr::ValueKind::String], - }, - location, - ))), - } - } -} - -// #[derive(Copy, Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Hash, Sequence, Deserr)] -// #[repr(u8)] -// pub enum Action { -// #[serde(rename = "*")] -// #[deserr(rename = "*")] -// All = 0, -// #[serde(rename = "search")] -// #[deserr(rename = "search")] -// Search, -// #[serde(rename = "documents.*")] -// #[deserr(rename = "documents.*")] -// DocumentsAll, -// #[serde(rename = "documents.add")] -// #[deserr(rename = "documents.add")] -// DocumentsAdd, -// #[serde(rename = "documents.get")] -// #[deserr(rename = "documents.get")] -// DocumentsGet, -// #[serde(rename = "documents.delete")] -// #[deserr(rename = "documents.delete")] -// DocumentsDelete, -// #[serde(rename = "indexes.*")] -// #[deserr(rename = "indexes.*")] -// IndexesAll, -// #[serde(rename = "indexes.create")] -// #[deserr(rename = "indexes.create")] -// IndexesAdd, -// #[serde(rename = "indexes.get")] -// #[deserr(rename = "indexes.get")] -// IndexesGet, -// #[serde(rename = "indexes.update")] -// #[deserr(rename = "indexes.update")] -// IndexesUpdate, -// #[serde(rename = "indexes.delete")] -// #[deserr(rename = "indexes.delete")] -// IndexesDelete, -// #[serde(rename = "indexes.swap")] -// #[deserr(rename = "indexes.swap")] -// IndexesSwap, -// #[serde(rename = "tasks.*")] -// #[deserr(rename = "tasks.*")] -// TasksAll, -// #[serde(rename = "tasks.cancel")] -// #[deserr(rename = "tasks.cancel")] -// TasksCancel, -// #[serde(rename = "tasks.delete")] -// #[deserr(rename = "tasks.delete")] -// TasksDelete, -// #[serde(rename = "tasks.get")] -// #[deserr(rename = "tasks.get")] -// TasksGet, -// #[serde(rename = "settings.*")] -// #[deserr(rename = "settings.*")] -// SettingsAll, -// #[serde(rename = "settings.get")] -// #[deserr(rename = "settings.get")] -// SettingsGet, -// #[serde(rename = "settings.update")] -// #[deserr(rename = "settings.update")] -// SettingsUpdate, -// #[serde(rename = "stats.*")] -// #[deserr(rename = "stats.*")] -// StatsAll, -// #[serde(rename = "stats.get")] -// #[deserr(rename = "stats.get")] -// StatsGet, -// #[serde(rename = "metrics.*")] -// #[deserr(rename = "metrics.*")] -// MetricsAll, -// #[serde(rename = "metrics.get")] -// #[deserr(rename = "metrics.get")] -// MetricsGet, -// #[serde(rename = "dumps.*")] -// #[deserr(rename = "dumps.*")] -// DumpsAll, -// #[serde(rename = "dumps.create")] -// #[deserr(rename = "dumps.create")] -// DumpsCreate, -// #[serde(rename = "snapshots.*")] -// #[deserr(rename = "snapshots.*")] -// SnapshotsAll, -// #[serde(rename = "snapshots.create")] -// #[deserr(rename = "snapshots.create")] -// SnapshotsCreate, -// #[serde(rename = "version")] -// #[deserr(rename = "version")] -// Version, -// #[serde(rename = "keys.create")] -// #[deserr(rename = "keys.create")] -// KeysAdd, -// #[serde(rename = "keys.get")] -// #[deserr(rename = "keys.get")] -// KeysGet, -// #[serde(rename = "keys.update")] -// #[deserr(rename = "keys.update")] -// KeysUpdate, -// #[serde(rename = "keys.delete")] -// #[deserr(rename = "keys.delete")] -// KeysDelete, -// #[serde(rename = "experimental.get")] -// #[deserr(rename = "experimental.get")] -// ExperimentalFeaturesGet, -// #[serde(rename = "experimental.update")] -// #[deserr(rename = "experimental.update")] -// ExperimentalFeaturesUpdate, -// } - impl Action { + const SERIALIZATION_MAP: [(&'static str, Self); 34] = [ + ("*", Self::All), + ("search", Self::Search), + ("documents.*", Self::DocumentsAll), + ("documents.add", Self::DocumentsAdd), + ("documents.get", Self::DocumentsGet), + ("documents.delete", Self::DocumentsDelete), + ("indexes.*", Self::IndexesAll), + ("indexes.create", Self::IndexesAdd), + ("indexes.get", Self::IndexesGet), + ("indexes.update", Self::IndexesUpdate), + ("indexes.delete", Self::IndexesDelete), + ("indexes.swap", Self::IndexesSwap), + ("tasks.*", Self::TasksAll), + ("tasks.cancel", Self::TasksCancel), + ("tasks.delete", Self::TasksDelete), + ("tasks.get", Self::TasksGet), + ("settings.*", Self::SettingsAll), + ("settings.get", Self::SettingsGet), + ("settings.update", Self::SettingsUpdate), + ("stats.*", Self::StatsAll), + ("stats.get", Self::StatsGet), + ("metrics.*", Self::MetricsAll), + ("metrics.get", Self::MetricsGet), + ("dumps.*", Self::DumpsAll), + ("dumps.create", Self::DumpsCreate), + ("snapshots.*", Self::SnapshotsAll), + ("snapshots.create", Self::SnapshotsCreate), + ("version", Self::Version), + ("keys.create", Self::KeysAdd), + ("keys.get", Self::KeysGet), + ("keys.update", Self::KeysUpdate), + ("keys.delete", Self::KeysDelete), + ("experimental.get", Self::ExperimentalFeaturesGet), + ("experimental.update", Self::ExperimentalFeaturesUpdate), + ]; + pub const fn from_repr(repr: u8) -> Option { use actions::*; match repr { @@ -464,44 +299,102 @@ impl Action { } pub const fn repr(&self) -> u8 { - *self as u8 + self.bits() + } +} + +impl Deserr for Action { + fn deserialize_from_value( + value: deserr::Value, + location: deserr::ValuePointerRef<'_>, + ) -> Result { + match value { + deserr::Value::String(s) => { + match Self::SERIALIZATION_MAP.iter().find(|(serialized, _)| s == *serialized) { + Some((_, action)) => Ok(*action), + None => Err(deserr::take_cf_content(E::error::( + None, + deserr::ErrorKind::Unexpected { msg: format!("TODO {}", s) }, + location, + ))), + } + } + _ => Err(take_cf_content(E::error( + None, + deserr::ErrorKind::IncorrectValueKind { + actual: value, + accepted: &[deserr::ValueKind::String], + }, + location, + ))), + } + } +} + +impl<'de> Deserialize<'de> for Action { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct Visitor; + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = Action; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "the name of a valid action (string)") + } + + fn visit_str(self, s: &str) -> Result + where + E: serde::de::Error, + { + // @TODO: Make a to_serialized and to_desiralized on Action + match Self::Value::SERIALIZATION_MAP.iter().find(|(serialized, _)| s == *serialized) + { + Some((_, action)) => Ok(*action), + None => Err(E::invalid_value(serde::de::Unexpected::Str(s), &"a valid action")), + } + } + } + + deserializer.deserialize_str(Visitor) } } pub mod actions { - use super::Action::*; + use super::Action as A; - pub(crate) const ALL: u8 = All.repr(); - pub const SEARCH: u8 = Search.repr(); - pub const DOCUMENTS_ALL: u8 = DocumentsAll.repr(); - pub const DOCUMENTS_ADD: u8 = DocumentsAdd.repr(); - pub const DOCUMENTS_GET: u8 = DocumentsGet.repr(); - pub const DOCUMENTS_DELETE: u8 = DocumentsDelete.repr(); - pub const INDEXES_ALL: u8 = IndexesAll.repr(); - pub const INDEXES_CREATE: u8 = IndexesAdd.repr(); - pub const INDEXES_GET: u8 = IndexesGet.repr(); - pub const INDEXES_UPDATE: u8 = IndexesUpdate.repr(); - pub const INDEXES_DELETE: u8 = IndexesDelete.repr(); - pub const INDEXES_SWAP: u8 = IndexesSwap.repr(); - pub const TASKS_ALL: u8 = TasksAll.repr(); - pub const TASKS_CANCEL: u8 = TasksCancel.repr(); - pub const TASKS_DELETE: u8 = TasksDelete.repr(); - pub const TASKS_GET: u8 = TasksGet.repr(); - pub const SETTINGS_ALL: u8 = SettingsAll.repr(); - pub const SETTINGS_GET: u8 = SettingsGet.repr(); - pub const SETTINGS_UPDATE: u8 = SettingsUpdate.repr(); - pub const STATS_ALL: u8 = StatsAll.repr(); - pub const STATS_GET: u8 = StatsGet.repr(); - pub const METRICS_ALL: u8 = MetricsAll.repr(); - pub const METRICS_GET: u8 = MetricsGet.repr(); - pub const DUMPS_ALL: u8 = DumpsAll.repr(); - pub const DUMPS_CREATE: u8 = DumpsCreate.repr(); - pub const SNAPSHOTS_CREATE: u8 = SnapshotsCreate.repr(); - pub const VERSION: u8 = Version.repr(); - pub const KEYS_CREATE: u8 = KeysAdd.repr(); - pub const KEYS_GET: u8 = KeysGet.repr(); - pub const KEYS_UPDATE: u8 = KeysUpdate.repr(); - pub const KEYS_DELETE: u8 = KeysDelete.repr(); - pub const EXPERIMENTAL_FEATURES_GET: u8 = ExperimentalFeaturesGet.repr(); - pub const EXPERIMENTAL_FEATURES_UPDATE: u8 = ExperimentalFeaturesUpdate.repr(); + pub(crate) const ALL: u8 = A::All.repr(); + pub const SEARCH: u8 = A::Search.repr(); + pub const DOCUMENTS_ALL: u8 = A::DocumentsAll.repr(); + pub const DOCUMENTS_ADD: u8 = A::DocumentsAdd.repr(); + pub const DOCUMENTS_GET: u8 = A::DocumentsGet.repr(); + pub const DOCUMENTS_DELETE: u8 = A::DocumentsDelete.repr(); + pub const INDEXES_ALL: u8 = A::IndexesAll.repr(); + pub const INDEXES_CREATE: u8 = A::IndexesAdd.repr(); + pub const INDEXES_GET: u8 = A::IndexesGet.repr(); + pub const INDEXES_UPDATE: u8 = A::IndexesUpdate.repr(); + pub const INDEXES_DELETE: u8 = A::IndexesDelete.repr(); + pub const INDEXES_SWAP: u8 = A::IndexesSwap.repr(); + pub const TASKS_ALL: u8 = A::TasksAll.repr(); + pub const TASKS_CANCEL: u8 = A::TasksCancel.repr(); + pub const TASKS_DELETE: u8 = A::TasksDelete.repr(); + pub const TASKS_GET: u8 = A::TasksGet.repr(); + pub const SETTINGS_ALL: u8 = A::SettingsAll.repr(); + pub const SETTINGS_GET: u8 = A::SettingsGet.repr(); + pub const SETTINGS_UPDATE: u8 = A::SettingsUpdate.repr(); + pub const STATS_ALL: u8 = A::StatsAll.repr(); + pub const STATS_GET: u8 = A::StatsGet.repr(); + pub const METRICS_ALL: u8 = A::MetricsAll.repr(); + pub const METRICS_GET: u8 = A::MetricsGet.repr(); + pub const DUMPS_ALL: u8 = A::DumpsAll.repr(); + pub const DUMPS_CREATE: u8 = A::DumpsCreate.repr(); + pub const SNAPSHOTS_CREATE: u8 = A::SnapshotsCreate.repr(); + pub const VERSION: u8 = A::Version.repr(); + pub const KEYS_CREATE: u8 = A::KeysAdd.repr(); + pub const KEYS_GET: u8 = A::KeysGet.repr(); + pub const KEYS_UPDATE: u8 = A::KeysUpdate.repr(); + pub const KEYS_DELETE: u8 = A::KeysDelete.repr(); + pub const EXPERIMENTAL_FEATURES_GET: u8 = A::ExperimentalFeaturesGet.repr(); + pub const EXPERIMENTAL_FEATURES_UPDATE: u8 = A::ExperimentalFeaturesUpdate.repr(); }