nu_plugin_core/serializers/
json.rs1use nu_plugin_protocol::{PluginInput, PluginOutput};
2use nu_protocol::{
3 ShellError,
4 shell_error::{self, io::IoError},
5};
6use serde::Deserialize;
7
8use crate::{Encoder, PluginEncoder};
9
10#[derive(Clone, Copy, Debug)]
17pub struct JsonSerializer;
18
19impl PluginEncoder for JsonSerializer {
20 fn name(&self) -> &str {
21 "json"
22 }
23}
24
25impl Encoder<PluginInput> for JsonSerializer {
26 fn encode(
27 &self,
28 plugin_input: &PluginInput,
29 writer: &mut impl std::io::Write,
30 ) -> Result<(), nu_protocol::ShellError> {
31 serde_json::to_writer(&mut *writer, plugin_input).map_err(json_encode_err)?;
32 writer.write_all(b"\n").map_err(|err| {
33 ShellError::Io(IoError::new_internal(
34 err,
35 "Failed to write final line break",
36 ))
37 })
38 }
39
40 fn decode(
41 &self,
42 reader: &mut impl std::io::BufRead,
43 ) -> Result<Option<PluginInput>, nu_protocol::ShellError> {
44 let mut de = serde_json::Deserializer::from_reader(reader);
45 PluginInput::deserialize(&mut de)
46 .map(Some)
47 .or_else(json_decode_err)
48 }
49}
50
51impl Encoder<PluginOutput> for JsonSerializer {
52 fn encode(
53 &self,
54 plugin_output: &PluginOutput,
55 writer: &mut impl std::io::Write,
56 ) -> Result<(), ShellError> {
57 serde_json::to_writer(&mut *writer, plugin_output).map_err(json_encode_err)?;
58 writer.write_all(b"\n").map_err(|err| {
59 ShellError::Io(IoError::new_internal(
60 err,
61 "JsonSerializer could not encode linebreak",
62 ))
63 })
64 }
65
66 fn decode(
67 &self,
68 reader: &mut impl std::io::BufRead,
69 ) -> Result<Option<PluginOutput>, ShellError> {
70 let mut de = serde_json::Deserializer::from_reader(reader);
71 PluginOutput::deserialize(&mut de)
72 .map(Some)
73 .or_else(json_decode_err)
74 }
75}
76
77fn json_encode_err(err: serde_json::Error) -> ShellError {
79 if err.is_io() {
80 ShellError::Io(IoError::new_internal(
81 shell_error::io::ErrorKind::from_std(err.io_error_kind().expect("is io")),
82 "Could not encode with json",
83 ))
84 } else {
85 ShellError::PluginFailedToEncode {
86 msg: err.to_string(),
87 }
88 }
89}
90
91fn json_decode_err<T>(err: serde_json::Error) -> Result<Option<T>, ShellError> {
93 if err.is_eof() {
94 Ok(None)
95 } else if err.is_io() {
96 Err(ShellError::Io(IoError::new_internal(
97 shell_error::io::ErrorKind::from_std(err.io_error_kind().expect("is io")),
98 "Could not decode with json",
99 )))
100 } else {
101 Err(ShellError::PluginFailedToDecode {
102 msg: err.to_string(),
103 })
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110 crate::serializers::tests::generate_tests!(JsonSerializer {});
111
112 #[test]
113 fn json_ends_in_newline() {
114 let mut out = vec![];
115 JsonSerializer {}
116 .encode(&PluginInput::Call(0, PluginCall::Signature), &mut out)
117 .expect("serialization error");
118 let string = std::str::from_utf8(&out).expect("utf-8 error");
119 assert!(
120 string.ends_with('\n'),
121 "doesn't end with newline: {string:?}"
122 );
123 }
124
125 #[test]
126 fn json_has_no_other_newlines() {
127 let mut out = vec![];
128 let output = PluginOutput::Data(
130 0,
131 StreamData::List(Value::test_list(vec![
132 Value::test_int(4),
133 Value::test_string("newline\ncontaining\nstring"),
135 ])),
136 );
137 JsonSerializer {}
138 .encode(&output, &mut out)
139 .expect("serialization error");
140 let string = std::str::from_utf8(&out).expect("utf-8 error");
141 assert_eq!(1, string.chars().filter(|ch| *ch == '\n').count());
142 }
143}