1use aion_core::{ContentType, Payload};
4use serde::Serialize;
5use serde::de::DeserializeOwned;
6
7use crate::error::ClientError;
8
9pub const JSON_CONTENT_TYPE: ContentType = ContentType::Json;
11
12pub fn to_payload<T>(value: &T) -> Result<Payload, ClientError>
18where
19 T: Serialize + ?Sized,
20{
21 let bytes = serde_json::to_vec(value).map_err(|source| {
22 ClientError::invalid_argument(format!("value cannot be JSON-encoded: {source}"))
23 })?;
24 Ok(Payload::new(JSON_CONTENT_TYPE, bytes))
25}
26
27pub fn from_payload<T>(payload: &Payload) -> Result<T, ClientError>
37where
38 T: DeserializeOwned,
39{
40 serde_json::from_slice(payload.bytes()).map_err(|source| {
41 ClientError::invalid_argument(format!(
42 "payload bytes do not match the requested typed shape: {source}"
43 ))
44 })
45}
46
47#[cfg(test)]
48mod tests {
49 use serde::{Deserialize, Serialize};
50
51 use super::{from_payload, to_payload};
52 use crate::error::ClientError;
53
54 #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
55 struct TypedPayload {
56 label: String,
57 count: u32,
58 }
59
60 #[test]
61 fn typed_payload_round_trips_through_json_payload() -> Result<(), ClientError> {
62 let value = TypedPayload {
63 label: String::from("checkout"),
64 count: 3,
65 };
66
67 let payload = to_payload(&value)?;
68 let decoded: TypedPayload = from_payload(&payload)?;
69
70 assert_eq!(decoded, value);
71 Ok(())
72 }
73}