1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
//! Defines the Response trait for AMQP 1.0 management responses.
use fe2o3_amqp_types::messaging::{FromBody, Message};
use crate::{
error::{InvalidType, StatusCodeNotFound, StatusError},
mgmt_ext::AmqpMessageManagementExt,
status::StatusCode,
};
/// A trait for AMQP 1.0 management response.
pub trait Response: Sized {
/// The status code of the response.
const STATUS_CODE: u16;
/// The body type of the response.
type Body: for<'de> FromBody<'de>;
/// The error type of the response.
type Error: From<StatusError> + From<InvalidType> + From<StatusCodeNotFound>;
/// Decodes the response from the message.
///
/// This is the only function that the user needs to implement in most cases. The full
/// response decoding takes place in the [`from_message`] function, please see [`from_message`]
/// for more details.
fn decode_message(message: Message<Self::Body>) -> Result<Self, Self::Error>;
/// Checks the status code and description of the response and returns `None` if status code is
/// not found or returns `Some(Err(error))` if the status code is not the expected one.
///
/// Please note that the blanket implementation will remove the status code and description.
/// The user should override the blanket implementation if they want to keep the status code
/// and description.
fn verify_status_code(message: &mut Message<Self::Body>) -> Result<StatusCode, Self::Error> {
let status_code = match message.remove_status_code().ok_or(StatusCodeNotFound {})? {
Ok(status_code) => status_code,
Err(err) => {
return Err(InvalidType {
expected: "u16".to_string(),
actual: format!("{:?}", err),
}
.into())
}
};
if status_code.0.get() != Self::STATUS_CODE {
let status_description = match message.remove_status_description() {
Some(Ok(status_description)) => Some(status_description),
Some(Err(err)) => {
return Err(InvalidType {
expected: "String".to_string(),
actual: format!("{:?}", err),
}
.into())
}
None => None,
};
return Err(StatusError {
code: status_code,
description: status_description.map(Into::into),
}
.into());
}
Ok(status_code)
}
/// Decodes the response from the message.
///
/// The blanket implementation simply calls [`verify_status_code`] and [`decode_message`],
/// which should work for most cases. The user should override this function if more than one
/// successful status code is expected.
fn from_message(mut message: Message<Self::Body>) -> Result<Self, Self::Error> {
Self::verify_status_code(&mut message)?;
Self::decode_message(message)
}
}