hindsight_copilot/
parser.rs1use serde_json::StreamDeserializer;
7use std::io::Read;
8
9use crate::error::CopilotError;
10use crate::lsp::LspMessage;
11
12pub struct LogParser<R: Read> {
14 deserializer: StreamDeserializer<'static, serde_json::de::IoRead<R>, LspMessage>,
15}
16
17impl<R: Read> LogParser<R> {
18 pub fn new(reader: R) -> Self {
20 let deserializer = serde_json::Deserializer::from_reader(reader).into_iter();
21 Self { deserializer }
22 }
23}
24
25impl<R: Read> Iterator for LogParser<R> {
26 type Item = Result<LspMessage, CopilotError>;
27
28 fn next(&mut self) -> Option<Self::Item> {
29 self.deserializer
30 .next()
31 .map(|result| result.map_err(CopilotError::from))
32 }
33}
34
35pub fn parse_json_stream(json: &str) -> Result<Vec<LspMessage>, CopilotError> {
41 let mut parser = LogParser::new(json.as_bytes());
42 let mut messages = Vec::new();
43
44 for result in &mut parser {
45 messages.push(result?);
46 }
47
48 Ok(messages)
49}
50
51pub fn parse_single_message(json: &str) -> Result<LspMessage, CopilotError> {
57 serde_json::from_str(json).map_err(CopilotError::from)
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use similar_asserts::assert_eq;
64 use std::io::Cursor;
65
66 #[test]
67 fn test_log_parser_single_message() {
68 let json = r#"{"jsonrpc":"2.0","method":"test","id":1}"#;
69 let reader = Cursor::new(json);
70 let mut parser = LogParser::new(reader);
71
72 let msg = parser
73 .next()
74 .expect("should have message")
75 .expect("should parse");
76 assert_eq!(msg.jsonrpc, "2.0");
77 assert_eq!(msg.method, Some("test".to_string()));
78
79 assert!(parser.next().is_none());
80 }
81
82 #[test]
83 fn test_log_parser_multiple_messages() {
84 let json = r#"{"jsonrpc":"2.0","method":"first","id":1}
85{"jsonrpc":"2.0","method":"second","id":2}"#;
86 let reader = Cursor::new(json);
87 let parser = LogParser::new(reader);
88
89 let messages: Vec<_> = parser.collect();
90 assert_eq!(messages.len(), 2);
91 assert!(messages[0].is_ok());
92 assert!(messages[1].is_ok());
93 }
94
95 #[test]
96 fn test_log_parser_empty_input() {
97 let json = "";
98 let reader = Cursor::new(json);
99 let mut parser = LogParser::new(reader);
100
101 assert!(parser.next().is_none());
102 }
103
104 #[test]
105 fn test_log_parser_invalid_json() {
106 let json = r#"{"jsonrpc":"2.0" invalid"#;
107 let reader = Cursor::new(json);
108 let mut parser = LogParser::new(reader);
109
110 let result = parser.next().expect("should have result");
111 assert!(result.is_err());
112 }
113
114 #[test]
115 fn test_parse_json_stream() {
116 let json = r#"{"jsonrpc":"2.0","method":"a","id":1}{"jsonrpc":"2.0","method":"b","id":2}"#;
117 let messages = parse_json_stream(json).expect("should parse");
118
119 assert_eq!(messages.len(), 2);
120 assert_eq!(messages[0].method, Some("a".to_string()));
121 assert_eq!(messages[1].method, Some("b".to_string()));
122 }
123
124 #[test]
125 fn test_parse_json_stream_empty() {
126 let messages = parse_json_stream("").expect("should parse");
127 assert!(messages.is_empty());
128 }
129
130 #[test]
131 fn test_parse_single_message() {
132 let json = r#"{"jsonrpc":"2.0","method":"test","id":1,"params":{"uri":"file:///test.rs"}}"#;
133 let msg = parse_single_message(json).expect("should parse");
134
135 assert_eq!(msg.jsonrpc, "2.0");
136 assert_eq!(msg.method, Some("test".to_string()));
137 assert!(msg.params.is_some());
138 }
139
140 #[test]
141 fn test_parse_single_message_invalid() {
142 let result = parse_single_message("not json");
143 assert!(result.is_err());
144 }
145
146 #[test]
147 fn test_parse_message_with_all_fields() {
148 let json = r#"{
149 "jsonrpc": "2.0",
150 "id": 42,
151 "method": "textDocument/completion",
152 "params": {"position": {"line": 10, "character": 5}},
153 "result": {"completions": []},
154 "error": null
155 }"#;
156
157 let msg = parse_single_message(json).expect("should parse");
158 assert_eq!(msg.id, Some(serde_json::json!(42)));
159 assert_eq!(msg.method, Some("textDocument/completion".to_string()));
160 assert!(msg.params.is_some());
161 }
162}