Skip to main content

aion_client/
payload.rs

1//! Typed conversion helpers for `Payload` values.
2
3use aion_core::{ContentType, Payload};
4use serde::Serialize;
5use serde::de::DeserializeOwned;
6
7use crate::error::ClientError;
8
9/// JSON content type used by the typed helper surface.
10pub const JSON_CONTENT_TYPE: ContentType = ContentType::Json;
11
12/// Serializes a typed value into an `application/json` [`Payload`].
13///
14/// # Errors
15///
16/// Returns [`ClientError::InvalidArgument`] when `value` cannot be JSON-encoded.
17pub 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
27/// Deserializes a JSON [`Payload`] into a typed value.
28///
29/// Decode failures are mapped to [`ClientError::InvalidArgument`]: the payload is
30/// present, but its bytes do not match the caller-requested typed shape.
31///
32/// # Errors
33///
34/// Returns [`ClientError::InvalidArgument`] when the payload is not valid JSON
35/// for `T`.
36pub 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}