Skip to main content

ephemeris_forge/
codec.rs

1//! A planned [`Value`] round-tripped through JSON into a concrete shape,
2//! which is how a forge adapter decodes a planned field back into the
3//! typed request or response body a write expects.
4
5use facet::Facet;
6use facet_value::Value;
7
8/// Round-trip `value` through JSON into `T`.
9///
10/// # Errors
11///
12/// Returns an error when `T` cannot represent what `value` holds.
13///
14/// # Panics
15///
16/// Never in practice: every [`Value`] this crate builds encodes as JSON.
17#[expect(
18    clippy::unwrap_in_result,
19    reason = "the panicking step is encoding, which a Value this crate built cannot fail; only \
20              decoding into T, which cannot panic, can return the Err this signature promises"
21)]
22pub fn redecode<T: for<'a> Facet<'a>>(value: &Value) -> Result<T, facet_json::DeserializeError> {
23    #[expect(
24        clippy::expect_used,
25        reason = "a Value this crate itself built always encodes as JSON"
26    )]
27    let raw = facet_json::to_string(value).expect("a Value always encodes");
28    facet_json::from_str(&raw)
29}
30
31/// Encode a request body that always encodes: a facet-derived struct of
32/// plain fields or a [`Value`] this crate built.
33///
34/// # Panics
35///
36/// Never in practice: such a body always encodes as JSON.
37#[must_use]
38pub fn encode<'facet, T: Facet<'facet> + ?Sized>(body: &T) -> String {
39    #[expect(
40        clippy::expect_used,
41        reason = "request bodies are facet-derived plain fields or Values that always encode"
42    )]
43    facet_json::to_string(body).expect("a request body always encodes")
44}