Skip to content

Commit b2c9024

Browse files
feat: new protocol for proc-macro-api
1 parent 5b2c8bc commit b2c9024

File tree

14 files changed

+714
-186
lines changed

14 files changed

+714
-186
lines changed

Cargo.lock

Lines changed: 94 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/proc-macro-api/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ rust-version.workspace = true
1414
[dependencies]
1515
serde.workspace = true
1616
serde_derive.workspace = true
17+
postcard = { version = "1.1.1", features = ["alloc"] }
1718
serde_json = { workspace = true, features = ["unbounded_depth"] }
1819
tracing.workspace = true
1920
rustc-hash.workspace = true
@@ -24,7 +25,7 @@ paths = { workspace = true, features = ["serde1"] }
2425
tt.workspace = true
2526
stdx.workspace = true
2627
# span = {workspace = true, default-features = false} does not work
27-
span = { path = "../span", version = "0.0.0", default-features = false}
28+
span = { path = "../span", version = "0.0.0", default-features = false }
2829

2930
intern.workspace = true
3031

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//! Implement how to send and receive legacy protocol message on stdio stream(protocol layer)
2+
//!
3+
//! The implementation follows:
4+
//! 1. Send Request
5+
//! 2. Receive Response
6+
7+
use std::{
8+
io::{self, BufRead, Write},
9+
sync::Arc,
10+
};
11+
12+
use crate::{
13+
ServerError,
14+
legacy_protocol::{
15+
json::{read_json, write_json},
16+
msg::{Request, Response},
17+
},
18+
task::TaskClient,
19+
};
20+
21+
/// Sends a request to the server and reads the response.
22+
fn send_request(
23+
mut writer: &mut dyn Write,
24+
mut reader: &mut dyn BufRead,
25+
req: Request,
26+
buf: &mut String,
27+
) -> Result<Option<Response>, ServerError> {
28+
use crate::legacy_protocol::msg::Message;
29+
30+
req.write(write_json, &mut writer).map_err(|err| ServerError {
31+
message: "failed to write request".into(),
32+
io: Some(Arc::new(err)),
33+
})?;
34+
let res = Response::read(read_json, &mut reader, buf).map_err(|err| ServerError {
35+
message: "failed to read response".into(),
36+
io: Some(Arc::new(err)),
37+
})?;
38+
Ok(res)
39+
}
40+
41+
pub struct JsonTaskClient<'a> {
42+
pub writer: &'a mut dyn Write,
43+
pub reader: &'a mut dyn BufRead,
44+
pub buf: &'a mut String,
45+
}
46+
47+
impl TaskClient for JsonTaskClient<'_> {
48+
type Task = Request;
49+
type TaskResult = Response;
50+
51+
// Implement send_task for Json Legacy Protocol
52+
// Basically what we have done in process.rs
53+
fn send_task(&mut self, task: Self::Task) -> Result<Self::TaskResult, ServerError> {
54+
send_request(self.writer, self.reader, task, self.buf).and_then(|res| {
55+
res.ok_or_else(|| {
56+
let message = "proc-macro server did not respond with data".to_owned();
57+
ServerError {
58+
io: Some(Arc::new(io::Error::new(io::ErrorKind::BrokenPipe, message.clone()))),
59+
message,
60+
}
61+
})
62+
})
63+
}
64+
}

crates/proc-macro-api/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,19 @@
88
pub mod legacy_protocol {
99
pub mod json;
1010
pub mod msg;
11+
pub mod task_impl;
1112
}
13+
14+
#[allow(dead_code)]
15+
pub mod new_protocol {
16+
pub mod encoding;
17+
pub mod msg;
18+
pub mod task_impl;
19+
}
20+
21+
#[allow(dead_code)]
22+
pub mod task;
23+
1224
mod process;
1325

1426
use paths::{AbsPath, AbsPathBuf};
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//! Implement how to encoding and decoding new protocol message on stdio stream
2+
//!
3+
//! Current implementation encoded message to | message length | message content |
4+
5+
use serde::de::DeserializeOwned;
6+
use std::io::{self, BufRead, Read, Write};
7+
8+
use super::msg::{C2SMsg, S2CMsg};
9+
10+
fn read_usize_be<R: Read + ?Sized>(reader: &mut R) -> io::Result<usize> {
11+
let mut buf = [0u8; std::mem::size_of::<usize>()];
12+
reader.read_exact(&mut buf)?;
13+
Ok(usize::from_be_bytes(buf))
14+
}
15+
16+
fn write_usize_be<W: Write + ?Sized>(writer: &mut W, value: usize) -> io::Result<()> {
17+
writer.write_all(&value.to_be_bytes()) // Convert and write as Big-Endian
18+
}
19+
20+
pub trait CodexPostcard: serde::Serialize + DeserializeOwned {
21+
fn receive_proto<R: BufRead + ?Sized>(reader: &mut R) -> io::Result<Self> {
22+
let msg_len = read_usize_be(reader)? as usize;
23+
let mut buf = vec![0u8; msg_len];
24+
25+
reader.read_exact(&mut buf)?;
26+
postcard::from_bytes::<Self>(&buf)
27+
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
28+
}
29+
30+
fn send_proto<W: Write + ?Sized>(&self, writer: &mut W) -> io::Result<()> {
31+
let bytes = postcard::to_allocvec(self)
32+
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
33+
34+
write_usize_be(writer, bytes.len())?;
35+
writer.write_all(&bytes)?;
36+
writer.flush()
37+
}
38+
}
39+
40+
// NOTE: With default implementation, C2SMsg and S2CMsg can both be send through stdio
41+
impl CodexPostcard for C2SMsg {}
42+
impl CodexPostcard for S2CMsg {}

0 commit comments

Comments
 (0)