lsp_io/
utils.rs

1use bytes::{Buf, BytesMut};
2use lsp_ty::{NotificationMessage, OneOf3, RequestMessage, ResponseMessage};
3
4use super::BUF_SIZE;
5
6fn parse_header(headers: &str) -> Result<(String, usize), String> {
7    let mut segs = headers.split(':');
8    let key = segs.next().unwrap();
9    let mut content_type = String::new();
10    let mut content_length = 0;
11    if key == "Content-Length" {
12        content_length = segs.next().unwrap().trim().parse().unwrap();
13    } else if key == "Content-Type" {
14        content_type = segs.next().unwrap().trim().to_string();
15    } else {
16        tracing::error!("unknown header {}", key);
17    }
18    if content_length == 0 {
19        let msg = "empty content length or missing Content-Length header";
20        tracing::error!(msg);
21        return Err(msg.to_string());
22    }
23    Ok((content_type, content_length))
24}
25
26#[derive(Debug, Clone)]
27pub struct CodecState {
28    pub content_type: String,
29    pub read_content_length: usize,
30    pub read_buf: [u8; BUF_SIZE],
31    pub read_data: BytesMut,
32}
33
34impl CodecState {
35    pub fn consume_body(
36        &mut self,
37    ) -> serde_json::Result<OneOf3<RequestMessage, ResponseMessage, NotificationMessage>> {
38        let msg = serde_json::from_slice(&self.read_data[..self.read_content_length])?;
39        // reset state after read
40        self.read_data.advance(self.read_content_length);
41        self.read_content_length = 0;
42        Ok(msg)
43    }
44
45    pub fn parse_header(&mut self, headers: String) -> Result<(), String> {
46        let (content_type, content_length) = parse_header(&headers)?;
47        self.content_type = content_type;
48        self.read_content_length = content_length;
49        Ok(())
50    }
51
52    fn header_pos(&self) -> Option<usize> {
53        self.read_data
54            .windows(4)
55            .position(|s| s == [b'\r', b'\n', b'\r', b'\n'])
56    }
57
58    pub fn try_parse_header(&mut self) -> Option<Result<(), String>> {
59        self.header_pos().map(|stop_at| {
60            let headers = String::from_utf8(self.read_data[..stop_at].to_vec()).unwrap();
61            self.read_data.advance(stop_at + 4);
62            self.parse_header(headers)
63        })
64    }
65
66    pub fn body_ready(&self) -> bool {
67        self.read_content_length <= self.read_data.len()
68    }
69}
70
71impl Default for CodecState {
72    fn default() -> Self {
73        Self {
74            content_type: "application/vscode-jsonrpc; charset=utf-8".to_string(),
75            read_content_length: Default::default(),
76            read_buf: [0; BUF_SIZE],
77            read_data: BytesMut::with_capacity(BUF_SIZE),
78        }
79    }
80}