1use serde::Serialize;
2
3use crate::error::{ProcedureError, SerializeError};
4
5pub struct DynOutput(Box<dyn erased_serde::Serialize + Send>);
10
11impl DynOutput {
12 pub fn new<T: Serialize + Send + 'static>(value: T) -> Self {
14 DynOutput(Box::new(value))
15 }
16
17 pub fn to_value(&self) -> Result<serde_json::Value, ProcedureError> {
19 serde_json::to_value(&self.0)
20 .map_err(|e| ProcedureError::Serialize(SerializeError::from(e)))
21 }
22
23 pub fn serialize_to<W: std::io::Write>(&self, writer: W) -> Result<(), ProcedureError> {
25 serde_json::to_writer(writer, &self.0)
26 .map_err(|e| ProcedureError::Serialize(SerializeError::from(e)))
27 }
28}
29
30impl Serialize for DynOutput {
31 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
32 erased_serde::serialize(&*self.0, serializer)
33 }
34}
35
36impl std::fmt::Debug for DynOutput {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 f.debug_struct("DynOutput").finish_non_exhaustive()
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45 use serde::Deserialize;
46
47 #[derive(Debug, Serialize, Deserialize, PartialEq)]
48 struct Planet {
49 name: String,
50 radius: u32,
51 }
52
53 #[test]
54 fn new_and_to_value_string() {
55 let output = DynOutput::new("hello".to_string());
56 let value = output.to_value().unwrap();
57 assert_eq!(value, serde_json::json!("hello"));
58 }
59
60 #[test]
61 fn new_and_to_value_struct() {
62 let output = DynOutput::new(Planet {
63 name: "Earth".into(),
64 radius: 6371,
65 });
66 let value = output.to_value().unwrap();
67 assert_eq!(value, serde_json::json!({"name": "Earth", "radius": 6371}));
68 }
69
70 #[test]
71 fn new_and_to_value_vec() {
72 let output = DynOutput::new(vec![1, 2, 3]);
73 let value = output.to_value().unwrap();
74 assert_eq!(value, serde_json::json!([1, 2, 3]));
75 }
76
77 #[test]
78 fn serialize_to_writer() {
79 let output = DynOutput::new(42u32);
80 let mut buf = Vec::new();
81 output.serialize_to(&mut buf).unwrap();
82 assert_eq!(std::str::from_utf8(&buf).unwrap(), "42");
83 }
84
85 #[test]
86 fn serde_serialize_impl() {
87 let output = DynOutput::new(Planet {
88 name: "Mars".into(),
89 radius: 3389,
90 });
91 let json = serde_json::to_string(&output).unwrap();
92 let parsed: Planet = serde_json::from_str(&json).unwrap();
93 assert_eq!(
94 parsed,
95 Planet {
96 name: "Mars".into(),
97 radius: 3389
98 }
99 );
100 }
101
102 #[test]
103 fn debug_output() {
104 let output = DynOutput::new(42u32);
105 let debug = format!("{output:?}");
106 assert!(debug.contains("DynOutput"));
107 }
108
109 #[test]
110 fn dyn_output_is_send() {
111 fn assert_send<T: Send>() {}
112 assert_send::<DynOutput>();
113 }
114}