Skip to content

Commit

Permalink
models: RawValue strips newlines
Browse files Browse the repository at this point in the history
We have several contexts where we'd like to directly serialize types
that contain RawValue and presume that they're valid serializations for
newline-delimited JSON.

To make that assumption, we must know that RawValue can never contain a
newline.
  • Loading branch information
jgraettinger committed Sep 13, 2024
1 parent edf3443 commit f618926
Showing 1 changed file with 42 additions and 5 deletions.
47 changes: 42 additions & 5 deletions crates/models/src/raw_value.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
#[derive(serde::Serialize, serde::Deserialize, Clone)]
/// RawValue is like serde_json::value::RawValue, but removes newlines to ensure
/// values can safely be used in newline-delimited contexts.
#[derive(serde::Serialize, Clone)]
pub struct RawValue(Box<serde_json::value::RawValue>);

impl RawValue {
pub fn is_null(&self) -> bool {
return self.get() == "null";
}
pub fn from_str(s: &str) -> serde_json::Result<Self> {
serde_json::value::RawValue::from_string(s.to_owned()).map(Into::into)
Self::from_string(s.to_owned())
}
pub fn from_string(s: String) -> serde_json::Result<Self> {
serde_json::value::RawValue::from_string(s).map(Into::into)
pub fn from_string(mut s: String) -> serde_json::Result<Self> {
s.retain(|c| c != '\n'); // Strip newlines.
let value = serde_json::value::RawValue::from_string(s)?;
Ok(Self(value))
}
pub fn from_value(value: &serde_json::Value) -> Self {
Self::from_string(value.to_string()).unwrap()
Expand All @@ -19,6 +23,16 @@ impl RawValue {
}
}

impl<'de> serde::Deserialize<'de> for RawValue {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let inner = Box::<serde_json::value::RawValue>::deserialize(deserializer)?;
Ok(inner.into())
}
}

impl Default for RawValue {
fn default() -> Self {
Self(serde_json::value::RawValue::from_string("null".to_string()).unwrap())
Expand All @@ -27,7 +41,12 @@ impl Default for RawValue {

impl From<Box<serde_json::value::RawValue>> for RawValue {
fn from(value: Box<serde_json::value::RawValue>) -> Self {
Self(value)
if value.get().contains('\n') {
let s: Box<str> = value.into();
Self::from_string(s.into()).unwrap()
} else {
Self(value)
}
}
}

Expand Down Expand Up @@ -73,3 +92,21 @@ impl schemars::JsonSchema for RawValue {
serde_json::Value::json_schema(gen)
}
}

#[cfg(test)]
mod test {

#[test]
fn test_newlines_are_removed() {
let fixture = serde_json::to_string_pretty(&serde_json::json!({
"one": 2,
"three": [4, 5]
}))
.unwrap();

let v = serde_json::value::RawValue::from_string(fixture).unwrap();
assert!(v.get().contains('\n'));
let v = super::RawValue::from(v);
assert!(!v.get().contains('\n'));
}
}

0 comments on commit f618926

Please sign in to comment.