1use std::ffi::CStr;
21use std::fmt;
22use std::future::Future;
23use std::marker::PhantomData;
24use std::pin::Pin;
25
26use anyhow::bail;
27use anyhow::Result;
28use futures::future::FutureExt;
29
30use crate::serialize;
31use crate::ApplicationException;
32use crate::ContextStack;
33use crate::Deserialize;
34use crate::MessageType;
35use crate::Protocol;
36use crate::ProtocolEncodedFinal;
37use crate::ProtocolReader;
38use crate::ProtocolWriter;
39use crate::RequestContext;
40use crate::ResultInfo;
41use crate::ResultType;
42use crate::Serialize;
43use crate::SerializedMessage;
44
45pub fn enum_display(
47 variants_by_number: &[(&str, i32)],
48 formatter: &mut fmt::Formatter,
49 number: i32,
50) -> fmt::Result {
51 match variants_by_number.binary_search_by_key(&number, |entry| entry.1) {
52 Ok(i) => formatter.write_str(variants_by_number[i].0),
53 Err(_) => write!(formatter, "{}", number),
54 }
55}
56
57pub fn enum_from_str(
59 variants_by_name: &[(&str, i32)],
60 value: &str,
61 type_name: &'static str,
62) -> Result<i32> {
63 match variants_by_name.binary_search_by_key(&value, |entry| entry.0) {
64 Ok(i) => Ok(variants_by_name[i].1),
65 Err(_) => bail!("Unable to parse {} as {}", value, type_name),
66 }
67}
68
69pub fn type_name_of_val<T>(_: &T) -> &'static str {
70 std::any::type_name::<T>()
71}
72
73pub fn serialize_result_envelope<P, CTXT, RES>(
75 name: &str,
76 name_cstr: &<CTXT::ContextStack as ContextStack>::Name,
77 seqid: u32,
78 rctxt: &CTXT,
79 ctx_stack: &mut CTXT::ContextStack,
80 res: RES,
81) -> anyhow::Result<ProtocolEncodedFinal<P>>
82where
83 P: Protocol,
84 RES: ResultInfo + Serialize<P::Sizer> + Serialize<P::Serializer>,
85 CTXT: RequestContext<Name = CStr>,
86{
87 let res_type = res.result_type();
88
89 if matches!(res_type, ResultType::Error | ResultType::Exception) {
90 assert_eq!(res.exn_is_declared(), res_type == ResultType::Error);
91
92 rctxt.set_user_exception_header(res.exn_name(), &res.exn_value())?;
93 }
94
95 ctx_stack.pre_write()?;
96 let envelope = serialize!(P, |p| {
97 p.write_message_begin(name, res_type.message_type(), seqid);
98 res.write(p);
99 p.write_message_end();
100 });
101
102 ctx_stack.on_write_data(&SerializedMessage {
103 protocol: P::PROTOCOL_ID,
104 method_name: &name_cstr,
105 buffer: PhantomData,
106 })?;
107 ctx_stack.post_write(0)?;
108
109 Ok(envelope)
110}
111
112pub fn serialize_stream_item<P, RES>(res: RES) -> anyhow::Result<ProtocolEncodedFinal<P>>
113where
114 P: Protocol,
115 RES: ResultInfo + Serialize<P::Sizer> + Serialize<P::Serializer>,
116{
117 Ok(serialize!(P, |p| {
118 res.write(p);
119 }))
120}
121
122pub fn serialize_request_envelope<P, ARGS>(
124 name: &str,
125 args: &ARGS,
126) -> anyhow::Result<ProtocolEncodedFinal<P>>
127where
128 P: Protocol,
129 ARGS: Serialize<P::Sizer> + Serialize<P::Serializer>,
130{
131 let envelope = serialize!(P, |p| {
132 p.write_message_begin(name, MessageType::Call, 0);
136 args.write(p);
137 p.write_message_end();
138 });
139
140 Ok(envelope)
141}
142
143pub fn deserialize_response_envelope<P, T>(
146 de: &mut P::Deserializer,
147) -> anyhow::Result<Result<T, ApplicationException>>
148where
149 P: Protocol,
150 T: Deserialize<P::Deserializer>,
151{
152 let (_, message_type, _) = de.read_message_begin(|_| ())?;
153
154 let res = match message_type {
155 MessageType::Reply => Ok(T::read(de)?),
156 MessageType::Exception => Err(ApplicationException::read(de)?),
157 MessageType::Call | MessageType::Oneway | MessageType::InvalidMessageType => {
158 bail!("Unwanted message type `{:?}`", message_type)
159 }
160 };
161
162 de.read_message_end()?;
163
164 Ok(res)
165}
166
167pub trait Spawner: 'static {
169 fn spawn<F, R>(func: F) -> Pin<Box<dyn Future<Output = R> + Send>>
170 where
171 F: FnOnce() -> R + Send + 'static,
172 R: Send + 'static;
173}
174
175pub struct NoopSpawner;
177impl Spawner for NoopSpawner {
178 #[inline]
179 fn spawn<F, R>(func: F) -> Pin<Box<dyn Future<Output = R> + Send>>
180 where
181 F: FnOnce() -> R + Send + 'static,
182 R: Send + 'static,
183 {
184 async { func() }.boxed()
185 }
186}
187
188pub async fn async_deserialize_response_envelope<P, T, S>(
189 de: P::Deserializer,
190) -> anyhow::Result<(Result<T, ApplicationException>, P::Deserializer)>
191where
192 P: Protocol,
193 P::Deserializer: Send,
194 T: Deserialize<P::Deserializer> + Send + 'static,
195 S: Spawner,
196{
197 S::spawn(move || {
198 let mut de = de;
199 let res = deserialize_response_envelope::<P, T>(&mut de);
200 res.map(|res| (res, de))
201 })
202 .await
203}