| mod accessor; |
| pub(crate) mod elem; |
| mod option_kind; |
| mod repeated; |
| mod singular; |
| mod tag; |
| pub(crate) mod type_ext; |
| |
| use protobuf::descriptor::field_descriptor_proto::Type; |
| use protobuf::descriptor::*; |
| use protobuf::reflect::ReflectValueRef; |
| use protobuf::reflect::RuntimeFieldType; |
| use protobuf::reflect::Syntax; |
| use protobuf::rt; |
| use protobuf::rt::WireType; |
| use protobuf_parse::camel_case; |
| use protobuf_parse::ProtobufAbsPath; |
| |
| use crate::customize::ctx::CustomizeElemCtx; |
| use crate::customize::rustproto_proto::customize_from_rustproto_for_field; |
| use crate::customize::Customize; |
| use crate::gen::code_writer::CodeWriter; |
| use crate::gen::code_writer::Visibility; |
| use crate::gen::field::elem::field_elem; |
| use crate::gen::field::elem::FieldElem; |
| use crate::gen::field::elem::FieldElemEnum; |
| use crate::gen::field::elem::HowToGetMessageSize; |
| use crate::gen::field::option_kind::OptionKind; |
| use crate::gen::field::repeated::RepeatedField; |
| use crate::gen::field::singular::SingularField; |
| use crate::gen::field::singular::SingularFieldFlag; |
| use crate::gen::field::tag::make_tag; |
| use crate::gen::field::type_ext::TypeExt; |
| use crate::gen::file_and_mod::FileAndMod; |
| use crate::gen::inside::protobuf_crate_path; |
| use crate::gen::map::map_entry; |
| use crate::gen::oneof::OneofField; |
| use crate::gen::protoc_insertion_point::write_protoc_insertion_point_for_field; |
| use crate::gen::rust::ident::RustIdent; |
| use crate::gen::rust::quote::quote_escape_bytes; |
| use crate::gen::rust::quote::quote_escape_str; |
| use crate::gen::rust::snippets::EXPR_NONE; |
| use crate::gen::rust_types_values::PrimitiveTypeVariant; |
| use crate::gen::rust_types_values::RustType; |
| use crate::gen::rust_types_values::RustValueTyped; |
| use crate::gen::scope::FieldWithContext; |
| use crate::gen::scope::MessageWithScope; |
| use crate::gen::scope::RootScope; |
| |
| fn field_type_protobuf_name<'a>(field: &'a FieldDescriptorProto) -> &'a str { |
| if field.has_type_name() { |
| field.type_name() |
| } else { |
| field.type_().protobuf_name() |
| } |
| } |
| |
| #[derive(Clone)] |
| pub struct MapField<'a> { |
| _message: MessageWithScope<'a>, |
| 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> { |
| pub(crate) fn default( |
| &self, |
| customize: &Customize, |
| reference: &FileAndMod, |
| const_expr: bool, |
| ) -> String { |
| match self { |
| FieldKind::Singular(s) => s.default_value(customize, reference, const_expr), |
| FieldKind::Repeated(r) => r.default(), |
| FieldKind::Oneof(..) => EXPR_NONE.to_owned(), |
| FieldKind::Map(..) => panic!("map fields cannot have field value"), |
| } |
| } |
| } |
| |
| #[derive(Clone)] |
| pub(crate) enum SingularOrOneofField<'a> { |
| Singular(SingularField<'a>), |
| Oneof(OneofField<'a>), |
| } |
| |
| impl<'a> SingularOrOneofField<'a> { |
| fn elem(&self) -> &FieldElem { |
| match self { |
| SingularOrOneofField::Singular(SingularField { ref elem, .. }) => elem, |
| SingularOrOneofField::Oneof(OneofField { ref elem, .. }) => elem, |
| } |
| } |
| |
| // Type of `xxx` function for singular type. |
| pub(crate) fn getter_return_type(&self, reference: &FileAndMod) -> RustType { |
| let elem = self.elem(); |
| if let FieldElem::Enum(ref en) = elem { |
| en.enum_rust_type(reference) |
| } else if elem.is_copy() { |
| elem.rust_storage_elem_type(reference) |
| } else { |
| elem.rust_storage_elem_type(reference).ref_type() |
| } |
| } |
| } |
| |
| // Representation of map entry: key type and value type |
| #[derive(Clone, Debug)] |
| pub struct EntryKeyValue<'a>(FieldElem<'a>, FieldElem<'a>); |
| |
| #[derive(Clone)] |
| pub(crate) struct FieldGen<'a> { |
| syntax: Syntax, |
| pub proto_field: FieldWithContext<'a>, |
| // field name in generated code |
| pub rust_name: RustIdent, |
| pub proto_type: Type, |
| wire_type: WireType, |
| pub kind: FieldKind<'a>, |
| pub generate_accessors: bool, |
| pub generate_getter: bool, |
| customize: Customize, |
| path: Vec<i32>, |
| info: Option<&'a SourceCodeInfo>, |
| } |
| |
| impl<'a> FieldGen<'a> { |
| pub(crate) fn parse( |
| field: FieldWithContext<'a>, |
| root_scope: &'a RootScope<'a>, |
| parent_customize: &CustomizeElemCtx<'a>, |
| path: Vec<i32>, |
| info: Option<&'a SourceCodeInfo>, |
| ) -> anyhow::Result<FieldGen<'a>> { |
| let customize = parent_customize |
| .child( |
| &customize_from_rustproto_for_field(field.field.proto().options.get_or_default()), |
| &field.field, |
| ) |
| .for_elem; |
| |
| let syntax = field.message.scope.file_scope.syntax(); |
| |
| let field_may_have_custom_default_value = syntax == Syntax::Proto2 |
| && field.field.proto().label() != field_descriptor_proto::Label::LABEL_REPEATED |
| && field.field.proto().type_() != Type::TYPE_MESSAGE; |
| |
| let generate_accessors = customize |
| .generate_accessors |
| .unwrap_or(field_may_have_custom_default_value) |
| || field.is_oneof(); |
| |
| let default_generate_getter = generate_accessors || field_may_have_custom_default_value; |
| let generate_getter = |
| customize.generate_getter.unwrap_or(default_generate_getter) || field.is_oneof(); |
| |
| let kind = match field.field.runtime_field_type() { |
| RuntimeFieldType::Map(..) => { |
| let message = root_scope |
| .find_message(&ProtobufAbsPath::from(field.field.proto().type_name())); |
| |
| let (key, value) = map_entry(&message).unwrap(); |
| |
| let key = field_elem(&key, root_scope, &customize); |
| let value = field_elem(&value, root_scope, &customize); |
| |
| FieldKind::Map(MapField { |
| _message: message, |
| key, |
| value, |
| }) |
| } |
| RuntimeFieldType::Repeated(..) => { |
| let elem = field_elem(&field, root_scope, &customize); |
| |
| FieldKind::Repeated(RepeatedField { |
| elem, |
| packed: field.field.proto().options.get_or_default().packed(), |
| }) |
| } |
| RuntimeFieldType::Singular(..) => { |
| let elem = field_elem(&field, root_scope, &customize); |
| |
| if let Some(oneof) = field.oneof() { |
| FieldKind::Oneof(OneofField::parse(&oneof, &field.field, elem, root_scope)) |
| } else { |
| let flag = if field.message.scope.file_scope.syntax() == Syntax::Proto3 |
| && field.field.proto().type_() != field_descriptor_proto::Type::TYPE_MESSAGE |
| && !field.field.proto().proto3_optional() |
| { |
| SingularFieldFlag::WithoutFlag |
| } else { |
| let required = field.field.proto().label() |
| == field_descriptor_proto::Label::LABEL_REQUIRED; |
| let option_kind = match field.field.proto().type_() { |
| field_descriptor_proto::Type::TYPE_MESSAGE => OptionKind::MessageField, |
| _ => OptionKind::Option, |
| }; |
| |
| SingularFieldFlag::WithFlag { |
| required, |
| option_kind, |
| } |
| }; |
| FieldKind::Singular(SingularField { elem, flag }) |
| } |
| } |
| }; |
| |
| Ok(FieldGen { |
| syntax: field.message.message.file_descriptor().syntax(), |
| rust_name: rust_field_name_for_protobuf_field_name(&field.field.name()), |
| proto_type: field.field.proto().type_(), |
| wire_type: WireType::for_type(field.field.proto().type_()), |
| proto_field: field, |
| kind, |
| generate_accessors, |
| generate_getter, |
| customize, |
| path, |
| info, |
| }) |
| } |
| |
| // for message level |
| fn file_and_mod(&self) -> FileAndMod { |
| self.proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()) |
| } |
| |
| fn tag_size(&self) -> u32 { |
| rt::tag_size(self.proto_field.number() as u32) as u32 |
| } |
| |
| fn is_singular(&self) -> bool { |
| match self.kind { |
| FieldKind::Singular(..) => true, |
| _ => false, |
| } |
| } |
| |
| fn is_repeated_packed(&self) -> bool { |
| match self.kind { |
| FieldKind::Repeated(RepeatedField { packed: true, .. }) => true, |
| _ => false, |
| } |
| } |
| |
| pub(crate) 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(crate) fn full_storage_type(&self, reference: &FileAndMod) -> RustType { |
| match self.kind { |
| FieldKind::Repeated(ref repeated) => repeated.rust_type(reference), |
| FieldKind::Map(MapField { |
| ref key, ref value, .. |
| }) => RustType::HashMap( |
| Box::new(key.rust_storage_elem_type(reference)), |
| Box::new(value.rust_storage_elem_type(reference)), |
| ), |
| FieldKind::Singular(ref singular) => singular.rust_storage_type(reference), |
| FieldKind::Oneof(..) => unreachable!(), |
| } |
| } |
| |
| // type of `v` in `for v in field` |
| fn full_storage_iter_elem_type(&self, reference: &FileAndMod) -> RustType { |
| if let FieldKind::Oneof(ref oneof) = self.kind { |
| oneof.elem.rust_storage_elem_type(reference) |
| } else { |
| self.full_storage_type(reference).iter_elem_type() |
| } |
| } |
| |
| // suffix `xxx` as in `os.write_xxx_no_tag(..)` |
| fn os_write_fn_suffix(&self) -> &str { |
| self.proto_type.protobuf_name() |
| } |
| |
| fn os_write_fn_suffix_with_unknown_for_enum(&self) -> &str { |
| if self.proto_type == field_descriptor_proto::Type::TYPE_ENUM { |
| "enum_or_unknown" |
| } else { |
| self.os_write_fn_suffix() |
| } |
| } |
| |
| // for field `foo`, type of param of `fn set_foo(..)` |
| fn set_xxx_param_type(&self, reference: &FileAndMod) -> RustType { |
| match self.kind { |
| FieldKind::Singular(SingularField { ref elem, .. }) |
| | FieldKind::Oneof(OneofField { ref elem, .. }) => { |
| elem.rust_set_xxx_param_type(reference) |
| } |
| FieldKind::Repeated(..) | FieldKind::Map(..) => self.full_storage_type(reference), |
| } |
| } |
| |
| // for field `foo`, return type if `fn take_foo(..)` |
| fn take_xxx_return_type(&self, reference: &FileAndMod) -> RustType { |
| self.set_xxx_param_type(reference) |
| } |
| |
| // for field `foo`, return type of `fn mut_foo(..)` |
| fn mut_xxx_return_type(&self, reference: &FileAndMod) -> RustType { |
| RustType::Ref(Box::new(match self.kind { |
| FieldKind::Singular(SingularField { ref elem, .. }) |
| | FieldKind::Oneof(OneofField { ref elem, .. }) => { |
| elem.rust_storage_elem_type(reference) |
| } |
| FieldKind::Repeated(..) | FieldKind::Map(..) => self.full_storage_type(reference), |
| })) |
| } |
| |
| // for field `foo`, return type of `fn foo(..)` |
| fn getter_return_type(&self) -> RustType { |
| let reference = self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()); |
| match &self.kind { |
| FieldKind::Singular(s) => { |
| SingularOrOneofField::Singular(s.clone()).getter_return_type(&reference) |
| } |
| FieldKind::Oneof(o) => { |
| SingularOrOneofField::Oneof(o.clone()).getter_return_type(&reference) |
| } |
| FieldKind::Repeated(RepeatedField { ref elem, .. }) => RustType::Ref(Box::new( |
| RustType::Slice(Box::new(elem.rust_storage_elem_type(&reference))), |
| )), |
| FieldKind::Map(..) => RustType::Ref(Box::new(self.full_storage_type(&reference))), |
| } |
| } |
| |
| // elem data is not stored in heap |
| pub(crate) fn elem_type_is_copy(&self) -> bool { |
| self.proto_type.is_copy() |
| } |
| |
| fn defaut_value_from_proto_float(f: f64, type_name: &str) -> String { |
| 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 singular_or_oneof_default_value_from_proto(&self, elem: &FieldElem) -> Option<String> { |
| if !self.proto_field.field.proto().has_default_value() { |
| return None; |
| } |
| |
| let default_value = self.proto_field.field.singular_default_value(); |
| Some(match default_value { |
| ReflectValueRef::Bool(b) => format!("{}", b), |
| ReflectValueRef::I32(v) => format!("{}i32", v), |
| ReflectValueRef::I64(v) => format!("{}i64", v), |
| ReflectValueRef::U32(v) => format!("{}u32", v), |
| ReflectValueRef::U64(v) => format!("{}u64", v), |
| ReflectValueRef::String(v) => quote_escape_str(v), |
| ReflectValueRef::Bytes(v) => quote_escape_bytes(v), |
| ReflectValueRef::F32(v) => Self::defaut_value_from_proto_float(v as f64, "f32"), |
| ReflectValueRef::F64(v) => Self::defaut_value_from_proto_float(v as f64, "f64"), |
| ReflectValueRef::Enum(_e, _v) => { |
| if let &FieldElem::Enum(ref e) = elem { |
| format!("{}", e.default_value_rust_expr(&self.file_and_mod())) |
| } else { |
| unreachable!() |
| } |
| } |
| t => panic!("default value is not implemented for type: {:?}", t), |
| }) |
| } |
| |
| fn default_value_from_proto(&self) -> Option<String> { |
| match self.kind { |
| FieldKind::Oneof(OneofField { ref elem, .. }) |
| | FieldKind::Singular(SingularField { ref elem, .. }) => { |
| self.singular_or_oneof_default_value_from_proto(elem) |
| } |
| _ => unreachable!(), |
| } |
| } |
| |
| fn default_value_from_proto_typed(&self) -> Option<RustValueTyped> { |
| self.default_value_from_proto().map(|v| { |
| let default_value_type = match self.proto_type { |
| field_descriptor_proto::Type::TYPE_STRING => RustType::Ref(Box::new(RustType::Str)), |
| field_descriptor_proto::Type::TYPE_BYTES => { |
| RustType::Ref(Box::new(RustType::Slice(Box::new(RustType::u8())))) |
| } |
| _ => self.full_storage_iter_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ), |
| }; |
| |
| RustValueTyped { |
| value: v, |
| rust_type: default_value_type, |
| } |
| }) |
| } |
| |
| // default value to be returned from `fn xxx` for field `xxx`. |
| fn xxx_default_value_rust(&self) -> String { |
| match self.kind { |
| FieldKind::Singular(..) | FieldKind::Oneof(..) => { |
| self.default_value_from_proto().unwrap_or_else(|| { |
| self.getter_return_type() |
| .default_value(&self.customize, false) |
| }) |
| } |
| _ => unreachable!(), |
| } |
| } |
| |
| // default to be assigned to field |
| fn element_default_value_rust(&self) -> RustValueTyped { |
| match self.kind { |
| FieldKind::Singular(..) | FieldKind::Oneof(..) => { |
| self.default_value_from_proto_typed().unwrap_or_else(|| { |
| self.elem() |
| .rust_storage_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ) |
| .default_value_typed(&self.customize, false) |
| }) |
| } |
| _ => unreachable!(), |
| } |
| } |
| |
| pub(crate) fn reconstruct_def(&self) -> String { |
| let prefix = match (self.proto_field.field.proto().label(), self.syntax) { |
| (field_descriptor_proto::Label::LABEL_REPEATED, _) => "repeated ", |
| (_, Syntax::Proto3) => "", |
| (field_descriptor_proto::Label::LABEL_OPTIONAL, _) => "optional ", |
| (field_descriptor_proto::Label::LABEL_REQUIRED, _) => "required ", |
| }; |
| format!( |
| "{}{} {} = {}", |
| prefix, |
| field_type_protobuf_name(self.proto_field.field.proto()), |
| self.proto_field.name(), |
| self.proto_field.number() |
| ) |
| } |
| |
| pub(crate) fn write_clear(&self, w: &mut CodeWriter) { |
| match self.kind { |
| FieldKind::Oneof(ref o) => { |
| w.write_line(&format!( |
| "self.{} = ::std::option::Option::None;", |
| o.oneof_field_name |
| )); |
| } |
| _ => { |
| let clear_expr = self |
| .full_storage_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ) |
| .clear(&self.self_field(), &self.customize); |
| w.write_line(&format!("{};", clear_expr)); |
| } |
| } |
| } |
| |
| // output code that writes single element to stream |
| pub(crate) fn write_write_element( |
| &self, |
| elem: &FieldElem, |
| w: &mut CodeWriter, |
| os: &str, |
| v: &RustValueTyped, |
| ) { |
| assert!(!self.is_repeated_packed()); |
| |
| elem.write_write_element( |
| self.proto_field.number() as u32, |
| v, |
| &self.file_and_mod(), |
| &self.customize, |
| os, |
| w, |
| ); |
| } |
| |
| 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_none(&self) -> String { |
| assert!(self.is_singular()); |
| format!("{}.is_none()", self.self_field()) |
| } |
| |
| // field data viewed as Option |
| fn self_field_as_option(&self, elem: &FieldElem, option_kind: OptionKind) -> RustValueTyped { |
| match self.full_storage_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ) { |
| RustType::Option(ref e) if e.is_copy() => { |
| return RustType::Option(e.clone()).value(self.self_field()); |
| } |
| _ => {} |
| }; |
| |
| let as_option_type = option_kind.as_ref_type( |
| elem.rust_storage_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ), |
| ); |
| |
| as_option_type.value(format!("{}.as_ref()", self.self_field())) |
| } |
| |
| pub(crate) fn write_struct_field(&self, w: &mut CodeWriter) { |
| if self.proto_type == field_descriptor_proto::Type::TYPE_GROUP { |
| w.comment(&format!("{}: <group>", &self.rust_name)); |
| } else { |
| w.all_documentation(self.info, &self.path); |
| |
| write_protoc_insertion_point_for_field(w, &self.customize, &self.proto_field.field); |
| w.field_decl_vis( |
| Visibility::Public, |
| &self.rust_name.to_string(), |
| &self |
| .full_storage_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ) |
| .to_code(&self.customize), |
| ); |
| } |
| } |
| |
| fn write_if_let_self_field_is_some<F>(&self, s: &SingularField, w: &mut CodeWriter, cb: F) |
| where |
| F: Fn(&RustValueTyped, &mut CodeWriter), |
| { |
| match s { |
| SingularField { |
| flag: SingularFieldFlag::WithFlag { option_kind, .. }, |
| ref elem, |
| } => { |
| let var = "v"; |
| let ref_prefix = match elem |
| .rust_storage_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ) |
| .is_copy() |
| { |
| true => "", |
| false => "", |
| }; |
| let as_option = self.self_field_as_option(elem, *option_kind); |
| w.if_let_stmt( |
| &format!("Some({}{})", ref_prefix, var), |
| &as_option.value, |
| |w| { |
| let v = RustValueTyped { |
| value: var.to_owned(), |
| rust_type: as_option.rust_type.elem_type(), |
| }; |
| cb(&v, w); |
| }, |
| ); |
| } |
| SingularField { |
| flag: SingularFieldFlag::WithoutFlag, |
| ref elem, |
| } => match *elem { |
| FieldElem::Primitive(field_descriptor_proto::Type::TYPE_STRING, ..) |
| | FieldElem::Primitive(field_descriptor_proto::Type::TYPE_BYTES, ..) => { |
| w.if_stmt(format!("!{}.is_empty()", self.self_field()), |w| { |
| let v = RustValueTyped { |
| value: self.self_field(), |
| rust_type: self.full_storage_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ), |
| }; |
| cb(&v, w); |
| }); |
| } |
| _ => { |
| w.if_stmt( |
| format!( |
| "{} != {}", |
| self.self_field(), |
| self.full_storage_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()) |
| ) |
| .default_value(&self.customize, false) |
| ), |
| |w| { |
| let v = RustValueTyped { |
| value: self.self_field(), |
| rust_type: self.full_storage_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ), |
| }; |
| cb(&v, w); |
| }, |
| ); |
| } |
| }, |
| } |
| } |
| |
| pub(crate) 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(crate) fn write_for_self_field<F>(&self, w: &mut CodeWriter, varn: &str, cb: F) |
| where |
| F: Fn(&mut CodeWriter, &RustType), |
| { |
| let file_and_mod = self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()); |
| |
| match &self.kind { |
| FieldKind::Oneof(oneof_field) => { |
| let cond = format!( |
| "Some({}(ref {}))", |
| oneof_field.variant_path(&file_and_mod.relative_mod), |
| varn |
| ); |
| w.if_let_stmt( |
| &cond, |
| &format!("self.{}", oneof_field.oneof_field_name), |
| |w| cb(w, &oneof_field.elem.rust_storage_elem_type(&file_and_mod)), |
| ) |
| } |
| _ => { |
| let v_type = self.full_storage_iter_elem_type(&file_and_mod); |
| 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, s: &SingularField, value: &str) { |
| match s { |
| &SingularField { |
| flag: SingularFieldFlag::WithFlag { option_kind, .. }, |
| .. |
| } => { |
| self.write_self_field_assign(w, &option_kind.wrap_value(value, &self.customize)); |
| } |
| &SingularField { |
| flag: SingularFieldFlag::WithoutFlag, |
| .. |
| } => { |
| self.write_self_field_assign(w, value); |
| } |
| } |
| } |
| |
| fn write_self_field_assign_value_singular( |
| &self, |
| w: &mut CodeWriter, |
| s: &SingularField, |
| value: &RustValueTyped, |
| ) { |
| let SingularField { ref elem, ref flag } = s; |
| let converted = value.into_type( |
| elem.rust_storage_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ) |
| .clone(), |
| &self.customize, |
| ); |
| let wrapped = match flag { |
| SingularFieldFlag::WithoutFlag => converted.value, |
| SingularFieldFlag::WithFlag { option_kind, .. } => { |
| option_kind.wrap_value(&converted.value, &self.customize) |
| } |
| }; |
| self.write_self_field_assign(w, &wrapped); |
| } |
| |
| fn write_self_field_assign_value(&self, w: &mut CodeWriter, value: &RustValueTyped) { |
| match self.kind { |
| FieldKind::Repeated(..) | FieldKind::Map(..) => { |
| let converted = value.into_type( |
| self.full_storage_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ), |
| &self.customize, |
| ); |
| self.write_self_field_assign(w, &converted.value); |
| } |
| FieldKind::Singular(ref s) => { |
| self.write_self_field_assign_value_singular(w, s, value); |
| } |
| FieldKind::Oneof(..) => unreachable!(), |
| } |
| } |
| |
| fn write_self_field_assign_default( |
| &self, |
| field_kind: &SingularOrOneofField, |
| w: &mut CodeWriter, |
| ) { |
| match field_kind { |
| SingularOrOneofField::Oneof(oneof) => { |
| w.write_line(format!( |
| "self.{} = ::std::option::Option::Some({}({}))", |
| oneof.oneof_field_name, |
| oneof.variant_path(&self.proto_field.message.scope.rust_path_to_file()), |
| // TODO: default from .proto is not needed here (?) |
| self.element_default_value_rust() |
| .into_type( |
| self.full_storage_iter_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()) |
| ), |
| &self.customize |
| ) |
| .value |
| )); |
| } |
| SingularOrOneofField::Singular(singular) => { |
| // Note it is different from C++ protobuf, where field is initialized |
| // with default value |
| match singular.flag { |
| SingularFieldFlag::WithFlag { option_kind, .. } => match option_kind { |
| OptionKind::MessageField => { |
| let self_field = self.self_field(); |
| w.write_line(&format!("{}.set_default();", self_field)); |
| } |
| _ => { |
| self.write_self_field_assign_some( |
| w, |
| singular, |
| &self |
| .elem() |
| .rust_storage_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ) |
| .default_value_typed(&self.customize, false) |
| .into_type( |
| singular.elem.rust_storage_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ), |
| &self.customize, |
| ) |
| .value, |
| ); |
| } |
| }, |
| SingularFieldFlag::WithoutFlag => unimplemented!(), |
| } |
| } |
| } |
| } |
| |
| fn self_field_vec_packed_size(&self) -> String { |
| let fn_name = match self.proto_type { |
| Type::TYPE_ENUM => "vec_packed_enum_or_unknown_size", |
| Type::TYPE_SINT32 => "vec_packed_sint32_size", |
| Type::TYPE_SINT64 => "vec_packed_sint64_size", |
| Type::TYPE_INT32 => "vec_packed_int32_size", |
| Type::TYPE_INT64 => "vec_packed_int64_size", |
| Type::TYPE_UINT32 => "vec_packed_uint32_size", |
| Type::TYPE_UINT64 => "vec_packed_uint64_size", |
| Type::TYPE_BOOL => "vec_packed_bool_size", |
| Type::TYPE_FIXED32 => "vec_packed_fixed32_size", |
| Type::TYPE_FIXED64 => "vec_packed_fixed64_size", |
| Type::TYPE_SFIXED32 => "vec_packed_sfixed32_size", |
| Type::TYPE_SFIXED64 => "vec_packed_sfixed64_size", |
| Type::TYPE_FLOAT => "vec_packed_float_size", |
| Type::TYPE_DOUBLE => "vec_packed_double_size", |
| t => unreachable!("{:?}", t), |
| }; |
| format!( |
| "{}::rt::{fn_name}({}, &{})", |
| protobuf_crate_path(&self.customize), |
| self.proto_field.number(), |
| self.self_field() |
| ) |
| } |
| |
| pub(crate) fn clear_field_func(&self) -> String { |
| format!("clear_{}", self.rust_name) |
| } |
| |
| fn write_merge_from_field_message_string_bytes_repeated( |
| &self, |
| r: &RepeatedField, |
| w: &mut CodeWriter, |
| ) { |
| let read_fn = match &r.elem { |
| FieldElem::Message(..) => "read_message", |
| FieldElem::Primitive(Type::TYPE_STRING, PrimitiveTypeVariant::Default) => "read_string", |
| FieldElem::Primitive(Type::TYPE_STRING, PrimitiveTypeVariant::TokioBytes) => { |
| "read_tokio_chars" |
| } |
| FieldElem::Primitive(Type::TYPE_BYTES, PrimitiveTypeVariant::Default) => "read_bytes", |
| FieldElem::Primitive(Type::TYPE_BYTES, PrimitiveTypeVariant::TokioBytes) => { |
| "read_tokio_bytes" |
| } |
| _ => unreachable!("for field {}", self.proto_field.field), |
| }; |
| w.write_line(&format!("self.{}.push(is.{}()?);", self.rust_name, read_fn,)); |
| } |
| |
| fn tag_with_wire_type(&self, wire_type: WireType) -> u32 { |
| make_tag(self.proto_field.number() as u32, wire_type) |
| } |
| |
| fn tag(&self) -> u32 { |
| self.tag_with_wire_type(self.wire_type) |
| } |
| |
| // Write `merge_from` part for this oneof field |
| fn write_merge_from_oneof_case_block(&self, o: &OneofField, w: &mut CodeWriter) { |
| w.case_block(&format!("{}", self.tag()), |w| { |
| let typed = RustValueTyped { |
| value: format!( |
| "{}?", |
| self.proto_type.read("is", o.elem.primitive_type_variant()) |
| ), |
| rust_type: self.full_storage_iter_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ), |
| }; |
| |
| let maybe_boxed = if o.boxed { |
| typed.boxed(&self.customize) |
| } else { |
| typed |
| }; |
| |
| w.write_line(&format!( |
| "self.{} = ::std::option::Option::Some({}({}));", |
| o.oneof_field_name, |
| o.variant_path(&self.proto_field.message.scope.rust_path_to_file()), |
| maybe_boxed.value |
| )); |
| }) |
| } |
| |
| // Write `merge_from` part for this map field |
| fn write_merge_from_map_case_block(&self, map: &MapField, w: &mut CodeWriter) { |
| let MapField { key, value, .. } = map; |
| w.case_block(&format!("{}", self.tag()), |w| { |
| w.write_line(&format!("let len = is.read_raw_varint32()?;",)); |
| w.write_line(&format!("let old_limit = is.push_limit(len as u64)?;")); |
| w.write_line(&format!( |
| "let mut key = ::std::default::Default::default();" |
| )); |
| w.write_line(&format!( |
| "let mut value = ::std::default::Default::default();" |
| )); |
| w.while_block("let Some(tag) = is.read_raw_tag_or_eof()?", |w| { |
| w.match_block("tag", |w| { |
| let key_tag = make_tag(1, WireType::for_type(key.proto_type())); |
| let value_tag = make_tag(2, WireType::for_type(value.proto_type())); |
| w.case_expr( |
| &format!("{key_tag}"), |
| &format!("key = {read}", read = key.read_one_liner()), |
| ); |
| w.case_expr( |
| &format!("{value_tag}"), |
| &format!("value = {read}", read = value.read_one_liner()), |
| ); |
| w.case_expr( |
| "_", |
| &format!( |
| "{protobuf_crate}::rt::skip_field_for_tag(tag, is)?", |
| protobuf_crate = protobuf_crate_path(&self.customize) |
| ), |
| ); |
| }); |
| }); |
| w.write_line(&format!("is.pop_limit(old_limit);")); |
| w.write_line(&format!( |
| "{field}.insert(key, value);", |
| field = self.self_field() |
| )); |
| }); |
| } |
| |
| // Write `merge_from` part for this singular field |
| fn write_merge_from_singular_case_block(&self, s: &SingularField, w: &mut CodeWriter) { |
| w.case_block(&format!("{}", self.tag()), |w| match s.elem { |
| FieldElem::Message(..) => { |
| w.write_line(&format!( |
| "{}::rt::read_singular_message_into_field(is, &mut self.{})?;", |
| protobuf_crate_path(&self.customize), |
| self.rust_name, |
| )); |
| } |
| _ => { |
| let read_proc = s.elem.read_one_liner(); |
| self.write_self_field_assign_some(w, s, &read_proc); |
| } |
| }) |
| } |
| |
| // Write `merge_from` part for this repeated field |
| fn write_merge_from_repeated_case_block(&self, w: &mut CodeWriter) { |
| let field = match self.kind { |
| FieldKind::Repeated(ref field) => field, |
| _ => panic!(), |
| }; |
| |
| match field.elem { |
| FieldElem::Message(..) |
| | FieldElem::Primitive(field_descriptor_proto::Type::TYPE_STRING, ..) |
| | FieldElem::Primitive(field_descriptor_proto::Type::TYPE_BYTES, ..) => { |
| w.case_block(&format!("{}", self.tag()), |w| { |
| self.write_merge_from_field_message_string_bytes_repeated(field, w); |
| }) |
| } |
| FieldElem::Enum(..) => { |
| w.case_block( |
| &format!("{}", self.tag_with_wire_type(WireType::Varint)), |
| |w| { |
| w.write_line(&format!( |
| "self.{}.push(is.read_enum_or_unknown()?);", |
| self.rust_name, |
| )); |
| }, |
| ); |
| w.case_block( |
| &format!("{}", self.tag_with_wire_type(WireType::LengthDelimited)), |
| |w| { |
| w.write_line(&format!( |
| "{}::rt::read_repeated_packed_enum_or_unknown_into(is, &mut self.{})?", |
| protobuf_crate_path(&self.customize), |
| self.rust_name, |
| )); |
| }, |
| ); |
| } |
| _ => { |
| assert_ne!(self.wire_type, WireType::LengthDelimited); |
| w.case_block( |
| &format!("{}", self.tag_with_wire_type(WireType::LengthDelimited)), |
| |w| { |
| w.write_line(&format!( |
| "is.read_repeated_packed_{}_into(&mut self.{})?;", |
| self.proto_type.protobuf_name(), |
| self.rust_name |
| )); |
| }, |
| ); |
| w.case_block(&format!("{}", self.tag()), |w| { |
| w.write_line(&format!( |
| "self.{}.push(is.read_{}()?);", |
| self.rust_name, |
| self.proto_type.protobuf_name(), |
| )); |
| }); |
| } |
| } |
| } |
| |
| /// Write `merge_from` part for this field |
| pub(crate) fn write_merge_from_field_case_block(&self, w: &mut CodeWriter) { |
| match &self.kind { |
| FieldKind::Oneof(oneof) => self.write_merge_from_oneof_case_block(oneof, w), |
| FieldKind::Map(map) => self.write_merge_from_map_case_block(map, w), |
| FieldKind::Singular(ref s) => self.write_merge_from_singular_case_block(s, w), |
| FieldKind::Repeated(..) => self.write_merge_from_repeated_case_block(w), |
| } |
| } |
| |
| pub(crate) fn write_element_size( |
| &self, |
| elem: &FieldElem, |
| w: &mut CodeWriter, |
| item_var: &RustValueTyped, |
| sum_var: &str, |
| ) { |
| assert!(!self.is_repeated_packed()); |
| |
| elem.write_element_size( |
| self.proto_field.number() as u32, |
| item_var, |
| HowToGetMessageSize::Compute, |
| sum_var, |
| &self.customize, |
| w, |
| ); |
| } |
| |
| fn write_write_map_field( |
| &self, |
| key: &FieldElem, |
| value: &FieldElem, |
| os: &str, |
| w: &mut CodeWriter, |
| ) { |
| self.for_each_map_entry(key, value, w, |k, v, w| { |
| w.write_line("let mut entry_size = 0;"); |
| key.write_element_size( |
| 1, |
| k, |
| HowToGetMessageSize::GetCached, |
| "entry_size", |
| &self.customize, |
| w, |
| ); |
| value.write_element_size( |
| 2, |
| v, |
| HowToGetMessageSize::GetCached, |
| "entry_size", |
| &self.customize, |
| w, |
| ); |
| w.write_line(&format!( |
| "{os}.write_raw_varint32({tag})?; // Tag.", |
| tag = make_tag(self.proto_field.number() as u32, WireType::LengthDelimited), |
| )); |
| w.write_line(&format!("{os}.write_raw_varint32(entry_size as u32)?;",)); |
| key.write_write_element(1, k, &self.file_and_mod(), &self.customize, os, w); |
| value.write_write_element(2, v, &self.file_and_mod(), &self.customize, os, w); |
| }); |
| } |
| |
| pub(crate) fn write_message_write_field(&self, os: &str, w: &mut CodeWriter) { |
| match &self.kind { |
| FieldKind::Singular(s @ SingularField { elem, .. }) => { |
| self.write_if_let_self_field_is_some(s, w, |v, w| { |
| self.write_write_element(&elem, w, os, &v); |
| }); |
| } |
| FieldKind::Repeated(RepeatedField { |
| packed: false, |
| elem, |
| .. |
| }) => { |
| self.write_for_self_field(w, "v", |w, v_type| { |
| let v = RustValueTyped { |
| value: "v".to_owned(), |
| rust_type: v_type.clone(), |
| }; |
| self.write_write_element(elem, w, "os", &v); |
| }); |
| } |
| FieldKind::Repeated(RepeatedField { packed: true, .. }) => { |
| w.write_line(&format!( |
| "os.write_repeated_packed_{}({}, &{})?;", |
| self.os_write_fn_suffix_with_unknown_for_enum(), |
| self.proto_field.number(), |
| self.self_field() |
| )); |
| } |
| FieldKind::Map(MapField { key, value, .. }) => { |
| self.write_write_map_field(key, value, os, w) |
| } |
| FieldKind::Oneof(..) => unreachable!(), |
| }; |
| } |
| |
| fn for_each_map_entry( |
| &self, |
| key: &FieldElem, |
| value: &FieldElem, |
| w: &mut CodeWriter, |
| cb: impl FnOnce(&RustValueTyped, &RustValueTyped, &mut CodeWriter), |
| ) { |
| w.for_stmt(&format!("&{}", self.self_field()), "(k, v)", move |w| { |
| let k = RustValueTyped { |
| value: "k".to_owned(), |
| rust_type: key.rust_storage_elem_type(&self.file_and_mod()).wrap_ref(), |
| }; |
| let v = RustValueTyped { |
| value: "v".to_owned(), |
| rust_type: value |
| .rust_storage_elem_type(&self.file_and_mod()) |
| .wrap_ref(), |
| }; |
| cb(&k, &v, w) |
| }); |
| } |
| |
| fn write_compute_map_field_size( |
| &self, |
| sum_var: &str, |
| key: &FieldElem<'a>, |
| value: &FieldElem<'a>, |
| w: &mut CodeWriter, |
| ) { |
| self.for_each_map_entry(key, value, w, |k, v, w| { |
| w.write_line("let mut entry_size = 0;"); |
| key.write_element_size(1, k, HowToGetMessageSize::Compute, "entry_size", &self.customize, w); |
| value.write_element_size(2, v, HowToGetMessageSize::Compute, "entry_size", &self.customize, w); |
| w.write_line(&format!("{sum_var} += {tag_size} + {protobuf_crate}::rt::compute_raw_varint64_size(entry_size) + entry_size", |
| tag_size = self.tag_size(), |
| protobuf_crate = protobuf_crate_path(&self.customize), |
| )); |
| }); |
| } |
| |
| pub(crate) fn write_message_compute_field_size(&self, sum_var: &str, w: &mut CodeWriter) { |
| match &self.kind { |
| FieldKind::Singular(s @ SingularField { elem, .. }) => { |
| self.write_if_let_self_field_is_some(s, w, |v, w| { |
| self.write_element_size(&elem, w, v, sum_var) |
| }); |
| } |
| FieldKind::Repeated(RepeatedField { |
| packed: false, |
| elem, |
| .. |
| }) => { |
| match elem.proto_type().encoded_size() { |
| Some(s) => { |
| let tag_size = self.tag_size(); |
| let self_field = self.self_field(); |
| w.write_line(&format!( |
| "{} += {} * {}.len() as u64;", |
| sum_var, |
| (s + tag_size) as isize, |
| self_field |
| )); |
| } |
| None => { |
| self.write_for_self_field(w, "value", |w, value_type| { |
| self.write_element_size( |
| elem, |
| w, |
| &RustValueTyped { |
| value: "value".to_owned(), |
| rust_type: value_type.clone(), |
| }, |
| sum_var, |
| ); |
| }); |
| } |
| }; |
| } |
| FieldKind::Repeated(RepeatedField { packed: true, .. }) => { |
| let size_expr = self.self_field_vec_packed_size(); |
| w.write_line(&format!("{} += {};", sum_var, size_expr)); |
| } |
| FieldKind::Map(MapField { key, value, .. }) => { |
| self.write_compute_map_field_size(sum_var, key, value, w) |
| } |
| FieldKind::Oneof(..) => unreachable!(), |
| } |
| } |
| |
| fn write_message_field_get_singular_message(&self, s: &SingularField, w: &mut CodeWriter) { |
| match s.flag { |
| SingularFieldFlag::WithoutFlag => unimplemented!(), |
| SingularFieldFlag::WithFlag { option_kind, .. } => { |
| let self_field = self.self_field(); |
| let ref field_type_name = self.elem().rust_storage_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ); |
| w.write_line(option_kind.unwrap_ref_or_else( |
| &format!("{}.as_ref()", self_field), |
| &format!( |
| "<{} as {}::Message>::default_instance()", |
| field_type_name.to_code(&self.customize), |
| protobuf_crate_path(&self.customize), |
| ), |
| )); |
| } |
| } |
| } |
| |
| fn write_message_field_get_singular_enum( |
| &self, |
| flag: SingularFieldFlag, |
| _elem: &FieldElemEnum, |
| w: &mut CodeWriter, |
| ) { |
| match flag { |
| SingularFieldFlag::WithoutFlag => { |
| w.write_line(&format!("self.{}.enum_value_or_default()", self.rust_name)); |
| } |
| SingularFieldFlag::WithFlag { .. } => { |
| w.match_expr(&self.self_field(), |w| { |
| let default_value = self.xxx_default_value_rust(); |
| w.case_expr("Some(e)", &format!("e.enum_value_or({})", default_value)); |
| w.case_expr("None", &format!("{}", default_value)); |
| }); |
| } |
| } |
| } |
| |
| fn write_message_field_get_singular(&self, singular: &SingularField, w: &mut CodeWriter) { |
| let get_xxx_return_type = self.getter_return_type(); |
| |
| match singular.elem { |
| FieldElem::Message(..) => self.write_message_field_get_singular_message(singular, w), |
| FieldElem::Enum(ref en) => { |
| self.write_message_field_get_singular_enum(singular.flag, en, w) |
| } |
| _ => { |
| let get_xxx_default_value_rust = self.xxx_default_value_rust(); |
| let self_field = self.self_field(); |
| match singular { |
| &SingularField { |
| ref elem, |
| flag: SingularFieldFlag::WithFlag { option_kind, .. }, |
| .. |
| } => { |
| if get_xxx_return_type.is_ref().is_some() { |
| let as_option = self.self_field_as_option(elem, option_kind); |
| w.match_expr(&as_option.value, |w| { |
| let v_type = as_option.rust_type.elem_type(); |
| let r_type = self.getter_return_type(); |
| w.case_expr( |
| "Some(v)", |
| v_type.into_target(&r_type, "v", &self.customize), |
| ); |
| let get_xxx_default_value_rust = self.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( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ) |
| .into_target( |
| &get_xxx_return_type, |
| &self_field, |
| &self.customize, |
| ), |
| ); |
| } |
| } |
| } |
| } |
| } |
| |
| fn write_message_field_get_oneof(&self, o: &OneofField, w: &mut CodeWriter) { |
| let get_xxx_return_type = SingularOrOneofField::Oneof(o.clone()).getter_return_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ); |
| let OneofField { ref elem, .. } = o; |
| w.match_expr(&format!("self.{}", o.oneof_field_name), |w| { |
| let (refv, vtype) = if !elem.is_copy() { |
| ( |
| "ref v", |
| elem.rust_storage_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ) |
| .ref_type(), |
| ) |
| } else { |
| ( |
| "v", |
| elem.rust_storage_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ), |
| ) |
| }; |
| w.case_expr( |
| format!( |
| "::std::option::Option::Some({}({}))", |
| o.variant_path(&self.proto_field.message.scope.rust_path_to_file()), |
| refv |
| ), |
| vtype.into_target(&get_xxx_return_type, "v", &self.customize), |
| ); |
| w.case_expr("_", self.xxx_default_value_rust()); |
| }); |
| } |
| |
| fn write_message_field_get(&self, w: &mut CodeWriter) { |
| let get_xxx_return_type = self.getter_return_type(); |
| let fn_def = format!( |
| "{}(&self) -> {}", |
| self.rust_name, |
| get_xxx_return_type.to_code(&self.customize) |
| ); |
| |
| w.pub_fn(&fn_def, |w| match self.kind { |
| FieldKind::Oneof(ref o) => { |
| self.write_message_field_get_oneof(o, w); |
| } |
| FieldKind::Singular(ref s) => { |
| self.write_message_field_get_singular(s, 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) -> RustIdent { |
| RustIdent::new(&format!("has_{}", self.rust_name.get())) |
| } |
| |
| fn set_name(&self) -> RustIdent { |
| RustIdent::new(&format!("set_{}", self.rust_name.get())) |
| } |
| |
| fn mut_name(&self) -> RustIdent { |
| RustIdent::new(&format!("mut_{}", self.rust_name.get())) |
| } |
| |
| fn write_message_field_has(&self, w: &mut CodeWriter) { |
| w.pub_fn( |
| &format!("{}(&self) -> bool", self.has_name()), |
| |w| match self.kind { |
| FieldKind::Oneof(ref oneof) => { |
| w.match_expr(&format!("self.{}", oneof.oneof_field_name), |w| { |
| w.case_expr( |
| format!( |
| "::std::option::Option::Some({}(..))", |
| oneof.variant_path( |
| &self.proto_field.message.scope.rust_path_to_file() |
| ) |
| ), |
| "true", |
| ); |
| w.case_expr("_", "false"); |
| }); |
| } |
| _ => { |
| let self_field_is_some = self.self_field_is_some(); |
| w.write_line(self_field_is_some); |
| } |
| }, |
| ); |
| } |
| |
| fn write_message_field_set(&self, w: &mut CodeWriter) { |
| let set_xxx_param_type = self.set_xxx_param_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ); |
| w.comment("Param is passed by value, moved"); |
| w.pub_fn( |
| &format!( |
| "{}(&mut self, v: {})", |
| self.set_name(), |
| set_xxx_param_type.to_code(&self.customize) |
| ), |
| |w| { |
| let value_typed = RustValueTyped { |
| value: "v".to_owned(), |
| rust_type: set_xxx_param_type.clone(), |
| }; |
| match self.kind { |
| FieldKind::Oneof(ref oneof) => { |
| let v = set_xxx_param_type.into_target( |
| &oneof.rust_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ), |
| "v", |
| &self.customize, |
| ); |
| w.write_line(&format!( |
| "self.{} = ::std::option::Option::Some({}({}))", |
| oneof.oneof_field_name, |
| oneof.variant_path(&self.proto_field.message.scope.rust_path_to_file()), |
| v |
| )); |
| } |
| _ => { |
| self.write_self_field_assign_value(w, &value_typed); |
| } |
| } |
| }, |
| ); |
| } |
| |
| fn write_message_field_mut_singular_with_flag( |
| &self, |
| s: &SingularField, |
| option_kind: OptionKind, |
| w: &mut CodeWriter, |
| ) { |
| let self_field = self.self_field(); |
| match option_kind { |
| OptionKind::MessageField => { |
| w.write_line(&format!("{}.mut_or_insert_default()", self_field)) |
| } |
| OptionKind::Option => { |
| self.write_if_self_field_is_none(w, |w| { |
| self.write_self_field_assign_default( |
| &SingularOrOneofField::Singular(s.clone()), |
| w, |
| ); |
| }); |
| w.write_line(&format!("{}.as_mut().unwrap()", self_field)); |
| } |
| } |
| } |
| |
| fn write_message_field_mut_singular(&self, s: &SingularField, w: &mut CodeWriter) { |
| match s { |
| s @ SingularField { |
| flag: SingularFieldFlag::WithFlag { option_kind, .. }, |
| .. |
| } => self.write_message_field_mut_singular_with_flag(s, *option_kind, w), |
| SingularField { |
| flag: SingularFieldFlag::WithoutFlag, |
| .. |
| } => w.write_line(&format!("&mut {}", self.self_field())), |
| } |
| } |
| |
| fn write_message_field_mut(&self, w: &mut CodeWriter) { |
| let mut_xxx_return_type = self.mut_xxx_return_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ); |
| 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 self) -> &mut {}", |
| self.mut_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(ref s) => { |
| self.write_message_field_mut_singular(s, w); |
| } |
| FieldKind::Oneof(ref o) => { |
| let self_field_oneof = format!("self.{}", o.oneof_field_name); |
| |
| // if oneof does not contain current field |
| w.if_let_else_stmt( |
| &format!( |
| "::std::option::Option::Some({}(_))", |
| o.variant_path(&self.proto_field.message.scope.rust_path_to_file()) |
| )[..], |
| &self_field_oneof[..], |
| |w| { |
| // initialize it with default value |
| w.write_line(&format!( |
| "{} = ::std::option::Option::Some({}({}));", |
| self_field_oneof, |
| o.variant_path(&self.proto_field.message.scope.rust_path_to_file()), |
| self.element_default_value_rust() |
| .into_type( |
| o.rust_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()) |
| ), |
| &self.customize |
| ) |
| .value |
| )); |
| }, |
| ); |
| |
| // extract field |
| w.match_expr(self_field_oneof, |w| { |
| w.case_expr( |
| format!( |
| "::std::option::Option::Some({}(ref mut v))", |
| o.variant_path(&self.proto_field.message.scope.rust_path_to_file()) |
| ), |
| "v", |
| ); |
| w.case_expr("_", "panic!()"); |
| }); |
| } |
| } |
| }); |
| } |
| |
| fn write_message_field_take_oneof(&self, o: &OneofField, w: &mut CodeWriter) { |
| let take_xxx_return_type = self.take_xxx_return_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ); |
| |
| // TODO: replace with if let |
| w.write_line(&format!("if self.{}() {{", self.has_name())); |
| w.indented(|w| { |
| let self_field_oneof = format!("self.{}", o.oneof_field_name); |
| w.match_expr(format!("{}.take()", self_field_oneof), |w| { |
| let value_in_some = o |
| .rust_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ) |
| .value("v".to_owned()); |
| let converted = value_in_some.into_type( |
| self.take_xxx_return_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ), |
| &self.customize, |
| ); |
| w.case_expr( |
| format!( |
| "::std::option::Option::Some({}(v))", |
| o.variant_path(&self.proto_field.message.scope.rust_path_to_file()) |
| ), |
| &converted.value, |
| ); |
| w.case_expr("_", "panic!()"); |
| }); |
| }); |
| w.write_line("} else {"); |
| w.indented(|w| { |
| w.write_line( |
| self.elem() |
| .rust_storage_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ) |
| .default_value_typed(&self.customize, false) |
| .into_type(take_xxx_return_type.clone(), &self.customize) |
| .value, |
| ); |
| }); |
| w.write_line("}"); |
| } |
| |
| fn write_message_field_take_singular(&self, s: &SingularField, w: &mut CodeWriter) { |
| match s { |
| SingularField { |
| ref elem, |
| flag: SingularFieldFlag::WithFlag { option_kind, .. }, |
| } => { |
| if !elem.is_copy() { |
| w.write_line( |
| &option_kind.unwrap_or_else( |
| &format!("{}.take()", self.self_field()), |
| &elem |
| .rust_storage_elem_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ) |
| .default_value(&self.customize, false), |
| ), |
| ); |
| } else { |
| w.write_line(&format!( |
| "{}.take().unwrap_or({})", |
| self.self_field(), |
| self.element_default_value_rust().value |
| )); |
| } |
| } |
| SingularField { |
| flag: SingularFieldFlag::WithoutFlag, |
| .. |
| } => w.write_line(&format!( |
| "::std::mem::replace(&mut {}, {})", |
| self.self_field(), |
| self.full_storage_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()) |
| ) |
| .default_value(&self.customize, false) |
| )), |
| } |
| } |
| |
| fn write_message_field_take(&self, w: &mut CodeWriter) { |
| let take_xxx_return_type = self.take_xxx_return_type( |
| &self |
| .proto_field |
| .message |
| .scope |
| .file_and_mod(self.customize.clone()), |
| ); |
| 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::Singular(ref s) => self.write_message_field_take_singular(&s, w), |
| FieldKind::Oneof(ref o) => self.write_message_field_take_oneof(o, 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, false) |
| )); |
| } |
| }, |
| ); |
| } |
| |
| pub(crate) fn write_message_single_field_accessors(&self, w: &mut CodeWriter) { |
| if self.generate_accessors || self.generate_getter { |
| w.write_line(""); |
| let reconstruct_def = self.reconstruct_def(); |
| w.comment(&(reconstruct_def + ";")); |
| } |
| |
| if self.generate_getter { |
| w.write_line(""); |
| self.write_message_field_get(w); |
| } |
| |
| if !self.generate_accessors { |
| return; |
| } |
| |
| w.write_line(""); |
| 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 { |
| RustIdent::new(name) |
| } |
| |
| pub(crate) fn rust_variant_name_for_protobuf_oneof_field_name(name: &str) -> RustIdent { |
| let name = camel_case(name); |
| RustIdent::new(&name) |
| } |