//! //! This module holds traits for extending functionalities for existing datatypes //! & inbuilt datatypes. //! use error_stack::{IntoReport, ResultExt}; use masking::{ExposeInterface, Secret, Strategy}; use serde::{Deserialize, Serialize}; use crate::errors::{self, CustomResult}; /// /// Encode interface /// An interface for performing type conversions and serialization /// pub trait Encode<'e, P> where Self: 'e + std::fmt::Debug, { // If needed get type information/custom error implementation. /// /// Converting `Self` into an intermediate representation `

` /// and then performing encoding operation using the `Serialize` trait from `serde` /// Specifically to convert into json, by using `serde_json` /// fn convert_and_encode(&'e self) -> CustomResult where P: TryFrom<&'e Self> + Serialize, Result>::Error>: ResultExt, >::Error> as ResultExt>::Ok: Serialize; /// /// Converting `Self` into an intermediate representation `

` /// and then performing encoding operation using the `Serialize` trait from `serde` /// Specifically, to convert into urlencoded, by using `serde_urlencoded` /// fn convert_and_url_encode(&'e self) -> CustomResult where P: TryFrom<&'e Self> + Serialize, Result>::Error>: ResultExt, >::Error> as ResultExt>::Ok: Serialize; /// /// Functionality, for specifically encoding `Self` into `String` /// after serialization by using `serde::Serialize` /// fn encode(&'e self) -> CustomResult where Self: Serialize; /// /// Functionality, for specifically encoding `Self` into `String` /// after serialization by using `serde::Serialize` /// specifically, to convert into JSON `String`. /// fn encode_to_string_of_json(&'e self) -> CustomResult where Self: Serialize; /// /// Functionality, for specifically encoding `Self` into `serde_json::Value` /// after serialization by using `serde::Serialize` /// fn encode_to_value(&'e self) -> CustomResult where Self: Serialize; /// /// Functionality, for specifically encoding `Self` into `Vec` /// after serialization by using `serde::Serialize` /// fn encode_to_vec(&'e self) -> CustomResult, errors::ParsingError> where Self: Serialize; } impl<'e, P, A> Encode<'e, P> for A where Self: 'e + std::fmt::Debug, { fn convert_and_encode(&'e self) -> CustomResult where P: TryFrom<&'e Self> + Serialize, Result>::Error>: ResultExt, >::Error> as ResultExt>::Ok: Serialize, { serde_json::to_string(&P::try_from(self).change_context(errors::ParsingError)?) .into_report() .change_context(errors::ParsingError) .attach_printable_lazy(|| format!("Unable to convert {:?} to a request", self)) } fn convert_and_url_encode(&'e self) -> CustomResult where P: TryFrom<&'e Self> + Serialize, Result>::Error>: ResultExt, >::Error> as ResultExt>::Ok: Serialize, { serde_urlencoded::to_string(&P::try_from(self).change_context(errors::ParsingError)?) .into_report() .change_context(errors::ParsingError) .attach_printable_lazy(|| format!("Unable to convert {:?} to a request", self)) } // Check without two functions can we combine this fn encode(&'e self) -> CustomResult where Self: Serialize, { serde_urlencoded::to_string(self) .into_report() .change_context(errors::ParsingError) .attach_printable_lazy(|| format!("Unable to convert {:?} to a request", self)) } fn encode_to_string_of_json(&'e self) -> CustomResult where Self: Serialize, { serde_json::to_string(self) .into_report() .change_context(errors::ParsingError) .attach_printable_lazy(|| format!("Unable to convert {:?} to a request", self)) } fn encode_to_value(&'e self) -> CustomResult where Self: Serialize, { serde_json::to_value(self) .into_report() .change_context(errors::ParsingError) .attach_printable_lazy(|| format!("Unable to convert {:?} to a value", self)) } fn encode_to_vec(&'e self) -> CustomResult, errors::ParsingError> where Self: Serialize, { serde_json::to_vec(self) .into_report() .change_context(errors::ParsingError) .attach_printable_lazy(|| format!("Unable to convert {:?} to a value", self)) } } /// /// Extending functionalities of `bytes::Bytes` /// pub trait BytesExt { /// /// Convert `bytes::Bytes` into type `` using `serde::Deserialize` /// fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult where T: Deserialize<'de>; } impl BytesExt for bytes::Bytes { fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult where T: Deserialize<'de>, { use bytes::Buf; serde_json::from_slice::(self.chunk()) .into_report() .change_context(errors::ParsingError) .attach_printable_lazy(|| format!("Unable to parse {type_name} from bytes")) } } /// /// Extending functionalities of `[u8]` for performing parsing /// pub trait ByteSliceExt { /// /// Convert `[u8]` into type `` by using `serde::Deserialize` /// fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult where T: Deserialize<'de>; } impl ByteSliceExt for [u8] { fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult where T: Deserialize<'de>, { serde_json::from_slice(self) .into_report() .change_context(errors::ParsingError) .attach_printable_lazy(|| format!("Unable to parse {type_name} from &[u8]")) } } /// /// Extending functionalities of `serde_json::Value` for performing parsing /// pub trait ValueExt { /// /// Convert `serde_json::Value` into type `` by using `serde::Deserialize` /// fn parse_value(self, type_name: &str) -> CustomResult where T: serde::de::DeserializeOwned; } impl ValueExt for serde_json::Value { fn parse_value(self, type_name: &str) -> CustomResult where T: serde::de::DeserializeOwned, { let debug = format!( "Unable to parse {type_name} from serde_json::Value: {:?}", &self ); serde_json::from_value::(self) .into_report() .change_context(errors::ParsingError) .attach_printable_lazy(|| debug) } } impl ValueExt for Secret where MaskingStrategy: Strategy, { fn parse_value(self, type_name: &str) -> CustomResult where T: serde::de::DeserializeOwned, { self.expose().parse_value(type_name) } } /// /// Extending functionalities of `String` for performing parsing /// pub trait StringExt { /// /// Convert `String` into type `` (which being an `enum`) /// fn parse_enum(self, enum_name: &str) -> CustomResult where T: std::str::FromStr, // Requirement for converting the `Err` variant of `FromStr` to `Report` ::Err: std::error::Error + Send + Sync + 'static; /// /// Convert `serde_json::Value` into type `` by using `serde::Deserialize` /// fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult where T: Deserialize<'de>; } impl StringExt for String { fn parse_enum(self, enum_name: &str) -> CustomResult where T: std::str::FromStr, ::Err: std::error::Error + Send + Sync + 'static, { T::from_str(&self) .into_report() .change_context(errors::ParsingError) .attach_printable_lazy(|| format!("Invalid enum variant {self:?} for enum {enum_name}")) } fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult where T: Deserialize<'de>, { serde_json::from_str::(self) .into_report() .change_context(errors::ParsingError) .attach_printable_lazy(|| format!("Unable to parse {type_name} from string")) } } /// /// Extending functionalities of Wrapper types for idiomatic /// #[async_trait::async_trait] pub trait AsyncExt { /// Output type of the map function type WrappedSelf; /// /// Extending map by allowing functions which are async /// async fn async_map(self, func: F) -> Self::WrappedSelf where F: FnOnce(A) -> Fut + Send, Fut: futures::Future + Send; /// /// Extending the `and_then` by allowing functions which are async /// async fn async_and_then(self, func: F) -> Self::WrappedSelf where F: FnOnce(A) -> Fut + Send, Fut: futures::Future> + Send; } #[async_trait::async_trait] impl AsyncExt for Result { type WrappedSelf = Result; async fn async_and_then(self, func: F) -> Self::WrappedSelf where F: FnOnce(A) -> Fut + Send, Fut: futures::Future> + Send, { match self { Ok(a) => func(a).await, Err(err) => Err(err), } } async fn async_map(self, func: F) -> Self::WrappedSelf where F: FnOnce(A) -> Fut + Send, Fut: futures::Future + Send, { match self { Ok(a) => Ok(func(a).await), Err(err) => Err(err), } } } #[async_trait::async_trait] impl AsyncExt for Option { type WrappedSelf = Option; async fn async_and_then(self, func: F) -> Self::WrappedSelf where F: FnOnce(A) -> Fut + Send, Fut: futures::Future> + Send, { match self { Some(a) => func(a).await, None => None, } } async fn async_map(self, func: F) -> Self::WrappedSelf where F: FnOnce(A) -> Fut + Send, Fut: futures::Future + Send, { match self { Some(a) => Some(func(a).await), None => None, } } }