use std::fmt::Formatter; use std::ops::{Deref, DerefMut}; use std::result; use rocket::http::Status; use rocket::{async_trait, Data, Request}; use rocket::response::Responder; use serde::{Deserialize, Deserializer, Serialize}; use rocket::response::Result; use log::error; use quick_xml::se::Serializer; use quick_xml::{DeError, SeError}; use rocket::data::{ByteUnit, FromData, Outcome}; use rocket::response::content::RawXml; use serde::de::{DeserializeOwned, Error, Visitor}; pub fn serialize_with_version(serializable: &impl Serialize) -> result::Result, SeError>{ let mut write_dest = "".to_owned(); serializable.serialize(Serializer::new(&mut write_dest))?; Ok(write_dest.into_boxed_str()) } #[derive(Debug)] pub struct Xml(pub T); impl Deref for Xml{ type Target = T; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for Xml{ fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl<'r, 'o: 'r, T: Serialize> Responder<'r, 'o> for Xml{ fn respond_to(self, request: &'r Request<'_>) -> Result<'o> { match serialize_with_version(&self.0){ Ok(ser) => { RawXml(ser).respond_to(request) }, Err(e) => { error!("serialization error: {}", e); Err(Status::InternalServerError) } } } } #[async_trait] impl<'r, T: DeserializeOwned> FromData<'r> for Xml{ type Error = Option; async fn from_data(_req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> { let data = data.open(1 * ByteUnit::MB); let Ok(data) = data.into_string().await else { return Outcome::Error((Status::BadRequest, None)) }; match quick_xml::de::from_str(&data){ Ok(v) => Outcome::Success(Self(v)), Err(e) => Outcome::Error((Status::BadRequest, Some(e))) } } } pub struct YesNoVal(pub bool); struct YesNoVisitor; // #[derive(Debug, Error)] // #[error("did not find Y or N")] // struct NotYNError; impl<'de> Visitor<'de> for YesNoVisitor{ type Value = YesNoVal; fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { write!(formatter, "expected Y or N") } fn visit_str(self, v: &str) -> result::Result where E: Error, { match v{ "Y" => Ok(YesNoVal(true)), "N" => Ok(YesNoVal(false)), _ => Err(E::custom("didnt get N or Y")) } } fn visit_bytes(self, v: &[u8]) -> result::Result where E: Error, { const Y_BYTES: &[u8] = "Y".as_bytes(); const N_BYTES: &[u8] = "N".as_bytes(); match v{ Y_BYTES => Ok(YesNoVal(true)), N_BYTES => Ok(YesNoVal(false)), _ => Err(E::custom("didnt get N or Y")) } } } impl<'de> Deserialize<'de> for YesNoVal{ fn deserialize(deserializer: D) -> result::Result where D: Deserializer<'de> { deserializer.deserialize_str(YesNoVisitor) } } impl Serialize for YesNoVal{ fn serialize(&self, serializer: S) -> result::Result where S: serde::Serializer, { serializer.serialize_char( match self.0{ true => 'Y', false => 'N', } ) } }