1use std::collections::HashMap;
2use std::convert::TryFrom;
3
4use bytes::Bytes;
5
6use crate::Error;
7
8pub type RawFrame = HashMap<Vec<u8>, Bytes>;
9pub(crate) type Response = Result<RawFrame, WireError>;
10
11#[derive(Debug, Clone)]
12pub(crate) struct WireError {
13 pub(crate) code: Bytes,
14 pub(crate) description: Bytes,
15}
16
17#[derive(Debug, Clone)]
18pub(crate) enum Frame {
19 Request {
20 command: Bytes,
21 tag: Option<Bytes>,
22 fields: RawFrame,
23 },
24 Response {
25 tag: Bytes,
26 response: Response,
27 },
28}
29
30impl TryFrom<RawFrame> for Frame {
31 type Error = crate::Error;
32
33 fn try_from(mut frame: RawFrame) -> Result<Self, Self::Error> {
34 if frame.contains_key(b"_command".as_ref()) {
35 if frame.contains_key(b"_error".as_ref()) || frame.contains_key(b"_answer".as_ref()) {
36 return Err(Error::ConfusedFrame);
37 }
38 let command = frame.remove(b"_command".as_ref()).unwrap();
39 let tag = frame.remove(b"_ask".as_ref());
40
41 Ok(Frame::Request {
42 command,
43 tag,
44 fields: frame,
45 })
46 } else if frame.contains_key(b"_answer".as_ref()) {
47 if frame.contains_key(b"_error".as_ref()) || frame.contains_key(b"_command".as_ref()) {
48 return Err(Error::ConfusedFrame);
49 }
50
51 let tag = frame.remove(b"_answer".as_ref()).unwrap();
52 Ok(Frame::Response {
53 tag,
54 response: Ok(frame),
55 })
56 } else if frame.contains_key(b"_error".as_ref()) {
57 if frame.contains_key(b"_answer".as_ref()) || frame.contains_key(b"_command".as_ref()) {
58 return Err(Error::ConfusedFrame);
59 }
60 let tag = frame.remove(b"_error".as_ref()).unwrap();
61 let code = frame
62 .remove(b"_error_code".as_ref())
63 .ok_or(Error::IncompleteErrorFrame)?;
64 let description = frame
65 .remove(b"_error_description".as_ref())
66 .ok_or(Error::IncompleteErrorFrame)?;
67
68 Ok(Frame::Response {
69 tag,
70 response: Err(WireError { code, description }),
71 })
72 } else {
73 Err(Error::ConfusedFrame)
74 }
75 }
76}