diff --git a/src/resp.rs b/src/resp.rs new file mode 100644 index 0000000..7546f58 --- /dev/null +++ b/src/resp.rs @@ -0,0 +1,83 @@ +use std::io::{self, BufRead, Read}; // Убрали Write, добавили Read +use std::net::TcpStream; + +#[derive(Debug)] +pub enum Value { + SimpleString(String), + Error(String), + Integer(i64), + BulkString(String), + Array(Vec), + Null, +} + +pub struct Decoder<'a> { + stream: &'a TcpStream, + reader: io::BufReader<&'a TcpStream>, +} + +impl<'a> Decoder<'a> { + pub fn new(stream: &'a TcpStream) -> Self { + Self { + stream, + reader: io::BufReader::new(stream), + } + } + + pub fn decode(&mut self) -> io::Result { + let mut line = String::new(); + self.reader.read_line(&mut line)?; + + if line.is_empty() { + return Err(io::Error::new(io::ErrorKind::ConnectionAborted, "Connection closed by server")); + } + + let prefix = line.chars().next().unwrap_or('-'); + let content = &line[1..].trim_end(); + + match prefix { + '+' => Ok(Value::SimpleString(content.to_string())), + '-' => Ok(Value::Error(content.to_string())), + ':' => { + let num = content.parse().map_err(|e| { + io::Error::new(io::ErrorKind::InvalidData, format!("Invalid integer: {}", e)) + })?; + Ok(Value::Integer(num)) + } + '$' => { + let len: i64 = content.parse().map_err(|e| { + io::Error::new(io::ErrorKind::InvalidData, format!("Invalid bulk string length: {}", e)) + })?; + + if len == -1 { + Ok(Value::Null) + } else { + let mut buf = vec![0; len as usize]; + self.reader.read_exact(&mut buf)?; + // Read trailing \r\n + let mut crlf = [0; 2]; + self.reader.read_exact(&mut crlf)?; + Ok(Value::BulkString(String::from_utf8(buf).map_err(|e| { + io::Error::new(io::ErrorKind::InvalidData, format!("Invalid UTF-8: {}", e)) + })?)) + } + } + '*' => { + let len: i64 = content.parse().map_err(|e| { + io::Error::new(io::ErrorKind::InvalidData, format!("Invalid array length: {}", e)) + })?; + + if len == -1 { + Ok(Value::Null) + } else { + let mut arr = Vec::with_capacity(len as usize); + for _ in 0..len { + arr.push(self.decode()?); + } + Ok(Value::Array(arr)) + } + } + _ => Err(io::Error::new(io::ErrorKind::InvalidData, format!("Unknown prefix: {}", prefix))), + } + } +}