use serde::{Deserialize, Serialize};
use std::ops::{Deref, DerefMut};
pub(crate) const DEFAULT_VERSION_KEY: &str = "version";
pub(crate) const DEFAULT_DATA_KEY: &str = "data";
#[derive(Debug, Clone)]
pub struct ForwardContext {
pub(crate) original_version: String,
pub(crate) unknown_fields: serde_json::Map<String, serde_json::Value>,
pub(crate) was_lossy: bool,
pub(crate) version_key: String,
pub(crate) data_key: String,
pub(crate) was_flat: bool,
}
impl ForwardContext {
pub(crate) fn new(
original_version: String,
unknown_fields: serde_json::Map<String, serde_json::Value>,
was_lossy: bool,
version_key: String,
data_key: String,
was_flat: bool,
) -> Self {
Self {
original_version,
unknown_fields,
was_lossy,
version_key,
data_key,
was_flat,
}
}
pub fn original_version(&self) -> &str {
&self.original_version
}
pub fn was_lossy(&self) -> bool {
self.was_lossy
}
pub fn unknown_fields(&self) -> &serde_json::Map<String, serde_json::Value> {
&self.unknown_fields
}
}
#[derive(Debug, Clone)]
pub struct Forwardable<T> {
pub inner: T,
ctx: ForwardContext,
}
impl<T> Forwardable<T> {
pub(crate) fn new(inner: T, ctx: ForwardContext) -> Self {
Self { inner, ctx }
}
pub fn original_version(&self) -> &str {
self.ctx.original_version()
}
pub fn was_lossy(&self) -> bool {
self.ctx.was_lossy()
}
pub fn unknown_fields(&self) -> &serde_json::Map<String, serde_json::Value> {
self.ctx.unknown_fields()
}
pub fn context(&self) -> &ForwardContext {
&self.ctx
}
pub fn into_inner(self) -> T {
self.inner
}
}
impl<T> Deref for Forwardable<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> DerefMut for Forwardable<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<T: Serialize> Serialize for Forwardable<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.inner.serialize(serializer)
}
}
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Forwardable<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let inner = T::deserialize(deserializer)?;
Ok(Self {
inner,
ctx: ForwardContext::new(
String::new(),
serde_json::Map::new(),
false,
DEFAULT_VERSION_KEY.to_string(),
DEFAULT_DATA_KEY.to_string(),
false,
),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
struct TestEntity {
id: String,
name: String,
}
#[test]
fn test_forwardable_deref() {
let entity = TestEntity {
id: "1".to_string(),
name: "test".to_string(),
};
let ctx = ForwardContext::new(
"2.0.0".to_string(),
serde_json::Map::new(),
true,
"version".to_string(),
"data".to_string(),
false,
);
let forwardable = Forwardable::new(entity, ctx);
assert_eq!(forwardable.id, "1");
assert_eq!(forwardable.name, "test");
}
#[test]
fn test_forwardable_deref_mut() {
let entity = TestEntity {
id: "1".to_string(),
name: "test".to_string(),
};
let ctx = ForwardContext::new(
"2.0.0".to_string(),
serde_json::Map::new(),
true,
"version".to_string(),
"data".to_string(),
false,
);
let mut forwardable = Forwardable::new(entity, ctx);
forwardable.name = "updated".to_string();
assert_eq!(forwardable.name, "updated");
}
#[test]
fn test_forwardable_context_access() {
let mut unknown = serde_json::Map::new();
unknown.insert(
"new_field".to_string(),
serde_json::Value::String("value".to_string()),
);
let entity = TestEntity {
id: "1".to_string(),
name: "test".to_string(),
};
let ctx = ForwardContext::new(
"2.0.0".to_string(),
unknown,
true,
"version".to_string(),
"data".to_string(),
false,
);
let forwardable = Forwardable::new(entity, ctx);
assert_eq!(forwardable.original_version(), "2.0.0");
assert!(forwardable.was_lossy());
assert_eq!(forwardable.unknown_fields().len(), 1);
assert!(forwardable.unknown_fields().contains_key("new_field"));
}
#[test]
fn test_forwardable_into_inner() {
let entity = TestEntity {
id: "1".to_string(),
name: "test".to_string(),
};
let ctx = ForwardContext::new(
"1.0.0".to_string(),
serde_json::Map::new(),
false,
"version".to_string(),
"data".to_string(),
false,
);
let forwardable = Forwardable::new(entity.clone(), ctx);
let inner = forwardable.into_inner();
assert_eq!(inner, entity);
}
#[test]
fn test_forwardable_serialize() {
let entity = TestEntity {
id: "1".to_string(),
name: "test".to_string(),
};
let ctx = ForwardContext::new(
"2.0.0".to_string(),
serde_json::Map::new(),
true,
"version".to_string(),
"data".to_string(),
false,
);
let forwardable = Forwardable::new(entity, ctx);
let json = serde_json::to_string(&forwardable).unwrap();
assert!(json.contains("\"id\":\"1\""));
assert!(json.contains("\"name\":\"test\""));
}
#[test]
fn test_forwardable_deserialize() {
let json = r#"{"id":"1","name":"test"}"#;
let forwardable: Forwardable<TestEntity> = serde_json::from_str(json).unwrap();
assert_eq!(forwardable.id, "1");
assert_eq!(forwardable.name, "test");
assert_eq!(forwardable.original_version(), "");
assert!(!forwardable.was_lossy());
}
}