Hi!
I'm designing a data structure to represent CloudEvents in the new official cloudevents/sdk-rust library.
An Event could contain or not a payload, called data
. This data
field could have different internal representations, depending on how it comes from the wire:
pub enum Data {
String(String),
Binary(Vec<u8>),
Json(serde_json::Value),
}
While accessing to data
, the accessor converts it to the desired type using a TryFrom<Data>
impl:
impl TryFrom<Data> for serde_json::Value {
type Error = serde_json::Error;
fn try_from(value: Data) -> Result<Self, Self::Error> {
match value {
Data::String(s) => Ok(serde_json::from_str(&s)?),
Data::Binary(v) => Ok(serde_json::from_slice(&v)?),
Data::Json(v) => Ok(v),
}
}
}
Now, the accessor now looks like:
impl Event {
pub fn try_get_data<T: Sized + TryFrom<Data, Error = E>, E: std::error::Error>(
&self,
) -> Option<Result<T, E>> {
match self.data.as_ref() {
Some(d) => Some(T::try_from(d.clone())),
None => None,
}
}
}
Do you think it would be better, from a usability standpoint of view, to have this try_get_data
return a Result<T, E>
? In that case, E
would be custom defined like:
enum DataError {
NoData,
ConversionError(Box<dyn std::error::Error>),
}