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