use std::collections::HashMap;
use thiserror::Error;
#[derive(Debug, Error)]
#[error(r#"there's no "{field}" in `{type_str}`"#)]
pub struct DeserializeMaskError {
pub type_str: &'static str,
pub field: String,
pub depth: u8,
}
pub trait Maskable: Sized {
type Mask;
fn try_bitor_assign_mask(
mask: &mut Self::Mask,
field_mask_segs: &[&str],
) -> Result<(), DeserializeMaskError>;
}
pub trait SelfMaskable: Maskable {
fn apply_mask(&mut self, src: Self, mask: &Self::Mask);
}
pub trait OptionMaskable: Maskable {
fn apply_mask(&mut self, src: Self, mask: &Self::Mask) -> bool;
}
impl<T: SelfMaskable> OptionMaskable for T
where
T: Default,
T::Mask: PartialEq,
{
fn apply_mask(&mut self, src: Self, mask: &Self::Mask) -> bool {
self.apply_mask(src, mask);
true
}
}
impl<T: Maskable> Maskable for Option<T>
where
T: Default,
T::Mask: PartialEq,
{
type Mask = T::Mask;
fn try_bitor_assign_mask(
mask: &mut Self::Mask,
field_mask_segs: &[&str],
) -> Result<(), DeserializeMaskError> {
T::try_bitor_assign_mask(mask, field_mask_segs)
}
}
impl<T: OptionMaskable> SelfMaskable for Option<T>
where
T: Default,
T::Mask: PartialEq + Default,
{
fn apply_mask(&mut self, src: Self, mask: &Self::Mask) {
if mask == &Self::Mask::default() {
return;
}
match self {
Some(s) => match src {
Some(o) => {
if !s.apply_mask(o, mask) {
*self = None;
}
}
None => *self = None,
},
None => {
if let Some(o) = src {
let mut new = T::default();
if new.apply_mask(o, mask) {
*self = Some(new);
} else {
*self = None;
}
}
}
}
}
}
macro_rules! maskable {
($T:path) => {
impl Maskable for $T {
type Mask = bool;
fn try_bitor_assign_mask(
mask: &mut Self::Mask,
field_mask_segs: &[&str],
) -> Result<(), DeserializeMaskError> {
if field_mask_segs.len() == 0 {
*mask = true;
Ok(())
} else {
Err(DeserializeMaskError {
type_str: stringify!($T),
field: field_mask_segs[0].into(),
depth: 0,
})
}
}
}
impl SelfMaskable for $T {
fn apply_mask(&mut self, other: Self, mask: &Self::Mask) {
if *mask {
*self = other;
}
}
}
};
}
maskable!(bool);
maskable!(char);
maskable!(f32);
maskable!(f64);
maskable!(i8);
maskable!(u8);
maskable!(i16);
maskable!(u16);
maskable!(i32);
maskable!(u32);
maskable!(i64);
maskable!(u64);
maskable!(i128);
maskable!(u128);
maskable!(isize);
maskable!(usize);
maskable!(String);
#[cfg(feature = "prost")]
maskable!(prost::bytes::Bytes);
impl<T> Maskable for Vec<T> {
type Mask = bool;
fn try_bitor_assign_mask(
mask: &mut Self::Mask,
field_mask_segs: &[&str],
) -> Result<(), DeserializeMaskError> {
if field_mask_segs.is_empty() {
*mask = true;
Ok(())
} else {
Err(DeserializeMaskError {
type_str: "Vec",
field: field_mask_segs[0].into(),
depth: 0,
})
}
}
}
impl<T> SelfMaskable for Vec<T> {
fn apply_mask(&mut self, other: Self, mask: &Self::Mask) {
if *mask {
*self = other;
}
}
}
impl<K, V> Maskable for HashMap<K, V> {
type Mask = bool;
fn try_bitor_assign_mask(
mask: &mut Self::Mask,
field_mask_segs: &[&str],
) -> Result<(), DeserializeMaskError> {
if field_mask_segs.is_empty() {
*mask = true;
Ok(())
} else {
Err(DeserializeMaskError {
type_str: "HashMap",
field: field_mask_segs[0].into(),
depth: 0,
})
}
}
}
impl<K, V> SelfMaskable for HashMap<K, V> {
fn apply_mask(&mut self, other: Self, mask: &Self::Mask) {
if *mask {
*self = other;
}
}
}