use crate::core::{Type, TypeId};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Message {
Request(Request),
Response(Response),
Notification(Notification),
Heartbeat,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Request {
GetType { type_id: TypeId },
GetTypeByName { package: String, name: String },
CheckImplementation {
concrete_type: TypeId,
interface_type: TypeId,
},
CheckAssignable { from: TypeId, to: TypeId },
TypeCheckExpression {
expr: String,
context: TypeCheckContext,
},
GetCompletions {
prefix: String,
position: SourcePosition,
file: String,
},
ImportPackage { path: String },
ExportType { typ: Type },
Sync { checkpoint: u64 },
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct TypeCheckContext {
pub package: String,
pub file: String,
pub expected_type: Option<TypeId>,
pub scope_bindings: Vec<(String, TypeId)>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct SourcePosition {
pub line: u32,
pub column: u32,
pub offset: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Response {
Type(Option<Type>),
ImplementationCheck { implements: bool },
Assignable { assignable: bool },
TypeCheckResult(TypeCheckResult),
Completions(Vec<Completion>),
ImportResult(ImportResult),
ExportResult(ExportResult),
SyncAck { checkpoint: u64 },
Error(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TypeCheckResult {
pub valid: bool,
pub inferred_type: Option<TypeId>,
pub errors: Vec<TypeError>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TypeError {
pub message: String,
pub position: SourcePosition,
pub code: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Completion {
pub label: String,
pub kind: CompletionKind,
pub detail: String,
pub documentation: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CompletionKind {
Type,
Function,
Method,
Field,
Variable,
Constant,
Package,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImportResult {
pub success: bool,
pub types_imported: usize,
pub errors: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExportResult {
pub success: bool,
pub type_id: TypeId,
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Notification {
TypesChanged { type_ids: Vec<TypeId> },
PackageImported { path: String },
CompilationStarted,
CompilationFinished { success: bool },
Error { message: String },
}
pub const PROTOCOL_VERSION: &str = "0.1.0";
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageHeader {
pub version: String,
pub message_type: MessageType,
pub payload_len: u32,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum MessageType {
Request,
Response,
Notification,
Heartbeat,
}
impl MessageHeader {
pub fn new(message_type: MessageType, payload_len: u32) -> Self {
Self {
version: PROTOCOL_VERSION.to_string(),
message_type,
payload_len,
}
}
pub fn encode(&self) -> Vec<u8> {
bincode::serialize(self).unwrap_or_default()
}
pub fn decode(data: &[u8]) -> Option<Self> {
bincode::deserialize(data).ok()
}
}
pub fn serialize_message(msg: &Message) -> Vec<u8> {
bincode::serialize(msg).unwrap_or_default()
}
pub fn deserialize_message(data: &[u8]) -> Option<Message> {
bincode::deserialize(data).ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_message_serialization() {
let msg = Message::Request(Request::GetType {
type_id: TypeId(42),
});
let bytes = serialize_message(&msg);
let decoded = deserialize_message(&bytes);
assert!(decoded.is_some());
}
#[test]
fn test_header_encode_decode() {
let header = MessageHeader::new(MessageType::Request, 100);
let bytes = header.encode();
let decoded = MessageHeader::decode(&bytes);
assert!(decoded.is_some());
assert_eq!(decoded.unwrap().payload_len, 100);
}
}