diff options
Diffstat (limited to '2.27.1/src/field/mod.rs')
-rw-r--r-- | 2.27.1/src/field/mod.rs | 2031 |
1 files changed, 2031 insertions, 0 deletions
diff --git a/2.27.1/src/field/mod.rs b/2.27.1/src/field/mod.rs new file mode 100644 index 0000000..e4be944 --- /dev/null +++ b/2.27.1/src/field/mod.rs @@ -0,0 +1,2031 @@ +use std::marker; + +use float; +use inside::protobuf_crate_path; +use message::RustTypeMessage; +use oneof::OneofField; +use protobuf::descriptor::*; +use protobuf::rt; +use protobuf::rust; +use protobuf::text_format; +use protobuf::wire_format; +use protobuf_name::ProtobufAbsolutePath; +use rust_name::RustIdent; +use rust_name::RustIdentWithPath; +use scope::FieldWithContext; +use scope::MessageOrEnumWithScope; +use scope::RootScope; +use scope::WithScope; +use syntax::Syntax; + +use super::code_writer::CodeWriter; +use super::customize::customize_from_rustproto_for_field; +use super::customize::Customize; +use super::enums::*; +use super::rust_types_values::*; + +fn type_is_copy(field_type: FieldDescriptorProto_Type) -> bool { + match field_type { + FieldDescriptorProto_Type::TYPE_MESSAGE + | FieldDescriptorProto_Type::TYPE_STRING + | FieldDescriptorProto_Type::TYPE_BYTES => false, + _ => true, + } +} + +trait FieldDescriptorProtoTypeExt { + fn read(&self, is: &str, primitive_type_variant: PrimitiveTypeVariant) -> String; + fn is_s_varint(&self) -> bool; +} + +impl FieldDescriptorProtoTypeExt for FieldDescriptorProto_Type { + fn read(&self, is: &str, primitive_type_variant: PrimitiveTypeVariant) -> String { + match primitive_type_variant { + PrimitiveTypeVariant::Default => format!("{}.read_{}()", is, protobuf_name(*self)), + PrimitiveTypeVariant::Carllerche => { + let protobuf_name = match self { + &FieldDescriptorProto_Type::TYPE_STRING => "chars", + _ => protobuf_name(*self), + }; + format!("{}.read_carllerche_{}()", is, protobuf_name) + } + } + } + + /// True if self is signed integer with zigzag encoding + fn is_s_varint(&self) -> bool { + match *self { + FieldDescriptorProto_Type::TYPE_SINT32 | FieldDescriptorProto_Type::TYPE_SINT64 => true, + _ => false, + } + } +} + +fn field_type_wire_type(field_type: FieldDescriptorProto_Type) -> wire_format::WireType { + use protobuf::wire_format::*; + match field_type { + FieldDescriptorProto_Type::TYPE_INT32 => WireTypeVarint, + FieldDescriptorProto_Type::TYPE_INT64 => WireTypeVarint, + FieldDescriptorProto_Type::TYPE_UINT32 => WireTypeVarint, + FieldDescriptorProto_Type::TYPE_UINT64 => WireTypeVarint, + FieldDescriptorProto_Type::TYPE_SINT32 => WireTypeVarint, + FieldDescriptorProto_Type::TYPE_SINT64 => WireTypeVarint, + FieldDescriptorProto_Type::TYPE_BOOL => WireTypeVarint, + FieldDescriptorProto_Type::TYPE_ENUM => WireTypeVarint, + FieldDescriptorProto_Type::TYPE_FIXED32 => WireTypeFixed32, + FieldDescriptorProto_Type::TYPE_FIXED64 => WireTypeFixed64, + FieldDescriptorProto_Type::TYPE_SFIXED32 => WireTypeFixed32, + FieldDescriptorProto_Type::TYPE_SFIXED64 => WireTypeFixed64, + FieldDescriptorProto_Type::TYPE_FLOAT => WireTypeFixed32, + FieldDescriptorProto_Type::TYPE_DOUBLE => WireTypeFixed64, + FieldDescriptorProto_Type::TYPE_STRING => WireTypeLengthDelimited, + FieldDescriptorProto_Type::TYPE_BYTES => WireTypeLengthDelimited, + FieldDescriptorProto_Type::TYPE_MESSAGE => WireTypeLengthDelimited, + FieldDescriptorProto_Type::TYPE_GROUP => WireTypeLengthDelimited, // not true + } +} + +fn type_protobuf_name(field_type: FieldDescriptorProto_Type) -> &'static str { + match field_type { + FieldDescriptorProto_Type::TYPE_INT32 => "int32", + FieldDescriptorProto_Type::TYPE_INT64 => "int64", + FieldDescriptorProto_Type::TYPE_UINT32 => "uint32", + FieldDescriptorProto_Type::TYPE_UINT64 => "uint64", + FieldDescriptorProto_Type::TYPE_SINT32 => "sint32", + FieldDescriptorProto_Type::TYPE_SINT64 => "sint64", + FieldDescriptorProto_Type::TYPE_BOOL => "bool", + FieldDescriptorProto_Type::TYPE_FIXED32 => "fixed32", + FieldDescriptorProto_Type::TYPE_FIXED64 => "fixed64", + FieldDescriptorProto_Type::TYPE_SFIXED32 => "sfixed32", + FieldDescriptorProto_Type::TYPE_SFIXED64 => "sfixed64", + FieldDescriptorProto_Type::TYPE_FLOAT => "float", + FieldDescriptorProto_Type::TYPE_DOUBLE => "double", + FieldDescriptorProto_Type::TYPE_STRING => "string", + FieldDescriptorProto_Type::TYPE_BYTES => "bytes", + FieldDescriptorProto_Type::TYPE_ENUM + | FieldDescriptorProto_Type::TYPE_MESSAGE + | FieldDescriptorProto_Type::TYPE_GROUP => panic!(), + } +} + +fn field_type_protobuf_name<'a>(field: &'a FieldDescriptorProto) -> &'a str { + if field.has_type_name() { + field.get_type_name() + } else { + type_protobuf_name(field.get_field_type()) + } +} + +// size of value for type, None if variable +fn field_type_size(field_type: FieldDescriptorProto_Type) -> Option<u32> { + match field_type { + FieldDescriptorProto_Type::TYPE_BOOL => Some(1), + t if field_type_wire_type(t) == wire_format::WireTypeFixed32 => Some(4), + t if field_type_wire_type(t) == wire_format::WireTypeFixed64 => Some(8), + _ => None, + } +} + +#[derive(Clone, PartialEq, Eq)] +pub enum SingularFieldFlag { + // proto2 or proto3 message + WithFlag { required: bool }, + // proto3 + WithoutFlag, +} + +impl SingularFieldFlag { + pub fn is_required(&self) -> bool { + match *self { + SingularFieldFlag::WithFlag { required, .. } => required, + SingularFieldFlag::WithoutFlag => false, + } + } +} + +#[derive(Clone)] +pub(crate) struct SingularField<'a> { + pub flag: SingularFieldFlag, + pub elem: FieldElem<'a>, +} + +impl<'a> SingularField<'a> { + fn rust_storage_type(&self) -> RustType { + match self.flag { + SingularFieldFlag::WithFlag { .. } => match self.elem.proto_type() { + FieldDescriptorProto_Type::TYPE_MESSAGE => { + RustType::SingularPtrField(Box::new(self.elem.rust_storage_type())) + } + FieldDescriptorProto_Type::TYPE_STRING | FieldDescriptorProto_Type::TYPE_BYTES + if self.elem.primitive_type_variant() == PrimitiveTypeVariant::Default => + { + RustType::SingularField(Box::new(self.elem.rust_storage_type())) + } + _ => RustType::Option(Box::new(self.elem.rust_storage_type())), + }, + SingularFieldFlag::WithoutFlag => self.elem.rust_storage_type(), + } + } +} + +#[derive(Clone)] +pub(crate) struct RepeatedField<'a> { + pub elem: FieldElem<'a>, + pub packed: bool, +} + +impl<'a> RepeatedField<'a> { + fn rust_type(&self) -> RustType { + if !self.elem.is_copy() + && self.elem.primitive_type_variant() != PrimitiveTypeVariant::Carllerche + { + RustType::RepeatedField(Box::new(self.elem.rust_storage_type())) + } else { + RustType::Vec(Box::new(self.elem.rust_storage_type())) + } + } +} + +#[derive(Clone)] +pub struct MapField<'a> { + _name: String, + key: FieldElem<'a>, + value: FieldElem<'a>, +} + +#[derive(Clone)] +pub(crate) enum FieldKind<'a> { + // optional or required + Singular(SingularField<'a>), + // repeated except map + Repeated(RepeatedField<'a>), + // map + Map(MapField<'a>), + // part of oneof + Oneof(OneofField<'a>), +} + +impl<'a> FieldKind<'a> { + fn elem(&self) -> &FieldElem { + match self { + &FieldKind::Singular(ref s) => &s.elem, + &FieldKind::Repeated(ref r) => &r.elem, + &FieldKind::Oneof(ref o) => &o.elem, + &FieldKind::Map(..) => { + panic!("no single elem type for map field"); + } + } + } + + fn primitive_type_variant(&self) -> PrimitiveTypeVariant { + self.elem().primitive_type_variant() + } +} + +// Representation of map entry: key type and value type +#[derive(Clone, Debug)] +pub struct EntryKeyValue<'a>(FieldElem<'a>, FieldElem<'a>); + +#[derive(Clone, Debug)] +pub(crate) enum FieldElem<'a> { + Primitive(FieldDescriptorProto_Type, PrimitiveTypeVariant), + // name, file name, entry + Message( + String, + String, + Option<Box<EntryKeyValue<'a>>>, + marker::PhantomData<&'a ()>, + ), + // name, file name, default value + Enum(String, String, RustIdent), + Group, +} + +impl<'a> FieldElem<'a> { + fn proto_type(&self) -> FieldDescriptorProto_Type { + match *self { + FieldElem::Primitive(t, ..) => t, + FieldElem::Group => FieldDescriptorProto_Type::TYPE_GROUP, + FieldElem::Message(..) => FieldDescriptorProto_Type::TYPE_MESSAGE, + FieldElem::Enum(..) => FieldDescriptorProto_Type::TYPE_ENUM, + } + } + + fn is_copy(&self) -> bool { + type_is_copy(self.proto_type()) + } + + pub fn rust_storage_type(&self) -> RustType { + match *self { + FieldElem::Primitive(t, PrimitiveTypeVariant::Default) => rust_name(t), + FieldElem::Primitive( + FieldDescriptorProto_Type::TYPE_STRING, + PrimitiveTypeVariant::Carllerche, + ) => RustType::Chars, + FieldElem::Primitive( + FieldDescriptorProto_Type::TYPE_BYTES, + PrimitiveTypeVariant::Carllerche, + ) => RustType::Bytes, + FieldElem::Primitive(.., PrimitiveTypeVariant::Carllerche) => unreachable!(), + FieldElem::Group => RustType::Group, + FieldElem::Message(ref name, ..) => { + RustType::Message(RustTypeMessage(RustIdentWithPath::new(name.clone()))) + } + FieldElem::Enum(ref name, _, ref default_value) => { + RustType::Enum(name.clone(), default_value.clone()) + } + } + } + + fn protobuf_type_gen(&self) -> ProtobufTypeGen { + match *self { + FieldElem::Primitive(t, v) => ProtobufTypeGen::Primitive(t, v), + FieldElem::Message(ref name, ..) => ProtobufTypeGen::Message(name.clone()), + FieldElem::Enum(ref name, ..) => ProtobufTypeGen::Enum(name.clone()), + FieldElem::Group => unreachable!(), + } + } + + /// implementation of ProtobufType trait + fn lib_protobuf_type(&self, customize: &Customize) -> String { + self.protobuf_type_gen().rust_type(customize) + } + + fn primitive_type_variant(&self) -> PrimitiveTypeVariant { + match self { + &FieldElem::Primitive(_, v) => v, + _ => PrimitiveTypeVariant::Default, + } + } +} + +fn field_elem<'a>( + field: &FieldWithContext, + root_scope: &'a RootScope<'a>, + parse_map: bool, + customize: &Customize, +) -> (FieldElem<'a>, Option<EnumValueGen>) { + if field.field.get_field_type() == FieldDescriptorProto_Type::TYPE_GROUP { + (FieldElem::Group, None) + } else if field.field.has_type_name() { + let message_or_enum = root_scope + .find_message_or_enum(&ProtobufAbsolutePath::from(field.field.get_type_name())); + let file_name = message_or_enum + .get_scope() + .file_scope + .file_descriptor + .get_name() + .to_owned(); + let rust_relative_name = type_name_to_rust_relative( + &ProtobufAbsolutePath::from(field.field.get_type_name()), + field.message.get_scope().file_scope.file_descriptor, + false, + root_scope, + customize, + ); + match (field.field.get_field_type(), message_or_enum) { + ( + FieldDescriptorProto_Type::TYPE_MESSAGE, + MessageOrEnumWithScope::Message(message_with_scope), + ) => { + let entry_key_value = if let (true, Some((key, value))) = + (parse_map, message_with_scope.map_entry()) + { + Some(Box::new(EntryKeyValue( + field_elem(&key, root_scope, false, customize).0, + field_elem(&value, root_scope, false, customize).0, + ))) + } else { + None + }; + ( + FieldElem::Message( + rust_relative_name, + file_name, + entry_key_value, + marker::PhantomData, + ), + None, + ) + } + ( + FieldDescriptorProto_Type::TYPE_ENUM, + MessageOrEnumWithScope::Enum(enum_with_scope), + ) => { + let e = EnumGen::new( + &enum_with_scope, + field.message.get_scope().get_file_descriptor(), + customize, + root_scope, + ); + let ev = if field.field.has_default_value() { + e.value_by_name(field.field.get_default_value()).clone() + } else { + e.values_unique().into_iter().next().unwrap() + }; + ( + FieldElem::Enum( + rust_relative_name, + file_name, + RustIdent::from(enum_with_scope.values()[0].rust_name().to_owned()), + ), + Some(ev), + ) + } + _ => panic!("unknown named type: {:?}", field.field.get_field_type()), + } + } else if field.field.has_field_type() { + let carllerche_for_bytes = customize.carllerche_bytes_for_bytes.unwrap_or(false); + let carllerche_for_string = customize.carllerche_bytes_for_string.unwrap_or(false); + + let elem = match field.field.get_field_type() { + FieldDescriptorProto_Type::TYPE_STRING if carllerche_for_string => { + FieldElem::Primitive( + FieldDescriptorProto_Type::TYPE_STRING, + PrimitiveTypeVariant::Carllerche, + ) + } + FieldDescriptorProto_Type::TYPE_BYTES if carllerche_for_bytes => FieldElem::Primitive( + FieldDescriptorProto_Type::TYPE_BYTES, + PrimitiveTypeVariant::Carllerche, + ), + t => FieldElem::Primitive(t, PrimitiveTypeVariant::Default), + }; + + (elem, None) + } else { + panic!( + "neither type_name, nor field_type specified for field: {}", + field.field.get_name() + ); + } +} + +pub enum AccessorStyle { + Lambda, + HasGet, +} + +pub struct AccessorFn { + name: String, + type_params: Vec<String>, + pub style: AccessorStyle, +} + +impl AccessorFn { + pub fn sig(&self) -> String { + let mut s = self.name.clone(); + s.push_str("::<_"); + for p in &self.type_params { + s.push_str(", "); + s.push_str(&p); + } + s.push_str(">"); + s + } +} + +#[derive(Clone)] +pub(crate) struct FieldGen<'a> { + _root_scope: &'a RootScope<'a>, + syntax: Syntax, + pub proto_field: FieldWithContext<'a>, + // field name in generated code + pub rust_name: RustIdent, + pub proto_type: FieldDescriptorProto_Type, + wire_type: wire_format::WireType, + enum_default_value: Option<EnumValueGen>, + pub kind: FieldKind<'a>, + pub expose_field: bool, + pub generate_accessors: bool, + pub(crate) customize: Customize, +} + +impl<'a> FieldGen<'a> { + pub fn parse( + field: FieldWithContext<'a>, + root_scope: &'a RootScope<'a>, + customize: &Customize, + ) -> FieldGen<'a> { + let mut customize = customize.clone(); + customize.update_with(&customize_from_rustproto_for_field( + &field.field.get_options(), + )); + + let (elem, enum_default_value) = field_elem(&field, root_scope, true, &customize); + + let generate_accessors = customize.generate_accessors.unwrap_or(true); + + let syntax = field.message.scope.file_scope.syntax(); + + let field_may_have_custom_default_value = syntax == Syntax::PROTO2 + && field.field.get_label() != FieldDescriptorProto_Label::LABEL_REPEATED + && field.field.get_field_type() != FieldDescriptorProto_Type::TYPE_MESSAGE; + + let default_expose_field = !field_may_have_custom_default_value; + + let expose_field = customize.expose_fields.unwrap_or(default_expose_field); + + let kind = if field.field.get_label() == FieldDescriptorProto_Label::LABEL_REPEATED { + match (elem, true) { + // map field + (FieldElem::Message(name, _, Some(key_value), _), true) => { + FieldKind::Map(MapField { + _name: name, + key: key_value.0.clone(), + value: key_value.1.clone(), + }) + } + // regular repeated field + (elem, _) => FieldKind::Repeated(RepeatedField { + elem, + packed: field.field.get_options().get_packed(), + }), + } + } else if let Some(oneof) = field.oneof() { + FieldKind::Oneof(OneofField::parse(&oneof, &field, elem, root_scope)) + } else { + let flag = if field.message.scope.file_scope.syntax() == Syntax::PROTO3 + && field.field.get_field_type() != FieldDescriptorProto_Type::TYPE_MESSAGE + { + SingularFieldFlag::WithoutFlag + } else { + SingularFieldFlag::WithFlag { + required: field.field.get_label() == FieldDescriptorProto_Label::LABEL_REQUIRED, + } + }; + FieldKind::Singular(SingularField { elem, flag }) + }; + + FieldGen { + _root_scope: root_scope, + syntax: field.message.get_scope().file_scope.syntax(), + rust_name: field.rust_name(), + proto_type: field.field.get_field_type(), + wire_type: field_type_wire_type(field.field.get_field_type()), + enum_default_value, + proto_field: field.clone(), + kind, + expose_field, + generate_accessors, + customize, + } + } + + fn tag_size(&self) -> u32 { + rt::tag_size(self.proto_field.number()) + } + + pub fn is_oneof(&self) -> bool { + match self.kind { + FieldKind::Oneof(..) => true, + _ => false, + } + } + + pub fn oneof(&self) -> &OneofField { + match self.kind { + FieldKind::Oneof(ref oneof) => &oneof, + _ => panic!("not a oneof field: {}", self.reconstruct_def()), + } + } + + fn is_singular(&self) -> bool { + match self.kind { + FieldKind::Singular(..) => true, + _ => false, + } + } + + fn is_repeated_not_map(&self) -> bool { + match self.kind { + FieldKind::Repeated(..) => true, + _ => false, + } + } + + fn is_repeated_or_map(&self) -> bool { + match self.kind { + FieldKind::Repeated(..) | FieldKind::Map(..) => true, + _ => false, + } + } + + fn is_repeated_packed(&self) -> bool { + match self.kind { + FieldKind::Repeated(RepeatedField { packed: true, .. }) => true, + _ => false, + } + } + + #[allow(dead_code)] + fn repeated(&self) -> &RepeatedField { + match self.kind { + FieldKind::Repeated(ref repeated) => &repeated, + _ => panic!("not a repeated field: {}", self.reconstruct_def()), + } + } + + fn singular(&self) -> &SingularField { + match self.kind { + FieldKind::Singular(ref singular) => &singular, + _ => panic!("not a singular field: {}", self.reconstruct_def()), + } + } + + fn map(&self) -> &MapField { + match self.kind { + FieldKind::Map(ref map) => &map, + _ => panic!("not a map field: {}", self.reconstruct_def()), + } + } + + fn variant_path(&self) -> String { + // TODO: should reuse code from OneofVariantGen + format!( + "{}::{}", + self.oneof().oneof_type_name.to_code(&self.customize), + self.rust_name + ) + } + + // TODO: drop it + pub fn elem(&self) -> &FieldElem { + match self.kind { + FieldKind::Singular(SingularField { ref elem, .. }) => &elem, + FieldKind::Repeated(RepeatedField { ref elem, .. }) => &elem, + FieldKind::Oneof(OneofField { ref elem, .. }) => &elem, + FieldKind::Map(..) => unreachable!(), + } + } + + // type of field in struct + pub fn full_storage_type(&self) -> RustType { + match self.kind { + FieldKind::Repeated(ref repeated) => repeated.rust_type(), + FieldKind::Map(MapField { + ref key, ref value, .. + }) => RustType::HashMap( + Box::new(key.rust_storage_type()), + Box::new(value.rust_storage_type()), + ), + FieldKind::Singular(ref singular) => singular.rust_storage_type(), + FieldKind::Oneof(..) => unreachable!(), + } + } + + // type of `v` in `for v in field` + fn full_storage_iter_elem_type(&self) -> RustType { + if let FieldKind::Oneof(ref oneof) = self.kind { + oneof.elem.rust_storage_type() + } else { + self.full_storage_type().iter_elem_type() + } + } + + // suffix `xxx` as in `os.write_xxx_no_tag(..)` + fn os_write_fn_suffix(&self) -> &str { + protobuf_name(self.proto_type) + } + + // type of `v` in `os.write_xxx_no_tag(v)` + fn os_write_fn_param_type(&self) -> RustType { + match self.proto_type { + FieldDescriptorProto_Type::TYPE_STRING => RustType::Ref(Box::new(RustType::Str)), + FieldDescriptorProto_Type::TYPE_BYTES => { + RustType::Ref(Box::new(RustType::Slice(Box::new(RustType::Int(false, 8))))) + } + FieldDescriptorProto_Type::TYPE_ENUM => RustType::Int(true, 32), + t => rust_name(t), + } + } + + // for field `foo`, type of param of `fn set_foo(..)` + fn set_xxx_param_type(&self) -> RustType { + match self.kind { + FieldKind::Singular(SingularField { ref elem, .. }) + | FieldKind::Oneof(OneofField { ref elem, .. }) => elem.rust_storage_type(), + FieldKind::Repeated(..) | FieldKind::Map(..) => self.full_storage_type(), + } + } + + // for field `foo`, return type if `fn take_foo(..)` + fn take_xxx_return_type(&self) -> RustType { + self.set_xxx_param_type() + } + + // for field `foo`, return type of `fn mut_foo(..)` + fn mut_xxx_return_type(&self) -> RustType { + RustType::Ref(Box::new(match self.kind { + FieldKind::Singular(SingularField { ref elem, .. }) + | FieldKind::Oneof(OneofField { ref elem, .. }) => elem.rust_storage_type(), + FieldKind::Repeated(..) | FieldKind::Map(..) => self.full_storage_type(), + })) + } + + // for field `foo`, return type of `fn get_foo(..)` + fn get_xxx_return_type(&self) -> RustType { + match self.kind { + FieldKind::Singular(SingularField { ref elem, .. }) + | FieldKind::Oneof(OneofField { ref elem, .. }) => match elem.is_copy() { + true => elem.rust_storage_type(), + false => elem.rust_storage_type().ref_type(), + }, + FieldKind::Repeated(RepeatedField { ref elem, .. }) => RustType::Ref(Box::new( + RustType::Slice(Box::new(elem.rust_storage_type())), + )), + FieldKind::Map(..) => RustType::Ref(Box::new(self.full_storage_type())), + } + } + + // fixed size type? + fn is_fixed(&self) -> bool { + field_type_size(self.proto_type).is_some() + } + + // must use zigzag encoding? + fn is_zigzag(&self) -> bool { + match self.proto_type { + FieldDescriptorProto_Type::TYPE_SINT32 | FieldDescriptorProto_Type::TYPE_SINT64 => true, + _ => false, + } + } + + // data is enum + fn is_enum(&self) -> bool { + match self.proto_type { + FieldDescriptorProto_Type::TYPE_ENUM => true, + _ => false, + } + } + + // elem data is not stored in heap + pub fn elem_type_is_copy(&self) -> bool { + type_is_copy(self.proto_type) + } + + fn defaut_value_from_proto_float(&self) -> String { + assert!(self.proto_field.field.has_default_value()); + + let type_name = match self.proto_type { + FieldDescriptorProto_Type::TYPE_FLOAT => "f32", + FieldDescriptorProto_Type::TYPE_DOUBLE => "f64", + _ => unreachable!(), + }; + let proto_default = self.proto_field.field.get_default_value(); + + let f = float::parse_protobuf_float(proto_default) + .expect(&format!("failed to parse float: {:?}", proto_default)); + + if f.is_nan() { + format!("::std::{}::NAN", type_name) + } else if f.is_infinite() { + if f > 0.0 { + format!("::std::{}::INFINITY", type_name) + } else { + format!("::std::{}::NEG_INFINITY", type_name) + } + } else { + format!("{:?}{}", f, type_name) + } + } + + fn default_value_from_proto(&self) -> Option<String> { + assert!(self.is_singular() || self.is_oneof()); + if self.enum_default_value.is_some() { + Some(self.enum_default_value.as_ref().unwrap().rust_name_outer()) + } else if self.proto_field.field.has_default_value() { + let proto_default = self.proto_field.field.get_default_value(); + Some(match self.proto_type { + // For numeric types, contains the original text representation of the value + FieldDescriptorProto_Type::TYPE_DOUBLE | FieldDescriptorProto_Type::TYPE_FLOAT => { + self.defaut_value_from_proto_float() + } + FieldDescriptorProto_Type::TYPE_INT32 + | FieldDescriptorProto_Type::TYPE_SINT32 + | FieldDescriptorProto_Type::TYPE_SFIXED32 => format!("{}i32", proto_default), + FieldDescriptorProto_Type::TYPE_UINT32 + | FieldDescriptorProto_Type::TYPE_FIXED32 => format!("{}u32", proto_default), + FieldDescriptorProto_Type::TYPE_INT64 + | FieldDescriptorProto_Type::TYPE_SINT64 + | FieldDescriptorProto_Type::TYPE_SFIXED64 => format!("{}i64", proto_default), + FieldDescriptorProto_Type::TYPE_UINT64 + | FieldDescriptorProto_Type::TYPE_FIXED64 => format!("{}u64", proto_default), + + // For booleans, "true" or "false" + FieldDescriptorProto_Type::TYPE_BOOL => format!("{}", proto_default), + // For strings, contains the default text contents (not escaped in any way) + FieldDescriptorProto_Type::TYPE_STRING => rust::quote_escape_str(proto_default), + // For bytes, contains the C escaped value. All bytes >= 128 are escaped + FieldDescriptorProto_Type::TYPE_BYTES => { + rust::quote_escape_bytes(&text_format::unescape_string(proto_default)) + } + // TODO: resolve outer message prefix + FieldDescriptorProto_Type::TYPE_GROUP | FieldDescriptorProto_Type::TYPE_ENUM => { + unreachable!() + } + FieldDescriptorProto_Type::TYPE_MESSAGE => panic!( + "default value is not implemented for type: {:?}", + self.proto_type + ), + }) + } else { + None + } + } + + fn default_value_from_proto_typed(&self) -> Option<RustValueTyped> { + self.default_value_from_proto().map(|v| { + let default_value_type = match self.proto_type { + FieldDescriptorProto_Type::TYPE_STRING => RustType::Ref(Box::new(RustType::Str)), + FieldDescriptorProto_Type::TYPE_BYTES => { + RustType::Ref(Box::new(RustType::Slice(Box::new(RustType::u8())))) + } + _ => self.full_storage_iter_elem_type(), + }; + + RustValueTyped { + value: v, + rust_type: default_value_type, + } + }) + } + + // default value to be returned from fn get_xxx + fn get_xxx_default_value_rust(&self) -> String { + assert!(self.is_singular() || self.is_oneof()); + self.default_value_from_proto() + .unwrap_or_else(|| self.get_xxx_return_type().default_value(&self.customize)) + } + + // default to be assigned to field + fn element_default_value_rust(&self) -> RustValueTyped { + assert!( + self.is_singular() || self.is_oneof(), + "field is not singular: {}", + self.reconstruct_def() + ); + self.default_value_from_proto_typed().unwrap_or_else(|| { + self.elem() + .rust_storage_type() + .default_value_typed(&self.customize) + }) + } + + pub fn reconstruct_def(&self) -> String { + let prefix = match (self.proto_field.field.get_label(), self.syntax) { + (FieldDescriptorProto_Label::LABEL_REPEATED, _) => "repeated ", + (_, Syntax::PROTO3) => "", + (FieldDescriptorProto_Label::LABEL_OPTIONAL, _) => "optional ", + (FieldDescriptorProto_Label::LABEL_REQUIRED, _) => "required ", + }; + format!( + "{}{} {} = {}", + prefix, + field_type_protobuf_name(&self.proto_field.field), + self.proto_field.name(), + self.proto_field.number() + ) + } + + pub fn accessor_fn(&self) -> AccessorFn { + match self.kind { + FieldKind::Repeated(RepeatedField { ref elem, .. }) => { + let coll = match self.full_storage_type() { + RustType::Vec(..) => "vec", + RustType::RepeatedField(..) => "repeated_field", + _ => unreachable!(), + }; + let name = format!("make_{}_accessor", coll); + AccessorFn { + name: name, + type_params: vec![elem.lib_protobuf_type(&self.customize)], + style: AccessorStyle::Lambda, + } + } + FieldKind::Map(MapField { + ref key, ref value, .. + }) => AccessorFn { + name: "make_map_accessor".to_owned(), + type_params: vec![ + key.lib_protobuf_type(&self.customize), + value.lib_protobuf_type(&self.customize), + ], + style: AccessorStyle::Lambda, + }, + FieldKind::Singular(SingularField { + ref elem, + flag: SingularFieldFlag::WithoutFlag, + }) => { + if let &FieldElem::Message(ref name, ..) = elem { + // TODO: old style, needed because of default instance + + AccessorFn { + name: "make_singular_message_accessor".to_owned(), + type_params: vec![name.clone()], + style: AccessorStyle::HasGet, + } + } else { + AccessorFn { + name: "make_simple_field_accessor".to_owned(), + type_params: vec![elem.lib_protobuf_type(&self.customize)], + style: AccessorStyle::Lambda, + } + } + } + FieldKind::Singular(SingularField { + ref elem, + flag: SingularFieldFlag::WithFlag { .. }, + }) => { + let coll = match self.full_storage_type() { + RustType::Option(..) => "option", + RustType::SingularField(..) => "singular_field", + RustType::SingularPtrField(..) => "singular_ptr_field", + _ => unreachable!(), + }; + let name = format!("make_{}_accessor", coll); + AccessorFn { + name: name, + type_params: vec![elem.lib_protobuf_type(&self.customize)], + style: AccessorStyle::Lambda, + } + } + FieldKind::Oneof(OneofField { ref elem, .. }) => { + // TODO: uses old style + + let suffix = match &self.elem().rust_storage_type() { + t if t.is_primitive() => t.to_code(&self.customize), + &RustType::String | &RustType::Chars => "string".to_string(), + &RustType::Vec(ref t) if t.is_u8() => "bytes".to_string(), + &RustType::Bytes => "bytes".to_string(), + &RustType::Enum(..) => "enum".to_string(), + &RustType::Message(..) => "message".to_string(), + t => panic!("unexpected field type: {:?}", t), + }; + + let name = format!("make_singular_{}_accessor", suffix); + + let mut type_params = Vec::new(); + match elem { + &FieldElem::Message(ref name, ..) | &FieldElem::Enum(ref name, ..) => { + type_params.push(name.to_owned()); + } + _ => (), + } + + AccessorFn { + name: name, + type_params: type_params, + style: AccessorStyle::HasGet, + } + } + } + } + + pub fn write_clear(&self, w: &mut CodeWriter) { + if self.is_oneof() { + w.write_line(&format!( + "self.{} = ::std::option::Option::None;", + self.oneof().oneof_rust_field_name + )); + } else { + let clear_expr = self + .full_storage_type() + .clear(&self.self_field(), &self.customize); + w.write_line(&format!("{};", clear_expr)); + } + } + + // expression that returns size of data is variable + fn element_size(&self, var: &str, var_type: &RustType) -> String { + assert!(!self.is_repeated_packed()); + + match field_type_size(self.proto_type) { + Some(data_size) => format!("{}", data_size + self.tag_size()), + None => match self.proto_type { + FieldDescriptorProto_Type::TYPE_MESSAGE => panic!("not a single-liner"), + FieldDescriptorProto_Type::TYPE_BYTES => format!( + "{}::rt::bytes_size({}, &{})", + protobuf_crate_path(&self.customize), + self.proto_field.number(), + var + ), + FieldDescriptorProto_Type::TYPE_STRING => format!( + "{}::rt::string_size({}, &{})", + protobuf_crate_path(&self.customize), + self.proto_field.number(), + var + ), + FieldDescriptorProto_Type::TYPE_ENUM => { + let param_type = match var_type { + &RustType::Ref(ref t) => (**t).clone(), + t => t.clone(), + }; + format!( + "{}::rt::enum_size({}, {})", + protobuf_crate_path(&self.customize), + self.proto_field.number(), + var_type.into_target(¶m_type, var, &self.customize) + ) + } + _ => { + let param_type = match var_type { + &RustType::Ref(ref t) => (**t).clone(), + t => t.clone(), + }; + if self.proto_type.is_s_varint() { + format!( + "{}::rt::value_varint_zigzag_size({}, {})", + protobuf_crate_path(&self.customize), + self.proto_field.number(), + var_type.into_target(¶m_type, var, &self.customize) + ) + } else { + format!( + "{}::rt::value_size({}, {}, {}::wire_format::{:?})", + protobuf_crate_path(&self.customize), + self.proto_field.number(), + var_type.into_target(¶m_type, var, &self.customize), + protobuf_crate_path(&self.customize), + self.wire_type, + ) + } + } + }, + } + } + + // output code that writes single element to stream + pub fn write_write_element(&self, w: &mut CodeWriter, os: &str, var: &str, ty: &RustType) { + if let FieldKind::Repeated(RepeatedField { packed: true, .. }) = self.kind { + unreachable!(); + }; + + match self.proto_type { + FieldDescriptorProto_Type::TYPE_MESSAGE => { + w.write_line(&format!( + "{}.write_tag({}, {}::wire_format::{:?})?;", + os, + self.proto_field.number(), + protobuf_crate_path(&self.customize), + wire_format::WireTypeLengthDelimited + )); + w.write_line(&format!( + "{}.write_raw_varint32({}.get_cached_size())?;", + os, var + )); + w.write_line(&format!("{}.write_to_with_cached_sizes({})?;", var, os)); + } + _ => { + let param_type = self.os_write_fn_param_type(); + let os_write_fn_suffix = self.os_write_fn_suffix(); + let number = self.proto_field.number(); + w.write_line(&format!( + "{}.write_{}({}, {})?;", + os, + os_write_fn_suffix, + number, + ty.into_target(¶m_type, var, &self.customize) + )); + } + } + } + + fn self_field(&self) -> String { + format!("self.{}", self.rust_name) + } + + fn self_field_is_some(&self) -> String { + assert!(self.is_singular()); + format!("{}.is_some()", self.self_field()) + } + + fn self_field_is_not_empty(&self) -> String { + assert!(self.is_repeated_or_map()); + format!("!{}.is_empty()", self.self_field()) + } + + fn self_field_is_none(&self) -> String { + assert!(self.is_singular()); + format!("{}.is_none()", self.self_field()) + } + + // type of expression returned by `as_option()` + fn as_option_type(&self) -> RustType { + assert!(self.is_singular()); + match self.full_storage_type() { + RustType::Option(ref e) if e.is_copy() => RustType::Option(e.clone()), + RustType::Option(e) => RustType::Option(Box::new(e.ref_type())), + RustType::SingularField(ty) | RustType::SingularPtrField(ty) => { + RustType::Option(Box::new(RustType::Ref(ty))) + } + x => panic!("cannot convert {:?} to option", x), + } + } + + // field data viewed as Option + fn self_field_as_option(&self) -> RustValueTyped { + assert!(self.is_singular()); + + let suffix = match self.full_storage_type() { + RustType::Option(ref e) if e.is_copy() => "", + _ => ".as_ref()", + }; + + self.as_option_type() + .value(format!("{}{}", self.self_field(), suffix)) + } + + fn write_if_let_self_field_is_some<F>(&self, w: &mut CodeWriter, cb: F) + where + F: Fn(&str, &RustType, &mut CodeWriter), + { + match self.kind { + FieldKind::Repeated(..) | FieldKind::Map(..) => panic!("field is not singular"), + FieldKind::Singular(SingularField { + flag: SingularFieldFlag::WithFlag { .. }, + ref elem, + }) => { + let var = "v"; + let ref_prefix = match elem.rust_storage_type().is_copy() { + true => "", + false => "ref ", + }; + let as_option = self.self_field_as_option(); + w.if_let_stmt( + &format!("Some({}{})", ref_prefix, var), + &as_option.value, + |w| { + let v_type = as_option.rust_type.elem_type(); + cb(var, &v_type, w); + }, + ); + } + FieldKind::Singular(SingularField { + flag: SingularFieldFlag::WithoutFlag, + ref elem, + }) => match *elem { + FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_STRING, ..) + | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_BYTES, ..) => { + w.if_stmt(format!("!{}.is_empty()", self.self_field()), |w| { + cb(&self.self_field(), &self.full_storage_type(), w); + }); + } + _ => { + w.if_stmt( + format!( + "{} != {}", + self.self_field(), + self.full_storage_type().default_value(&self.customize) + ), + |w| { + cb(&self.self_field(), &self.full_storage_type(), w); + }, + ); + } + }, + FieldKind::Oneof(..) => unreachable!(), + } + } + + fn write_if_self_field_is_not_empty<F>(&self, w: &mut CodeWriter, cb: F) + where + F: Fn(&mut CodeWriter), + { + assert!(self.is_repeated_or_map()); + let self_field_is_not_empty = self.self_field_is_not_empty(); + w.if_stmt(self_field_is_not_empty, cb); + } + + pub fn write_if_self_field_is_none<F>(&self, w: &mut CodeWriter, cb: F) + where + F: Fn(&mut CodeWriter), + { + let self_field_is_none = self.self_field_is_none(); + w.if_stmt(self_field_is_none, cb) + } + + // repeated or singular + pub fn write_for_self_field<F>(&self, w: &mut CodeWriter, varn: &str, cb: F) + where + F: Fn(&mut CodeWriter, &RustType), + { + match self.kind { + FieldKind::Oneof(OneofField { + ref elem, + ref oneof_type_name, + .. + }) => { + let cond = format!( + "Some({}::{}(ref {}))", + oneof_type_name.to_code(&self.customize), + self.rust_name, + varn + ); + w.if_let_stmt(&cond, &self.self_field_oneof(), |w| { + cb(w, &elem.rust_storage_type()) + }) + } + _ => { + let v_type = self.full_storage_iter_elem_type(); + let self_field = self.self_field(); + w.for_stmt(&format!("&{}", self_field), varn, |w| cb(w, &v_type)); + } + } + } + + fn write_self_field_assign(&self, w: &mut CodeWriter, value: &str) { + let self_field = self.self_field(); + w.write_line(&format!("{} = {};", self_field, value)); + } + + fn write_self_field_assign_some(&self, w: &mut CodeWriter, value: &str) { + let full_storage_type = self.full_storage_type(); + match self.singular() { + &SingularField { + flag: SingularFieldFlag::WithFlag { .. }, + .. + } => { + self.write_self_field_assign( + w, + &full_storage_type.wrap_value(value, &self.customize), + ); + } + &SingularField { + flag: SingularFieldFlag::WithoutFlag, + .. + } => { + self.write_self_field_assign(w, value); + } + } + } + + fn write_self_field_assign_value(&self, w: &mut CodeWriter, value: &str, ty: &RustType) { + match self.kind { + FieldKind::Repeated(..) | FieldKind::Map(..) => { + let converted = ty.into_target(&self.full_storage_type(), value, &self.customize); + self.write_self_field_assign(w, &converted); + } + FieldKind::Singular(SingularField { ref elem, ref flag }) => { + let converted = ty.into_target(&elem.rust_storage_type(), value, &self.customize); + let wrapped = if *flag == SingularFieldFlag::WithoutFlag { + converted + } else { + self.full_storage_type() + .wrap_value(&converted, &self.customize) + }; + self.write_self_field_assign(w, &wrapped); + } + FieldKind::Oneof(..) => unreachable!(), + } + } + + fn write_self_field_assign_default(&self, w: &mut CodeWriter) { + assert!(self.is_singular()); + if self.is_oneof() { + let self_field_oneof = self.self_field_oneof(); + w.write_line(format!( + "{} = ::std::option::Option::Some({}({}))", + self_field_oneof, + self.variant_path(), + // TODO: default from .proto is not needed here (?) + self.element_default_value_rust() + .into_type(self.full_storage_iter_elem_type(), &self.customize) + .value + )); + } else { + // Note it is different from C++ protobuf, where field is initialized + // with default value + match self.full_storage_type() { + RustType::SingularField(..) | RustType::SingularPtrField(..) => { + let self_field = self.self_field(); + w.write_line(&format!("{}.set_default();", self_field)); + } + _ => { + self.write_self_field_assign_some( + w, + &self + .elem() + .rust_storage_type() + .default_value_typed(&self.customize) + .into_type(self.elem().rust_storage_type(), &self.customize) + .value, + ); + } + } + } + } + + fn self_field_vec_packed_fixed_data_size(&self) -> String { + assert!(self.is_fixed()); + format!( + "({}.len() * {}) as u32", + self.self_field(), + field_type_size(self.proto_type).unwrap() + ) + } + + fn self_field_vec_packed_varint_data_size(&self) -> String { + assert!(!self.is_fixed()); + let fn_name = if self.is_enum() { + "vec_packed_enum_data_size".to_string() + } else { + let zigzag_suffix = if self.is_zigzag() { "_zigzag" } else { "" }; + format!("vec_packed_varint{}_data_size", zigzag_suffix) + }; + format!( + "{}::rt::{}(&{})", + protobuf_crate_path(&self.customize), + fn_name, + self.self_field() + ) + } + + fn self_field_vec_packed_data_size(&self) -> String { + assert!(self.is_repeated_not_map()); + if self.is_fixed() { + self.self_field_vec_packed_fixed_data_size() + } else { + self.self_field_vec_packed_varint_data_size() + } + } + + fn self_field_vec_packed_fixed_size(&self) -> String { + // zero is filtered outside + format!( + "{} + {}::rt::compute_raw_varint32_size({}) + {}", + self.tag_size(), + protobuf_crate_path(&self.customize), + self.self_field_vec_packed_fixed_data_size(), + self.self_field_vec_packed_fixed_data_size() + ) + } + + fn self_field_vec_packed_varint_size(&self) -> String { + // zero is filtered outside + assert!(!self.is_fixed()); + let fn_name = if self.is_enum() { + "vec_packed_enum_size".to_string() + } else { + let zigzag_suffix = if self.is_zigzag() { "_zigzag" } else { "" }; + format!("vec_packed_varint{}_size", zigzag_suffix) + }; + format!( + "{}::rt::{}({}, &{})", + protobuf_crate_path(&self.customize), + fn_name, + self.proto_field.number(), + self.self_field() + ) + } + + fn self_field_oneof(&self) -> String { + format!("self.{}", self.oneof().oneof_rust_field_name) + } + + pub fn clear_field_func(&self) -> String { + format!("clear_{}", self.rust_name) + } + + // Write `merge_from` part for this singular or repeated field + // of type message, string or bytes + fn write_merge_from_field_message_string_bytes(&self, w: &mut CodeWriter) { + let singular_or_repeated = match self.kind { + FieldKind::Repeated(..) => "repeated", + FieldKind::Singular(SingularField { + flag: SingularFieldFlag::WithFlag { .. }, + .. + }) => "singular", + FieldKind::Singular(SingularField { + flag: SingularFieldFlag::WithoutFlag, + .. + }) => "singular_proto3", + FieldKind::Map(..) | FieldKind::Oneof(..) => unreachable!(), + }; + let carllerche = match self.kind.primitive_type_variant() { + PrimitiveTypeVariant::Carllerche => "carllerche_", + PrimitiveTypeVariant::Default => "", + }; + let type_name_for_fn = protobuf_name(self.proto_type); + w.write_line(&format!( + "{}::rt::read_{}_{}{}_into(wire_type, is, &mut self.{})?;", + protobuf_crate_path(&self.customize), + singular_or_repeated, + carllerche, + type_name_for_fn, + self.rust_name + )); + } + + fn write_error_unexpected_wire_type(&self, wire_type_var: &str, w: &mut CodeWriter) { + w.write_line(&format!( + "return ::std::result::Result::Err({}::rt::unexpected_wire_type({}));", + protobuf_crate_path(&self.customize), + wire_type_var + )); + } + + fn write_assert_wire_type(&self, wire_type_var: &str, w: &mut CodeWriter) { + w.if_stmt( + &format!( + "{} != {}::wire_format::{:?}", + wire_type_var, + protobuf_crate_path(&self.customize), + self.wire_type + ), + |w| { + self.write_error_unexpected_wire_type(wire_type_var, w); + }, + ); + } + + // Write `merge_from` part for this oneof field + fn write_merge_from_oneof(&self, f: &OneofField, wire_type_var: &str, w: &mut CodeWriter) { + self.write_assert_wire_type(wire_type_var, w); + + let typed = RustValueTyped { + value: format!( + "{}?", + self.proto_type.read("is", f.elem.primitive_type_variant()) + ), + rust_type: self.full_storage_iter_elem_type(), + }; + + let maybe_boxed = if f.boxed { + typed.boxed(&self.customize) + } else { + typed + }; + + w.write_line(&format!( + "self.{} = ::std::option::Option::Some({}({}));", + self.oneof().oneof_rust_field_name, + self.variant_path(), + maybe_boxed.value + )); // TODO: into_type + } + + // Write `merge_from` part for this map field + fn write_merge_from_map(&self, w: &mut CodeWriter) { + let &MapField { + ref key, ref value, .. + } = self.map(); + w.write_line(&format!( + "{}::rt::read_map_into::<{}, {}>(wire_type, is, &mut {})?;", + protobuf_crate_path(&self.customize), + key.lib_protobuf_type(&self.customize), + value.lib_protobuf_type(&self.customize), + self.self_field() + )); + } + + // Write `merge_from` part for this singular field + fn write_merge_from_singular(&self, wire_type_var: &str, w: &mut CodeWriter) { + let field = match self.kind { + FieldKind::Singular(ref field) => field, + _ => panic!(), + }; + + match field.elem { + FieldElem::Message(..) + | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_STRING, ..) + | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_BYTES, ..) => { + self.write_merge_from_field_message_string_bytes(w); + } + FieldElem::Enum(..) => { + let version = match field.flag { + SingularFieldFlag::WithFlag { .. } => "proto2", + SingularFieldFlag::WithoutFlag => "proto3", + }; + w.write_line(&format!( + "{}::rt::read_{}_enum_with_unknown_fields_into({}, is, &mut self.{}, {}, &mut self.unknown_fields)?", + protobuf_crate_path(&self.customize), + version, + wire_type_var, + self.rust_name, + self.proto_field.number() + )); + } + _ => { + let read_proc = format!( + "{}?", + self.proto_type.read("is", PrimitiveTypeVariant::Default) + ); + + self.write_assert_wire_type(wire_type_var, w); + w.write_line(&format!("let tmp = {};", read_proc)); + self.write_self_field_assign_some(w, "tmp"); + } + } + } + + // Write `merge_from` part for this repeated field + fn write_merge_from_repeated(&self, wire_type_var: &str, w: &mut CodeWriter) { + let field = match self.kind { + FieldKind::Repeated(ref field) => field, + _ => panic!(), + }; + + match field.elem { + FieldElem::Message(..) + | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_STRING, ..) + | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_BYTES, ..) => { + self.write_merge_from_field_message_string_bytes(w); + } + FieldElem::Enum(..) => { + w.write_line(&format!( + "{}::rt::read_repeated_enum_with_unknown_fields_into({}, is, &mut self.{}, {}, &mut self.unknown_fields)?", + protobuf_crate_path(&self.customize), + wire_type_var, + self.rust_name, + self.proto_field.number() + )); + } + _ => { + w.write_line(&format!( + "{}::rt::read_repeated_{}_into({}, is, &mut self.{})?;", + protobuf_crate_path(&self.customize), + protobuf_name(self.proto_type), + wire_type_var, + self.rust_name + )); + } + } + } + + // Write `merge_from` part for this field + pub fn write_merge_from_field(&self, wire_type_var: &str, w: &mut CodeWriter) { + match self.kind { + FieldKind::Oneof(ref f) => self.write_merge_from_oneof(&f, wire_type_var, w), + FieldKind::Map(..) => self.write_merge_from_map(w), + FieldKind::Singular(..) => self.write_merge_from_singular(wire_type_var, w), + FieldKind::Repeated(..) => self.write_merge_from_repeated(wire_type_var, w), + } + } + + fn self_field_vec_packed_size(&self) -> String { + match self.kind { + FieldKind::Repeated(RepeatedField { packed: true, .. }) => { + // zero is filtered outside + if self.is_fixed() { + self.self_field_vec_packed_fixed_size() + } else { + self.self_field_vec_packed_varint_size() + } + } + _ => { + panic!("not packed"); + } + } + } + + pub fn write_element_size( + &self, + w: &mut CodeWriter, + item_var: &str, + item_var_type: &RustType, + sum_var: &str, + ) { + assert!(!self.is_repeated_packed()); + + match self.proto_type { + FieldDescriptorProto_Type::TYPE_MESSAGE => { + w.write_line(&format!("let len = {}.compute_size();", item_var)); + let tag_size = self.tag_size(); + w.write_line(&format!( + "{} += {} + {}::rt::compute_raw_varint32_size(len) + len;", + sum_var, + tag_size, + protobuf_crate_path(&self.customize) + )); + } + _ => { + w.write_line(&format!( + "{} += {};", + sum_var, + self.element_size(item_var, item_var_type) + )); + } + } + } + + pub fn write_message_write_field(&self, w: &mut CodeWriter) { + match self.kind { + FieldKind::Singular(..) => { + self.write_if_let_self_field_is_some(w, |v, v_type, w| { + self.write_write_element(w, "os", v, v_type); + }); + } + FieldKind::Repeated(RepeatedField { packed: false, .. }) => { + self.write_for_self_field(w, "v", |w, v_type| { + self.write_write_element(w, "os", "v", v_type); + }); + } + FieldKind::Repeated(RepeatedField { packed: true, .. }) => { + self.write_if_self_field_is_not_empty(w, |w| { + let number = self.proto_field.number(); + w.write_line(&format!( + "os.write_tag({}, {}::wire_format::{:?})?;", + number, + protobuf_crate_path(&self.customize), + wire_format::WireTypeLengthDelimited + )); + w.comment("TODO: Data size is computed again, it should be cached"); + let data_size_expr = self.self_field_vec_packed_data_size(); + w.write_line(&format!("os.write_raw_varint32({})?;", data_size_expr)); + self.write_for_self_field(w, "v", |w, v_type| { + let param_type = self.os_write_fn_param_type(); + let os_write_fn_suffix = self.os_write_fn_suffix(); + w.write_line(&format!( + "os.write_{}_no_tag({})?;", + os_write_fn_suffix, + v_type.into_target(¶m_type, "v", &self.customize) + )); + }); + }); + } + FieldKind::Map(MapField { + ref key, ref value, .. + }) => { + w.write_line(&format!( + "{}::rt::write_map_with_cached_sizes::<{}, {}>({}, &{}, os)?;", + protobuf_crate_path(&self.customize), + key.lib_protobuf_type(&self.customize), + value.lib_protobuf_type(&self.customize), + self.proto_field.number(), + self.self_field() + )); + } + FieldKind::Oneof(..) => unreachable!(), + }; + } + + pub fn write_message_compute_field_size(&self, sum_var: &str, w: &mut CodeWriter) { + match self.kind { + FieldKind::Singular(..) => { + self.write_if_let_self_field_is_some(w, |v, v_type, w| { + match field_type_size(self.proto_type) { + Some(s) => { + let tag_size = self.tag_size(); + w.write_line(&format!("{} += {};", sum_var, (s + tag_size) as isize)); + } + None => { + self.write_element_size(w, v, v_type, sum_var); + } + }; + }); + } + FieldKind::Repeated(RepeatedField { packed: false, .. }) => { + match field_type_size(self.proto_type) { + Some(s) => { + let tag_size = self.tag_size(); + let self_field = self.self_field(); + w.write_line(&format!( + "{} += {} * {}.len() as u32;", + sum_var, + (s + tag_size) as isize, + self_field + )); + } + None => { + self.write_for_self_field(w, "value", |w, value_type| { + self.write_element_size(w, "value", value_type, sum_var); + }); + } + }; + } + FieldKind::Map(MapField { + ref key, ref value, .. + }) => { + w.write_line(&format!( + "{} += {}::rt::compute_map_size::<{}, {}>({}, &{});", + sum_var, + protobuf_crate_path(&self.customize), + key.lib_protobuf_type(&self.customize), + value.lib_protobuf_type(&self.customize), + self.proto_field.number(), + self.self_field() + )); + } + FieldKind::Repeated(RepeatedField { packed: true, .. }) => { + self.write_if_self_field_is_not_empty(w, |w| { + let size_expr = self.self_field_vec_packed_size(); + w.write_line(&format!("{} += {};", sum_var, size_expr)); + }); + } + FieldKind::Oneof(..) => unreachable!(), + } + } + + fn write_message_field_get_singular(&self, w: &mut CodeWriter) { + let get_xxx_return_type = self.get_xxx_return_type(); + + if self.proto_type == FieldDescriptorProto_Type::TYPE_MESSAGE { + let self_field = self.self_field(); + let ref rust_type_message = match self.elem().rust_storage_type() { + RustType::Message(m) => m, + _ => unreachable!(), + }; + w.write_line(&format!( + "{}.as_ref().unwrap_or_else(|| {})", + self_field, + rust_type_message.default_instance(&self.customize) + )); + } else { + let get_xxx_default_value_rust = self.get_xxx_default_value_rust(); + let self_field = self.self_field(); + match self.singular() { + &SingularField { + flag: SingularFieldFlag::WithFlag { .. }, + .. + } => { + if get_xxx_return_type.is_ref() { + let as_option = self.self_field_as_option(); + w.match_expr(&as_option.value, |w| { + let v_type = as_option.rust_type.elem_type(); + let r_type = self.get_xxx_return_type(); + w.case_expr( + "Some(v)", + v_type.into_target(&r_type, "v", &self.customize), + ); + let get_xxx_default_value_rust = self.get_xxx_default_value_rust(); + w.case_expr("None", get_xxx_default_value_rust); + }); + } else { + w.write_line(&format!( + "{}.unwrap_or({})", + self_field, get_xxx_default_value_rust + )); + } + } + &SingularField { + flag: SingularFieldFlag::WithoutFlag, + .. + } => { + w.write_line(self.full_storage_type().into_target( + &get_xxx_return_type, + &self_field, + &self.customize, + )); + } + } + } + } + + fn write_message_field_get(&self, w: &mut CodeWriter) { + let get_xxx_return_type = self.get_xxx_return_type(); + let fn_def = format!( + "get_{}(&self) -> {}", + self.rust_name, + get_xxx_return_type.to_code(&self.customize) + ); + + w.pub_fn(&fn_def, |w| match self.kind { + FieldKind::Oneof(OneofField { ref elem, .. }) => { + let self_field_oneof = self.self_field_oneof(); + w.match_expr(self_field_oneof, |w| { + let (refv, vtype) = if !self.elem_type_is_copy() { + ("ref v", elem.rust_storage_type().ref_type()) + } else { + ("v", elem.rust_storage_type()) + }; + w.case_expr( + format!( + "::std::option::Option::Some({}({}))", + self.variant_path(), + refv + ), + vtype.into_target(&get_xxx_return_type, "v", &self.customize), + ); + w.case_expr("_", self.get_xxx_default_value_rust()); + }) + } + FieldKind::Singular(..) => { + self.write_message_field_get_singular(w); + } + FieldKind::Repeated(..) | FieldKind::Map(..) => { + let self_field = self.self_field(); + w.write_line(&format!("&{}", self_field)); + } + }); + } + + fn has_has(&self) -> bool { + match self.kind { + FieldKind::Repeated(..) | FieldKind::Map(..) => false, + FieldKind::Singular(SingularField { + flag: SingularFieldFlag::WithFlag { .. }, + .. + }) => true, + FieldKind::Singular(SingularField { + flag: SingularFieldFlag::WithoutFlag, + .. + }) => false, + FieldKind::Oneof(..) => true, + } + } + + fn has_mut(&self) -> bool { + match self.kind { + FieldKind::Repeated(..) | FieldKind::Map(..) => true, + // TODO: string should be public, and mut is not needed + FieldKind::Singular(..) | FieldKind::Oneof(..) => !self.elem_type_is_copy(), + } + } + + fn has_take(&self) -> bool { + match self.kind { + FieldKind::Repeated(..) | FieldKind::Map(..) => true, + // TODO: string should be public, and mut is not needed + FieldKind::Singular(..) | FieldKind::Oneof(..) => !self.elem_type_is_copy(), + } + } + + fn has_name(&self) -> String { + format!("has_{}", self.rust_name) + } + + fn write_message_field_has(&self, w: &mut CodeWriter) { + w.pub_fn(&format!("{}(&self) -> bool", self.has_name()), |w| { + if !self.is_oneof() { + let self_field_is_some = self.self_field_is_some(); + w.write_line(self_field_is_some); + } else { + let self_field_oneof = self.self_field_oneof(); + w.match_expr(self_field_oneof, |w| { + w.case_expr( + format!("::std::option::Option::Some({}(..))", self.variant_path()), + "true", + ); + w.case_expr("_", "false"); + }); + } + }); + } + + fn write_message_field_set(&self, w: &mut CodeWriter) { + let set_xxx_param_type = self.set_xxx_param_type(); + w.comment("Param is passed by value, moved"); + let ref name = self.rust_name; + w.pub_fn( + &format!( + "set_{}(&mut self, v: {})", + name, + set_xxx_param_type.to_code(&self.customize) + ), + |w| { + if !self.is_oneof() { + self.write_self_field_assign_value(w, "v", &set_xxx_param_type); + } else { + let self_field_oneof = self.self_field_oneof(); + let v = set_xxx_param_type.into_target( + &self.oneof().rust_type(), + "v", + &self.customize, + ); + w.write_line(&format!( + "{} = ::std::option::Option::Some({}({}))", + self_field_oneof, + self.variant_path(), + v + )); + } + }, + ); + } + + fn write_message_field_mut(&self, w: &mut CodeWriter) { + let mut_xxx_return_type = self.mut_xxx_return_type(); + w.comment("Mutable pointer to the field."); + if self.is_singular() { + w.comment("If field is not initialized, it is initialized with default value first."); + } + let fn_def = match mut_xxx_return_type { + RustType::Ref(ref param) => format!( + "mut_{}(&mut self) -> &mut {}", + self.rust_name, + param.to_code(&self.customize) + ), + _ => panic!( + "not a ref: {}", + mut_xxx_return_type.to_code(&self.customize) + ), + }; + w.pub_fn(&fn_def, |w| { + match self.kind { + FieldKind::Repeated(..) | FieldKind::Map(..) => { + let self_field = self.self_field(); + w.write_line(&format!("&mut {}", self_field)); + } + FieldKind::Singular(SingularField { + flag: SingularFieldFlag::WithFlag { .. }, + .. + }) => { + self.write_if_self_field_is_none(w, |w| { + self.write_self_field_assign_default(w); + }); + let self_field = self.self_field(); + w.write_line(&format!("{}.as_mut().unwrap()", self_field)); + } + FieldKind::Singular(SingularField { + flag: SingularFieldFlag::WithoutFlag, + .. + }) => w.write_line(&format!("&mut {}", self.self_field())), + FieldKind::Oneof(..) => { + let self_field_oneof = self.self_field_oneof(); + + // if oneof does not contain current field + w.if_let_else_stmt( + &format!("::std::option::Option::Some({}(_))", self.variant_path())[..], + &self_field_oneof[..], + |w| { + // initialize it with default value + w.write_line(&format!( + "{} = ::std::option::Option::Some({}({}));", + self_field_oneof, + self.variant_path(), + self.element_default_value_rust() + .into_type(self.oneof().rust_type(), &self.customize) + .value + )); + }, + ); + + // extract field + w.match_expr(self_field_oneof, |w| { + w.case_expr( + format!( + "::std::option::Option::Some({}(ref mut v))", + self.variant_path() + ), + "v", + ); + w.case_expr("_", "panic!()"); + }); + } + } + }); + } + + fn write_message_field_take_oneof(&self, w: &mut CodeWriter) { + let take_xxx_return_type = self.take_xxx_return_type(); + + // TODO: replace with if let + w.write_line(&format!("if self.{}() {{", self.has_name())); + w.indented(|w| { + let self_field_oneof = self.self_field_oneof(); + w.match_expr(format!("{}.take()", self_field_oneof), |w| { + let value_in_some = self.oneof().rust_type().value("v".to_owned()); + let converted = + value_in_some.into_type(self.take_xxx_return_type(), &self.customize); + w.case_expr( + format!("::std::option::Option::Some({}(v))", self.variant_path()), + &converted.value, + ); + w.case_expr("_", "panic!()"); + }); + }); + w.write_line("} else {"); + w.indented(|w| { + w.write_line( + self.elem() + .rust_storage_type() + .default_value_typed(&self.customize) + .into_type(take_xxx_return_type.clone(), &self.customize) + .value, + ); + }); + w.write_line("}"); + } + + fn write_message_field_take(&self, w: &mut CodeWriter) { + let take_xxx_return_type = self.take_xxx_return_type(); + w.comment("Take field"); + w.pub_fn( + &format!( + "take_{}(&mut self) -> {}", + self.rust_name, + take_xxx_return_type.to_code(&self.customize) + ), + |w| match self.kind { + FieldKind::Oneof(..) => { + self.write_message_field_take_oneof(w); + } + FieldKind::Repeated(..) | FieldKind::Map(..) => { + w.write_line(&format!( + "::std::mem::replace(&mut self.{}, {})", + self.rust_name, + take_xxx_return_type.default_value(&self.customize) + )); + } + FieldKind::Singular(SingularField { + ref elem, + flag: SingularFieldFlag::WithFlag { .. }, + }) => { + if !elem.is_copy() { + w.write_line(&format!( + "{}.take().unwrap_or_else(|| {})", + self.self_field(), + elem.rust_storage_type().default_value(&self.customize) + )); + } else { + w.write_line(&format!( + "{}.take().unwrap_or({})", + self.self_field(), + self.element_default_value_rust().value + )); + } + } + FieldKind::Singular(SingularField { + flag: SingularFieldFlag::WithoutFlag, + .. + }) => w.write_line(&format!( + "::std::mem::replace(&mut {}, {})", + self.self_field(), + self.full_storage_type().default_value(&self.customize) + )), + }, + ); + } + + pub fn write_message_single_field_accessors(&self, w: &mut CodeWriter) { + // TODO: do not generate `get` when !proto2 and !generate_accessors` + w.write_line(""); + self.write_message_field_get(w); + + if !self.generate_accessors { + return; + } + + let clear_field_func = self.clear_field_func(); + w.pub_fn(&format!("{}(&mut self)", clear_field_func), |w| { + self.write_clear(w); + }); + + if self.has_has() { + w.write_line(""); + self.write_message_field_has(w); + } + + w.write_line(""); + self.write_message_field_set(w); + + if self.has_mut() { + w.write_line(""); + self.write_message_field_mut(w); + } + + if self.has_take() { + w.write_line(""); + self.write_message_field_take(w); + } + } +} + +pub(crate) fn rust_field_name_for_protobuf_field_name(name: &str) -> RustIdent { + if rust::is_rust_keyword(name) { + RustIdent::new(&format!("field_{}", name)) + } else { + RustIdent::new(name) + } +} |