use crate::generated::descriptor::field_descriptor_proto::{Label, Type};
use crate::generated::descriptor::{DescriptorProto, FieldDescriptorProto, OneofDescriptorProto};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::context::{ancillary_prefix, AncillaryKind, CodeGenContext, MessageScope, SENTINEL_MOD};
use crate::features::ResolvedFeatures;
use crate::impl_message::{
closed_enum_decode, closed_enum_decode_with_unknown, decode_fn_token, effective_type,
effective_type_in_map_entry, field_string_repr, find_map_entry_fields,
is_explicit_presence_scalar, is_packed_type, is_real_oneof_member, is_required_field,
is_supported_field_type, map_string_repr, map_value_bytes_repr, validated_field_number,
wire_type_check, wire_type_token,
};
use crate::message::{is_closed_enum, is_map_field, make_field_ident, rust_path_to_tokens};
use crate::oneof::{is_null_value_field, serde_helper_path};
use crate::CodeGenError;
fn closed_enum_view_unknown_route(preserve_unknown_fields: bool) -> TokenStream {
if preserve_unknown_fields {
quote! {
let __span_len = before_tag.len() - cur.len();
view.__buffa_unknown_fields.push_record(before_tag, __span_len, ctx)?;
}
} else {
quote! {}
}
}
fn bytes_to_owned(
ctx: &CodeGenContext,
proto_fqn: &str,
field_name: &str,
expr: TokenStream,
) -> TokenStream {
match crate::impl_message::field_bytes_repr(ctx, proto_fqn, field_name) {
crate::BytesRepr::Bytes => {
quote! { ::buffa::view::bytes_from_source(__buffa_src, #expr) }
}
crate::BytesRepr::Vec => quote! { (#expr).to_vec() },
crate::BytesRepr::Custom(_) => {
quote! { ::core::convert::Into::into((#expr).to_vec()) }
}
}
}
pub(crate) fn generate_view_with_nesting(
scope: MessageScope<'_>,
msg: &DescriptorProto,
rust_name: &str,
) -> Result<(TokenStream, TokenStream), CodeGenError> {
let MessageScope {
ctx,
current_package,
proto_fqn,
features,
nesting,
} = scope;
let oneof_idents = crate::oneof::resolve_oneof_idents(msg);
let view_ident = format_ident!("{}View", rust_name);
let view_depth = nesting + 2;
let view_scope = MessageScope {
nesting: view_depth,
..scope
};
let view_oneof_prefix = ancillary_prefix(
AncillaryKind::ViewOneof,
current_package,
proto_fqn,
view_depth,
);
let owned_oneof_prefix =
ancillary_prefix(AncillaryKind::Oneof, current_package, proto_fqn, view_depth);
let view_fields = msg
.field
.iter()
.filter(|f| is_supported_field_type(f.r#type.unwrap_or_default()))
.map(|f| view_struct_field(view_scope, msg, f))
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.flatten()
.collect::<Vec<_>>();
let direct_fields: Vec<&TokenStream> =
view_fields.iter().map(|(tokens, _, _)| tokens).collect();
let oneof_view_fields =
oneof_view_struct_fields(ctx, msg, &view_oneof_prefix, features, &oneof_idents)?;
let oneof_struct_fields: Vec<&TokenStream> =
oneof_view_fields.iter().map(|(tokens, _)| tokens).collect();
let oneof_view_enums = msg
.oneof_decl
.iter()
.enumerate()
.map(|(idx, oneof)| generate_oneof_view_enum(scope, msg, idx, oneof, &oneof_idents))
.collect::<Result<Vec<_>, _>>()?;
let required = required_presence(view_scope, msg);
let required_seen_struct_fields = &required.struct_fields;
let required_has_methods = &required.has_methods;
let required_has_impl = if required.has_methods.is_empty() {
quote! {}
} else {
quote! {
impl<'a> #view_ident<'a> {
#(#required_has_methods)*
}
}
};
let (scalar_arms, repeated_arms, oneof_arms) = build_decode_arms(
view_scope,
msg,
&view_oneof_prefix,
&oneof_idents,
&required.bit_stmts,
)?;
let owned_fields = build_to_owned_fields(
view_scope,
msg,
&view_oneof_prefix,
&owned_oneof_prefix,
&oneof_idents,
)?;
let unknown_fields_field = if ctx.config.preserve_unknown_fields {
quote! { pub __buffa_unknown_fields: ::buffa::UnknownFieldsView<'a>, }
} else {
quote! {}
};
let view_encode_methods = crate::impl_message::build_view_encode_methods(
ctx,
msg,
ctx.config.preserve_unknown_fields,
features,
&oneof_idents,
&view_oneof_prefix,
None,
"e! {},
)?;
let view_encode_impl = quote! {
impl<'a> ::buffa::ViewEncode<'a> for #view_ident<'a> {
#view_encode_methods
}
};
let message_name_impl = crate::impl_message::message_name_impl(
current_package,
proto_fqn,
"e! { <'a> },
"e! { #view_ident<'a> },
);
let serialize_impl = if ctx.config.generate_json {
crate::feature_gates::cfg_block(
generate_view_serialize(
view_scope,
msg,
&view_ident,
&view_oneof_prefix,
&oneof_idents,
)?,
ctx.config.feature_gates().json,
)
} else {
quote! {}
};
let is_map_entry = msg
.options
.as_option()
.is_some_and(|o| o.map_entry.unwrap_or(false));
let reflect_view_impls =
if ctx.config.generate_reflection && ctx.config.generate_reflection_vtable && !is_map_entry
{
crate::feature_gates::cfg_const_block(
crate::reflect_view::reflect_view_impls(
view_scope,
msg,
&view_ident,
view_depth,
&view_oneof_prefix,
&oneof_idents,
)?,
ctx.config.feature_gates().reflect,
)
} else {
quote! {}
};
let before_tag_param = if ctx.config.preserve_unknown_fields {
format_ident!("before_tag")
} else {
format_ident!("_before_tag")
};
let unknown_field_handling = if ctx.config.preserve_unknown_fields {
quote! {
let span_len = before_tag.len() - cur.len();
view.__buffa_unknown_fields.push_record(before_tag, span_len, ctx)?;
}
} else {
quote! {}
};
let phantom_field =
if message_view_has_borrowing_field(ctx, msg, features, ctx.config.preserve_unknown_fields)
{
quote! {}
} else {
quote! { #[doc(hidden)] pub __buffa_phantom: ::core::marker::PhantomData<&'a ()>, }
};
let mod_items = quote! {
#(#oneof_view_enums)*
};
let owned_path: TokenStream = {
let dotted = format!(".{proto_fqn}");
let p = ctx
.rust_type_relative(&dotted, current_package, view_depth)
.ok_or_else(|| {
CodeGenError::Other(format!(
"owned type for '{proto_fqn}' not resolvable from view tree"
))
})?;
rust_path_to_tokens(&p)
};
let view_doc =
crate::comments::doc_attrs_resolved(ctx.comment(proto_fqn), proto_fqn, &ctx.type_map);
let owned_view_wrapper = if is_map_entry {
quote! {}
} else {
crate::owned_view::generate_owned_view_wrapper(
view_scope,
msg,
rust_name,
&view_ident,
&owned_path,
&view_oneof_prefix,
&oneof_idents,
)?
};
let any_redacted = view_fields.iter().any(|(_, _, redacted)| *redacted);
let (view_debug_derive, view_debug_impl) = if any_redacted {
let placeholder = crate::message::DEBUG_REDACT_PLACEHOLDER;
let view_name_str = view_ident.to_string();
let mut debug_field_names: Vec<String> = Vec::new();
let mut debug_field_values: Vec<TokenStream> = Vec::new();
for (_, ident, redacted) in &view_fields {
debug_field_names.push(ident.to_string().trim_start_matches("r#").to_string());
debug_field_values.push(if *redacted {
quote! { &::core::format_args!(#placeholder) }
} else {
quote! { &self.#ident }
});
}
for (_, ident) in &oneof_view_fields {
debug_field_names.push(ident.to_string().trim_start_matches("r#").to_string());
debug_field_values.push(quote! { &self.#ident });
}
(
quote! { #[derive(Clone, Default)] },
quote! {
impl<'a> ::core::fmt::Debug for #view_ident<'a> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
f.debug_struct(#view_name_str)
#(.field(#debug_field_names, #debug_field_values))*
.finish()
}
}
},
)
} else {
(quote! { #[derive(Clone, Debug, Default)] }, quote! {})
};
let top_level = quote! {
#view_doc
#view_debug_derive
pub struct #view_ident<'a> {
#(#direct_fields)*
#(#oneof_struct_fields)*
#unknown_fields_field
#(#required_seen_struct_fields)*
#phantom_field
}
#view_debug_impl
#required_has_impl
impl<'a> ::buffa::MessageView<'a> for #view_ident<'a> {
type Owned = #owned_path;
fn decode_view(
buf: &'a [u8],
) -> ::core::result::Result<Self, ::buffa::DecodeError> {
let __limit = ::core::cell::Cell::new(::buffa::DEFAULT_UNKNOWN_FIELD_LIMIT);
<Self as ::buffa::MessageView>::decode_view_ctx(
buf,
::buffa::DecodeContext::new(::buffa::RECURSION_LIMIT, &__limit),
)
}
fn decode_view_with_ctx(
buf: &'a [u8],
ctx: ::buffa::DecodeContext<'_>,
) -> ::core::result::Result<Self, ::buffa::DecodeError> {
<Self as ::buffa::MessageView>::decode_view_ctx(buf, ctx)
}
fn merge_view_field(
&mut self,
tag: ::buffa::encoding::Tag,
cur: &'a [u8],
#before_tag_param: &'a [u8],
ctx: ::buffa::DecodeContext<'_>,
) -> ::core::result::Result<&'a [u8], ::buffa::DecodeError> {
let _ = ctx;
#[allow(unused_variables)]
let view = self;
let mut cur = cur;
match tag.field_number() {
#(#scalar_arms)*
#(#repeated_arms)*
#(#oneof_arms)*
_ => {
::buffa::encoding::skip_field_depth(tag, &mut cur, ctx.depth())?;
#unknown_field_handling
}
}
::core::result::Result::Ok(cur)
}
fn to_owned_message(
&self,
) -> ::core::result::Result<#owned_path, ::buffa::DecodeError> {
self.to_owned_from_source(None)
}
#[allow(clippy::useless_conversion, clippy::needless_update)]
fn to_owned_from_source(
&self,
__buffa_src: ::core::option::Option<&::buffa::bytes::Bytes>,
) -> ::core::result::Result<#owned_path, ::buffa::DecodeError> {
#[allow(unused_imports)]
use ::buffa::alloc::string::ToString as _;
let _ = __buffa_src;
::core::result::Result::Ok(#owned_path {
#(#owned_fields)*
..::core::default::Default::default()
})
}
}
#view_encode_impl
#serialize_impl
#message_name_impl
::buffa::impl_default_view_instance!(#view_ident);
::buffa::impl_view_reborrow!(#view_ident);
#owned_view_wrapper
#reflect_view_impls
};
Ok((top_level, mod_items))
}
fn view_struct_field(
scope: MessageScope<'_>,
msg: &DescriptorProto,
field: &FieldDescriptorProto,
) -> Result<Option<(TokenStream, proc_macro2::Ident, bool)>, CodeGenError> {
let MessageScope { ctx, proto_fqn, .. } = scope;
if is_real_oneof_member(field) {
return Ok(None);
}
let field_name = field
.name
.as_deref()
.ok_or(CodeGenError::MissingField("field.name"))?;
let label = field.label.unwrap_or_default();
let is_repeated = label == Label::LABEL_REPEATED;
let field_fqn = format!("{}.{}", proto_fqn, field_name);
let proto_comment = ctx.comment(&field_fqn);
if is_repeated && is_map_field(msg, field) {
let ident = make_field_ident(field_name);
let number = field.number.unwrap_or(0);
let tag_line = format!("Field {number}: `{field_name}` (map)");
let doc = crate::comments::doc_attrs_with_tag_resolved(
proto_comment,
&tag_line,
proto_fqn,
&ctx.type_map,
);
let map_ty = view_map_type(scope, msg, field, "e! { 'a })?;
let tokens = quote! {
#doc
pub #ident: #map_ty,
};
return Ok(Some((
tokens,
ident,
crate::message::is_debug_redacted(field),
)));
}
let ident = make_field_ident(field_name);
let number = field.number.unwrap_or(0);
let tag_line = format!("Field {number}: `{field_name}`");
let doc = crate::comments::doc_attrs_with_tag_resolved(
proto_comment,
&tag_line,
proto_fqn,
&ctx.type_map,
);
let rust_type = if is_repeated {
view_repeated_type(scope, field, "e! { 'a })?
} else {
view_singular_type(scope, field, "e! { 'a })?
};
let self_fqn = format!(".{proto_fqn}");
let struct_ty = if field.type_name.as_deref() == Some(self_fqn.as_str()) {
if is_repeated {
quote! { ::buffa::RepeatedView<'a, Self> }
} else {
quote! { ::buffa::MessageFieldView<Self> }
}
} else {
rust_type
};
let tokens = quote! {
#doc
pub #ident: #struct_ty,
};
Ok(Some((
tokens,
ident,
crate::message::is_debug_redacted(field),
)))
}
pub(crate) fn view_singular_type(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
lt: &TokenStream,
) -> Result<TokenStream, CodeGenError> {
let MessageScope {
ctx,
features: parent_features,
..
} = scope;
let features = &crate::features::resolve_field(ctx, field, parent_features);
let ty = effective_type(ctx, field, features);
if is_explicit_presence_scalar(field, ty, features) {
return Ok(match ty {
Type::TYPE_STRING => quote! { ::core::option::Option<&#lt str> },
Type::TYPE_BYTES => quote! { ::core::option::Option<&#lt [u8]> },
Type::TYPE_ENUM => {
let et = resolve_enum_ty(scope, field)?;
if is_closed_enum(features) {
quote! { ::core::option::Option<#et> }
} else {
quote! { ::core::option::Option<::buffa::EnumValue<#et>> }
}
}
_ => {
let st = scalar_ty(ty);
quote! { ::core::option::Option<#st> }
}
});
}
match ty {
Type::TYPE_STRING => Ok(quote! { &#lt str }),
Type::TYPE_BYTES => Ok(quote! { &#lt [u8] }),
Type::TYPE_MESSAGE | Type::TYPE_GROUP => {
let view_ty = resolve_view_ty_tokens(scope, field, lt)?;
Ok(quote! { ::buffa::MessageFieldView<#view_ty> })
}
Type::TYPE_ENUM => {
let et = resolve_enum_ty(scope, field)?;
if is_closed_enum(features) {
Ok(quote! { #et })
} else {
Ok(quote! { ::buffa::EnumValue<#et> })
}
}
_ => Ok(scalar_ty(ty)),
}
}
pub(crate) fn view_repeated_type(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
lt: &TokenStream,
) -> Result<TokenStream, CodeGenError> {
let MessageScope {
ctx,
features: parent_features,
..
} = scope;
let features = &crate::features::resolve_field(ctx, field, parent_features);
let ty = effective_type(ctx, field, features);
match ty {
Type::TYPE_STRING => Ok(quote! { ::buffa::RepeatedView<#lt, &#lt str> }),
Type::TYPE_BYTES => Ok(quote! { ::buffa::RepeatedView<#lt, &#lt [u8]> }),
Type::TYPE_MESSAGE | Type::TYPE_GROUP => {
let view_ty = resolve_view_ty_tokens(scope, field, lt)?;
Ok(quote! { ::buffa::RepeatedView<#lt, #view_ty> })
}
Type::TYPE_ENUM => {
let et = resolve_enum_ty(scope, field)?;
if is_closed_enum(features) {
Ok(quote! { ::buffa::RepeatedView<#lt, #et> })
} else {
Ok(quote! { ::buffa::RepeatedView<#lt, ::buffa::EnumValue<#et>> })
}
}
_ => {
let st = scalar_ty(ty);
Ok(quote! { ::buffa::RepeatedView<#lt, #st> })
}
}
}
pub(crate) fn view_map_type(
scope: MessageScope<'_>,
msg: &DescriptorProto,
field: &FieldDescriptorProto,
lt: &TokenStream,
) -> Result<TokenStream, CodeGenError> {
let MessageScope { ctx, features, .. } = scope;
let (key_fd, val_fd) = find_map_entry_fields(msg, field)?;
let key_ty = match effective_type_in_map_entry(ctx, key_fd, features) {
Type::TYPE_STRING => quote! { &#lt str },
Type::TYPE_BYTES => quote! { &#lt [u8] },
ty => scalar_ty(ty),
};
let val_ty = match effective_type_in_map_entry(ctx, val_fd, features) {
Type::TYPE_STRING => quote! { &#lt str },
Type::TYPE_BYTES => quote! { &#lt [u8] },
Type::TYPE_MESSAGE => {
let view_ty = resolve_view_ty_tokens(scope, val_fd, lt)?;
quote! { #view_ty }
}
Type::TYPE_ENUM => {
let et = resolve_enum_ty(scope, val_fd)?;
let val_features = crate::features::resolve_field(ctx, val_fd, features);
if is_closed_enum(&val_features) {
quote! { #et }
} else {
quote! { ::buffa::EnumValue<#et> }
}
}
ty => scalar_ty(ty),
};
Ok(quote! { ::buffa::MapView<#lt, #key_ty, #val_ty> })
}
pub(crate) fn oneof_view_needs_lifetime(
ctx: &CodeGenContext,
fields: &[&FieldDescriptorProto],
features: &ResolvedFeatures,
) -> bool {
fields.iter().any(|f| {
matches!(
effective_type(ctx, f, features),
Type::TYPE_STRING | Type::TYPE_BYTES | Type::TYPE_MESSAGE | Type::TYPE_GROUP
)
})
}
pub(crate) fn message_view_has_borrowing_field(
ctx: &CodeGenContext,
msg: &DescriptorProto,
features: &ResolvedFeatures,
preserve_unknown_fields: bool,
) -> bool {
if preserve_unknown_fields {
return true;
}
for f in &msg.field {
if is_real_oneof_member(f) {
continue; }
if f.label.unwrap_or_default()
== crate::generated::descriptor::field_descriptor_proto::Label::LABEL_REPEATED
{
return true;
}
if matches!(
effective_type(ctx, f, features),
Type::TYPE_STRING | Type::TYPE_BYTES | Type::TYPE_MESSAGE | Type::TYPE_GROUP
) {
return true;
}
}
for (idx, _) in msg.oneof_decl.iter().enumerate() {
let fields: Vec<_> = msg
.field
.iter()
.filter(|f| is_real_oneof_member(f) && f.oneof_index == Some(idx as i32))
.collect();
if oneof_view_needs_lifetime(ctx, &fields, features) {
return true;
}
}
false
}
pub(crate) fn oneof_view_struct_fields(
ctx: &CodeGenContext,
msg: &DescriptorProto,
view_oneof_prefix: &TokenStream,
features: &ResolvedFeatures,
oneof_idents: &std::collections::HashMap<usize, proc_macro2::Ident>,
) -> Result<Vec<(TokenStream, proc_macro2::Ident)>, CodeGenError> {
let mut out = Vec::new();
for (idx, oneof) in msg.oneof_decl.iter().enumerate() {
let enum_ident = match oneof_idents.get(&idx) {
Some(id) => id,
None => continue,
};
let fields: Vec<_> = msg
.field
.iter()
.filter(|f| is_real_oneof_member(f) && f.oneof_index == Some(idx as i32))
.collect();
if fields.is_empty() {
continue;
}
let oneof_name = oneof
.name
.as_deref()
.ok_or(CodeGenError::MissingField("oneof.name"))?;
let field_ident = make_field_ident(oneof_name);
let generics = if oneof_view_needs_lifetime(ctx, &fields, features) {
quote! { <'a> }
} else {
quote! {}
};
let tokens = quote! {
pub #field_ident: ::core::option::Option<#view_oneof_prefix #enum_ident #generics>,
};
out.push((tokens, field_ident));
}
Ok(out)
}
fn generate_oneof_view_enum(
scope: MessageScope<'_>,
msg: &DescriptorProto,
idx: usize,
_oneof: &OneofDescriptorProto,
oneof_idents: &std::collections::HashMap<usize, proc_macro2::Ident>,
) -> Result<TokenStream, CodeGenError> {
let MessageScope { ctx, features, .. } = scope;
let base_ident = match oneof_idents.get(&idx) {
Some(id) => id,
None => return Ok(TokenStream::new()),
};
let fields: Vec<_> = msg
.field
.iter()
.filter(|f| is_real_oneof_member(f) && f.oneof_index == Some(idx as i32))
.collect();
if fields.is_empty() {
return Ok(TokenStream::new());
}
let enum_body_depth = scope.nesting + 4;
let body_scope = MessageScope {
nesting: enum_body_depth,
..scope
};
let variants = fields
.iter()
.map(|f| {
let name = f
.name
.as_deref()
.ok_or(CodeGenError::MissingField("field.name"))?;
let variant = crate::oneof::oneof_variant_ident(name);
let ty = effective_type(ctx, f, features);
let f_features = crate::features::resolve_field(ctx, f, features);
let vty = match ty {
Type::TYPE_STRING => quote! { &'a str },
Type::TYPE_BYTES => quote! { &'a [u8] },
Type::TYPE_MESSAGE | Type::TYPE_GROUP => {
let view_ty = resolve_view_ty_tokens(body_scope, f, "e! { 'a })?;
quote! { ::buffa::alloc::boxed::Box<#view_ty> }
}
Type::TYPE_ENUM => {
let et = resolve_enum_ty(body_scope, f)?;
if is_closed_enum(&f_features) {
quote! { #et }
} else {
quote! { ::buffa::EnumValue<#et> }
}
}
_ => scalar_ty(ty),
};
Ok(quote! { #variant(#vty) })
})
.collect::<Result<Vec<_>, CodeGenError>>()?;
let generics = if oneof_view_needs_lifetime(ctx, &fields, features) {
quote! { <'a> }
} else {
quote! {}
};
let any_redacted = fields.iter().any(|f| crate::message::is_debug_redacted(f));
let (debug_derive, debug_impl) = if any_redacted {
let placeholder = crate::message::DEBUG_REDACT_PLACEHOLDER;
let arms = fields
.iter()
.map(|field| {
let name = field
.name
.as_deref()
.ok_or(CodeGenError::MissingField("field.name"))?;
let ident = crate::oneof::oneof_variant_ident(name);
let label = ident.to_string();
Ok(if crate::message::is_debug_redacted(field) {
quote! {
Self::#ident(_) => f
.debug_tuple(#label)
.field(&::core::format_args!(#placeholder))
.finish(),
}
} else {
quote! {
Self::#ident(value) => f.debug_tuple(#label).field(value).finish(),
}
})
})
.collect::<Result<Vec<_>, CodeGenError>>()?;
(
quote! { #[derive(Clone)] },
quote! {
impl #generics ::core::fmt::Debug for #base_ident #generics {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
match self {
#(#arms)*
}
}
}
},
)
} else {
(quote! { #[derive(Clone, Debug)] }, quote! {})
};
Ok(quote! {
#debug_derive
pub enum #base_ident #generics {
#(#variants,)*
}
#debug_impl
})
}
pub(crate) struct RequiredPresence {
pub(crate) struct_fields: Vec<TokenStream>,
pub(crate) has_methods: Vec<TokenStream>,
pub(crate) bit_stmts: std::collections::HashMap<u32, TokenStream>,
}
pub(crate) fn required_presence(
scope: MessageScope<'_>,
msg: &DescriptorProto,
) -> RequiredPresence {
let fields = required_view_fields(scope, msg);
let bit_count = fields.iter().filter(|r| r.bit.is_some()).count();
let struct_fields = (0..bit_count.div_ceil(64))
.map(required_seen_word_ident)
.map(|w| quote! { #[doc(hidden)] pub #w: u64, })
.collect();
let bit_stmts = fields
.iter()
.filter_map(|r| {
let bit = r.bit?;
let word = required_seen_word_ident(bit / 64);
let mask = 1u64 << (bit % 64);
Some((r.field_number, quote! { view.#word |= #mask; }))
})
.collect();
RequiredPresence {
struct_fields,
has_methods: required_has_methods(&fields),
bit_stmts,
}
}
struct RequiredViewField<'a> {
ident: proc_macro2::Ident,
proto_name: &'a str,
field_number: u32,
bit: Option<usize>,
}
fn required_view_fields<'a>(
scope: MessageScope<'_>,
msg: &'a DescriptorProto,
) -> Vec<RequiredViewField<'a>> {
let mut out = Vec::new();
let mut next_bit = 0usize;
for f in &msg.field {
let ty = f.r#type.unwrap_or_default();
if is_real_oneof_member(f)
|| f.label.unwrap_or_default() == Label::LABEL_REPEATED
|| !is_supported_field_type(ty)
|| !crate::impl_message::is_required_field(f, scope.features)
{
continue;
}
let (Some(proto_name), Some(number)) = (f.name.as_deref(), f.number) else {
continue;
};
let bit = if matches!(ty, Type::TYPE_MESSAGE | Type::TYPE_GROUP) {
None
} else {
let b = next_bit;
next_bit += 1;
Some(b)
};
out.push(RequiredViewField {
ident: make_field_ident(proto_name),
proto_name,
field_number: number as u32,
bit,
});
}
out
}
fn required_seen_word_ident(w: usize) -> proc_macro2::Ident {
format_ident!("__buffa_required_seen_{}", w)
}
fn required_has_methods(required: &[RequiredViewField<'_>]) -> Vec<TokenStream> {
required
.iter()
.map(|r| {
let method = format_ident!("has_{}", r.proto_name);
match r.bit {
Some(bit) => {
let doc = format!(
"Whether required field `{}` was present on the wire.\n\n\
Distinguishes a field that was absent from one explicitly \
encoded with its default value (required scalar fields are \
stored as bare, non-`Option` types, so the value alone \
cannot tell the two apart). Presence is recorded only by \
the wire decoder: a default or hand-built view reports \
`false`. Encoding is unaffected — required fields are \
always written.",
r.proto_name
);
let word = required_seen_word_ident(bit / 64);
let mask = 1u64 << (bit % 64);
quote! {
#[doc = #doc]
#[must_use]
#[inline]
pub const fn #method(&self) -> bool {
self.#word & #mask != 0
}
}
}
None => {
let doc = format!(
"Whether required field `{}` is set.\n\n\
Mirrors `is_set()` on the field: `true` after decoding a \
message where the field was present on the wire, and `true` \
on a hand-built view whose field is populated. Encoding is \
unaffected — required fields are always written.",
r.proto_name
);
let ident = &r.ident;
quote! {
#[doc = #doc]
#[must_use]
#[inline]
pub const fn #method(&self) -> bool {
self.#ident.is_set()
}
}
}
}
})
.collect()
}
#[allow(clippy::type_complexity)]
fn build_decode_arms(
scope: MessageScope<'_>,
msg: &DescriptorProto,
view_oneof_prefix: &TokenStream,
oneof_idents: &std::collections::HashMap<usize, proc_macro2::Ident>,
required_bit_stmts: &std::collections::HashMap<u32, TokenStream>,
) -> Result<(Vec<TokenStream>, Vec<TokenStream>, Vec<TokenStream>), CodeGenError> {
let scalar_fields: Vec<_> = msg
.field
.iter()
.filter(|f| {
if is_real_oneof_member(f) {
return false;
}
f.label.unwrap_or_default() != Label::LABEL_REPEATED
&& is_supported_field_type(f.r#type.unwrap_or_default())
})
.collect();
let scalar_arms = scalar_fields
.iter()
.map(|f| {
let bit_stmt = f.number.and_then(|n| required_bit_stmts.get(&(n as u32)));
scalar_decode_arm(scope, f, bit_stmt)
})
.collect::<Result<Vec<_>, _>>()?;
let repeated_fields: Vec<_> = msg
.field
.iter()
.filter(|f| {
f.label.unwrap_or_default() == Label::LABEL_REPEATED
&& !is_map_field(msg, f)
&& is_supported_field_type(f.r#type.unwrap_or_default())
})
.collect();
let mut repeated_arms: Vec<_> = repeated_fields
.iter()
.map(|f| repeated_decode_arm(scope, f))
.collect::<Result<Vec<_>, _>>()?;
let map_fields: Vec<_> = msg
.field
.iter()
.filter(|f| f.label.unwrap_or_default() == Label::LABEL_REPEATED && is_map_field(msg, f))
.collect();
let map_arms = map_fields
.iter()
.map(|f| map_decode_arm(scope, msg, f))
.collect::<Result<Vec<_>, _>>()?;
repeated_arms.extend(map_arms);
let mut oneof_arms: Vec<TokenStream> = Vec::new();
for (idx, oneof) in msg.oneof_decl.iter().enumerate() {
let base_ident = match oneof_idents.get(&idx) {
Some(id) => id,
None => continue,
};
let oneof_name = oneof
.name
.as_deref()
.ok_or(CodeGenError::MissingField("oneof.name"))?;
let fields: Vec<_> = msg
.field
.iter()
.filter(|f| is_real_oneof_member(f) && f.oneof_index == Some(idx as i32))
.collect();
oneof_arms.extend(oneof_decode_arms(
scope,
base_ident,
oneof_name,
&fields,
view_oneof_prefix,
)?);
}
Ok((scalar_arms, repeated_arms, oneof_arms))
}
pub(crate) fn scalar_decode_arm(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
required_bit_stmt: Option<&TokenStream>,
) -> Result<TokenStream, CodeGenError> {
let MessageScope {
ctx,
features: parent_features,
..
} = scope;
let preserve_unknown_fields = ctx.config.preserve_unknown_fields;
let features = &crate::features::resolve_field(ctx, field, parent_features);
let field_name = field
.name
.as_deref()
.ok_or(CodeGenError::MissingField("field.name"))?;
let field_number = validated_field_number(field)?;
let ty = effective_type(ctx, field, features);
let ident = make_field_ident(field_name);
let wire_type = wire_type_token(ty);
let wire_check = wire_type_check("e! { tag }, &wire_type);
if is_explicit_presence_scalar(field, ty, features) {
let assign = match ty {
Type::TYPE_STRING => {
quote! { view.#ident = Some(::buffa::types::borrow_str(&mut cur)?); }
}
Type::TYPE_BYTES => {
quote! { view.#ident = Some(::buffa::types::borrow_bytes(&mut cur)?); }
}
Type::TYPE_ENUM => {
if is_closed_enum(features) {
let unknown_route = closed_enum_view_unknown_route(preserve_unknown_fields);
closed_enum_decode_with_unknown(
"e! { &mut cur },
quote! { view.#ident = Some(__v); },
unknown_route,
)
} else {
quote! {
view.#ident = Some(::buffa::EnumValue::from(::buffa::types::decode_int32(&mut cur)?));
}
}
}
_ => {
let dfn = decode_fn_token(ty);
quote! { view.#ident = Some(#dfn(&mut cur)?); }
}
};
return Ok(quote! { #field_number => { #wire_check #assign } });
}
let bit_stmt = required_bit_stmt.cloned().unwrap_or_default();
let assign = match ty {
Type::TYPE_STRING => {
quote! { view.#ident = ::buffa::types::borrow_str(&mut cur)?; #bit_stmt }
}
Type::TYPE_BYTES => {
quote! { view.#ident = ::buffa::types::borrow_bytes(&mut cur)?; #bit_stmt }
}
Type::TYPE_ENUM => {
if is_closed_enum(features) {
let unknown_route = closed_enum_view_unknown_route(preserve_unknown_fields);
closed_enum_decode_with_unknown(
"e! { &mut cur },
quote! { view.#ident = __v; #bit_stmt },
unknown_route,
)
} else {
quote! { view.#ident = ::buffa::EnumValue::from(::buffa::types::decode_int32(&mut cur)?); #bit_stmt }
}
}
Type::TYPE_MESSAGE => {
let vt = resolve_view_decode_tokens(scope, field)?;
quote! {
let __sub_ctx = ctx.descend()?;
let sub = ::buffa::types::borrow_bytes(&mut cur)?;
match view.#ident.as_mut() {
Some(existing) => {
::buffa::MessageView::merge_into_view(existing, sub, __sub_ctx)?
}
None => view.#ident = ::buffa::MessageFieldView::set(
<#vt as ::buffa::MessageView>::decode_view_ctx(sub, __sub_ctx)?
),
}
}
}
Type::TYPE_GROUP => {
let vt = resolve_view_decode_tokens(scope, field)?;
quote! {
let __sub_ctx = ctx.descend()?;
let sub = ::buffa::types::borrow_group(&mut cur, #field_number, __sub_ctx.depth())?;
match view.#ident.as_mut() {
Some(existing) => {
::buffa::MessageView::merge_into_view(existing, sub, __sub_ctx)?
}
None => view.#ident = ::buffa::MessageFieldView::set(
<#vt as ::buffa::MessageView>::decode_view_ctx(sub, __sub_ctx)?
),
}
}
}
_ => {
let dfn = decode_fn_token(ty);
quote! { view.#ident = #dfn(&mut cur)?; #bit_stmt }
}
};
Ok(quote! { #field_number => { #wire_check #assign } })
}
pub(crate) fn repeated_decode_arm(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
) -> Result<TokenStream, CodeGenError> {
let MessageScope {
ctx,
features: parent_features,
..
} = scope;
let preserve_unknown_fields = ctx.config.preserve_unknown_fields;
let features = &crate::features::resolve_field(ctx, field, parent_features);
let field_name = field
.name
.as_deref()
.ok_or(CodeGenError::MissingField("field.name"))?;
let field_number = validated_field_number(field)?;
let ty = effective_type(ctx, field, features);
let ident = make_field_ident(field_name);
if ty == Type::TYPE_MESSAGE {
let ld_check = wire_type_check(
"e! { tag },
"e! { ::buffa::encoding::WireType::LengthDelimited },
);
let vt = resolve_view_decode_tokens(scope, field)?;
return Ok(quote! {
#field_number => {
#ld_check
let __sub_ctx = ctx.descend()?;
let sub = ::buffa::types::borrow_bytes(&mut cur)?;
view.#ident.push(<#vt as ::buffa::MessageView>::decode_view_ctx(sub, __sub_ctx)?);
}
});
}
if ty == Type::TYPE_GROUP {
let sg_check = wire_type_check(
"e! { tag },
"e! { ::buffa::encoding::WireType::StartGroup },
);
let vt = resolve_view_decode_tokens(scope, field)?;
return Ok(quote! {
#field_number => {
#sg_check
let __sub_ctx = ctx.descend()?;
let sub = ::buffa::types::borrow_group(&mut cur, #field_number, __sub_ctx.depth())?;
view.#ident.push(<#vt as ::buffa::MessageView>::decode_view_ctx(sub, __sub_ctx)?);
}
});
}
if !is_packed_type(ty) {
let ld_check = wire_type_check(
"e! { tag },
"e! { ::buffa::encoding::WireType::LengthDelimited },
);
let borrow = match ty {
Type::TYPE_STRING => quote! { ::buffa::types::borrow_str(&mut cur)? },
Type::TYPE_BYTES => quote! { ::buffa::types::borrow_bytes(&mut cur)? },
Type::TYPE_MESSAGE
| Type::TYPE_GROUP
| Type::TYPE_ENUM
| Type::TYPE_BOOL
| Type::TYPE_INT32
| Type::TYPE_INT64
| Type::TYPE_UINT32
| Type::TYPE_UINT64
| Type::TYPE_SINT32
| Type::TYPE_SINT64
| Type::TYPE_FIXED32
| Type::TYPE_FIXED64
| Type::TYPE_SFIXED32
| Type::TYPE_SFIXED64
| Type::TYPE_FLOAT
| Type::TYPE_DOUBLE => {
unreachable!("view repeated decode arm: unhandled unpacked type {:?}", ty)
}
};
return Ok(quote! {
#field_number => {
#ld_check
view.#ident.push(#borrow);
}
});
}
let elem_wire_type = wire_type_token(ty);
let closed = is_closed_enum(features);
let push_known = quote! { view.#ident.push(__v); };
let packed_elem = if ty == Type::TYPE_ENUM {
if closed {
closed_enum_decode("e! { &mut pcur }, push_known.clone())
} else {
quote! { view.#ident.push(::buffa::EnumValue::from(::buffa::types::decode_int32(&mut pcur)?)); }
}
} else {
let dfn = decode_fn_token(ty);
quote! { view.#ident.push(#dfn(&mut pcur)?); }
};
let reserve_divisor: usize = match ty {
Type::TYPE_FIXED32 | Type::TYPE_SFIXED32 | Type::TYPE_FLOAT => 4,
Type::TYPE_FIXED64 | Type::TYPE_SFIXED64 | Type::TYPE_DOUBLE => 8,
_ => 1,
};
let reserve_stmt = if reserve_divisor > 1 {
quote! { view.#ident.reserve(payload.len() / #reserve_divisor); }
} else {
quote! { view.#ident.reserve(::buffa::encoding::count_varints(payload)); }
};
let unpacked_elem = if ty == Type::TYPE_ENUM {
if closed {
let unknown_route = closed_enum_view_unknown_route(preserve_unknown_fields);
closed_enum_decode_with_unknown("e! { &mut cur }, push_known, unknown_route)
} else {
quote! { view.#ident.push(::buffa::EnumValue::from(::buffa::types::decode_int32(&mut cur)?)); }
}
} else {
let dfn = decode_fn_token(ty);
quote! { view.#ident.push(#dfn(&mut cur)?); }
};
Ok(quote! {
#field_number => {
if tag.wire_type() == ::buffa::encoding::WireType::LengthDelimited {
let payload = ::buffa::types::borrow_bytes(&mut cur)?;
#reserve_stmt
let mut pcur: &[u8] = payload;
while !pcur.is_empty() { #packed_elem }
} else if tag.wire_type() == #elem_wire_type {
#unpacked_elem
} else {
return Err(::buffa::encoding::wire_type_mismatch(
tag,
::buffa::encoding::WireType::LengthDelimited,
));
}
}
})
}
pub(crate) fn map_decode_arm(
scope: MessageScope<'_>,
msg: &DescriptorProto,
field: &FieldDescriptorProto,
) -> Result<TokenStream, CodeGenError> {
let MessageScope { ctx, features, .. } = scope;
let preserve_unknown_fields = ctx.config.preserve_unknown_fields;
let field_name = field
.name
.as_deref()
.ok_or(CodeGenError::MissingField("field.name"))?;
let field_number = validated_field_number(field)?;
let ident = make_field_ident(field_name);
let (key_fd, val_fd) = find_map_entry_fields(msg, field)?;
let ld_check = wire_type_check(
"e! { tag },
"e! { ::buffa::encoding::WireType::LengthDelimited },
);
let key_default = match effective_type_in_map_entry(ctx, key_fd, features) {
Type::TYPE_STRING => quote! { "" },
Type::TYPE_BYTES => quote! { &[][..] },
_ => quote! { ::core::default::Default::default() },
};
let val_default = match effective_type_in_map_entry(ctx, val_fd, features) {
Type::TYPE_STRING => quote! { "" },
Type::TYPE_BYTES => quote! { &[][..] },
_ => quote! { ::core::default::Default::default() },
};
let val_features = crate::features::resolve_field(ctx, val_fd, features);
let val_is_closed_enum = effective_type_in_map_entry(ctx, val_fd, features) == Type::TYPE_ENUM
&& is_closed_enum(&val_features);
let closed_enum_hooks = val_is_closed_enum.then(|| {
(
quote! { __entry_unknown = false; },
quote! { __entry_unknown = true; },
)
});
let decode_key = map_view_entry_decode(scope, key_fd, &format_ident!("key"), None)?;
let decode_val =
map_view_entry_decode(scope, val_fd, &format_ident!("val"), closed_enum_hooks)?;
let push = quote! { view.#ident.push(key, val); };
let (entry_unknown_decl, entry_finish) = if val_is_closed_enum {
let finish = if preserve_unknown_fields {
quote! {
if __entry_unknown {
let __span_len = before_tag.len() - cur.len();
view.__buffa_unknown_fields.push_record(before_tag, __span_len, ctx)?;
} else {
#push
}
}
} else {
quote! { if !__entry_unknown { #push } }
};
(quote! { let mut __entry_unknown = false; }, finish)
} else {
(quote! {}, push)
};
Ok(quote! {
#field_number => {
#ld_check
let entry_bytes = ::buffa::types::borrow_bytes(&mut cur)?;
let mut entry_cur: &'a [u8] = entry_bytes;
let mut key = #key_default;
let mut val = #val_default;
#entry_unknown_decl
while !entry_cur.is_empty() {
let entry_tag = ::buffa::encoding::Tag::decode(&mut entry_cur)?;
match entry_tag.field_number() {
1 => { #decode_key }
2 => { #decode_val }
_ => { ::buffa::encoding::skip_field_depth(entry_tag, &mut entry_cur, ctx.depth())?; }
}
}
#entry_finish
}
})
}
fn map_view_entry_decode(
scope: MessageScope<'_>,
fd: &FieldDescriptorProto,
var: &proc_macro2::Ident,
closed_enum_hooks: Option<(TokenStream, TokenStream)>,
) -> Result<TokenStream, CodeGenError> {
let MessageScope {
ctx,
features: parent_features,
..
} = scope;
let features = &crate::features::resolve_field(ctx, fd, parent_features);
let ty = effective_type_in_map_entry(ctx, fd, features);
let wire_type = wire_type_token(ty);
let tag_check = wire_type_check("e! { entry_tag }, &wire_type);
let assign = match ty {
Type::TYPE_STRING => quote! { #var = ::buffa::types::borrow_str(&mut entry_cur)?; },
Type::TYPE_BYTES => quote! { #var = ::buffa::types::borrow_bytes(&mut entry_cur)?; },
Type::TYPE_ENUM => {
if is_closed_enum(features) {
if let Some((on_known, on_unknown)) = closed_enum_hooks {
closed_enum_decode_with_unknown(
"e! { &mut entry_cur },
quote! { #var = __v; #on_known },
on_unknown,
)
} else {
closed_enum_decode("e! { &mut entry_cur }, quote! { #var = __v; })
}
} else {
quote! { #var = ::buffa::EnumValue::from(::buffa::types::decode_int32(&mut entry_cur)?); }
}
}
Type::TYPE_MESSAGE => {
let vt = resolve_view_decode_tokens(scope, fd)?;
quote! {
let __sub_ctx = ctx.descend()?;
let sub = ::buffa::types::borrow_bytes(&mut entry_cur)?;
#var = <#vt as ::buffa::MessageView>::decode_view_ctx(sub, __sub_ctx)?;
}
}
_ => {
let dfn = decode_fn_token(ty);
quote! { #var = #dfn(&mut entry_cur)?; }
}
};
Ok(quote! { #tag_check #assign })
}
pub(crate) fn oneof_decode_arms(
scope: MessageScope<'_>,
base_ident: &proc_macro2::Ident,
oneof_name: &str,
fields: &[&FieldDescriptorProto],
view_oneof_prefix: &TokenStream,
) -> Result<Vec<TokenStream>, CodeGenError> {
let MessageScope { ctx, features, .. } = scope;
let preserve_unknown_fields = ctx.config.preserve_unknown_fields;
let field_ident = make_field_ident(oneof_name);
let view_enum: TokenStream = quote! { #view_oneof_prefix #base_ident };
fields
.iter()
.map(|field| {
let name = field
.name
.as_deref()
.ok_or(CodeGenError::MissingField("field.name"))?;
let field_number = validated_field_number(field)?;
let ty = effective_type(ctx, field, features);
let field_features = crate::features::resolve_field(ctx, field, features);
let variant = crate::oneof::oneof_variant_ident(name);
let wire_type = wire_type_token(ty);
let wire_check = wire_type_check("e! { tag }, &wire_type);
let value = match ty {
Type::TYPE_STRING => quote! { ::buffa::types::borrow_str(&mut cur)? },
Type::TYPE_BYTES => quote! { ::buffa::types::borrow_bytes(&mut cur)? },
Type::TYPE_MESSAGE => {
let vt = resolve_view_decode_tokens(scope, field)?;
return Ok(quote! {
#field_number => {
#wire_check
let __sub_ctx = ctx.descend()?;
let sub = ::buffa::types::borrow_bytes(&mut cur)?;
if let Some(#view_enum::#variant(ref mut existing)) = view.#field_ident {
::buffa::MessageView::merge_into_view(
&mut **existing,
sub,
__sub_ctx,
)?;
} else {
view.#field_ident = Some(#view_enum::#variant(
::buffa::alloc::boxed::Box::new(
<#vt as ::buffa::MessageView>::decode_view_ctx(sub, __sub_ctx)?
)
));
}
}
});
}
Type::TYPE_GROUP => {
let vt = resolve_view_decode_tokens(scope, field)?;
return Ok(quote! {
#field_number => {
#wire_check
let __sub_ctx = ctx.descend()?;
let sub = ::buffa::types::borrow_group(&mut cur, #field_number, __sub_ctx.depth())?;
if let Some(#view_enum::#variant(ref mut existing)) = view.#field_ident {
::buffa::MessageView::merge_into_view(
&mut **existing,
sub,
__sub_ctx,
)?;
} else {
view.#field_ident = Some(#view_enum::#variant(
::buffa::alloc::boxed::Box::new(
<#vt as ::buffa::MessageView>::decode_view_ctx(sub, __sub_ctx)?
)
));
}
}
});
}
Type::TYPE_ENUM => {
if is_closed_enum(&field_features) {
let unknown_route =
closed_enum_view_unknown_route(preserve_unknown_fields);
let decode = closed_enum_decode_with_unknown(
"e! { &mut cur },
quote! { view.#field_ident = Some(#view_enum::#variant(__v)); },
unknown_route,
);
return Ok(quote! {
#field_number => {
#wire_check
#decode
}
});
}
quote! { ::buffa::EnumValue::from(::buffa::types::decode_int32(&mut cur)?) }
}
_ => {
let dfn = decode_fn_token(ty);
quote! { #dfn(&mut cur)? }
}
};
Ok(quote! {
#field_number => {
#wire_check
view.#field_ident = Some(#view_enum::#variant(#value));
}
})
})
.collect()
}
fn build_to_owned_fields(
scope: MessageScope<'_>,
msg: &DescriptorProto,
view_oneof_prefix: &TokenStream,
owned_oneof_prefix: &TokenStream,
oneof_idents: &std::collections::HashMap<usize, proc_macro2::Ident>,
) -> Result<Vec<TokenStream>, CodeGenError> {
let MessageScope { ctx, features, .. } = scope;
let preserve_unknown_fields = ctx.config.preserve_unknown_fields;
let mut out = Vec::new();
for field in &msg.field {
if is_real_oneof_member(field) {
continue;
}
let name = field
.name
.as_deref()
.ok_or(CodeGenError::MissingField("field.name"))?;
let ident = make_field_ident(name);
let is_repeated = field.label.unwrap_or_default() == Label::LABEL_REPEATED;
if is_repeated && is_map_field(msg, field) {
let expr = map_to_owned_expr(scope, msg, field, &ident)?;
out.push(quote! { #ident: #expr, });
continue;
}
let ty = effective_type(ctx, field, features);
let init = if is_repeated {
repeated_to_owned(scope, ty, &ident, name)
} else {
singular_to_owned(scope, field, ty, &ident, name)?
};
out.push(quote! { #ident: #init, });
}
for (idx, oneof) in msg.oneof_decl.iter().enumerate() {
let base_ident = match oneof_idents.get(&idx) {
Some(id) => id,
None => continue,
};
let oneof_name = oneof
.name
.as_deref()
.ok_or(CodeGenError::MissingField("oneof.name"))?;
let group: Vec<_> = msg
.field
.iter()
.filter(|f| is_real_oneof_member(f) && f.oneof_index == Some(idx as i32))
.collect();
if group.is_empty() {
continue;
}
let field_ident = make_field_ident(oneof_name);
let view_enum: TokenStream = quote! { #view_oneof_prefix #base_ident };
let owned_enum: TokenStream = quote! { #owned_oneof_prefix #base_ident };
let match_arms = group
.iter()
.map(|f| {
let fname = f
.name
.as_deref()
.ok_or(CodeGenError::MissingField("field.name"))?;
let variant = crate::oneof::oneof_variant_ident(fname);
let ty = effective_type(ctx, f, features);
let conv = oneof_variant_to_owned(scope, ty, oneof_name, fname);
Ok(quote! {
#view_enum::#variant(v) => #owned_enum::#variant(#conv),
})
})
.collect::<Result<Vec<_>, CodeGenError>>()?;
let has_fallible_variant = group.iter().any(|f| {
let t = effective_type(ctx, f, features);
t == Type::TYPE_MESSAGE || t == Type::TYPE_GROUP
});
if has_fallible_variant {
out.push(quote! {
#field_ident: match self.#field_ident.as_ref() {
::core::option::Option::Some(v) => {
::core::option::Option::Some(match v { #(#match_arms)* })
}
::core::option::Option::None => ::core::option::Option::None,
},
});
} else {
out.push(quote! {
#field_ident: self.#field_ident.as_ref().map(|v| match v { #(#match_arms)* }),
});
}
}
if preserve_unknown_fields {
out.push(quote! {
__buffa_unknown_fields: self.__buffa_unknown_fields.to_owned()?.into(),
});
}
Ok(out)
}
fn str_view_to_owned(
repr: crate::StringRepr,
binding: TokenStream,
double_ref: bool,
) -> TokenStream {
if repr.is_default() {
quote! { #binding.to_string() }
} else if double_ref {
quote! { ::core::convert::Into::into(*#binding) }
} else {
quote! { ::core::convert::Into::into(#binding) }
}
}
pub(crate) fn singular_to_owned(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
ty: Type,
ident: &proc_macro2::Ident,
field_name: &str,
) -> Result<TokenStream, CodeGenError> {
let MessageScope {
ctx,
proto_fqn,
features,
..
} = scope;
if is_explicit_presence_scalar(field, ty, features) {
return Ok(match ty {
Type::TYPE_STRING => {
if field_string_repr(ctx, proto_fqn, field_name).is_default() {
quote! { self.#ident.map(|s| s.to_string()) }
} else {
quote! { self.#ident.map(::core::convert::Into::into) }
}
}
Type::TYPE_BYTES => {
let conv = bytes_to_owned(ctx, proto_fqn, field_name, quote! { b });
quote! { self.#ident.map(|b| #conv) }
}
_ => quote! { self.#ident },
});
}
Ok(match ty {
Type::TYPE_STRING => str_view_to_owned(
field_string_repr(ctx, proto_fqn, field_name),
quote! { self.#ident },
false,
),
Type::TYPE_BYTES => bytes_to_owned(ctx, proto_fqn, field_name, quote! { self.#ident }),
Type::TYPE_MESSAGE | Type::TYPE_GROUP => {
let owned_path = resolve_owned_path(scope, field)?;
let owned_ty = crate::message::rust_path_to_tokens(&owned_path);
let some_path = crate::impl_message::field_pointer_repr(ctx, proto_fqn, field_name)
.some_path(&owned_ty)?;
quote! {
match self.#ident.as_option() {
Some(v) => #some_path::some(
v.to_owned_from_source(__buffa_src)?,
),
None => ::buffa::MessageField::none(),
}
}
}
_ => quote! { self.#ident },
})
}
pub(crate) fn repeated_to_owned(
scope: MessageScope<'_>,
ty: Type,
ident: &proc_macro2::Ident,
field_name: &str,
) -> TokenStream {
let MessageScope { ctx, proto_fqn, .. } = scope;
match ty {
Type::TYPE_STRING => {
let conv = str_view_to_owned(
field_string_repr(ctx, proto_fqn, field_name),
quote! { s },
true,
);
quote! { self.#ident.iter().map(|s| #conv).collect() }
}
Type::TYPE_BYTES => {
let conv = bytes_to_owned(ctx, proto_fqn, field_name, quote! { b });
quote! { self.#ident.iter().map(|b| #conv).collect() }
}
Type::TYPE_MESSAGE | Type::TYPE_GROUP => {
quote! {
self.#ident
.iter()
.map(|v| v.to_owned_from_source(__buffa_src))
.collect::<::core::result::Result<_, ::buffa::DecodeError>>()?
}
}
_ => {
if crate::impl_message::field_repeated_repr(ctx, proto_fqn, field_name).is_default() {
quote! { self.#ident.to_vec() }
} else {
quote! { self.#ident.iter().copied().collect() }
}
}
}
}
pub(crate) fn map_to_owned_expr(
scope: MessageScope<'_>,
msg: &DescriptorProto,
field: &FieldDescriptorProto,
ident: &proc_macro2::Ident,
) -> Result<TokenStream, CodeGenError> {
let MessageScope {
ctx,
proto_fqn,
features,
..
} = scope;
let (key_fd, val_fd) = find_map_entry_fields(msg, field)?;
let field_name = field
.name
.as_deref()
.ok_or(CodeGenError::MissingField("field.name"))?;
let key_ty = effective_type_in_map_entry(ctx, key_fd, features);
let val_ty = effective_type_in_map_entry(ctx, val_fd, features);
let key_string_repr = map_string_repr(ctx, key_ty, proto_fqn, field_name);
let key_conv = match key_ty {
Type::TYPE_STRING => match key_string_repr {
crate::StringRepr::String => quote! { k.to_string() },
crate::StringRepr::Custom(_) => quote! { ::core::convert::Into::into(k.to_string()) },
},
Type::TYPE_BYTES => quote! { k.to_vec() },
_ => quote! { *k },
};
let value_bytes_repr =
map_value_bytes_repr(ctx, Some(key_ty), Some(val_ty), proto_fqn, field_name);
let val_string_repr = map_string_repr(ctx, val_ty, proto_fqn, field_name);
let val_conv = match val_ty {
Type::TYPE_STRING => match val_string_repr {
crate::StringRepr::String => quote! { v.to_string() },
crate::StringRepr::Custom(_) => quote! { ::core::convert::Into::into(v.to_string()) },
},
Type::TYPE_BYTES => match value_bytes_repr {
crate::BytesRepr::Vec => quote! { v.to_vec() },
crate::BytesRepr::Bytes => {
quote! { ::buffa::view::bytes_from_source(__buffa_src, v) }
}
crate::BytesRepr::Custom(_) => quote! { ::core::convert::Into::into(v.to_vec()) },
},
Type::TYPE_MESSAGE => {
let _owned_path = resolve_owned_path(scope, val_fd)?;
quote! { v.to_owned_from_source(__buffa_src)? }
}
_ => quote! { *v },
};
if val_ty == Type::TYPE_MESSAGE {
return Ok(quote! {
self.#ident
.iter()
.map(|(k, v)| {
::core::result::Result::<_, ::buffa::DecodeError>::Ok((#key_conv, #val_conv))
})
.collect::<::core::result::Result<_, ::buffa::DecodeError>>()?
});
}
Ok(quote! {
self.#ident.iter().map(|(k, v)| (#key_conv, #val_conv)).collect()
})
}
pub(crate) fn oneof_variant_to_owned(
scope: MessageScope<'_>,
ty: Type,
oneof_name: &str,
field_name: &str,
) -> TokenStream {
let MessageScope { ctx, proto_fqn, .. } = scope;
match ty {
Type::TYPE_STRING => {
str_view_to_owned(
field_string_repr(ctx, proto_fqn, field_name),
quote! { v },
true,
)
}
Type::TYPE_BYTES => bytes_to_owned(ctx, proto_fqn, field_name, quote! { v }),
Type::TYPE_MESSAGE | Type::TYPE_GROUP => {
let owned = quote! { v.to_owned_from_source(__buffa_src)? };
let variant_fqn = format!(".{proto_fqn}.{oneof_name}.{field_name}");
if crate::oneof::variant_boxed(ctx, ty, &variant_fqn) {
if matches!(ctx.pointer_repr(&variant_fqn), crate::PointerRepr::Box) {
quote! { ::buffa::alloc::boxed::Box::new(#owned) }
} else {
quote! { ::buffa::ProtoBox::new(#owned) }
}
} else {
owned
}
}
_ => quote! { *v },
}
}
fn generate_view_serialize(
scope: MessageScope<'_>,
msg: &DescriptorProto,
view_ident: &proc_macro2::Ident,
view_oneof_prefix: &TokenStream,
oneof_idents: &std::collections::HashMap<usize, proc_macro2::Ident>,
) -> Result<TokenStream, CodeGenError> {
let mut stmts: Vec<TokenStream> = Vec::new();
for field in &msg.field {
if is_real_oneof_member(field) {
continue;
}
if !is_supported_field_type(field.r#type.unwrap_or_default()) {
continue;
}
stmts.push(view_field_serialize_stmt(scope, msg, field)?);
}
for (idx, oneof) in msg.oneof_decl.iter().enumerate() {
let base_ident = match oneof_idents.get(&idx) {
Some(id) => id,
None => continue,
};
let oneof_name = oneof
.name
.as_deref()
.ok_or(CodeGenError::MissingField("oneof.name"))?;
let field_ident = make_field_ident(oneof_name);
let view_enum = quote! { #view_oneof_prefix #base_ident };
let fields: Vec<_> = msg
.field
.iter()
.filter(|f| is_real_oneof_member(f) && f.oneof_index == Some(idx as i32))
.collect();
if fields.is_empty() {
continue;
}
let arms = fields
.iter()
.map(|f| view_oneof_serialize_arm(scope, f, &view_enum))
.collect::<Result<Vec<_>, _>>()?;
stmts.push(quote! {
if let ::core::option::Option::Some(ref __ov) = self.#field_ident {
match __ov { #(#arms)* }
}
});
}
Ok(quote! {
impl<'__a> ::serde::Serialize for #view_ident<'__a> {
fn serialize<__S: ::serde::Serializer>(
&self,
__s: __S,
) -> ::core::result::Result<__S::Ok, __S::Error> {
use ::serde::ser::SerializeMap as _;
let mut __map = __s.serialize_map(::core::option::Option::None)?;
#(#stmts)*
__map.end()
}
}
})
}
pub(crate) fn view_field_serialize_stmt(
scope: MessageScope<'_>,
msg: &DescriptorProto,
field: &FieldDescriptorProto,
) -> Result<TokenStream, CodeGenError> {
let MessageScope {
ctx,
features: parent_features,
..
} = scope;
let f_features = crate::features::resolve_field(ctx, field, parent_features);
let field_name = field
.name
.as_deref()
.ok_or(CodeGenError::MissingField("field.name"))?;
let json_name = field.json_name.as_deref().unwrap_or(field_name);
let ident = make_field_ident(field_name);
let label = field.label.unwrap_or_default();
let is_repeated = label == Label::LABEL_REPEATED;
let is_required = is_required_field(field, parent_features);
let ty = effective_type(ctx, field, parent_features);
if is_repeated && is_map_field(msg, field) {
let (key_fd, val_fd) = find_map_entry_fields(msg, field)?;
let key_raw = effective_type_in_map_entry(ctx, key_fd, parent_features);
let val_raw = effective_type_in_map_entry(ctx, val_fd, parent_features);
let val_f = crate::features::resolve_field(ctx, val_fd, parent_features);
let key_ty = match key_raw {
Type::TYPE_STRING => quote! { &'__a str },
Type::TYPE_BYTES => quote! { &'__a [u8] },
kt => scalar_ty(kt),
};
let val_ty = match val_raw {
Type::TYPE_STRING => quote! { &'__a str },
Type::TYPE_BYTES => quote! { &'__a [u8] },
Type::TYPE_MESSAGE => {
let path = resolve_view_path(scope, val_fd)?;
quote! { #path <'__a> }
}
Type::TYPE_ENUM => {
let et = resolve_enum_ty(scope, val_fd)?;
if is_closed_enum(&val_f) {
quote! { #et }
} else {
quote! { ::buffa::EnumValue<#et> }
}
}
vt => scalar_ty(vt),
};
let (key_wrapper, key_expr) = match key_raw {
Type::TYPE_STRING => (quote! {}, quote! { k }),
Type::TYPE_BYTES => (quote! {}, quote! { &::buffa::json_helpers::BytesJson(k) }),
_ => (quote! {}, quote! { &::buffa::json_helpers::MapKeyJson(k) }),
};
let (val_wrapper, val_expr) = match val_raw {
Type::TYPE_BYTES => (quote! {}, quote! { &::buffa::json_helpers::BytesJson(v) }),
Type::TYPE_ENUM if is_closed_enum(&val_f) => (
quote! {},
quote! { &::buffa::json_helpers::ClosedEnumJson(v) },
),
vt if serde_helper_path(vt).is_some() => {
(quote! {}, quote! { &::buffa::json_helpers::ProtoJson(v) })
}
_ => (quote! {}, quote! { v }),
};
let key_uses_a = matches!(key_raw, Type::TYPE_STRING | Type::TYPE_BYTES);
let val_uses_a = matches!(
val_raw,
Type::TYPE_STRING | Type::TYPE_BYTES | Type::TYPE_MESSAGE
);
let (wm_struct_decl, wm_impl_hdr, wm_impl_ty) = if key_uses_a || val_uses_a {
(
quote! { struct _WM<'__a, '__x>(&'__x ::buffa::MapView<'__x, #key_ty, #val_ty>); },
quote! { impl<'__a> },
quote! { _WM<'__a, '_> },
)
} else {
(
quote! { struct _WM<'__x>(&'__x ::buffa::MapView<'__x, #key_ty, #val_ty>); },
quote! { impl },
quote! { _WM<'_> },
)
};
return Ok(quote! {
if !self.#ident.is_empty() {
#wm_struct_decl
#wm_impl_hdr ::serde::Serialize for #wm_impl_ty {
fn serialize<__S: ::serde::Serializer>(&self, __s: __S) -> ::core::result::Result<__S::Ok, __S::Error> {
use ::serde::ser::SerializeMap as _;
#key_wrapper
#val_wrapper
let mut __m = __s.serialize_map(::core::option::Option::Some(self.0.len()))?;
for (k, v) in self.0.iter_unique() {
__m.serialize_entry(#key_expr, #val_expr)?;
}
__m.end()
}
}
__map.serialize_entry(#json_name, &_WM(&self.#ident))?;
}
});
}
if is_repeated {
let seq_adapter = match ty {
Type::TYPE_BYTES => quote! { ::buffa::json_helpers::BytesSeqJson },
Type::TYPE_ENUM if is_closed_enum(&f_features) => {
quote! { ::buffa::json_helpers::ClosedEnumSeqJson }
}
Type::TYPE_ENUM => quote! { ::buffa::json_helpers::EnumSeqJson },
scalar_ty_val if serde_helper_path(scalar_ty_val).is_some() => {
quote! { ::buffa::json_helpers::RepeatedJson }
}
_ => quote! {},
};
let seq_val = if seq_adapter.is_empty() {
quote! { &*self.#ident }
} else {
quote! { &#seq_adapter(&self.#ident) }
};
return Ok(quote! {
if !self.#ident.is_empty() {
__map.serialize_entry(#json_name, #seq_val)?;
}
});
}
if is_explicit_presence_scalar(field, ty, &f_features) {
let entry = match ty {
Type::TYPE_STRING => quote! {
if let ::core::option::Option::Some(__v) = self.#ident {
__map.serialize_entry(#json_name, __v)?;
}
},
Type::TYPE_BYTES => quote! {
if let ::core::option::Option::Some(__v) = self.#ident {
__map.serialize_entry(
#json_name,
&::buffa::json_helpers::BytesJson(__v),
)?;
}
},
Type::TYPE_ENUM if is_closed_enum(&f_features) => {
quote! {
if let ::core::option::Option::Some(__v) = self.#ident {
__map.serialize_entry(
#json_name,
&::buffa::json_helpers::ClosedEnumJson(&__v),
)?;
}
}
}
Type::TYPE_ENUM => quote! {
if let ::core::option::Option::Some(ref __v) = self.#ident {
__map.serialize_entry(#json_name, __v)?;
}
},
scalar if serde_helper_path(scalar).is_some() => {
quote! {
if let ::core::option::Option::Some(__v) = self.#ident {
__map.serialize_entry(
#json_name,
&::buffa::json_helpers::ProtoJson(&__v),
)?;
}
}
}
_ => quote! {
if let ::core::option::Option::Some(__v) = self.#ident {
__map.serialize_entry(#json_name, &__v)?;
}
},
};
return Ok(entry);
}
let (skip_cond, serialize_stmt) = match ty {
Type::TYPE_STRING => (
quote! { !::buffa::json_helpers::skip_if::is_empty_str(self.#ident) },
quote! { __map.serialize_entry(#json_name, self.#ident)?; },
),
Type::TYPE_BYTES => (
quote! { !::buffa::json_helpers::skip_if::is_empty_bytes(self.#ident) },
quote! {
__map.serialize_entry(
#json_name,
&::buffa::json_helpers::BytesJson(self.#ident),
)?;
},
),
Type::TYPE_MESSAGE | Type::TYPE_GROUP => (
quote! { self.#ident.is_set() },
quote! {
if let ::core::option::Option::Some(__v) = self.#ident.as_option() {
__map.serialize_entry(#json_name, __v)?;
}
},
),
Type::TYPE_ENUM if is_closed_enum(&f_features) => {
let skip_fn = quote! { ::buffa::json_helpers::skip_if::is_default_closed_enum };
(
quote! { !#skip_fn(&self.#ident) },
quote! {
__map.serialize_entry(
#json_name,
&::buffa::json_helpers::ClosedEnumJson(&self.#ident),
)?;
},
)
}
Type::TYPE_ENUM => (
quote! { !::buffa::json_helpers::skip_if::is_default_enum_value(&self.#ident) },
quote! { __map.serialize_entry(#json_name, &self.#ident)?; },
),
scalar if serde_helper_path(scalar).is_some() => {
let skip_path = scalar_skip_predicate(scalar);
(
quote! { !#skip_path(&self.#ident) },
quote! {
__map.serialize_entry(
#json_name,
&::buffa::json_helpers::ProtoJson(&self.#ident),
)?;
},
)
}
Type::TYPE_BOOL => (
quote! { self.#ident },
quote! { __map.serialize_entry(#json_name, &self.#ident)?; },
),
_ => (
quote! { self.#ident != ::core::default::Default::default() },
quote! { __map.serialize_entry(#json_name, &self.#ident)?; },
),
};
if matches!(ty, Type::TYPE_MESSAGE | Type::TYPE_GROUP) || is_required {
return Ok(quote! { { #serialize_stmt } });
}
Ok(quote! {
if #skip_cond {
#serialize_stmt
}
})
}
fn scalar_skip_predicate(ty: Type) -> TokenStream {
match ty {
Type::TYPE_BOOL => quote! { ::buffa::json_helpers::skip_if::is_false },
Type::TYPE_INT32 | Type::TYPE_SINT32 | Type::TYPE_SFIXED32 => {
quote! { ::buffa::json_helpers::skip_if::is_zero_i32 }
}
Type::TYPE_UINT32 | Type::TYPE_FIXED32 => {
quote! { ::buffa::json_helpers::skip_if::is_zero_u32 }
}
Type::TYPE_INT64 | Type::TYPE_SINT64 | Type::TYPE_SFIXED64 => {
quote! { ::buffa::json_helpers::skip_if::is_zero_i64 }
}
Type::TYPE_UINT64 | Type::TYPE_FIXED64 => {
quote! { ::buffa::json_helpers::skip_if::is_zero_u64 }
}
Type::TYPE_FLOAT => quote! { ::buffa::json_helpers::skip_if::is_zero_f32 },
Type::TYPE_DOUBLE => quote! { ::buffa::json_helpers::skip_if::is_zero_f64 },
Type::TYPE_STRING
| Type::TYPE_BYTES
| Type::TYPE_ENUM
| Type::TYPE_MESSAGE
| Type::TYPE_GROUP => {
unreachable!("scalar_skip_predicate called for non-scalar {:?}", ty)
}
}
}
pub(crate) fn view_oneof_serialize_arm(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
view_enum: &TokenStream,
) -> Result<TokenStream, CodeGenError> {
let MessageScope { ctx, features, .. } = scope;
let f_features = crate::features::resolve_field(ctx, field, features);
let name = field
.name
.as_deref()
.ok_or(CodeGenError::MissingField("field.name"))?;
let json_name = field.json_name.as_deref().unwrap_or(name);
let variant = crate::oneof::oneof_variant_ident(name);
let ty = effective_type(ctx, field, features);
if is_null_value_field(field) {
return Ok(quote! {
#view_enum::#variant(_) => {
__map.serialize_entry(#json_name, &())?;
}
});
}
let arm_body = match ty {
Type::TYPE_STRING => {
quote! { __map.serialize_entry(#json_name, v)?; }
}
Type::TYPE_BYTES => {
quote! {
__map.serialize_entry(#json_name, &::buffa::json_helpers::BytesJson(v))?;
}
}
Type::TYPE_MESSAGE | Type::TYPE_GROUP => {
quote! { __map.serialize_entry(#json_name, v)?; }
}
Type::TYPE_ENUM if is_closed_enum(&f_features) => {
quote! {
__map.serialize_entry(
#json_name,
&::buffa::json_helpers::ClosedEnumJson(v),
)?;
}
}
Type::TYPE_ENUM => {
quote! { __map.serialize_entry(#json_name, v)?; }
}
scalar if serde_helper_path(scalar).is_some() => {
quote! {
__map.serialize_entry(#json_name, &::buffa::json_helpers::ProtoJson(v))?;
}
}
_ => {
quote! { __map.serialize_entry(#json_name, v)?; }
}
};
Ok(quote! {
#view_enum::#variant(v) => { #arm_body }
})
}
fn scalar_ty(ty: Type) -> TokenStream {
match ty {
Type::TYPE_DOUBLE => quote! { f64 },
Type::TYPE_FLOAT => quote! { f32 },
Type::TYPE_INT64 | Type::TYPE_SINT64 | Type::TYPE_SFIXED64 => quote! { i64 },
Type::TYPE_UINT64 | Type::TYPE_FIXED64 => quote! { u64 },
Type::TYPE_INT32 | Type::TYPE_SINT32 | Type::TYPE_SFIXED32 => quote! { i32 },
Type::TYPE_UINT32 | Type::TYPE_FIXED32 => quote! { u32 },
Type::TYPE_BOOL => quote! { bool },
Type::TYPE_STRING
| Type::TYPE_BYTES
| Type::TYPE_ENUM
| Type::TYPE_MESSAGE
| Type::TYPE_GROUP => unreachable!("scalar_ty called for non-scalar {:?}", ty),
}
}
fn resolve_enum_ty(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
) -> Result<TokenStream, CodeGenError> {
let type_name = field
.type_name
.as_deref()
.ok_or(CodeGenError::MissingField("field.type_name"))?;
let path = scope
.ctx
.rust_type_relative(type_name, scope.current_package, scope.nesting)
.ok_or_else(|| CodeGenError::Other(format!("enum type '{type_name}' not found")))?;
Ok(rust_path_to_tokens(&path))
}
pub(crate) fn resolve_view_ty_tokens(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
lt: &TokenStream,
) -> Result<TokenStream, CodeGenError> {
let path = resolve_view_path(scope, field)?;
Ok(quote! { #path <#lt> })
}
pub(crate) fn resolve_view_decode_tokens(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
) -> Result<TokenStream, CodeGenError> {
resolve_view_path(scope, field)
}
fn resolve_view_path(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
) -> Result<TokenStream, CodeGenError> {
resolve_view_family_path(scope, field, "View")
}
pub(crate) fn resolve_lazy_view_path(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
) -> Result<TokenStream, CodeGenError> {
resolve_view_family_path(scope, field, "LazyView")
}
pub(crate) fn resolve_lazy_view_ty_tokens(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
lt: &TokenStream,
) -> Result<TokenStream, CodeGenError> {
let path = resolve_lazy_view_path(scope, field)?;
Ok(quote! { #path <#lt> })
}
fn resolve_view_family_path(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
suffix: &str,
) -> Result<TokenStream, CodeGenError> {
let tree = if suffix == "LazyView" {
make_field_ident("lazy_view")
} else {
make_field_ident("view")
};
let type_name = field
.type_name
.as_deref()
.ok_or(CodeGenError::MissingField("field.type_name"))?;
let split = scope
.ctx
.rust_type_relative_split(type_name, scope.current_package, scope.nesting)
.ok_or_else(|| CodeGenError::Other(format!("message type '{type_name}' not found")))?;
let to_pkg = if split.to_package.is_empty() {
TokenStream::new()
} else {
let p = rust_path_to_tokens(&split.to_package);
quote! { #p :: }
};
let sentinel = make_field_ident(SENTINEL_MOD);
let (within_prefix, last) = match split.within_package.rsplit_once("::") {
Some((prefix, last)) => {
let p = rust_path_to_tokens(prefix);
(quote! { #p :: }, last.to_string())
}
None => (TokenStream::new(), split.within_package.clone()),
};
let view_ident = make_field_ident(&format!("{last}{suffix}"));
Ok(quote! { #to_pkg #sentinel :: #tree :: #within_prefix #view_ident })
}
pub(crate) fn resolve_owned_path(
scope: MessageScope<'_>,
field: &FieldDescriptorProto,
) -> Result<String, CodeGenError> {
let type_name = field
.type_name
.as_deref()
.ok_or(CodeGenError::MissingField("field.type_name"))?;
scope
.ctx
.rust_type_relative(type_name, scope.current_package, scope.nesting)
.ok_or_else(|| CodeGenError::Other(format!("message type '{type_name}' not found")))
}