use std::fmt;
#[cfg(any(feature = "lsp", feature = "dap"))]
use std::io::{self, BufRead, Write};
use serde::{Deserialize, Serialize};
#[cfg(feature = "dap")]
use crate::dap;
#[cfg(feature = "lsp")]
use crate::lsp;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(transparent)]
pub struct RequestId(IdRepr);
impl RequestId {
#[cfg(all(feature = "dap", feature = "server"))]
pub(crate) fn dap(id: RequestId) -> i64 {
match id.0 {
IdRepr::I32(it) => it as i64,
IdRepr::String(it) => panic!("unexpected string ID in DAP: {it}"),
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[serde(untagged)]
enum IdRepr {
I32(i32),
String(String),
}
impl From<i32> for RequestId {
fn from(id: i32) -> RequestId {
RequestId(IdRepr::I32(id))
}
}
impl From<String> for RequestId {
fn from(id: String) -> RequestId {
RequestId(IdRepr::String(id))
}
}
impl fmt::Display for RequestId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
IdRepr::I32(it) => fmt::Display::fmt(it, f),
IdRepr::String(it) => fmt::Debug::fmt(it, f),
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ResponseError {
pub code: i32,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<serde_json::Value>,
}
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub enum ErrorCode {
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
ServerErrorStart = -32099,
ServerErrorEnd = -32000,
ServerNotInitialized = -32002,
UnknownErrorCode = -32001,
RequestCanceled = -32800,
ContentModified = -32801,
ServerCancelled = -32802,
RequestFailed = -32803,
}
#[cfg(feature = "lsp")]
pub type LspMessage = lsp::Message;
#[cfg(feature = "dap")]
pub type DapMessage = dap::Message;
#[derive(Debug)]
pub enum Message {
#[cfg(feature = "lsp")]
Lsp(LspMessage),
#[cfg(feature = "dap")]
Dap(DapMessage),
}
impl Message {
#[cfg(feature = "lsp")]
pub fn read_lsp<R: std::io::BufRead>(reader: &mut R) -> std::io::Result<Option<Self>> {
let msg = lsp::Message::read(reader)?;
Ok(msg.map(Message::Lsp))
}
#[cfg(feature = "dap")]
pub fn read_dap<R: std::io::BufRead>(reader: &mut R) -> std::io::Result<Option<Self>> {
let msg = dap::Message::read(reader)?;
Ok(msg.map(Message::Dap))
}
pub fn write<W: std::io::Write>(self, _writer: &mut W) -> std::io::Result<()> {
match self {
#[cfg(feature = "lsp")]
Message::Lsp(msg) => msg.write(_writer),
#[cfg(feature = "dap")]
Message::Dap(msg) => msg.write(_writer),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MessageKind {
#[cfg(feature = "lsp")]
Lsp,
#[cfg(feature = "dap")]
Dap,
}
pub trait GetMessageKind {
fn get_message_kind() -> MessageKind;
}
#[cfg(feature = "lsp")]
impl GetMessageKind for LspMessage {
fn get_message_kind() -> MessageKind {
MessageKind::Lsp
}
}
#[cfg(feature = "dap")]
impl GetMessageKind for DapMessage {
fn get_message_kind() -> MessageKind {
MessageKind::Dap
}
}
#[allow(unused)]
pub(crate) enum LspOrDapResponse {
#[cfg(feature = "lsp")]
Lsp(lsp::Response),
#[cfg(feature = "dap")]
Dap(dap::Response),
}
#[cfg(any(feature = "lsp", feature = "dap"))]
pub(crate) fn read_msg_text(inp: &mut dyn BufRead) -> io::Result<Option<String>> {
let mut size = None;
let mut buf = String::new();
loop {
buf.clear();
if inp.read_line(&mut buf)? == 0 {
return Ok(None);
}
if !buf.ends_with("\r\n") {
return Err(invalid_data_fmt!("malformed header: {buf:?}"));
}
let buf = &buf[..buf.len() - 2];
if buf.is_empty() {
break;
}
let mut parts = buf.splitn(2, ": ");
let header_name = parts.next().unwrap();
let header_value = parts
.next()
.ok_or_else(|| invalid_data_fmt!("malformed header: {buf:?}"))?;
if header_name.eq_ignore_ascii_case("Content-Length") {
size = Some(header_value.parse::<usize>().map_err(invalid_data)?);
}
}
let size: usize = size.ok_or_else(|| invalid_data_fmt!("no Content-Length"))?;
let mut buf = buf.into_bytes();
buf.resize(size, 0);
inp.read_exact(&mut buf)?;
let buf = String::from_utf8(buf).map_err(invalid_data)?;
log::debug!("< {buf}");
Ok(Some(buf))
}
#[cfg(any(feature = "lsp", feature = "dap"))]
pub(crate) fn write_msg_text(out: &mut dyn Write, msg: &str) -> io::Result<()> {
log::debug!("> {msg}");
write!(out, "Content-Length: {}\r\n\r\n", msg.len())?;
out.write_all(msg.as_bytes())?;
out.flush()?;
Ok(())
}
#[cfg(any(feature = "lsp", feature = "dap"))]
pub(crate) fn invalid_data(
error: impl Into<Box<dyn std::error::Error + Send + Sync>>,
) -> io::Error {
io::Error::new(io::ErrorKind::InvalidData, error)
}
#[cfg(any(feature = "lsp", feature = "dap"))]
macro_rules! invalid_data_fmt {
($($tt:tt)*) => ($crate::invalid_data(format!($($tt)*)))
}
#[cfg(any(feature = "lsp", feature = "dap"))]
pub(crate) use invalid_data_fmt;