1use crate::frame::error::FrameParseError;
6use crate::frame::FrameTypeMarker;
7use crate::Role;
8
9#[derive(Clone, Copy, Debug, PartialEq)]
12pub enum CommandResponse {
13 Command,
14 Response,
15}
16
17impl CommandResponse {
18 pub(crate) fn classify(
20 role: Role,
21 frame_type: FrameTypeMarker,
22 cr_bit: bool,
23 ) -> Result<Self, FrameParseError> {
24 use FrameTypeMarker::*;
25 if role.is_multiplexer_started() {
27 let res = match (frame_type, role, cr_bit) {
28 (UnnumberedInfoHeaderCheck, Role::Initiator, _) => Ok(CommandResponse::Command),
31 (UnnumberedInfoHeaderCheck, Role::Responder, _) => Ok(CommandResponse::Response),
32 (UnnumberedInfoHeaderCheck, role, _) => Err(FrameParseError::InvalidRole(role)),
33 (_, Role::Initiator, true) | (_, Role::Responder, false) => {
36 Ok(CommandResponse::Command)
37 }
38 (_, _, _) => Ok(CommandResponse::Response),
39 };
40 return res;
41 }
42
43 match (frame_type, cr_bit) {
45 (SetAsynchronousBalancedMode, true) => Ok(CommandResponse::Command),
46 (SetAsynchronousBalancedMode, false) => Ok(CommandResponse::Response),
47 (DisconnectedMode | UnnumberedAcknowledgement, true) => Ok(CommandResponse::Response),
48 (DisconnectedMode | UnnumberedAcknowledgement, false) => Ok(CommandResponse::Command),
49 (frame_type, _) => Err(FrameParseError::InvalidFrameBeforeMuxStartup(frame_type)),
50 }
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 use assert_matches::assert_matches;
59
60 #[test]
61 fn classify_frame_after_mux_startup() {
62 let role = Role::Initiator;
64 let frame = FrameTypeMarker::SetAsynchronousBalancedMode;
65 assert_matches!(
66 CommandResponse::classify(role, frame, true),
67 Ok(CommandResponse::Command)
68 );
69
70 let role = Role::Initiator;
71 let frame = FrameTypeMarker::SetAsynchronousBalancedMode;
72 assert_matches!(
73 CommandResponse::classify(role, frame, false),
74 Ok(CommandResponse::Response)
75 );
76
77 let role = Role::Responder;
78 let frame = FrameTypeMarker::Disconnect;
79 assert_matches!(
80 CommandResponse::classify(role, frame, true),
81 Ok(CommandResponse::Response)
82 );
83
84 let role = Role::Responder;
85 let frame = FrameTypeMarker::DisconnectedMode;
86 assert_matches!(
87 CommandResponse::classify(role, frame, false),
88 Ok(CommandResponse::Command)
89 );
90 }
91
92 #[test]
93 fn classify_uih_frame_after_mux_startup() {
94 let frame = FrameTypeMarker::UnnumberedInfoHeaderCheck;
95
96 assert_matches!(
97 CommandResponse::classify(Role::Initiator, frame, true),
98 Ok(CommandResponse::Command)
99 );
100
101 assert_matches!(
102 CommandResponse::classify(Role::Initiator, frame, false),
103 Ok(CommandResponse::Command)
104 );
105
106 assert_matches!(
107 CommandResponse::classify(Role::Responder, frame, true),
108 Ok(CommandResponse::Response)
109 );
110
111 assert_matches!(
112 CommandResponse::classify(Role::Responder, frame, false),
113 Ok(CommandResponse::Response)
114 );
115 }
116
117 #[test]
120 fn classify_sabm_before_mux_startup() {
121 let role = Role::Unassigned;
123 let frame = FrameTypeMarker::SetAsynchronousBalancedMode;
124 let cr_bit = true;
125 assert_matches!(
126 CommandResponse::classify(role, frame, cr_bit),
127 Ok(CommandResponse::Command)
128 );
129
130 let role = Role::Negotiating;
132 let frame = FrameTypeMarker::SetAsynchronousBalancedMode;
133 let cr_bit = false;
134 assert_matches!(
135 CommandResponse::classify(role, frame, cr_bit),
136 Ok(CommandResponse::Response)
137 );
138 }
139
140 #[test]
142 fn classify_dm_before_mux_startup() {
143 let frame = FrameTypeMarker::DisconnectedMode;
144
145 let role = Role::Negotiating;
147 let cr_bit = true;
148 assert_matches!(
149 CommandResponse::classify(role, frame, cr_bit),
150 Ok(CommandResponse::Response)
151 );
152
153 let role = Role::Unassigned;
154 let cr_bit = false;
155 assert_matches!(
156 CommandResponse::classify(role, frame, cr_bit),
157 Ok(CommandResponse::Command)
158 );
159 }
160
161 #[test]
162 fn classify_ua_before_mux_startup() {
163 let frame = FrameTypeMarker::UnnumberedAcknowledgement;
164
165 let role = Role::Unassigned;
166 let cr_bit = true;
167 assert_matches!(
168 CommandResponse::classify(role, frame, cr_bit),
169 Ok(CommandResponse::Response)
170 );
171
172 let role = Role::Negotiating;
173 let cr_bit = false;
174 assert_matches!(
175 CommandResponse::classify(role, frame, cr_bit),
176 Ok(CommandResponse::Command)
177 );
178 }
179
180 #[test]
181 fn classify_invalid_frame_before_mux_startup_is_error() {
182 let role = Role::Unassigned;
184 let frame = FrameTypeMarker::Disconnect;
185 let cr_bit = true;
186 assert_matches!(
187 CommandResponse::classify(role, frame, cr_bit),
188 Err(FrameParseError::InvalidFrameBeforeMuxStartup(_))
189 );
190
191 let role = Role::Unassigned;
193 let frame = FrameTypeMarker::UnnumberedInfoHeaderCheck;
194 let cr_bit = true;
195 assert_matches!(
196 CommandResponse::classify(role, frame, cr_bit),
197 Err(FrameParseError::InvalidFrameBeforeMuxStartup(_))
198 );
199 }
200}