use std::{borrow::Cow, convert::TryFrom, io};
use crate::{
io::ParseBuf,
misc::raw::{bytes::LenEnc, Const, RawBytes, RawInt},
proto::MyDeserialize,
};
use super::jsonb;
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum JsonDiffOperation {
REPLACE,
INSERT,
REMOVE,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, thiserror::Error)]
#[error("Unknown JsonDiff operation {}", _0)]
#[repr(transparent)]
pub struct UnknownJsonDiffOperation(pub u8);
impl From<UnknownJsonDiffOperation> for u8 {
fn from(x: UnknownJsonDiffOperation) -> Self {
x.0
}
}
impl TryFrom<u8> for JsonDiffOperation {
type Error = UnknownJsonDiffOperation;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::REPLACE),
1 => Ok(Self::INSERT),
2 => Ok(Self::REMOVE),
x => Err(UnknownJsonDiffOperation(x)),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct JsonDiff<'a> {
path: RawBytes<'a, LenEnc>,
operation: Const<JsonDiffOperation, u8>,
value: Option<jsonb::Value<'a>>,
}
impl<'a> JsonDiff<'a> {
pub fn path(&'a self) -> &'a [u8] {
self.path.as_bytes()
}
pub fn path_str(&'a self) -> Cow<'a, str> {
self.path.as_str()
}
pub fn operation(&self) -> JsonDiffOperation {
*self.operation
}
pub fn value(&'a self) -> Option<&'a jsonb::Value<'a>> {
self.value.as_ref()
}
pub fn into_owned(self) -> JsonDiff<'static> {
JsonDiff {
path: self.path.into_owned(),
operation: self.operation,
value: self.value.map(|x| x.into_owned()),
}
}
}
impl<'de> MyDeserialize<'de> for JsonDiff<'de> {
const SIZE: Option<usize> = None;
type Ctx = ();
fn deserialize((): Self::Ctx, buf: &mut ParseBuf<'de>) -> io::Result<Self> {
let operation: Const<JsonDiffOperation, u8> = buf.parse(())?;
let path = buf.parse(())?;
let value = if *operation != JsonDiffOperation::REMOVE {
let len: RawInt<LenEnc> = buf.parse(())?;
let mut value: ParseBuf = buf.parse(*len as usize)?;
Some(value.parse(())?)
} else {
None
};
Ok(Self {
path,
operation,
value,
})
}
}