use crate::frame::error::FrameParseError;
use crate::frame::FrameTypeMarker;
use crate::Role;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CommandResponse {
Command,
Response,
}
impl CommandResponse {
pub(crate) fn classify(
role: Role,
frame_type: FrameTypeMarker,
cr_bit: bool,
) -> Result<Self, FrameParseError> {
use FrameTypeMarker::*;
if role.is_multiplexer_started() {
let res = match (frame_type, role, cr_bit) {
(UnnumberedInfoHeaderCheck, Role::Initiator, _) => Ok(CommandResponse::Command),
(UnnumberedInfoHeaderCheck, Role::Responder, _) => Ok(CommandResponse::Response),
(UnnumberedInfoHeaderCheck, role, _) => Err(FrameParseError::InvalidRole(role)),
(_, Role::Initiator, true) | (_, Role::Responder, false) => {
Ok(CommandResponse::Command)
}
(_, _, _) => Ok(CommandResponse::Response),
};
return res;
}
match (frame_type, cr_bit) {
(SetAsynchronousBalancedMode, true) => Ok(CommandResponse::Command),
(SetAsynchronousBalancedMode, false) => Ok(CommandResponse::Response),
(DisconnectedMode | UnnumberedAcknowledgement, true) => Ok(CommandResponse::Response),
(DisconnectedMode | UnnumberedAcknowledgement, false) => Ok(CommandResponse::Command),
(frame_type, _) => Err(FrameParseError::InvalidFrameBeforeMuxStartup(frame_type)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert_matches::assert_matches;
#[test]
fn classify_frame_after_mux_startup() {
let role = Role::Initiator;
let frame = FrameTypeMarker::SetAsynchronousBalancedMode;
assert_matches!(
CommandResponse::classify(role, frame, true),
Ok(CommandResponse::Command)
);
let role = Role::Initiator;
let frame = FrameTypeMarker::SetAsynchronousBalancedMode;
assert_matches!(
CommandResponse::classify(role, frame, false),
Ok(CommandResponse::Response)
);
let role = Role::Responder;
let frame = FrameTypeMarker::Disconnect;
assert_matches!(
CommandResponse::classify(role, frame, true),
Ok(CommandResponse::Response)
);
let role = Role::Responder;
let frame = FrameTypeMarker::DisconnectedMode;
assert_matches!(
CommandResponse::classify(role, frame, false),
Ok(CommandResponse::Command)
);
}
#[test]
fn classify_uih_frame_after_mux_startup() {
let frame = FrameTypeMarker::UnnumberedInfoHeaderCheck;
assert_matches!(
CommandResponse::classify(Role::Initiator, frame, true),
Ok(CommandResponse::Command)
);
assert_matches!(
CommandResponse::classify(Role::Initiator, frame, false),
Ok(CommandResponse::Command)
);
assert_matches!(
CommandResponse::classify(Role::Responder, frame, true),
Ok(CommandResponse::Response)
);
assert_matches!(
CommandResponse::classify(Role::Responder, frame, false),
Ok(CommandResponse::Response)
);
}
#[test]
fn classify_sabm_before_mux_startup() {
let role = Role::Unassigned;
let frame = FrameTypeMarker::SetAsynchronousBalancedMode;
let cr_bit = true;
assert_matches!(
CommandResponse::classify(role, frame, cr_bit),
Ok(CommandResponse::Command)
);
let role = Role::Negotiating;
let frame = FrameTypeMarker::SetAsynchronousBalancedMode;
let cr_bit = false;
assert_matches!(
CommandResponse::classify(role, frame, cr_bit),
Ok(CommandResponse::Response)
);
}
#[test]
fn classify_dm_before_mux_startup() {
let frame = FrameTypeMarker::DisconnectedMode;
let role = Role::Negotiating;
let cr_bit = true;
assert_matches!(
CommandResponse::classify(role, frame, cr_bit),
Ok(CommandResponse::Response)
);
let role = Role::Unassigned;
let cr_bit = false;
assert_matches!(
CommandResponse::classify(role, frame, cr_bit),
Ok(CommandResponse::Command)
);
}
#[test]
fn classify_ua_before_mux_startup() {
let frame = FrameTypeMarker::UnnumberedAcknowledgement;
let role = Role::Unassigned;
let cr_bit = true;
assert_matches!(
CommandResponse::classify(role, frame, cr_bit),
Ok(CommandResponse::Response)
);
let role = Role::Negotiating;
let cr_bit = false;
assert_matches!(
CommandResponse::classify(role, frame, cr_bit),
Ok(CommandResponse::Command)
);
}
#[test]
fn classify_invalid_frame_before_mux_startup_is_error() {
let role = Role::Unassigned;
let frame = FrameTypeMarker::Disconnect;
let cr_bit = true;
assert_matches!(
CommandResponse::classify(role, frame, cr_bit),
Err(FrameParseError::InvalidFrameBeforeMuxStartup(_))
);
let role = Role::Unassigned;
let frame = FrameTypeMarker::UnnumberedInfoHeaderCheck;
let cr_bit = true;
assert_matches!(
CommandResponse::classify(role, frame, cr_bit),
Err(FrameParseError::InvalidFrameBeforeMuxStartup(_))
);
}
}