diff --git a/changelog.d/1304.enhancement.md b/changelog.d/1304.enhancement.md new file mode 100644 index 0000000000..2722c7aaff --- /dev/null +++ b/changelog.d/1304.enhancement.md @@ -0,0 +1 @@ +The `encode_proto` function was enhanced to automatically convert integer, float, and boolean values when passed to string proto fields. diff --git a/src/protobuf/encode.rs b/src/protobuf/encode.rs index fa4f6a1141..60b3e5df75 100644 --- a/src/protobuf/encode.rs +++ b/src/protobuf/encode.rs @@ -127,6 +127,10 @@ fn convert_value_raw( .map_err(|e| format!("Error setting 'nanos' field: {}", e))?; Ok(prost_reflect::Value::Message(message)) } + (Value::Boolean(b), Kind::String) => Ok(prost_reflect::Value::String(b.to_string())), + (Value::Integer(i), Kind::String) => Ok(prost_reflect::Value::String(i.to_string())), + (Value::Float(f), Kind::String) => Ok(prost_reflect::Value::String(f.to_string())), + (Value::Timestamp(t), Kind::String) => Ok(prost_reflect::Value::String(t.to_string())), _ => Err(format!( "Cannot encode `{kind_str}` into protobuf `{kind:?}`", )), @@ -168,7 +172,12 @@ pub fn encode_message( match map.get(field.name()) { None | Some(Value::Null) => message.clear_field(&field), Some(value) => message - .try_set_field(&field, convert_value(&field, value.clone())?) + .try_set_field( + &field, + convert_value(&field, value.clone()).map_err(|e| { + format!("Error converting {} field: {}", field.name(), e) + })?, + ) .map_err(|e| format!("Error setting {} field: {}", field.name(), e))?, } } @@ -448,6 +457,45 @@ mod tests { ); } + #[test] + fn test_encode_value_as_string() { + let mut message = encode_message( + &test_message_descriptor("Bytes"), + Value::Object(BTreeMap::from([("text".into(), Value::Boolean(true))])), + ) + .unwrap(); + assert_eq!(Some("true"), mfield!(message, "text").as_str()); + message = encode_message( + &test_message_descriptor("Bytes"), + Value::Object(BTreeMap::from([("text".into(), Value::Integer(123))])), + ) + .unwrap(); + assert_eq!(Some("123"), mfield!(message, "text").as_str()); + message = encode_message( + &test_message_descriptor("Bytes"), + Value::Object(BTreeMap::from([( + "text".into(), + Value::Float(NotNan::new(45.67).unwrap()), + )])), + ) + .unwrap(); + assert_eq!(Some("45.67"), mfield!(message, "text").as_str()); + message = encode_message( + &test_message_descriptor("Bytes"), + Value::Object(BTreeMap::from([( + "text".into(), + Value::Timestamp( + DateTime::from_timestamp(8675, 309).expect("could not compute timestamp"), + ), + )])), + ) + .unwrap(); + assert_eq!( + Some("1970-01-01 02:24:35.000000309 UTC"), + mfield!(message, "text").as_str() + ); + } + fn read_pb_file(protobuf_bin_message_path: &str) -> String { fs::read_to_string(test_data_dir().join(protobuf_bin_message_path)).unwrap() } diff --git a/tests/data/protobuf/Makefile b/tests/data/protobuf/Makefile new file mode 100644 index 0000000000..a44a3306ee --- /dev/null +++ b/tests/data/protobuf/Makefile @@ -0,0 +1,4 @@ +generate-desc: + protoc --proto_path=. --include_imports --descriptor_set_out=test.desc test.proto + protoc --proto_path=. --include_imports --descriptor_set_out=test_protobuf.desc test_protobuf.proto + protoc --proto_path=. --include_imports --descriptor_set_out=test_protobuf3.desc test_protobuf3.proto diff --git a/tests/data/protobuf/test.proto b/tests/data/protobuf/test.proto new file mode 100644 index 0000000000..82356febb5 --- /dev/null +++ b/tests/data/protobuf/test.proto @@ -0,0 +1,61 @@ +syntax = "proto3"; + +import "google/protobuf/timestamp.proto"; + +package test; + +message Integers { + int32 i32 = 1; + int64 i64 = 2; + uint32 u32 = 3; + uint64 u64 = 4; +} + +message Floats { + double d = 1; + float f = 2; +} + +message Bytes { + string text = 1; + bytes binary = 2; +} + +message Map { + message Person { + string nickname = 1; + uint32 age = 2; + } + + map names = 1; + map people = 2; + +} + +message Enum { + enum Fruit { + APPLE = 0; + OLIVE = 1; + TOMATO = 2; + } + Fruit breakfast = 1; + Fruit lunch = 2; + Fruit dinner = 3; +} + +message Timestamp { + google.protobuf.Timestamp morning = 1; +} + +message RepeatedPrimitive { + repeated int64 numbers = 1; +} + +message RepeatedMessage { + repeated EmbeddedMessage messages = 1; + + message EmbeddedMessage { + optional string text = 1; + optional uint32 index = 2; + } +} diff --git a/tests/data/protobuf/test_protobuf.desc b/tests/data/protobuf/test_protobuf.desc index 43e7acf6cf..658b7f8d61 100644 Binary files a/tests/data/protobuf/test_protobuf.desc and b/tests/data/protobuf/test_protobuf.desc differ diff --git a/tests/data/protobuf/test_protobuf3.desc b/tests/data/protobuf/test_protobuf3.desc index 9fcfec71b4..ab2f3ca6ec 100644 Binary files a/tests/data/protobuf/test_protobuf3.desc and b/tests/data/protobuf/test_protobuf3.desc differ