Skip to main content

temporalio_common/protos/
utilities.rs

1use std::collections::HashMap;
2
3use prost::{EncodeError, Message};
4
5/// Extension trait for converting `Option<F>` to `Option<T>`, returning `None` on failure.
6pub trait TryIntoOrNone<F, T> {
7    /// Turn an option of something into an option of another thing, trying to convert along the way
8    /// and returning `None` if that conversion fails
9    fn try_into_or_none(self) -> Option<T>;
10}
11
12impl<F, T> TryIntoOrNone<F, T> for Option<F>
13where
14    F: TryInto<T>,
15{
16    fn try_into_or_none(self) -> Option<T> {
17        self.map(TryInto::try_into).transpose().ok().flatten()
18    }
19}
20
21/// Use to encode an message into a proto `Any`.
22///
23/// Delete this once `prost_wkt_types` supports `prost` `0.12.x` which has built-in any packing.
24pub fn pack_any<T: Message>(type_url: String, msg: &T) -> Result<prost_types::Any, EncodeError> {
25    let mut value = Vec::new();
26    Message::encode(msg, &mut value)?;
27    Ok(prost_types::Any { type_url, value })
28}
29
30/// Decode a specific protobuf message type from gRPC status details bytes.
31///
32/// The details bytes should be the serialized `google.rpc.Status` message from
33/// `tonic::Status::details()`.
34pub fn decode_status_detail<T: Message + Default>(details: &[u8]) -> Option<T> {
35    let status = super::google::rpc::Status::decode(details).ok()?;
36    let first_detail = status.details.first()?;
37    T::decode(first_detail.value.as_slice()).ok()
38}
39
40/// Given a header map, lowercase all the keys and return it as a new map.
41/// Any keys that are duplicated after lowercasing will clobber each other in undefined ordering.
42pub fn normalize_http_headers(headers: HashMap<String, String>) -> HashMap<String, String> {
43    let mut new_headers = HashMap::new();
44    for (header_key, val) in headers.into_iter() {
45        new_headers.insert(header_key.to_lowercase(), val);
46    }
47    new_headers
48}