8000 Refactor ascii check by stphnt · Pull Request #94 · stphnt/zproto · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Refactor ascii check #94

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 25 additions & 16 deletions src/ascii/port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,9 +426,9 @@ impl<'a, B: Backend> Port<'a, B> {
builder: ResponseBuilder::default(),
packet_hook: None,
unexpected_alert_hook: None,
// Use check::default to check all responses by default
// Use check::strict to check all responses by default
default_response_check: Some(DefaultResponseCheckDebugWrapper::from(
check::AnyResponseCheck::from(check::default::<AnyResponse>()),
check::AnyResponseCheck::from(check::strict::<AnyResponse>()),
)),
}
}
Expand Down Expand Up @@ -1539,7 +1539,7 @@ impl<'a, B: Backend> Port<'a, B> {
///
/// The contents of all responses are checked by the port when they are
/// received using the `checker` defined here. By default the `Port` uses
/// [`check::default`], unless it is explicit set otherwise. To temporarily
/// [`check::strict`], unless it is explicitly set otherwise. To temporarily
/// change how the contents of responses are checked, it is advisable to use
/// one of the `Port`'s [`*_with_check`](Port::command_reply_with_check)
/// methods, which take a temporary override that will be used for that call.
Expand Down Expand Up @@ -1614,7 +1614,7 @@ impl<'a, B: Backend> Port<'a, B> {
/// # }
/// ```
///
/// Provide an explicit type to solve the compiler error.
/// Provide an explicit type to resolve the compiler error.
///
/// ```
/// # use zproto::backend::Backend;
Expand All @@ -1632,13 +1632,17 @@ impl<'a, B: Backend> Port<'a, B> {
/// # use zproto::backend::Backend;
/// # use zproto::ascii::{check, AnyResponse, Port};
/// # fn wrapper<B: Backend>(mut port: Port<B>) -> Result<(), Box<dyn std::error::Error>> {
/// port.set_default_response_check(check::default::<AnyResponse>());
/// port.set_default_response_check(check::strict::<AnyResponse>());
/// # Ok(())
/// # }
/// ```
///
/// Use [`clear_default_response_check`](Port::clear_default_response_check)
/// to not check the contents of responses.
/// to not check the contents of responses. However, in the majority of
/// cases it is recommended to check the contents of responses with a check
/// that is at least as rigorous as [`check::minimal`]. It ensures all reply
/// flags are `OK` and that there are no fault-level (`F*`) warnings, as
/// they indicate an immediate issue with a device.
pub fn set_default_response_check<K, R>(
&mut self,
checker: K,
Expand All @@ -1655,14 +1659,19 @@ impl<'a, B: Backend> Port<'a, B> {
.map(|wrapper| wrapper.0)
}

/// Clear the default response check. The contents of responses will not be
/// checked.
///
/// In most cases this is not recommended. In the vast majority of cases
/// reply flags should be checked, ensuring that they are OK.
/// Clear the default response check and return the previous check. The
/// contents of responses will no longer be checked.
///
/// See [`set_default_response_check`](Port::set_default_response_check) for
/// more details on default response checks.
///
/// ## Warning
///
/// In the majority of cases it is recommended to check the contents of
/// responses with a check that is at least as rigorous as
/// [`check::minimal`]. It ensures all reply flags are `OK` and that there
/// are no fault-level (`F*`) warnings, as they indicate an immediate issue
/// with a device.
pub fn clear_default_response_check(
&mut self,
) -> Option<Box<dyn check::Check<AnyResponse> + 'a>> {
Expand Down Expand Up @@ -2348,12 +2357,12 @@ mod test {
/// allows for the explicit type
#[test]
fn type_inference_regression_test() {
use super::check::default;
use super::check::strict;

let mut port = Port::open_mock();
let _ = port.response_with_check::<AnyResponse, _>(default());
let _ = port.response_n_with_check::<AnyResponse, _>(2, default());
let _ = port.responses_until_timeout_with_check::<AnyResponse, _>(default());
let _ = port.response_with_check::<AnyResponse, _>(strict());
let _ = port.response_n_with_check::<AnyResponse, _>(2, strict());
let _ = port.responses_until_timeout_with_check::<AnyResponse, _>(strict());
}

#[test]
Expand Down Expand Up @@ -2497,7 +2506,7 @@ mod test {
use super::*;

/// Check that the default response check after creating a port is
/// `check::default()`, which behaves as follows:
/// `check::strict()`, which behaves as follows:
/// * replies with any warning or an RJ flag should raise an error
/// * alerts with any warning should raise an error
/// * infos are not checked
Expand Down
103 changes: 77 additions & 26 deletions src/ascii/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ mod private {
use super::{Alert, AnyResponse, AsciiCheckError, Flag, Info, Kind, Reply, Warning};
use crate::error::{AsciiCheckFlagError, AsciiCheckWarningError};

pub trait Sealed: DataMut + DefaultCheck + WillTryFromSucceed<AnyResponse> {}
pub trait Sealed: DataMut + CommonChecks + WillTryFromSucceed<AnyResponse> {}

impl Sealed for Reply {}
impl Sealed for Alert {}
Expand Down Expand Up @@ -420,34 +420,51 @@ mod private {
}
}

/// Defines the default check to use for the kind of response.
pub trait DefaultCheck: Sized {
/// Return the default check for this response.
/// Defines the common checks for responses.
pub trait CommonChecks: Sized {
/// Return a strict check for this response.
///
/// This needs to be defined here so we can get the default check based on
/// the response type, but users shouldn't access it here. Instead users
/// should use [`crate::ascii::check::default`]
fn default_check() -> fn(Self) -> Result<Self, AsciiCheckError<Self>>;
/// should use [`crate::ascii::check::strict`]
fn strict() -> fn(Self) -> Result<Self, AsciiCheckError<Self>>;
/// Return the minimally recommended check for this response.
///
/// This needs to be defined here so we can get the default check based on
/// the response type, but users shouldn't access it here. Instead users
/// should use [`crate::ascii::check::minimal`]
fn minimal() -> fn(Self) -> Result<Self, AsciiCheckError<Self>>;
}

impl DefaultCheck for AnyResponse {
fn default_check() -> fn(Self) -> Result<Self, AsciiCheckError<Self>> {
impl CommonChecks for AnyResponse {
fn strict() -> fn(Self) -> Result<Self, AsciiCheckError<Self>> {
|response| match response {
AnyResponse::Reply(reply) => Reply::default_check()(reply)
.map(From::from)
.map_err(From::from),
AnyResponse::Info(info) => Info::default_check()(info)
.map(From::from)
.map_err(From::from),
AnyResponse::Alert(alert) => Alert::default_check()(alert)
.map(From::from)
.map_err(From::from),
AnyResponse::Reply(reply) => {
Reply::strict()(reply).map(From::from).map_err(From::from)
}
AnyResponse::Info(info) => Info::strict()(info).map(From::from).map_err(From::from),
AnyResponse::Alert(alert) => {
Alert::strict()(alert).map(From::from).map_err(From::from)
}
}
}
fn minimal() -> fn(Self) -> Result<Self, AsciiCheckError<Self>> {
|response| match response {
AnyResponse::Reply(reply) => {
Reply::minimal()(reply).map(From::from).map_err(From::from)
}
AnyResponse::Info(info) => {
Info::minimal()(info).map(From::from).map_err(From::from)
}
AnyResponse::Alert(alert) => {
Alert::minimal()(alert).map(From::from).map_err(From::from)
}
}
}
}
impl DefaultCheck for Reply {
// If this logic changes update the documentation for `ascii::check::default`
fn default_check() -> fn(Self) -> Result<Self, AsciiCheckError<Self>> {
impl CommonChecks for Reply {
// If this logic changes update the documentation for `ascii::check::strict`
fn strict() -> fn(Self) -> Result<Self, AsciiCheckError<Self>> {
|reply| {
if reply.flag() != Flag::Ok {
Err(AsciiCheckFlagError::new(Flag::Ok, reply).into())
Expand All @@ -462,16 +479,36 @@ mod private {
}
}
}
// If this logic changes update the documentation for `ascii::check::minimal`
fn minimal() -> fn(Self) -> Result<Self, AsciiCheckError<Self>> {
|reply| {
if reply.flag() != Flag::Ok {
Err(AsciiCheckFlagError::new(Flag::Ok, reply).into())
} else if reply.warning().is_fault() {
Err(AsciiCheckWarningError::new(
"expected warning below fault (F) level",
reply,
)
.into())
} else {
Ok(reply)
}
}
}
}
impl DefaultCheck for Info {
// If this logic changes update the documentation for `ascii::check::default`
fn default_check() -> fn(Self) -> Result<Self, AsciiCheckError<Self>> {
impl CommonChecks for Info {
// If this logic changes update the documentation for `ascii::check::strict`
fn strict() -> fn(Self) -> Result<Self, AsciiCheckError<Self>> {
Ok
}
// If this logic changes update the documentation for `ascii::check::minimal`
fn minimal() -> fn(Self) -> Result<Self, AsciiCheckError<Self>> {
Ok
}
}
impl DefaultCheck for Alert {
// If this logic changes update the documentation for `ascii::check::default`
fn default_check() -> fn(Self) -> Result<Self, AsciiCheckError<Self>> {
impl CommonChecks for Alert {
// If this logic changes update the documentation for `ascii::check::strict`
fn strict() -> fn(Self) -> Result<Self, AsciiCheckError<Self>> {
|alert| {
if alert.warning() == Warning::NONE {
Ok(alert)
Expand All @@ -484,6 +521,20 @@ mod private {
}
}
}
// If this logic changes update the documentation for `ascii::check::minimal`
fn minimal() -> fn(Self) -> Result<Self, AsciiCheckError<Self>> {
|alert| {
if alert.warning().is_fault() {
Err(AsciiCheckWarningError::new(
"expected warning below fault (F) level",
alert,
)
.into())
} else {
Ok(alert)
}
}
}
}

/// A trait indicating whether calling `TryFrom::try_from` on the type will
Expand Down
Loading
0