blob: 26f0ef48a0b123903221c00e511a36326554fd49 [file] [log] [blame]
use crate::gen::code_writer::CodeWriter;
use crate::gen::field::elem::FieldElem;
use crate::gen::field::elem::FieldElemEnum;
use crate::gen::field::option_kind::OptionKind;
use crate::gen::field::repeated::RepeatedField;
use crate::gen::field::repeated::RepeatedFieldKind;
use crate::gen::field::singular::SingularField;
use crate::gen::field::singular::SingularFieldFlag;
use crate::gen::field::FieldGen;
use crate::gen::field::FieldKind;
use crate::gen::field::MapField;
use crate::gen::inside::protobuf_crate_path;
use crate::gen::oneof::OneofField;
use crate::gen::rust_types_values::RustType;
use crate::gen::scope::WithScope;
struct AccessorFn {
name: String,
// function type params after first underscore
type_params: Vec<String>,
callback_params: Vec<String>,
}
impl AccessorFn {
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
}
}
impl FieldGen<'_> {
fn make_accessor_fns_lambda(&self) -> Vec<String> {
let message = self.proto_field.message.rust_name();
vec![
format!("|m: &{}| {{ &m.{} }}", message, self.rust_name),
format!("|m: &mut {}| {{ &mut m.{} }}", message, self.rust_name),
]
}
fn make_accessor_fns_has_get_set(&self) -> Vec<String> {
let message = self.proto_field.message.rust_name();
vec![
format!("{}::{}", message, self.has_name()),
format!("{}::{}", message, self.rust_name),
format!("{}::{}", message, self.set_name()),
]
}
fn make_accessor_fns_has_get_mut_set(&self) -> Vec<String> {
let message = self.proto_field.message.rust_name();
vec![
format!("{}::{}", message, self.has_name()),
format!("{}::{}", message, self.rust_name),
format!("{}::{}", message, self.mut_name()),
format!("{}::{}", message, self.set_name()),
]
}
fn accessor_fn_map(&self, map_field: &MapField) -> AccessorFn {
let MapField { .. } = map_field;
AccessorFn {
name: "make_map_simpler_accessor".to_owned(),
type_params: vec![format!("_"), format!("_")],
callback_params: self.make_accessor_fns_lambda(),
}
}
fn accessor_fn_repeated(&self, repeated_field: &RepeatedField) -> AccessorFn {
let RepeatedField { .. } = repeated_field;
let name = match repeated_field.kind() {
RepeatedFieldKind::Vec => "make_vec_simpler_accessor",
};
AccessorFn {
name: name.to_owned(),
type_params: vec![format!("_")],
callback_params: self.make_accessor_fns_lambda(),
}
}
fn accessor_fn_oneof_enum(&self, oneof: &OneofField, en: &FieldElemEnum) -> AccessorFn {
let message = self.proto_field.message.rust_name();
let variant_path = oneof.variant_path(&self.proto_field.message.scope.rust_path_to_file());
let getter = CodeWriter::with_no_error(|w| {
w.expr_block(
&format!(
"|message: &{}| match &message.{}",
message, oneof.oneof_field_name
),
|w| {
w.case_expr(
&format!("::std::option::Option::Some({}(e))", variant_path),
"::std::option::Option::Some(*e)",
);
w.case_expr("_", "::std::option::Option::None");
},
);
});
let setter = CodeWriter::with_no_error(|w| {
w.expr_block(
&format!(
"|message: &mut {}, e: {}::EnumOrUnknown<{}>|",
message,
protobuf_crate_path(&self.customize),
en.enum_rust_type(&self.file_and_mod())
.to_code(&self.customize)
),
|w| {
w.write_line(&format!(
"message.{} = ::std::option::Option::Some({}(e));",
oneof.oneof_field_name, variant_path
));
},
)
});
let default = self.xxx_default_value_rust();
AccessorFn {
name: "make_oneof_enum_accessors".to_owned(),
type_params: vec![format!("_")],
callback_params: vec![getter, setter, default],
}
}
fn accessor_fn_singular_without_flag(&self, _elem: &FieldElem) -> AccessorFn {
AccessorFn {
name: "make_simpler_field_accessor".to_owned(),
type_params: vec![format!("_")],
callback_params: self.make_accessor_fns_lambda(),
}
}
fn accessor_fn_singular_with_flag(
&self,
elem: &FieldElem,
_option_kind: OptionKind,
) -> AccessorFn {
match elem {
FieldElem::Message(m) => AccessorFn {
name: "make_message_field_accessor".to_owned(),
type_params: vec![format!("{}", m.rust_name_relative(&self.file_and_mod()))],
callback_params: self.make_accessor_fns_lambda(),
},
FieldElem::Primitive(..) | FieldElem::Enum(..) => AccessorFn {
name: "make_option_accessor".to_owned(),
type_params: vec!["_".to_owned()],
callback_params: self.make_accessor_fns_lambda(),
},
FieldElem::Group => {
unreachable!("no accessor for group field");
}
}
}
fn accessor_fn_oneof(&self, oneof: &OneofField) -> AccessorFn {
let OneofField { ref elem, .. } = oneof;
let reference = self
.proto_field
.message
.scope
.file_and_mod(self.customize.clone());
if let FieldElem::Enum(en) = &oneof.elem {
return self.accessor_fn_oneof_enum(oneof, en);
}
if elem.is_copy() {
return AccessorFn {
name: "make_oneof_copy_has_get_set_simpler_accessors".to_owned(),
type_params: vec![format!("_")],
callback_params: self.make_accessor_fns_has_get_set(),
};
}
if let RustType::Message(name) = elem.rust_storage_elem_type(&reference) {
return AccessorFn {
name: "make_oneof_message_has_get_mut_set_accessor".to_owned(),
type_params: vec![format!("{}", name)],
callback_params: self.make_accessor_fns_has_get_mut_set(),
};
}
// string or bytes
AccessorFn {
name: "make_oneof_deref_has_get_set_simpler_accessor".to_owned(),
type_params: vec![format!("_")],
callback_params: self.make_accessor_fns_has_get_set(),
}
}
fn accessor_fn(&self) -> AccessorFn {
match self.kind {
FieldKind::Repeated(ref repeated_field) => self.accessor_fn_repeated(repeated_field),
FieldKind::Map(ref map_field) => self.accessor_fn_map(map_field),
FieldKind::Singular(SingularField {
ref elem,
flag: SingularFieldFlag::WithoutFlag,
}) => self.accessor_fn_singular_without_flag(elem),
FieldKind::Singular(SingularField {
ref elem,
flag: SingularFieldFlag::WithFlag { option_kind, .. },
}) => self.accessor_fn_singular_with_flag(elem, option_kind),
FieldKind::Oneof(ref oneof) => self.accessor_fn_oneof(oneof),
}
}
pub fn write_push_accessor(&self, fields_var: &str, w: &mut CodeWriter) {
let accessor_fn = self.accessor_fn();
w.write_line(&format!(
"{}.push({}::reflect::rt::v2::{}(",
fields_var,
protobuf_crate_path(&self.customize),
accessor_fn.sig()
));
w.indented(|w| {
w.write_line(&format!("\"{}\",", self.proto_field.name()));
for callback in &accessor_fn.callback_params {
let callback_lines: Vec<&str> = callback.lines().collect();
for (i, callback_line) in callback_lines.iter().enumerate() {
let comma = if i == callback_lines.len() - 1 {
","
} else {
""
};
w.write_line(&format!("{}{}", callback_line, comma));
}
}
});
w.write_line("));");
}
}