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    #[doc(hidden)]
31    #[allow(private_interfaces)]
32    fn serializer() -> impl MessageSerializer<Self> {
33        DefaultSerializer::<Self>::new()
34    }
35}
36
37/// Internal API for message serialization.
38/// This is not intended for direct use by consumers of this crate.
39pub(crate) trait MessageSerializer<T> {
40    /// Store the value into a JSON object.
41    fn serialize_to_map(&self, message: &T) -> Result<Map, Error>;
42
43    /// Extract the value from a JSON object.
44    fn deserialize_from_map(&self, map: &Map) -> Result<T, Error>;
45}
46
47// Default serializer that most types can use.
48pub(crate) struct DefaultSerializer<T> {
49    _phantom: std::marker::PhantomData<T>,
50}
51
52impl<T> DefaultSerializer<T> {
53    pub fn new() -> Self {
54        Self {
55            _phantom: std::marker::PhantomData,
56        }
57    }
58}
59
60impl<T> MessageSerializer<T> for DefaultSerializer<T>
61where
62    T: Message,
63{
64    fn serialize_to_map(&self, message: &T) -> Result<Map, Error> {
65        to_json_object(message)
66    }
67
68    fn deserialize_from_map(&self, map: &Map) -> Result<T, Error> {
69        from_object(map)
70    }
71}
72
73// Serializes the type `T` into the `value` field.
74pub(crate) struct ValueSerializer<T> {
75    _phantom: std::marker::PhantomData<T>,
76}
77
78impl<T> ValueSerializer<T> {
79    pub fn new() -> Self {
80        Self {
81            _phantom: std::marker::PhantomData,
82        }
83    }
84}
85
86impl<T> MessageSerializer<T> for ValueSerializer<T>
87where
88    T: Message,
89{
90    fn serialize_to_map(&self, message: &T) -> Result<Map, Error> {
91        to_json_other(message)
92    }
93
94    fn deserialize_from_map(&self, map: &Map) -> Result<T, Error> {
95        from_other(map)
96    }
97}
98
99/// Write the serialization of `T` flatly into a map.
100///
101/// We use this for types that do not have special encodings, as defined in:
102/// https://protobuf.dev/programming-guides/json/
103///
104/// That typically means that `T` is an object.
105pub(crate) fn to_json_object<T>(message: &T) -> Result<Map, Error>
106where
107    T: Message,
108{
109    use serde_json::Value;
110
111    let value = serde_json::to_value(message).map_err(Error::ser)?;
112    match value {
113        Value::Object(mut map) => {
114            map.insert(
115                "@type".to_string(),
116                Value::String(T::typename().to_string()),
117            );
118            Ok(map)
119        }
120        _ => Err(unexpected_json_type()),
121    }
122}
123
124/// Write the serialization of `T` into the `value` field of a map.
125///
126/// We use this for types that have special encodings, as defined in:
127/// https://protobuf.dev/programming-guides/json/
128///
129/// Typically this means that the JSON serialization of `T` is not an object. It
130/// is also used for `Any`, as flatly serializing an `Any` would have
131/// conflicting `@type` fields.
132pub(crate) fn to_json_other<T>(message: &T) -> Result<Map, Error>
133where
134    T: Message,
135{
136    let value = serde_json::to_value(message).map_err(Error::ser)?;
137    let mut map = crate::message::Map::new();
138    map.insert("@type".to_string(), T::typename().into());
139    map.insert("value".to_string(), value);
140    Ok(map)
141}
142
143/// The analog of `to_json_object()`
144pub(crate) fn from_object<T>(map: &Map) -> Result<T, Error>
145where
146    T: Message,
147{
148    let map = map
149        .iter()
150        .filter_map(|(k, v)| {
151            if k == "@type" {
152                return None;
153            }
154            Some((k.clone(), v.clone()))
155        })
156        .collect();
157    serde_json::from_value::<T>(serde_json::Value::Object(map)).map_err(Error::deser)
158}
159
160/// The analog of `to_json_other()`
161pub(crate) fn from_other<T>(map: &Map) -> Result<T, Error>
162where
163    T: Message,
164{
165    map.get("value")
166        .map(|v| serde_json::from_value::<T>(v.clone()))
167        .ok_or_else(missing_value_field)?
168        .map_err(Error::deser)
169}
170
171pub(crate) fn missing_value_field() -> Error {
172    Error::deser("value field is missing")
173}
174
175fn unexpected_json_type() -> Error {
176    Error::ser("unexpected JSON type, only Object and String are supported")
177}
178
179#[cfg(test)]
180mod tests {
181    use super::*;
182    use serde_json::json;
183
184    #[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
185    struct TestMessage {
186        #[serde(flatten)]
187        _unknown_fields: serde_json::Map<String, serde_json::Value>,
188    }
189
190    impl Message for TestMessage {
191        fn typename() -> &'static str {
192            "TestMessage"
193        }
194    }
195
196    #[test]
197    fn drop_type_field() {
198        let input = json!({
199            "@type": "TestMessage",
200            "a": 1,
201            "b": 2,
202        });
203        let map = input.as_object().cloned().unwrap();
204
205        let serializer = TestMessage::serializer();
206        let test = serializer.deserialize_from_map(&map).unwrap();
207
208        assert!(test._unknown_fields.get("@type").is_none(), "{test:?}");
209    }
210}