add manual impl Serialize for BatchInfo

This commit is contained in:
Dmitry Belyaev 2023-08-24 13:34:29 +03:00
parent 85a879e9ec
commit 67e7d4daef
Signed by: b4tman
GPG Key ID: 41A00BF15EA7E5F3
3 changed files with 114 additions and 17 deletions

7
Cargo.lock generated
View File

@ -215,9 +215,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.3.3"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "block-buffer"
@ -330,6 +330,7 @@ dependencies = [
"async-compression 0.4.1",
"async-stream",
"async_zip",
"bitflags 2.4.0",
"fmmap",
"futures",
"futures-core",
@ -1403,7 +1404,7 @@ version = "0.38.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5"
dependencies = [
"bitflags 2.3.3",
"bitflags 2.4.0",
"errno 0.3.1",
"libc",
"linux-raw-sys 0.4.3",

View File

@ -47,6 +47,7 @@ zstd = { version = "^0.12", default-features = false, optional = true }
memmap = { version = "0.7.0", optional = true }
pin-project = { version = "1.1.3", optional = true }
postcard = { version = "1.0.6", default-features = false }
bitflags = "2.4.0"
[dev-dependencies]
insta = { version = "1.31.0", features = ["yaml"] }

View File

@ -1,32 +1,77 @@
use serde_derive::{Deserialize, Serialize};
use serde::ser::SerializeStruct;
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
use bitflags::bitflags;
bitflags! {
#[repr(transparent)]
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BatchFlags: u16 {
const FILENAME = 1;
const DESCRIPTION = 1 << 1;
const AUTHOR = 1 << 2;
const COMMENT = 1 << 3;
const URL = 1 << 4;
const DATE = 1 << 5;
const PROCESSED = 1 << 6;
const REDACTED = 1 << 7;
const COPYRIGHT = 1 << 8;
const THEME = 1 << 9;
const KIND = 1 << 10;
const SOURCE = 1 << 11;
const RATING = 1 << 12;
}
}
bitflags! {
#[repr(transparent)]
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct QuestionFlags: u16 {
const NUM = 1;
const AUTHOR = 1 << 1;
const COMMENT = 1 << 2;
const COMMENT1 = 1 << 3;
const TOUR = 1 << 4;
const URL = 1 << 5;
const DATE = 1 << 6;
const PROCESSED_BY = 1 << 7;
const REDACTED_BY = 1 << 8;
const COPYRIGHT = 1 << 9;
const THEME = 1 << 10;
const KIND = 1 << 11;
const SOURCE = 1 << 12;
const RATING = 1 << 13;
const BATCH_INFO = 1 << 14;
}
}
#[derive(Debug, Default, Clone, Deserialize, PartialEq)]
pub struct BatchInfo {
#[serde(default, skip_serializing_if = "String::is_empty")]
#[serde(default)]
pub filename: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
#[serde(default)]
pub description: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
#[serde(default)]
pub author: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
#[serde(default)]
pub comment: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
#[serde(default)]
pub url: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
#[serde(default)]
pub date: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
#[serde(default)]
pub processed_by: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
#[serde(default)]
pub redacted_by: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
#[serde(default)]
pub copyright: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
#[serde(default)]
pub theme: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
#[serde(default)]
pub kind: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
#[serde(default)]
pub source: String,
#[serde(default, skip_serializing_if = "String::is_empty")]
#[serde(default)]
pub rating: String,
}
@ -79,6 +124,56 @@ impl BatchInfo {
}
}
macro_rules! count_string_fields {
(($self:ident, $flags:ident, $len:ident, $FlagsType:ident) <- {$($field:ident:$flag:ident),+} ) => {$(
$len += 1;
if !$self.$field.is_empty() {
$flags |= $FlagsType::$flag;
}
)+}
}
macro_rules! serialize_fields {
(($self:ident, $flags:ident, $state:ident, $FlagsType:ident) <- {$($field:ident:$flag:ident),+} ) => {$(
if $flags.intersects($FlagsType::$flag) {
$state.serialize_field(std::stringify!($field), &$self.$field)?;
} else {
$state.skip_field(std::stringify!($field))?;
}
)+}
}
impl serde::Serialize for BatchInfo {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let is_human_readable = serializer.is_human_readable();
let mut flags: BatchFlags = Default::default();
let mut len = 1;
count_string_fields!((self, flags, len, BatchFlags) <- {
filename: FILENAME, description: DESCRIPTION, author: AUTHOR, comment: COMMENT, url: URL, date: DATE,
processed_by: PROCESSED, copyright: COPYRIGHT, theme: THEME, kind: KIND, source: SOURCE, rating: RATING
});
let mut state = serializer.serialize_struct("BatchInfo", len)?;
if is_human_readable {
state.skip_field("_flags")?;
} else {
state.serialize_field("_flags", &flags.bits())?;
}
serialize_fields!((self, flags, state, BatchFlags) <- {
filename: FILENAME, description: DESCRIPTION, author: AUTHOR, comment: COMMENT, url: URL, date: DATE,
processed_by: PROCESSED, copyright: COPYRIGHT, theme: THEME, kind: KIND, source: SOURCE, rating: RATING
});
state.end()
}
}
#[cfg(any(feature = "convert", feature = "convert_async"))]
pub mod convert_common {
use super::{BatchInfo, Question};