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