google_cloud_wkt/
message.rs

1// Copyright 2025 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Define traits required of all messages.
16
17pub(crate) type Map = serde_json::Map<String, serde_json::Value>;
18use crate::AnyError as Error;
19
20/// A trait that must be implemented by all messages.
21///
22/// Messages sent to and received from Google Cloud services may be wrapped in
23/// [Any][crate::any::Any]. `Any` uses a `@type` field to encode the type
24/// name and then validates extraction and insertion against this type.
25pub trait Message: serde::ser::Serialize + serde::de::DeserializeOwned {
26    /// The typename of this message.
27    fn typename() -> &'static str;
28
29    /// Returns the serializer for this message type.
30    #[cfg_attr(not(feature = "_internal-semver"), doc(hidden))]
31    fn serializer() -> impl MessageSerializer<Self> {
32        DefaultSerializer::<Self>::new()
33    }
34}
35
36pub(crate) mod sealed {
37    pub trait MessageSerializer {}
38}
39
40#[cfg_attr(not(feature = "_internal-semver"), doc(hidden))]
41/// Internal API for message serialization.
42/// This is not intended for direct use by consumers of this crate.
43pub trait MessageSerializer<T>: sealed::MessageSerializer {
44    /// Store the value into a JSON object.
45    fn serialize_to_map(&self, message: &T) -> Result<Map, Error>;
46
47    /// Extract the value from a JSON object.
48    fn deserialize_from_map(&self, map: &Map) -> Result<T, Error>;
49}
50
51// Default serializer that most types can use.
52pub(crate) struct DefaultSerializer<T> {
53    _phantom: std::marker::PhantomData<T>,
54}
55
56impl<T> DefaultSerializer<T> {
57    pub fn new() -> Self {
58        Self {
59            _phantom: std::marker::PhantomData,
60        }
61    }
62}
63
64#[cfg_attr(not(feature = "_internal-semver"), doc(hidden))]
65impl<T> sealed::MessageSerializer for DefaultSerializer<T> {}
66
67impl<T> MessageSerializer<T> for DefaultSerializer<T>
68where
69    T: Message,
70{
71    fn serialize_to_map(&self, message: &T) -> Result<Map, Error> {
72        to_json_object(message)
73    }
74
75    fn deserialize_from_map(&self, map: &Map) -> Result<T, Error> {
76        from_object(map)
77    }
78}
79
80// Serializes the type `T` into the `value` field.
81pub(crate) struct ValueSerializer<T> {
82    _phantom: std::marker::PhantomData<T>,
83}
84
85impl<T> ValueSerializer<T> {
86    pub fn new() -> Self {
87        Self {
88            _phantom: std::marker::PhantomData,
89        }
90    }
91}
92
93#[cfg_attr(not(feature = "_internal-semver"), doc(hidden))]
94impl<T> sealed::MessageSerializer for ValueSerializer<T> {}
95
96impl<T> MessageSerializer<T> for ValueSerializer<T>
97where
98    T: Message,
99{
100    fn serialize_to_map(&self, message: &T) -> Result<Map, Error> {
101        to_json_other(message)
102    }
103
104    fn deserialize_from_map(&self, map: &Map) -> Result<T, Error> {
105        from_other(map)
106    }
107}
108
109/// Write the serialization of `T` flatly into a map.
110///
111/// We use this for types that do not have special encodings, as defined in:
112/// https://protobuf.dev/programming-guides/json/
113///
114/// That typically means that `T` is an object.
115pub(crate) fn to_json_object<T>(message: &T) -> Result<Map, Error>
116where
117    T: Message,
118{
119    use serde_json::Value;
120
121    let value = serde_json::to_value(message).map_err(Error::ser)?;
122    match value {
123        Value::Object(mut map) => {
124            map.insert(
125                "@type".to_string(),
126                Value::String(T::typename().to_string()),
127            );
128            Ok(map)
129        }
130        _ => Err(unexpected_json_type()),
131    }
132}
133
134/// Write the serialization of `T` into the `value` field of a map.
135///
136/// We use this for types that have special encodings, as defined in:
137/// https://protobuf.dev/programming-guides/json/
138///
139/// Typically this means that the JSON serialization of `T` is not an object. It
140/// is also used for `Any`, as flatly serializing an `Any` would have
141/// conflicting `@type` fields.
142pub(crate) fn to_json_other<T>(message: &T) -> Result<Map, Error>
143where
144    T: Message,
145{
146    let value = serde_json::to_value(message).map_err(Error::ser)?;
147    let mut map = crate::message::Map::new();
148    map.insert("@type".to_string(), T::typename().into());
149    map.insert("value".to_string(), value);
150    Ok(map)
151}
152
153/// The analog of `to_json_object()`
154pub(crate) fn from_object<T>(map: &Map) -> Result<T, Error>
155where
156    T: Message,
157{
158    let map = map
159        .iter()
160        .filter_map(|(k, v)| {
161            if k == "@type" {
162                return None;
163            }
164            Some((k.clone(), v.clone()))
165        })
166        .collect();
167    serde_json::from_value::<T>(serde_json::Value::Object(map)).map_err(Error::deser)
168}
169
170/// The analog of `to_json_other()`
171pub(crate) fn from_other<T>(map: &Map) -> Result<T, Error>
172where
173    T: Message,
174{
175    map.get("value")
176        .map(|v| serde_json::from_value::<T>(v.clone()))
177        .ok_or_else(missing_value_field)?
178        .map_err(Error::deser)
179}
180
181pub(crate) fn missing_value_field() -> Error {
182    Error::deser("value field is missing")
183}
184
185fn unexpected_json_type() -> Error {
186    Error::ser("unexpected JSON type, only Object and String are supported")
187}
188
189#[cfg(test)]
190mod tests {
191    use super::*;
192    use serde_json::json;
193
194    #[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
195    struct TestMessage {
196        #[serde(flatten)]
197        _unknown_fields: serde_json::Map<String, serde_json::Value>,
198    }
199
200    impl Message for TestMessage {
201        fn typename() -> &'static str {
202            "TestMessage"
203        }
204    }
205
206    #[test]
207    fn drop_type_field() {
208        let input = json!({
209            "@type": "TestMessage",
210            "a": 1,
211            "b": 2,
212        });
213        let map = input.as_object().cloned().unwrap();
214
215        let serializer = TestMessage::serializer();
216        let test = serializer.deserialize_from_map(&map).unwrap();
217
218        assert!(test._unknown_fields.get("@type").is_none(), "{test:?}");
219    }
220}