use derive_more::From;
use serde::{Deserialize, Serialize};
use serde_json::value::RawValue;
use std::sync::Arc;
use crate::MaybeUndefined;
pub type Meta = serde_json::Map<String, serde_json::Value>;
pub fn apply_meta_update(stored: &mut MaybeUndefined<Meta>, update: MaybeUndefined<Meta>) {
match update {
MaybeUndefined::Undefined => {}
MaybeUndefined::Null => *stored = MaybeUndefined::Null,
MaybeUndefined::Value(patch) => {
let mut meta = match std::mem::take(stored) {
MaybeUndefined::Value(meta) => meta,
MaybeUndefined::Undefined | MaybeUndefined::Null => Meta::new(),
};
for (key, value) in patch {
if value.is_null() {
meta.remove(&key);
} else {
meta.insert(key, value);
}
}
*stored = MaybeUndefined::Value(meta);
}
}
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(transparent)]
#[non_exhaustive]
pub struct ExtRequest {
#[serde(skip)] pub method: Arc<str>,
#[cfg_attr(feature = "schemars", schemars(with = "serde_json::Value"))]
pub params: Arc<RawValue>,
}
impl ExtRequest {
#[must_use]
pub fn new(method: impl Into<Arc<str>>, params: Arc<RawValue>) -> Self {
Self {
method: method.into(),
params,
}
}
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Serialize, Deserialize, From)]
#[serde(transparent)]
#[non_exhaustive]
pub struct ExtResponse(
#[cfg_attr(feature = "schemars", schemars(with = "serde_json::Value"))] pub Arc<RawValue>,
);
impl ExtResponse {
#[must_use]
pub fn new(params: Arc<RawValue>) -> Self {
Self(params)
}
}
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(transparent)]
#[non_exhaustive]
pub struct ExtNotification {
#[serde(skip)] pub method: Arc<str>,
#[cfg_attr(feature = "schemars", schemars(with = "serde_json::Value"))]
pub params: Arc<RawValue>,
}
impl ExtNotification {
#[must_use]
pub fn new(method: impl Into<Arc<str>>, params: Arc<RawValue>) -> Self {
Self {
method: method.into(),
params,
}
}
}
#[cfg(test)]
mod tests {
use serde_json::{from_value, json};
use super::*;
fn meta(value: serde_json::Value) -> MaybeUndefined<Meta> {
from_value(value).unwrap()
}
#[test]
fn meta_update_patches_top_level_keys() {
let mut stored = meta(json!({
"zed.dev/kept": 1,
"zed.dev/removed": true,
"acme.dev/nested": {"a": 1, "b": 2},
"acme.dev/list": [1, 2]
}));
apply_meta_update(
&mut stored,
meta(json!({
"zed.dev/removed": null,
"zed.dev/absent": null,
"acme.dev/nested": {"b": 3, "c": null},
"acme.dev/list": [3],
"acme.dev/added": []
})),
);
assert_eq!(
stored,
meta(json!({
"zed.dev/kept": 1,
"acme.dev/nested": {"b": 3, "c": null},
"acme.dev/list": [3],
"acme.dev/added": []
}))
);
}
#[test]
fn meta_update_omitted_empty_and_null() {
let original = meta(json!({"zed.dev/kept": 1}));
let mut stored = original.clone();
apply_meta_update(&mut stored, MaybeUndefined::Undefined);
assert_eq!(stored, original);
apply_meta_update(&mut stored, meta(json!({})));
assert_eq!(stored, original);
apply_meta_update(&mut stored, MaybeUndefined::Null);
assert_eq!(stored, MaybeUndefined::Null);
}
#[test]
fn meta_update_starts_from_empty_after_clear_or_on_first_update() {
for initial in [MaybeUndefined::Undefined, MaybeUndefined::Null] {
let mut stored = initial;
apply_meta_update(
&mut stored,
meta(json!({"zed.dev/added": 1, "zed.dev/removed": null})),
);
assert_eq!(stored, meta(json!({"zed.dev/added": 1})));
}
}
}