Skip to content

Commit f618926

Browse files
committed
models: RawValue strips newlines
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.
1 parent edf3443 commit f618926

File tree

1 file changed

+42
-5
lines changed

1 file changed

+42
-5
lines changed

crates/models/src/raw_value.rs

+42-5
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
#[derive(serde::Serialize, serde::Deserialize, Clone)]
1+
/// RawValue is like serde_json::value::RawValue, but removes newlines to ensure
2+
/// values can safely be used in newline-delimited contexts.
3+
#[derive(serde::Serialize, Clone)]
24
pub struct RawValue(Box<serde_json::value::RawValue>);
35

46
impl RawValue {
57
pub fn is_null(&self) -> bool {
68
return self.get() == "null";
79
}
810
pub fn from_str(s: &str) -> serde_json::Result<Self> {
9-
serde_json::value::RawValue::from_string(s.to_owned()).map(Into::into)
11+
Self::from_string(s.to_owned())
1012
}
11-
pub fn from_string(s: String) -> serde_json::Result<Self> {
12-
serde_json::value::RawValue::from_string(s).map(Into::into)
13+
pub fn from_string(mut s: String) -> serde_json::Result<Self> {
14+
s.retain(|c| c != '\n'); // Strip newlines.
15+
let value = serde_json::value::RawValue::from_string(s)?;
16+
Ok(Self(value))
1317
}
1418
pub fn from_value(value: &serde_json::Value) -> Self {
1519
Self::from_string(value.to_string()).unwrap()
@@ -19,6 +23,16 @@ impl RawValue {
1923
}
2024
}
2125

26+
impl<'de> serde::Deserialize<'de> for RawValue {
27+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
28+
where
29+
D: serde::Deserializer<'de>,
30+
{
31+
let inner = Box::<serde_json::value::RawValue>::deserialize(deserializer)?;
32+
Ok(inner.into())
33+
}
34+
}
35+
2236
impl Default for RawValue {
2337
fn default() -> Self {
2438
Self(serde_json::value::RawValue::from_string("null".to_string()).unwrap())
@@ -27,7 +41,12 @@ impl Default for RawValue {
2741

2842
impl From<Box<serde_json::value::RawValue>> for RawValue {
2943
fn from(value: Box<serde_json::value::RawValue>) -> Self {
30-
Self(value)
44+
if value.get().contains('\n') {
45+
let s: Box<str> = value.into();
46+
Self::from_string(s.into()).unwrap()
47+
} else {
48+
Self(value)
49+
}
3150
}
3251
}
3352

@@ -73,3 +92,21 @@ impl schemars::JsonSchema for RawValue {
7392
serde_json::Value::json_schema(gen)
7493
}
7594
}
95+
96+
#[cfg(test)]
97+
mod test {
98+
99+
#[test]
100+
fn test_newlines_are_removed() {
101+
let fixture = serde_json::to_string_pretty(&serde_json::json!({
102+
"one": 2,
103+
"three": [4, 5]
104+
}))
105+
.unwrap();
106+
107+
let v = serde_json::value::RawValue::from_string(fixture).unwrap();
108+
assert!(v.get().contains('\n'));
109+
let v = super::RawValue::from(v);
110+
assert!(!v.get().contains('\n'));
111+
}
112+
}

0 commit comments

Comments
 (0)