From 08371878cc22fae85f73b436ee4577ca88195107 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Thu, 21 Feb 2019 03:47:40 +0000 Subject: [PATCH] Support more extension types in codegen Pure rust codegen doesn't support enum or message extensions --- protobuf-codegen-pure/src/convert.rs | 58 +++++++++++++++++- protobuf-test/src/common/v2/test_ext.rs | 29 +++++++++ protobuf-test/src/common/v2/test_ext_pb.proto | 60 +++++++++++++++++++ 3 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 protobuf-test/src/common/v2/test_ext.rs create mode 100644 protobuf-test/src/common/v2/test_ext_pb.proto diff --git a/protobuf-codegen-pure/src/convert.rs b/protobuf-codegen-pure/src/convert.rs index 4138a23c9..7d8a77915 100644 --- a/protobuf-codegen-pure/src/convert.rs +++ b/protobuf-codegen-pure/src/convert.rs @@ -10,13 +10,14 @@ use protobuf::prelude::*; use protobuf::Message; use protobuf::text_format::lexer::StrLitDecodeError; +use std::mem; #[derive(Debug)] pub enum ConvertError { UnsupportedOption(String), ExtensionNotFound(String), WrongExtensionType(String, &'static str), - UnsupportedExtensionType(String, String), + UnsupportedExtensionType(String, String, String), StrLitDecodeError(StrLitDecodeError), DefaultValueIsNotStringLiteral, WrongOptionType, @@ -884,14 +885,48 @@ impl<'a> Resolver<'a> { Ok(protobuf::UnknownValue::Varint(if b { 1 } else { 0 })) } } + // TODO: check overflow &model::ProtobufConstant::U64(v) => { match field_type { - &model::FieldType::Fixed64 => Ok(protobuf::UnknownValue::Fixed64(v)), - // TODO: check overflow + &model::FieldType::Fixed64 + | model::FieldType::Sfixed64 => Ok(protobuf::UnknownValue::Fixed64(v)), + &model::FieldType::Fixed32 + | model::FieldType::Sfixed32 => Ok(protobuf::UnknownValue::Fixed32(v as u32)), &model::FieldType::Int64 | &model::FieldType::Int32 | &model::FieldType::Uint64 | &model::FieldType::Uint32 => Ok(protobuf::UnknownValue::Varint(v)), + &model::FieldType::Sint64 => Ok(protobuf::UnknownValue::sint64(v as i64)), + &model::FieldType::Sint32 => Ok(protobuf::UnknownValue::sint32(v as i32)), + _ => Err(()), + } + } + &model::ProtobufConstant::I64(v) => { + match field_type { + &model::FieldType::Fixed64 + | model::FieldType::Sfixed64 => Ok(protobuf::UnknownValue::Fixed64(v as u64)), + &model::FieldType::Fixed32 + | model::FieldType::Sfixed32 => Ok(protobuf::UnknownValue::Fixed32(v as u32)), + &model::FieldType::Int64 + | &model::FieldType::Int32 + | &model::FieldType::Uint64 + | &model::FieldType::Uint32 => Ok(protobuf::UnknownValue::Varint(v as u64)), + &model::FieldType::Sint64 => Ok(protobuf::UnknownValue::sint64(v as i64)), + &model::FieldType::Sint32 => Ok(protobuf::UnknownValue::sint32(v as i32)), + _ => Err(()), + } + } + &model::ProtobufConstant::F64(f) => { + match field_type { + &model::FieldType::Float => Ok(protobuf::UnknownValue::Fixed32(unsafe { mem::transmute::(f as f32) })), + &model::FieldType::Double => Ok(protobuf::UnknownValue::Fixed64(unsafe { mem::transmute::(f) })), + _ => Err(()), + } + } + &model::ProtobufConstant::String(ref s) => { + match field_type { + &model::FieldType::String => Ok(protobuf::UnknownValue::LengthDelimited(s.decode_utf8()?.into_bytes())), + &model::FieldType::Bytes => Ok(protobuf::UnknownValue::LengthDelimited(s.decode_bytes()?)), _ => Err(()), } } @@ -902,6 +937,7 @@ impl<'a> Resolver<'a> { ConvertError::UnsupportedExtensionType( option_name.to_owned(), format!("{:?}", field_type), + format!("{:?}", value), ) }) } @@ -914,6 +950,16 @@ impl<'a> Resolver<'a> { self.custom_options(input, "google.protobuf.FileOptions", r.mut_unknown_fields())?; Ok(r) } + + fn extension( + &self, + input: &model::Extension, + ) -> ConvertResult { + let relative_path = RelativePath::new("".to_owned()); + let mut field = self.field(&input.field, None, &relative_path)?; + field.set_extendee(self.resolve_message_or_enum(&input.extendee, &relative_path).0.path); + Ok(field) + } } fn syntax(input: model::Syntax) -> String { @@ -962,5 +1008,11 @@ pub fn file_descriptor( .options .set_message(resolver.file_options(&input.options)?); + let mut extensions = protobuf::RepeatedField::new(); + for e in &input.extensions { + extensions.push(resolver.extension(e)?); + } + output.extension = extensions; + Ok(output) } diff --git a/protobuf-test/src/common/v2/test_ext.rs b/protobuf-test/src/common/v2/test_ext.rs new file mode 100644 index 000000000..107ba2cdd --- /dev/null +++ b/protobuf-test/src/common/v2/test_ext.rs @@ -0,0 +1,29 @@ +use protobuf::prelude::*; +use protobuf::Message; + +use super::test_ext_pb::*; + +#[test] +fn test_get() { + let descriptor = MyMessage::descriptor_static(); + let message = descriptor.get_proto().options.get_message(); + assert_eq!(10.5, exts::double_field.get(message).unwrap_or_default()); + assert_eq!(-8.5, exts::float_field.get(message).unwrap_or_default()); + assert_eq!(-3, exts::int32_field.get(message).unwrap_or_default()); + assert_eq!(-13, exts::int64_field.get(message).unwrap_or_default()); + assert_eq!(-4, exts::sint32_field.get(message).unwrap_or_default()); + assert_eq!(-14, exts::sint64_field.get(message).unwrap_or_default()); + assert_eq!(5, exts::uint32_field.get(message).unwrap_or_default()); + assert_eq!(15, exts::uint64_field.get(message).unwrap_or_default()); + assert_eq!(6, exts::fixed32_field.get(message).unwrap_or_default()); + assert_eq!(16, exts::fixed64_field.get(message).unwrap_or_default()); + assert_eq!(7, exts::sfixed32_field.get(message).unwrap_or_default()); + assert_eq!(-17, exts::sfixed64_field.get(message).unwrap_or_default()); + assert_eq!(true, exts::bool_field.get(message).unwrap_or_default()); + assert_eq!("Hello world!", exts::string_field.get(message).unwrap_or_default()); + if false { + // TODO: only implemented in `protoc`-based codegen + assert_eq!(TestEnum::RED, exts::enum_field.get(message).unwrap_or_default()); + assert_eq!(22, exts::message_field.get(message).unwrap().get_n()); + } +} diff --git a/protobuf-test/src/common/v2/test_ext_pb.proto b/protobuf-test/src/common/v2/test_ext_pb.proto new file mode 100644 index 000000000..dcc9fd91e --- /dev/null +++ b/protobuf-test/src/common/v2/test_ext_pb.proto @@ -0,0 +1,60 @@ +syntax = "proto2"; + +package test_ext; + +import "google/protobuf/descriptor.proto"; +import "rustproto.proto"; +option (rustproto.generate_accessors_all) = true; + + +message SubM { + optional int32 n = 1; +} + +enum TestEnum { + UNDEFINED = 0; + RED = 1; + BLUE = 2; + GREEN = 3; +} + + +extend google.protobuf.MessageOptions { + optional double double_field = 50001; + optional float float_field = 50002; + optional int32 int32_field = 50003; + optional int64 int64_field = 50004; + optional uint32 uint32_field = 50005; + optional uint64 uint64_field = 50006; + optional sint32 sint32_field = 50007; + optional sint64 sint64_field = 50008; + optional fixed32 fixed32_field = 50009; + optional fixed64 fixed64_field = 50010; + optional sfixed32 sfixed32_field = 50011; + optional sfixed64 sfixed64_field = 50012; + optional bool bool_field = 50013; + optional string string_field = 50014; + optional bytes bytes_field = 50015; + optional TestEnum enum_field = 50016; + optional SubM message_field = 50017; +} + +message MyMessage { + option (double_field) = 10.5; + option (float_field) = -8.5; + option (int32_field) = -3; + option (int64_field) = -13; + option (sint32_field) = -4; + option (sint64_field) = -14; + option (uint32_field) = 5; + option (uint64_field) = 15; + option (fixed32_field) = 6; + option (fixed64_field) = 16; + option (sfixed32_field) = 7; + option (sfixed64_field) = -17; + option (bool_field) = true; + option (string_field) = "Hello world!"; + option (bytes_field) = "bytes"; + option (enum_field) = RED; + option (message_field) = { n: 22 }; +}