1use std::io::{self, BufRead, Read, Write};
16
17pub const MAX_FRAME: usize = 16 * 1024 * 1024;
20
21pub fn write_line<W: Write, T: serde::Serialize>(w: &mut W, value: &T) -> io::Result<()> {
27 let buf = serde_json::to_vec(value).map_err(io::Error::other)?;
28 debug_assert!(
29 !buf.contains(&b'\n'),
30 "compact JSON must not contain newlines"
31 );
32 w.write_all(&buf)?;
33 w.write_all(b"\n")?;
34 w.flush()
35}
36
37pub fn read_line<R: BufRead>(r: &mut R) -> io::Result<Option<Vec<u8>>> {
41 let mut buf = Vec::new();
42 loop {
43 let mut byte = [0u8; 1];
44 match r.read(&mut byte)? {
45 0 => {
46 return if buf.is_empty() {
48 Ok(None)
49 } else {
50 Err(io::Error::new(io::ErrorKind::UnexpectedEof, "EOF mid-line"))
51 };
52 }
53 _ => {
54 if byte[0] == b'\n' {
55 return Ok(Some(buf));
56 }
57 if buf.len() >= MAX_FRAME {
58 return Err(io::Error::new(
59 io::ErrorKind::InvalidData,
60 "line exceeds MAX_FRAME",
61 ));
62 }
63 buf.push(byte[0]);
64 }
65 }
66 }
67}
68
69pub fn write_frame<W: Write, T: serde::Serialize>(w: &mut W, value: &T) -> io::Result<()> {
73 let buf = serde_json::to_vec(value).map_err(io::Error::other)?;
74 if buf.len() > MAX_FRAME {
75 return Err(io::Error::new(
76 io::ErrorKind::InvalidData,
77 "frame exceeds MAX_FRAME",
78 ));
79 }
80 w.write_all(&(buf.len() as u32).to_be_bytes())?;
81 w.write_all(&buf)?;
82 w.flush()
83}
84
85pub fn read_frame<R: Read>(r: &mut R) -> io::Result<Option<Vec<u8>>> {
89 let mut len_buf = [0u8; 4];
90 if !read_exact_or_eof(r, &mut len_buf)? {
91 return Ok(None); }
93 let len = u32::from_be_bytes(len_buf) as usize;
94 if len > MAX_FRAME {
95 return Err(io::Error::new(
96 io::ErrorKind::InvalidData,
97 "frame length exceeds MAX_FRAME",
98 ));
99 }
100 let mut buf = vec![0u8; len];
101 r.read_exact(&mut buf)?;
102 Ok(Some(buf))
103}
104
105fn read_exact_or_eof<R: Read>(r: &mut R, buf: &mut [u8]) -> io::Result<bool> {
108 let mut filled = 0;
109 while filled < buf.len() {
110 match r.read(&mut buf[filled..])? {
111 0 => {
112 return if filled == 0 {
113 Ok(false)
114 } else {
115 Err(io::Error::new(
116 io::ErrorKind::UnexpectedEof,
117 "EOF mid-frame",
118 ))
119 };
120 }
121 n => filled += n,
122 }
123 }
124 Ok(true)
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use crate::rpc::{Id, Response};
131 use std::io::Cursor;
132
133 #[test]
134 fn line_roundtrip() {
135 let mut buf = Vec::new();
136 write_line(&mut buf, &serde_json::json!({"a": 1})).unwrap();
137 assert_eq!(buf.last(), Some(&b'\n'));
138 let mut cur = Cursor::new(buf);
139 let line = read_line(&mut cur).unwrap().unwrap();
140 let v: serde_json::Value = serde_json::from_slice(&line).unwrap();
141 assert_eq!(v["a"], 1);
142 assert!(read_line(&mut cur).unwrap().is_none());
144 }
145
146 #[test]
147 fn frame_roundtrip() {
148 let mut buf = Vec::new();
149 let resp = Response::ok(Id::Num(1), serde_json::json!({"ok": true}));
150 write_frame(&mut buf, &resp).unwrap();
151 let mut cur = Cursor::new(buf);
152 let frame = read_frame(&mut cur).unwrap().unwrap();
153 let back: Response = serde_json::from_slice(&frame).unwrap();
154 assert_eq!(back.id, Id::Num(1));
155 assert!(read_frame(&mut cur).unwrap().is_none());
156 }
157
158 #[test]
159 fn frame_with_newline_payload_survives() {
160 let mut buf = Vec::new();
162 write_frame(&mut buf, &serde_json::json!({"text": "line1\nline2"})).unwrap();
163 let mut cur = Cursor::new(buf);
164 let frame = read_frame(&mut cur).unwrap().unwrap();
165 let v: serde_json::Value = serde_json::from_slice(&frame).unwrap();
166 assert_eq!(v["text"], "line1\nline2");
167 }
168
169 #[test]
170 fn oversize_length_rejected() {
171 let mut bytes = (MAX_FRAME as u32 + 1).to_be_bytes().to_vec();
172 bytes.push(0);
173 let mut cur = Cursor::new(bytes);
174 assert!(read_frame(&mut cur).is_err());
175 }
176}