vrl/protobuf/
encode.rs

1use crate::compiler::prelude::*;
2use crate::value::value::simdutf_bytes_utf8_lossy;
3use chrono::Timelike;
4#[cfg(feature = "enable_system_functions")]
5use prost::Message;
6use prost_reflect::{DynamicMessage, FieldDescriptor, Kind, MapKey, MessageDescriptor};
7use std::collections::HashMap;
8
9#[derive(Default, Debug, Clone, Eq, PartialEq)]
10pub struct Options {
11    pub use_json_names: bool,
12}
13
14/// Convert a single raw `Value` into a protobuf `Value`.
15///
16/// Unlike `convert_value`, this ignores any field metadata such as cardinality.
17fn convert_value_raw(
18    value: Value,
19    kind: &Kind,
20    options: &Options,
21) -> Result<prost_reflect::Value, String> {
22    let kind_str = value.kind_str().to_owned();
23    match (value, kind) {
24        (Value::Boolean(b), Kind::Bool) => Ok(prost_reflect::Value::Bool(b)),
25        (Value::Bytes(b), Kind::Bytes) => Ok(prost_reflect::Value::Bytes(b)),
26        (Value::Bytes(b), Kind::String) => Ok(prost_reflect::Value::String(
27            simdutf_bytes_utf8_lossy(&b).into_owned(),
28        )),
29        (Value::Bytes(b), Kind::Enum(descriptor)) => {
30            let string = simdutf_bytes_utf8_lossy(&b);
31            match descriptor
32                .values()
33                .find(|v| v.name().eq_ignore_ascii_case(&string))
34            {
35                Some(d) => Ok(prost_reflect::Value::EnumNumber(d.number())),
36                None => Err(format!(
37                    "Enum `{}` has no value that matches string '{}'",
38                    descriptor.full_name(),
39                    string
40                )),
41            }
42        }
43        (Value::Float(f), Kind::Double) => Ok(prost_reflect::Value::F64(f.into_inner())),
44        (Value::Float(f), Kind::Float) => Ok(prost_reflect::Value::F32(f.into_inner() as f32)),
45        (Value::Bytes(b), Kind::Double) => {
46            let string = simdutf_bytes_utf8_lossy(&b);
47            let val = string
48                .parse::<f64>()
49                .map_err(|e| format!("Cannot parse `{string}` as double: {e}"))?;
50            Ok(prost_reflect::Value::F64(val))
51        }
52        (Value::Bytes(b), Kind::Float) => {
53            let string = simdutf_bytes_utf8_lossy(&b);
54            let val = string
55                .parse::<f32>()
56                .map_err(|e| format!("Cannot parse `{string}` as float: {e}"))?;
57            Ok(prost_reflect::Value::F32(val))
58        }
59        (Value::Integer(i), Kind::Int32) => Ok(prost_reflect::Value::I32(i as i32)),
60        (Value::Integer(i), Kind::Int64) => Ok(prost_reflect::Value::I64(i)),
61        (Value::Integer(i), Kind::Sint32) => Ok(prost_reflect::Value::I32(i as i32)),
62        (Value::Integer(i), Kind::Sint64) => Ok(prost_reflect::Value::I64(i)),
63        (Value::Integer(i), Kind::Sfixed32) => Ok(prost_reflect::Value::I32(i as i32)),
64        (Value::Integer(i), Kind::Sfixed64) => Ok(prost_reflect::Value::I64(i)),
65        (Value::Integer(i), Kind::Uint32) => Ok(prost_reflect::Value::U32(i as u32)),
66        (Value::Integer(i), Kind::Uint64) => Ok(prost_reflect::Value::U64(i as u64)),
67        (Value::Integer(i), Kind::Fixed32) => Ok(prost_reflect::Value::U32(i as u32)),
68        (Value::Integer(i), Kind::Fixed64) => Ok(prost_reflect::Value::U64(i as u64)),
69        (Value::Integer(i), Kind::Double) => Ok(prost_reflect::Value::F64(i as f64)),
70        (Value::Integer(i), Kind::Enum(_)) => Ok(prost_reflect::Value::EnumNumber(i as i32)),
71        (Value::Bytes(b), Kind::Int32 | Kind::Sfixed32 | Kind::Sint32) => {
72            let string = simdutf_bytes_utf8_lossy(&b);
73            let number: i32 = string
74                .parse()
75                .map_err(|e| format!("Can't convert '{string}' to i32: {e}"))?;
76            Ok(prost_reflect::Value::I32(number))
77        }
78        (Value::Bytes(b), Kind::Int64 | Kind::Sfixed64 | Kind::Sint64) => {
79            let string = simdutf_bytes_utf8_lossy(&b);
80            let number: i64 = string
81                .parse()
82                .map_err(|e| format!("Can't convert '{string}' to i64: {e}"))?;
83            Ok(prost_reflect::Value::I64(number))
84        }
85        (Value::Bytes(b), Kind::Uint32 | Kind::Fixed32) => {
86            let string = simdutf_bytes_utf8_lossy(&b);
87            let number: u32 = string
88                .parse()
89                .map_err(|e| format!("Can't convert '{string}' to u32: {e}"))?;
90            Ok(prost_reflect::Value::U32(number))
91        }
92        (Value::Bytes(b), Kind::Uint64 | Kind::Fixed64) => {
93            let string = simdutf_bytes_utf8_lossy(&b);
94            let number: u64 = string
95                .parse()
96                .map_err(|e| format!("Can't convert '{string}' to u64: {e}"))?;
97            Ok(prost_reflect::Value::U64(number))
98        }
99        (Value::Object(o), Kind::Message(message_descriptor)) => {
100            if message_descriptor.is_map_entry() {
101                let value_field = message_descriptor
102                    .get_field_by_name("value")
103                    .ok_or("Internal error with proto map processing")?;
104                let mut map: HashMap<MapKey, prost_reflect::Value> = HashMap::new();
105                for (key, val) in o.into_iter() {
106                    match convert_value(&value_field, val, options) {
107                        Ok(prost_val) => {
108                            map.insert(MapKey::String(key.into()), prost_val);
109                        }
110                        Err(e) => return Err(e),
111                    }
112                }
113                Ok(prost_reflect::Value::Map(map))
114            } else {
115                // if it's not a map, it's an actual message
116                Ok(prost_reflect::Value::Message(encode_message(
117                    message_descriptor,
118                    Value::Object(o),
119                    options,
120                )?))
121            }
122        }
123        (Value::Regex(r), Kind::String) => Ok(prost_reflect::Value::String(r.as_str().to_owned())),
124        (Value::Regex(r), Kind::Bytes) => Ok(prost_reflect::Value::Bytes(r.as_bytes())),
125        (Value::Timestamp(t), Kind::Int64) => Ok(prost_reflect::Value::I64(t.timestamp_micros())),
126        (Value::Timestamp(t), Kind::Message(descriptor))
127            if descriptor.full_name() == "google.protobuf.Timestamp" =>
128        {
129            let mut message = DynamicMessage::new(descriptor.clone());
130            message
131                .try_set_field_by_name("seconds", prost_reflect::Value::I64(t.timestamp()))
132                .map_err(|e| format!("Error setting 'seconds' field: {e}"))?;
133            message
134                .try_set_field_by_name("nanos", prost_reflect::Value::I32(t.nanosecond() as i32))
135                .map_err(|e| format!("Error setting 'nanos' field: {e}"))?;
136            Ok(prost_reflect::Value::Message(message))
137        }
138        (Value::Boolean(b), Kind::String) => Ok(prost_reflect::Value::String(b.to_string())),
139        (Value::Integer(i), Kind::String) => Ok(prost_reflect::Value::String(i.to_string())),
140        (Value::Float(f), Kind::String) => Ok(prost_reflect::Value::String(f.to_string())),
141        (Value::Timestamp(t), Kind::String) => Ok(prost_reflect::Value::String(t.to_string())),
142        _ => Err(format!(
143            "Cannot encode `{kind_str}` into protobuf `{kind:?}`",
144        )),
145    }
146}
147
148/// Convert a `Value` into a protobuf `Value`.
149fn convert_value(
150    field_descriptor: &FieldDescriptor,
151    value: Value,
152    options: &Options,
153) -> Result<prost_reflect::Value, String> {
154    if let Value::Array(a) = value {
155        if field_descriptor.cardinality() == prost_reflect::Cardinality::Repeated {
156            let repeated: Result<Vec<prost_reflect::Value>, String> = a
157                .into_iter()
158                .map(|v| convert_value_raw(v, &field_descriptor.kind(), options))
159                .collect();
160            Ok(prost_reflect::Value::List(repeated?))
161        } else {
162            Err("Cannot encode array into a non-repeated protobuf field".into())
163        }
164    } else {
165        convert_value_raw(value, &field_descriptor.kind(), options)
166    }
167}
168
169/// Converts a VRL [`Value`] into a protobuf [`DynamicMessage`].
170///
171/// # Arguments
172///
173/// * `message_descriptor` - The protobuf message schema descriptor
174/// * `value` - The VRL value to encode
175/// * `options` - Encoding options (e.g., whether to use JSON field names)
176///
177/// # Returns
178///
179/// Returns `Ok(`[`DynamicMessage`]`)` on success, or `Err(String)` with a descriptive error message.
180///
181/// # Errors
182///
183/// * Returns an error if `value` is not a [`Value::Object`]
184/// * Returns an error if field type conversion fails (e.g., trying to encode a string as an integer)
185/// * Returns an error if setting a field on the message fails
186///
187/// # Behavior
188///
189/// * Only [`Value::Object`] is supported, since protobuf messages are collections of named fields
190/// * Fields present in the object with `null` values are explicitly cleared
191/// * Fields not present in the object retain their default protobuf values
192/// * Type conversion follows the mappings defined in `convert_value_raw`.
193pub fn encode_message(
194    message_descriptor: &MessageDescriptor,
195    value: Value,
196    options: &Options,
197) -> Result<DynamicMessage, String> {
198    let mut message = DynamicMessage::new(message_descriptor.clone());
199    if let Value::Object(map) = value {
200        for field in message_descriptor.fields() {
201            let field_name = if options.use_json_names {
202                field.json_name()
203            } else {
204                field.name()
205            };
206            match map.get(field_name) {
207                None | Some(Value::Null) => message.clear_field(&field),
208                Some(value) => message
209                    .try_set_field(
210                        &field,
211                        convert_value(&field, value.clone(), options)
212                            .map_err(|e| format!("Error converting {field_name} field: {e}"))?,
213                    )
214                    .map_err(|e| format!("Error setting {field_name} field: {e}"))?,
215            }
216        }
217        Ok(message)
218    } else {
219        Err("ProtobufSerializer only supports serializing objects".into())
220    }
221}
222
223#[cfg(feature = "enable_system_functions")]
224pub(crate) fn encode_proto(descriptor: &MessageDescriptor, value: Value) -> Resolved {
225    let message = encode_message(descriptor, value, &Options::default())?;
226    let mut buf = Vec::new();
227    message
228        .encode(&mut buf)
229        .map_err(|e| format!("Error encoding protobuf message: {e}"))?;
230    Ok(Value::Bytes(Bytes::from(buf)))
231}
232
233#[cfg(test)]
234mod tests {
235    use super::*;
236    use crate::protobuf::descriptor::get_message_descriptor;
237    use crate::protobuf::parse::parse_proto;
238    use crate::value;
239    use bytes::Bytes;
240    use chrono::DateTime;
241    use ordered_float::NotNan;
242    use prost_reflect::MapKey;
243    use std::collections::{BTreeMap, HashMap};
244    use std::path::PathBuf;
245    use std::{env, fs};
246
247    fn test_data_dir() -> PathBuf {
248        PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("tests/data/protobuf")
249    }
250
251    macro_rules! mfield {
252        ($m:expr_2021, $f:expr_2021) => {
253            $m.get_field_by_name($f).unwrap().into_owned()
254        };
255    }
256
257    fn test_message_descriptor(message_type: &str) -> MessageDescriptor {
258        let path = test_data_dir().join("test/v1/test.desc");
259        get_message_descriptor(&path, &format!("test.v1.{message_type}")).unwrap()
260    }
261
262    fn test_protobuf3_descriptor() -> MessageDescriptor {
263        let path = test_data_dir().join("test_protobuf3/v1/test_protobuf3.desc");
264        get_message_descriptor(&path, "test_protobuf3.v1.Person").unwrap()
265    }
266
267    #[test]
268    fn test_encode_integers() {
269        let message = encode_message(
270            &test_message_descriptor("Integers"),
271            Value::Object(BTreeMap::from([
272                ("i32".into(), Value::Integer(-1234)),
273                ("i64".into(), Value::Integer(-9876)),
274                ("u32".into(), Value::Integer(1234)),
275                ("u64".into(), Value::Integer(9876)),
276            ])),
277            &Options::default(),
278        )
279        .unwrap();
280        assert_eq!(Some(-1234), mfield!(message, "i32").as_i32());
281        assert_eq!(Some(-9876), mfield!(message, "i64").as_i64());
282        assert_eq!(Some(1234), mfield!(message, "u32").as_u32());
283        assert_eq!(Some(9876), mfield!(message, "u64").as_u64());
284    }
285
286    #[test]
287    fn test_encode_integers_from_bytes() {
288        let message = encode_message(
289            &test_message_descriptor("Integers"),
290            Value::Object(BTreeMap::from([
291                ("i32".into(), Value::Bytes(Bytes::from("-1234"))),
292                ("i64".into(), Value::Bytes(Bytes::from("-9876"))),
293                ("u32".into(), Value::Bytes(Bytes::from("1234"))),
294                ("u64".into(), Value::Bytes(Bytes::from("9876"))),
295            ])),
296            &Options::default(),
297        )
298        .unwrap();
299        assert_eq!(Some(-1234), mfield!(message, "i32").as_i32());
300        assert_eq!(Some(-9876), mfield!(message, "i64").as_i64());
301        assert_eq!(Some(1234), mfield!(message, "u32").as_u32());
302        assert_eq!(Some(9876), mfield!(message, "u64").as_u64());
303    }
304
305    #[test]
306    fn test_encode_floats() {
307        let message = encode_message(
308            &test_message_descriptor("Floats"),
309            Value::Object(BTreeMap::from([
310                ("d".into(), Value::Float(NotNan::new(11.0).unwrap())),
311                ("f".into(), Value::Float(NotNan::new(2.0).unwrap())),
312            ])),
313            &Options::default(),
314        )
315        .unwrap();
316        assert_eq!(Some(11.0), mfield!(message, "d").as_f64());
317        assert_eq!(Some(2.0), mfield!(message, "f").as_f32());
318    }
319
320    #[test]
321    fn test_encode_bytes_as_float() {
322        let message = encode_message(
323            &test_message_descriptor("Floats"),
324            Value::Object(BTreeMap::from([
325                ("d".into(), Value::Bytes(Bytes::from("11.0"))),
326                ("f".into(), Value::Bytes(Bytes::from("2.0"))),
327            ])),
328            &Options::default(),
329        )
330        .unwrap();
331        assert_eq!(Some(11.0), mfield!(message, "d").as_f64());
332        assert_eq!(Some(2.0), mfield!(message, "f").as_f32());
333    }
334
335    #[test]
336    fn test_encode_integer_as_double() {
337        let message = encode_message(
338            &test_message_descriptor("Floats"),
339            Value::Object(BTreeMap::from([("d".into(), Value::Integer(42))])),
340            &Options::default(),
341        )
342        .unwrap();
343        assert_eq!(Some(42.0), mfield!(message, "d").as_f64());
344    }
345
346    #[test]
347    fn test_encode_bytes() {
348        let bytes = Bytes::from(vec![0, 1, 2, 3]);
349        let message = encode_message(
350            &test_message_descriptor("Bytes"),
351            Value::Object(BTreeMap::from([
352                ("text".into(), Value::Bytes(Bytes::from("vector"))),
353                ("binary".into(), Value::Bytes(bytes.clone())),
354            ])),
355            &Options::default(),
356        )
357        .unwrap();
358        assert_eq!(Some("vector"), mfield!(message, "text").as_str());
359        assert_eq!(Some(&bytes), mfield!(message, "binary").as_bytes());
360    }
361
362    #[test]
363    fn test_encode_map() {
364        let message = encode_message(
365            &test_message_descriptor("Map"),
366            Value::Object(BTreeMap::from([
367                (
368                    "names".into(),
369                    Value::Object(BTreeMap::from([
370                        ("forty-four".into(), Value::Integer(44)),
371                        ("one".into(), Value::Integer(1)),
372                    ])),
373                ),
374                (
375                    "people".into(),
376                    Value::Object(BTreeMap::from([(
377                        "mark".into(),
378                        Value::Object(BTreeMap::from([
379                            ("nickname".into(), Value::Bytes(Bytes::from("jeff"))),
380                            ("age".into(), Value::Integer(22)),
381                        ])),
382                    )])),
383                ),
384            ])),
385            &Options::default(),
386        )
387        .unwrap();
388        // the simpler string->primitive map
389        assert_eq!(
390            Some(&HashMap::from([
391                (
392                    MapKey::String("forty-four".into()),
393                    prost_reflect::Value::I32(44),
394                ),
395                (MapKey::String("one".into()), prost_reflect::Value::I32(1),),
396            ])),
397            mfield!(message, "names").as_map()
398        );
399        // the not-simpler string->message map
400        let people = mfield!(message, "people").as_map().unwrap().to_owned();
401        assert_eq!(1, people.len());
402        assert_eq!(
403            Some("jeff"),
404            mfield!(
405                people[&MapKey::String("mark".into())].as_message().unwrap(),
406                "nickname"
407            )
408            .as_str()
409        );
410        assert_eq!(
411            Some(22),
412            mfield!(
413                people[&MapKey::String("mark".into())].as_message().unwrap(),
414                "age"
415            )
416            .as_u32()
417        );
418    }
419
420    #[test]
421    fn test_encode_enum() {
422        let message = encode_message(
423            &test_message_descriptor("Enum"),
424            Value::Object(BTreeMap::from([
425                (
426                    "breakfast".into(),
427                    Value::Bytes(Bytes::from("fruit_tomato")),
428                ),
429                ("dinner".into(), Value::Bytes(Bytes::from("FRUIT_OLIVE"))),
430                ("lunch".into(), Value::Integer(0)),
431            ])),
432            &Options::default(),
433        )
434        .unwrap();
435        assert_eq!(Some(2), mfield!(message, "breakfast").as_enum_number());
436        assert_eq!(Some(0), mfield!(message, "lunch").as_enum_number());
437        assert_eq!(Some(1), mfield!(message, "dinner").as_enum_number());
438    }
439
440    #[test]
441    fn test_encode_timestamp() {
442        let message = encode_message(
443            &test_message_descriptor("Timestamp"),
444            Value::Object(BTreeMap::from([(
445                "morning".into(),
446                Value::Timestamp(
447                    DateTime::from_timestamp(8675, 309).expect("could not compute timestamp"),
448                ),
449            )])),
450            &Options::default(),
451        )
452        .unwrap();
453        let timestamp = mfield!(message, "morning").as_message().unwrap().clone();
454        assert_eq!(Some(8675), mfield!(timestamp, "seconds").as_i64());
455        assert_eq!(Some(309), mfield!(timestamp, "nanos").as_i32());
456    }
457
458    #[test]
459    fn test_encode_repeated_primitive() {
460        let message = encode_message(
461            &test_message_descriptor("RepeatedPrimitive"),
462            Value::Object(BTreeMap::from([(
463                "numbers".into(),
464                Value::Array(vec![
465                    Value::Integer(8),
466                    Value::Integer(6),
467                    Value::Integer(4),
468                ]),
469            )])),
470            &Options::default(),
471        )
472        .unwrap();
473        let list = mfield!(message, "numbers").as_list().unwrap().to_vec();
474        assert_eq!(3, list.len());
475        assert_eq!(Some(8), list[0].as_i64());
476        assert_eq!(Some(6), list[1].as_i64());
477        assert_eq!(Some(4), list[2].as_i64());
478    }
479
480    #[test]
481    fn test_encode_repeated_message() {
482        let message = encode_message(
483            &test_message_descriptor("RepeatedMessage"),
484            Value::Object(BTreeMap::from([(
485                "messages".into(),
486                Value::Array(vec![
487                    Value::Object(BTreeMap::from([(
488                        "text".into(),
489                        Value::Bytes(Bytes::from("vector")),
490                    )])),
491                    Value::Object(BTreeMap::from([("index".into(), Value::Integer(4444))])),
492                    Value::Object(BTreeMap::from([
493                        ("text".into(), Value::Bytes(Bytes::from("protobuf"))),
494                        ("index".into(), Value::Integer(1)),
495                    ])),
496                ]),
497            )])),
498            &Options::default(),
499        )
500        .unwrap();
501        let list = mfield!(message, "messages").as_list().unwrap().to_vec();
502        assert_eq!(3, list.len());
503        assert_eq!(
504            Some("vector"),
505            mfield!(list[0].as_message().unwrap(), "text").as_str()
506        );
507        assert!(!list[0].as_message().unwrap().has_field_by_name("index"));
508        assert!(!list[1].as_message().unwrap().has_field_by_name("t4ext"));
509        assert_eq!(
510            Some(4444),
511            mfield!(list[1].as_message().unwrap(), "index").as_u32()
512        );
513        assert_eq!(
514            Some("protobuf"),
515            mfield!(list[2].as_message().unwrap(), "text").as_str()
516        );
517        assert_eq!(
518            Some(1),
519            mfield!(list[2].as_message().unwrap(), "index").as_u32()
520        );
521    }
522
523    #[test]
524    fn test_encode_value_as_string() {
525        let mut message = encode_message(
526            &test_message_descriptor("Bytes"),
527            Value::Object(BTreeMap::from([("text".into(), Value::Boolean(true))])),
528            &Options::default(),
529        )
530        .unwrap();
531        assert_eq!(Some("true"), mfield!(message, "text").as_str());
532        message = encode_message(
533            &test_message_descriptor("Bytes"),
534            Value::Object(BTreeMap::from([("text".into(), Value::Integer(123))])),
535            &Options::default(),
536        )
537        .unwrap();
538        assert_eq!(Some("123"), mfield!(message, "text").as_str());
539        message = encode_message(
540            &test_message_descriptor("Bytes"),
541            Value::Object(BTreeMap::from([(
542                "text".into(),
543                Value::Float(NotNan::new(45.67).unwrap()),
544            )])),
545            &Options::default(),
546        )
547        .unwrap();
548        assert_eq!(Some("45.67"), mfield!(message, "text").as_str());
549        message = encode_message(
550            &test_message_descriptor("Bytes"),
551            Value::Object(BTreeMap::from([(
552                "text".into(),
553                Value::Timestamp(
554                    DateTime::from_timestamp(8675, 309).expect("could not compute timestamp"),
555                ),
556            )])),
557            &Options::default(),
558        )
559        .unwrap();
560        assert_eq!(
561            Some("1970-01-01 02:24:35.000000309 UTC"),
562            mfield!(message, "text").as_str()
563        );
564    }
565
566    fn read_pb_file(protobuf_bin_message_path: &str) -> String {
567        fs::read_to_string(test_data_dir().join(protobuf_bin_message_path)).unwrap()
568    }
569
570    #[test]
571    fn test_parse_files() {
572        let value = value!({ name: "Someone", phones: [{number: "123-456"}] });
573        let path = test_data_dir().join("test_protobuf/v1/test_protobuf.desc");
574        let descriptor = get_message_descriptor(&path, "test_protobuf.v1.Person").unwrap();
575        let expected_value = value!(read_pb_file("test_protobuf/v1/input/person_someone.pb"));
576        let encoded_value = encode_proto(&descriptor, value.clone());
577        assert!(
578            encoded_value.is_ok(),
579            "Failed to encode proto: {:?}",
580            encoded_value.unwrap_err()
581        ); // Check if the Result is Ok
582        let encoded_value = encoded_value.unwrap();
583        assert_eq!(expected_value.as_bytes(), encoded_value.as_bytes());
584
585        // Also test parse_proto.
586        let parsed_value = parse_proto(&descriptor, encoded_value);
587        assert!(
588            parsed_value.is_ok(),
589            "Failed to parse proto: {:?}",
590            parsed_value.unwrap_err()
591        );
592        let parsed_value = parsed_value.unwrap();
593        assert_eq!(value, parsed_value)
594    }
595
596    #[test]
597    fn test_parse_proto3() {
598        let value =
599            value!({name: "Someone",phones: [{number: "123-456", type: "PHONE_TYPE_MOBILE"}]});
600        let descriptor = test_protobuf3_descriptor();
601        let expected_value = value!(read_pb_file("test_protobuf3/v1/input/person_someone.pb"));
602        let encoded_value = encode_proto(&descriptor, value.clone());
603        assert!(
604            encoded_value.is_ok(),
605            "Failed to encode proto: {:?}",
606            encoded_value.unwrap_err()
607        ); // Check if the Result is Ok
608        let encoded_value = encoded_value.unwrap();
609        assert_eq!(encoded_value.as_bytes(), expected_value.as_bytes());
610
611        // Also test parse_proto.
612        let parsed_value = parse_proto(&descriptor, encoded_value);
613        assert!(
614            parsed_value.is_ok(),
615            "Failed to parse proto: {:?}",
616            parsed_value.unwrap_err()
617        );
618        let parsed_value = parsed_value.unwrap();
619        assert_eq!(value, parsed_value)
620    }
621
622    #[test]
623    fn test_encode_with_default_options() {
624        let value = value!({
625            name: "Someone",
626            job_description: "Software Engineer"
627        });
628        let descriptor = test_protobuf3_descriptor();
629
630        let message = encode_message(&descriptor, value, &Options::default()).unwrap();
631
632        assert_eq!(Some("Someone"), mfield!(message, "name").as_str());
633        assert_eq!(
634            Some("Software Engineer"),
635            mfield!(message, "job_description").as_str()
636        );
637    }
638
639    #[test]
640    fn test_encode_with_json_names() {
641        let value = value!({
642            name: "Someone",
643            jobDescription: "Software Engineer"
644        });
645        let descriptor = test_protobuf3_descriptor();
646
647        let message = encode_message(
648            &descriptor,
649            value,
650            &Options {
651                use_json_names: true,
652            },
653        )
654        .unwrap();
655
656        assert_eq!(Some("Someone"), mfield!(message, "name").as_str());
657        assert_eq!(
658            Some("Software Engineer"),
659            mfield!(message, "job_description").as_str()
660        );
661    }
662}