use crate::error::{ParseError, SerializeError};
use crate::internal::SealedInternal;
use crate::message::{
Clear, ClearAndParse, CopyFrom, MergeFrom, Message, MessageMut, MessageType, MessageView,
Serialize, TakeFrom,
};
use crate::proxied::{AsMut, AsView, IntoMut, IntoView, MutProxied, Proxied};
use crate::string::{ProtoBytes, ProtoString};
use crate::wire::{
self, UnknownField, UnknownFields, WIRE_EGROUP, WIRE_I32, WIRE_I64, WIRE_LEN, WIRE_SGROUP,
WIRE_VARINT, decode_tag, decode_varint, encode_len_field, encode_tag, encode_varint,
encode_zigzag32, encode_zigzag64, key_len_value_len, read_fixed32, read_fixed64,
read_len_bytes, tag_len, varint_len,
};
use std::collections::{BTreeMap, BTreeSet};
use std::fmt;
use std::sync::Arc;
pub const RECURSION_LIMIT: u32 = 100;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FieldType {
Double = 1,
Float = 2,
Int64 = 3,
Uint64 = 4,
Int32 = 5,
Fixed64 = 6,
Fixed32 = 7,
Bool = 8,
String = 9,
Group = 10,
Message = 11,
Bytes = 12,
Uint32 = 13,
Enum = 14,
Sfixed32 = 15,
Sfixed64 = 16,
Sint32 = 17,
Sint64 = 18,
}
impl FieldType {
fn from_i32(v: i32) -> Option<Self> {
Some(match v {
1 => Self::Double,
2 => Self::Float,
3 => Self::Int64,
4 => Self::Uint64,
5 => Self::Int32,
6 => Self::Fixed64,
7 => Self::Fixed32,
8 => Self::Bool,
9 => Self::String,
10 => Self::Group,
11 => Self::Message,
12 => Self::Bytes,
13 => Self::Uint32,
14 => Self::Enum,
15 => Self::Sfixed32,
16 => Self::Sfixed64,
17 => Self::Sint32,
18 => Self::Sint64,
_ => return None,
})
}
pub(crate) fn is_packable(self) -> bool {
!matches!(
self,
Self::String | Self::Bytes | Self::Message | Self::Group
)
}
fn default_wire(self) -> u32 {
match self {
Self::Fixed64 | Self::Sfixed64 | Self::Double => WIRE_I64,
Self::Fixed32 | Self::Sfixed32 | Self::Float => WIRE_I32,
Self::String | Self::Bytes | Self::Message | Self::Group => WIRE_LEN,
_ => WIRE_VARINT,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Cardinality {
Optional,
Required,
Repeated,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Presence {
Implicit,
Explicit,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct SourceCodeInfo {
pub locations: Vec<SourceLocation>,
}
impl SourceCodeInfo {
pub fn find_location(&self, path: &[i32]) -> Option<&SourceLocation> {
self.locations
.iter()
.find(|loc| loc.path.as_slice() == path)
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct SourceLocation {
pub path: Vec<i32>,
pub span: Vec<i32>,
pub leading_comments: Option<String>,
pub trailing_comments: Option<String>,
pub leading_detached_comments: Vec<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Comments {
pub leading_comments: Option<String>,
pub trailing_comments: Option<String>,
pub leading_detached_comments: Vec<String>,
pub leading: Option<String>,
pub trailing: Option<String>,
pub span: Vec<i32>,
}
impl Comments {
pub fn leading(&self) -> Option<&str> {
self.leading_comments.as_deref()
}
pub fn trailing(&self) -> Option<&str> {
self.trailing_comments.as_deref()
}
pub fn is_empty(&self) -> bool {
self.leading_comments.as_ref().is_none_or(String::is_empty)
&& self.trailing_comments.as_ref().is_none_or(String::is_empty)
&& self.leading_detached_comments.is_empty()
}
}
#[derive(Clone, Debug)]
pub struct FieldDescriptor {
pub name: String,
pub number: u32,
pub field_type: FieldType,
pub cardinality: Cardinality,
pub presence: Presence,
pub packed: bool,
pub type_name: Option<String>,
pub json_name: String,
pub is_map: bool,
pub message: Option<Arc<MessageDescriptor>>,
pub enum_ty: Option<Arc<EnumDescriptor>>,
pub oneof_index: Option<u32>,
pub utf8_validate: bool,
pub default: Option<String>,
pub extendee: Option<String>,
pub delimited: bool,
pub extension_name: Option<String>,
pub options: Vec<DescriptorOption>,
pub comments: Comments,
pub deprecated: bool,
}
impl FieldDescriptor {
pub fn new(
name: impl Into<String>,
number: u32,
field_type: FieldType,
cardinality: Cardinality,
presence: Presence,
) -> Self {
let name = name.into();
Self {
json_name: name.clone(),
name,
number,
field_type,
cardinality,
presence,
packed: cardinality == Cardinality::Repeated && field_type.is_packable(),
type_name: None,
is_map: false,
message: None,
enum_ty: None,
oneof_index: None,
utf8_validate: true,
default: None,
extendee: None,
delimited: field_type == FieldType::Group,
extension_name: None,
options: Vec::new(),
comments: Comments::default(),
deprecated: false,
}
}
pub fn custom_option(&self, number: u32) -> Option<&[u8]> {
self.options
.iter()
.find(|o| o.number == number)
.map(|o| o.value.as_slice())
}
pub fn leading_comments(&self) -> Option<&str> {
self.comments.leading()
}
pub fn trailing_comments(&self) -> Option<&str> {
self.comments.trailing()
}
pub fn span(&self) -> &[i32] {
&self.comments.span
}
pub fn is_deprecated(&self) -> bool {
self.deprecated
}
}
#[derive(Clone, Debug)]
pub struct MessageDescriptor {
pub name: String,
pub full_name: String,
pub fields: BTreeMap<u32, FieldDescriptor>,
pub fields_by_name: BTreeMap<String, u32>,
pub is_map_entry: bool,
pub oneofs: Vec<Vec<u32>>,
pub fields_by_json_name: BTreeMap<String, u32>,
pub extension_ranges: Vec<(u32, u32)>,
pub reserved_names: BTreeSet<String>,
pub file_name: String,
pub message_set_wire_format: bool,
pub options: Vec<DescriptorOption>,
pub comments: Comments,
pub deprecated: bool,
}
impl MessageDescriptor {
pub fn builder(full_name: impl Into<String>) -> MessageDescriptorBuilder {
let full_name = full_name.into();
let name = full_name
.rsplit('.')
.next()
.unwrap_or(full_name.as_str())
.to_string();
MessageDescriptorBuilder {
desc: MessageDescriptor {
name,
full_name,
fields: BTreeMap::new(),
fields_by_name: BTreeMap::new(),
is_map_entry: false,
oneofs: Vec::new(),
fields_by_json_name: BTreeMap::new(),
extension_ranges: Vec::new(),
reserved_names: BTreeSet::new(),
file_name: String::new(),
message_set_wire_format: false,
options: Vec::new(),
comments: Comments::default(),
deprecated: false,
},
}
}
pub fn field(&self, number: u32) -> Option<&FieldDescriptor> {
self.fields.get(&number)
}
pub fn field_by_name(&self, name: &str) -> Option<&FieldDescriptor> {
let name = name
.strip_prefix('[')
.and_then(|s| s.strip_suffix(']'))
.unwrap_or(name);
self.fields_by_name
.get(name)
.or_else(|| self.fields_by_json_name.get(name))
.or_else(|| self.fields_by_name.get(&name.to_ascii_lowercase()))
.or_else(|| {
name.rsplit('.').next().and_then(|short| {
self.fields_by_name
.get(short)
.or_else(|| self.fields_by_name.get(&short.to_ascii_lowercase()))
})
})
.and_then(|n| self.fields.get(n))
}
pub fn is_reserved_name(&self, name: &str) -> bool {
self.reserved_names.contains(name)
}
pub fn custom_option(&self, number: u32) -> Option<&[u8]> {
self.options
.iter()
.find(|o| o.number == number)
.map(|o| o.value.as_slice())
}
pub fn leading_comments(&self) -> Option<&str> {
self.comments.leading()
}
pub fn trailing_comments(&self) -> Option<&str> {
self.comments.trailing()
}
pub fn span(&self) -> &[i32] {
&self.comments.span
}
pub fn is_deprecated(&self) -> bool {
self.deprecated
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DescriptorOption {
pub number: u32,
pub value: Vec<u8>,
}
#[derive(Clone, Debug, Default)]
pub struct EnumDescriptor {
pub name: String,
pub full_name: String,
pub file_name: String,
pub values: BTreeMap<i32, String>,
pub names: BTreeMap<String, i32>,
pub listed: Vec<(i32, String)>,
pub closed: bool,
pub options: Vec<DescriptorOption>,
pub comments: Comments,
pub value_comments: BTreeMap<i32, Comments>,
pub value_comments_by_name: BTreeMap<String, Comments>,
pub deprecated: bool,
pub deprecated_values: BTreeSet<i32>,
}
impl EnumDescriptor {
pub fn custom_option(&self, number: u32) -> Option<&[u8]> {
self.options
.iter()
.find(|o| o.number == number)
.map(|o| o.value.as_slice())
}
pub fn leading_comments(&self) -> Option<&str> {
self.comments.leading()
}
pub fn trailing_comments(&self) -> Option<&str> {
self.comments.trailing()
}
pub fn span(&self) -> &[i32] {
&self.comments.span
}
pub fn value_comments(&self, number: i32) -> Option<&Comments> {
self.value_comments.get(&number)
}
pub fn value_comments_by_name(&self, name: &str) -> Option<&Comments> {
self.value_comments_by_name.get(name)
}
pub fn is_deprecated(&self) -> bool {
self.deprecated
}
pub fn is_value_deprecated(&self, number: i32) -> bool {
self.deprecated_values.contains(&number)
}
}
pub struct MessageDescriptorBuilder {
desc: MessageDescriptor,
}
impl MessageDescriptorBuilder {
pub fn field(mut self, field: FieldDescriptor) -> Self {
self.desc
.fields_by_name
.insert(field.name.clone(), field.number);
self.desc
.fields_by_json_name
.insert(field.json_name.clone(), field.number);
self.desc.fields.insert(field.number, field);
self
}
pub fn map_entry(mut self, yes: bool) -> Self {
self.desc.is_map_entry = yes;
self
}
pub fn comments(mut self, comments: Comments) -> Self {
self.desc.comments = comments;
self
}
pub fn deprecated(mut self, deprecated: bool) -> Self {
self.desc.deprecated = deprecated;
self
}
pub fn build(self) -> MessageDescriptor {
self.desc
}
}
#[derive(Clone, Debug, Default)]
pub struct MethodDescriptor {
pub name: String,
pub input_type: String,
pub output_type: String,
pub client_streaming: bool,
pub server_streaming: bool,
pub options: Vec<DescriptorOption>,
pub comments: Comments,
pub deprecated: bool,
}
impl MethodDescriptor {
pub fn custom_option(&self, number: u32) -> Option<&[u8]> {
self.options
.iter()
.find(|o| o.number == number)
.map(|o| o.value.as_slice())
}
pub fn leading_comments(&self) -> Option<&str> {
self.comments.leading()
}
pub fn trailing_comments(&self) -> Option<&str> {
self.comments.trailing()
}
pub fn span(&self) -> &[i32] {
&self.comments.span
}
pub fn is_deprecated(&self) -> bool {
self.deprecated
}
}
#[derive(Clone, Debug, Default)]
pub struct ServiceDescriptor {
pub name: String,
pub full_name: String,
pub file_name: String,
pub methods: Vec<MethodDescriptor>,
pub comments: Comments,
pub deprecated: bool,
pub options: Vec<DescriptorOption>,
}
impl ServiceDescriptor {
pub fn custom_option(&self, number: u32) -> Option<&[u8]> {
self.options
.iter()
.find(|o| o.number == number)
.map(|o| o.value.as_slice())
}
pub fn leading_comments(&self) -> Option<&str> {
self.comments.leading()
}
pub fn trailing_comments(&self) -> Option<&str> {
self.comments.trailing()
}
pub fn span(&self) -> &[i32] {
&self.comments.span
}
pub fn is_deprecated(&self) -> bool {
self.deprecated
}
}
#[derive(Clone, Debug, Default)]
pub struct FileDescriptor {
pub name: String,
pub package: String,
pub options: Vec<DescriptorOption>,
pub source_code_info: Option<SourceCodeInfo>,
pub comments: Comments,
pub deprecated: bool,
}
impl FileDescriptor {
pub fn custom_option(&self, number: u32) -> Option<&[u8]> {
self.options
.iter()
.find(|o| o.number == number)
.map(|o| o.value.as_slice())
}
pub fn source_code_info(&self) -> Option<&SourceCodeInfo> {
self.source_code_info.as_ref()
}
pub fn leading_comments(&self) -> Option<&str> {
self.comments.leading()
}
pub fn trailing_comments(&self) -> Option<&str> {
self.comments.trailing()
}
pub fn is_deprecated(&self) -> bool {
self.deprecated
}
}
#[derive(Clone, Copy, Debug)]
struct FileMetadata {
edition: i32,
features: RawFeatures,
}
#[derive(Clone, Copy, Debug)]
struct SymbolMetadata {
features: RawFeatures,
declared_visibility: u32,
effective_visibility: u32,
}
#[derive(Clone, Debug, Default)]
pub struct DescriptorPool {
messages: BTreeMap<String, Arc<MessageDescriptor>>,
enums: BTreeMap<String, Arc<EnumDescriptor>>,
extensions_by_name: BTreeMap<String, (String, u32, String)>,
services: BTreeMap<String, Arc<ServiceDescriptor>>,
files: BTreeMap<String, Arc<FileDescriptor>>,
public_imports: BTreeMap<String, Vec<String>>,
file_metadata: BTreeMap<String, FileMetadata>,
symbol_metadata: BTreeMap<String, SymbolMetadata>,
}
impl DescriptorPool {
pub fn new() -> Self {
Self::default()
}
pub fn collect_names(&self) -> Vec<String> {
self.messages.keys().cloned().collect()
}
pub fn get_message(&self, full_name: &str) -> Option<Arc<MessageDescriptor>> {
self.messages
.get(full_name.trim_start_matches('.'))
.cloned()
}
pub fn get_enum(&self, full_name: &str) -> Option<Arc<EnumDescriptor>> {
self.enums.get(full_name.trim_start_matches('.')).cloned()
}
fn lookup_file_metadata(&self, file_name: &str) -> Option<&FileMetadata> {
let file = self.get_file(file_name)?;
self.file_metadata.get(&file.name)
}
pub fn file_edition(&self, file_name: &str) -> Option<i32> {
self.lookup_file_metadata(file_name).map(|m| m.edition)
}
pub fn file_json_format(&self, file_name: &str) -> Option<u32> {
self.lookup_file_metadata(file_name)
.map(|m| m.features.json_format)
}
pub fn file_naming_style(&self, file_name: &str) -> Option<u32> {
self.lookup_file_metadata(file_name)
.map(|m| m.features.naming_style)
}
pub fn file_default_symbol_visibility(&self, file_name: &str) -> Option<u32> {
self.lookup_file_metadata(file_name)
.map(|m| m.features.default_symbol_visibility)
}
pub fn symbol_json_format(&self, full_name: &str) -> Option<u32> {
self.symbol_metadata
.get(full_name.trim_start_matches('.'))
.map(|m| m.features.json_format)
}
pub fn symbol_naming_style(&self, full_name: &str) -> Option<u32> {
self.symbol_metadata
.get(full_name.trim_start_matches('.'))
.map(|m| m.features.naming_style)
}
pub fn declared_symbol_visibility(&self, full_name: &str) -> Option<u32> {
self.symbol_metadata
.get(full_name.trim_start_matches('.'))
.map(|m| m.declared_visibility)
}
pub fn effective_symbol_visibility(&self, full_name: &str) -> Option<u32> {
self.symbol_metadata
.get(full_name.trim_start_matches('.'))
.map(|m| m.effective_visibility)
}
pub fn collect_enum_names(&self) -> Vec<String> {
self.enums.keys().cloned().collect()
}
pub(crate) fn public_import_files(&self, targets: &[String]) -> Vec<String> {
let mut out = Vec::new();
for t in targets {
for (file, pubs) in &self.public_imports {
if file_name_matches(t, file) {
for p in pubs {
if !out.contains(p) {
out.push(p.clone());
}
}
}
}
}
out
}
pub fn get_extension(
&self,
full_name: &str,
) -> Option<(Arc<MessageDescriptor>, FieldDescriptor)> {
let key = full_name.trim_start_matches('.');
let (extendee, number, _) = self.extensions_by_name.get(key)?;
let desc = self.get_message(extendee)?;
let field = desc.field(*number)?.clone();
Some((desc, field))
}
pub fn file_for_extension(&self, containing_type: &str, number: u32) -> Option<&str> {
let ty = containing_type.trim_start_matches('.');
self.extensions_by_name
.values()
.find(|(extendee, n, _)| extendee == ty && *n == number)
.map(|(_, _, file)| file.as_str())
.filter(|file| !file.is_empty())
}
pub fn extension_numbers_of(&self, containing_type: &str) -> Vec<u32> {
let ty = containing_type.trim_start_matches('.');
let mut nums: Vec<u32> = self
.extensions_by_name
.values()
.filter(|(extendee, _, _)| extendee == ty)
.map(|(_, n, _)| *n)
.collect();
nums.sort_unstable();
nums.dedup();
nums
}
pub fn register_message(&mut self, desc: MessageDescriptor) -> Arc<MessageDescriptor> {
let key = desc.full_name.clone();
let _ = self.symbol_metadata.remove(&key);
let arc = Arc::new(desc);
self.messages.insert(key, arc.clone());
arc
}
pub fn get_service(&self, full_name: &str) -> Option<Arc<ServiceDescriptor>> {
self.services
.get(full_name.trim_start_matches('.'))
.cloned()
}
pub fn get_file(&self, name: &str) -> Option<Arc<FileDescriptor>> {
self.files.get(name).cloned().or_else(|| {
self.files
.values()
.find(|f| file_name_matches(name, &f.name))
.cloned()
})
}
pub fn collect_services(&self) -> Vec<Arc<ServiceDescriptor>> {
self.services.values().cloned().collect()
}
pub fn register_enum(&mut self, desc: EnumDescriptor) -> Arc<EnumDescriptor> {
let key = desc.full_name.clone();
let _ = self.symbol_metadata.remove(&key);
let arc = Arc::new(desc);
self.enums.insert(key, arc.clone());
arc
}
pub fn from_file_descriptor_set(bytes: &[u8]) -> Result<Self, ParseError> {
let files = parse_file_descriptor_set(bytes)?;
let mut raw: BTreeMap<String, RawMessage> = BTreeMap::new();
let mut raw_enums: BTreeMap<String, RawEnum> = BTreeMap::new();
let mut extensions = Vec::new();
for file in &files {
collect_raw(file, &mut raw, &mut raw_enums, &mut extensions);
}
let edition2024_files: BTreeSet<String> = files
.iter()
.filter(|file| file.edition == 1001)
.map(|file| file.name.clone())
.collect();
let mut pool = resolve_pool(raw, raw_enums, extensions, &edition2024_files)?;
for file in &files {
pool.file_metadata.insert(
file.name.clone(),
FileMetadata {
edition: file.edition,
features: file.features,
},
);
pool.files.insert(
file.name.clone(),
Arc::new(FileDescriptor {
name: file.name.clone(),
package: file.package.clone(),
options: file.options.clone(),
source_code_info: file.source_code_info.clone(),
comments: file.comments.clone(),
deprecated: file.deprecated,
}),
);
let pubs: Vec<String> = file
.public_dependency
.iter()
.filter_map(|&i| file.dependencies.get(i as usize).cloned())
.collect();
if !pubs.is_empty() {
pool.public_imports.insert(file.name.clone(), pubs);
}
for svc in &file.services {
for method in &svc.methods {
for name in [&method.input_type, &method.output_type] {
if let Some(target) = pool.get_message(name.trim_start_matches('.')) {
check_symbol_visible_from_file(
&file.name,
&target.file_name,
name.trim_start_matches('.'),
&pool.symbol_metadata,
)?;
}
}
}
let desc = Arc::new(ServiceDescriptor {
name: svc.name.clone(),
full_name: svc.full_name.clone(),
file_name: file.name.clone(),
methods: svc.methods.clone(),
comments: svc.comments.clone(),
deprecated: svc.deprecated,
options: svc.options.clone(),
});
pool.services.insert(desc.full_name.clone(), desc);
}
}
validate_edition2024_references(&files, &pool)?;
Ok(pool)
}
}
#[derive(Clone, Debug)]
pub enum Value {
Double(f64),
Float(f32),
Int32(i32),
Int64(i64),
Uint32(u32),
Uint64(u64),
Bool(bool),
String(ProtoString),
Bytes(ProtoBytes),
Enum(i32),
Message(DynamicMessage),
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Double(a), Self::Double(b)) => a.to_bits() == b.to_bits(),
(Self::Float(a), Self::Float(b)) => a.to_bits() == b.to_bits(),
(Self::Int32(a), Self::Int32(b)) => a == b,
(Self::Int64(a), Self::Int64(b)) => a == b,
(Self::Uint32(a), Self::Uint32(b)) => a == b,
(Self::Uint64(a), Self::Uint64(b)) => a == b,
(Self::Bool(a), Self::Bool(b)) => a == b,
(Self::String(a), Self::String(b)) => a == b,
(Self::Bytes(a), Self::Bytes(b)) => a == b,
(Self::Enum(a), Self::Enum(b)) => a == b,
(Self::Message(a), Self::Message(b)) => a == b,
_ => false,
}
}
}
impl Value {
pub(crate) fn is_implicit_default(&self) -> bool {
match self {
Self::Double(v) => v.to_bits() == 0f64.to_bits(),
Self::Float(v) => v.to_bits() == 0f32.to_bits(),
Self::Int32(v) | Self::Enum(v) => *v == 0,
Self::Int64(v) => *v == 0,
Self::Uint32(v) => *v == 0,
Self::Uint64(v) => *v == 0,
Self::Bool(v) => !*v,
Self::String(v) => v.is_empty(),
Self::Bytes(v) => v.is_empty(),
Self::Message(_) => false,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum FieldValue {
Singular(Value),
Repeated(Vec<Value>),
Map(BTreeMap<MapKeyValue, Value>),
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum MapKeyValue {
I32(i32),
I64(i64),
U32(u32),
U64(u64),
Bool(bool),
String(ProtoString),
}
#[derive(Clone)]
pub struct DynamicMessage {
desc: Arc<MessageDescriptor>,
pool: Option<Arc<DescriptorPool>>,
fields: BTreeMap<u32, FieldValue>,
unknown: UnknownFields,
}
impl PartialEq for DynamicMessage {
fn eq(&self, other: &Self) -> bool {
self.desc.full_name == other.desc.full_name
&& self.fields == other.fields
&& self.unknown == other.unknown
}
}
impl fmt::Debug for DynamicMessage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DynamicMessage")
.field("type", &self.desc.full_name)
.field("fields", &self.fields)
.finish()
}
}
impl DynamicMessage {
pub fn new(desc: Arc<MessageDescriptor>) -> Self {
Self {
desc,
pool: None,
fields: BTreeMap::new(),
unknown: UnknownFields::default(),
}
}
pub fn set_pool(&mut self, pool: Arc<DescriptorPool>) {
self.pool = Some(pool);
}
pub fn pool(&self) -> Option<&Arc<DescriptorPool>> {
self.pool.as_ref()
}
pub fn descriptor(&self) -> &Arc<MessageDescriptor> {
&self.desc
}
pub(crate) fn raw_fields(&self) -> &BTreeMap<u32, FieldValue> {
&self.fields
}
pub fn parse_with(desc: Arc<MessageDescriptor>, data: &[u8]) -> Result<Self, ParseError> {
Self::parse_with_pool(desc, None, data)
}
pub fn parse_with_pool(
desc: Arc<MessageDescriptor>,
pool: Option<Arc<DescriptorPool>>,
data: &[u8],
) -> Result<Self, ParseError> {
Self::parse_with_pool_depth(desc, pool, data, 0, true)
}
pub(crate) fn parse_with_pool_depth(
desc: Arc<MessageDescriptor>,
pool: Option<Arc<DescriptorPool>>,
data: &[u8],
depth: u32,
enforce_required: bool,
) -> Result<Self, ParseError> {
let mut msg = Self::new(desc);
msg.pool = pool;
msg.merge_bytes(data, enforce_required, depth)?;
Ok(msg)
}
pub fn unknown_fields(&self) -> &UnknownFields {
&self.unknown
}
pub fn has(&self, number: u32) -> bool {
self.fields.contains_key(&number)
}
pub fn get_singular(&self, number: u32) -> Option<&Value> {
match self.fields.get(&number) {
Some(FieldValue::Singular(v)) => Some(v),
_ => None,
}
}
pub fn get_repeated(&self, number: u32) -> Option<&[Value]> {
match self.fields.get(&number) {
Some(FieldValue::Repeated(v)) => Some(v),
_ => None,
}
}
pub fn get_map(&self, number: u32) -> Option<&BTreeMap<MapKeyValue, Value>> {
match self.fields.get(&number) {
Some(FieldValue::Map(v)) => Some(v),
_ => None,
}
}
pub fn set(&mut self, number: u32, value: Value) {
if let Some(field) = self.desc.field(number) {
if let Some(idx) = field.oneof_index {
if let Some(members) = self.desc.oneofs.get(idx as usize) {
for n in members.clone() {
if n != number {
self.fields.remove(&n);
}
}
}
}
}
self.fields.insert(number, FieldValue::Singular(value));
}
pub fn set_extension(&mut self, number: u32, value: Value) {
self.set(number, value);
}
pub fn get_extension(&self, number: u32) -> Option<&Value> {
self.get_singular(number)
}
pub fn has_extension(&self, number: u32) -> bool {
self.has(number)
}
pub fn clear_extension(&mut self, number: u32) {
self.clear_field(number);
}
pub fn to_json(&self) -> Result<String, SerializeError> {
crate::json::encode(self)
}
pub fn from_json(desc: Arc<MessageDescriptor>, json: &str) -> Result<Self, ParseError> {
crate::json::decode(desc, json, false, None)
}
pub fn from_json_ignore_unknown(
desc: Arc<MessageDescriptor>,
json: &str,
) -> Result<Self, ParseError> {
crate::json::decode(desc, json, true, None)
}
pub fn from_json_with_pool(
desc: Arc<MessageDescriptor>,
pool: Option<Arc<DescriptorPool>>,
json: &str,
ignore_unknown: bool,
) -> Result<Self, ParseError> {
crate::json::decode(desc, json, ignore_unknown, pool)
}
pub fn to_text(&self) -> Result<String, SerializeError> {
crate::text::encode(self)
}
pub fn to_text_with_unknown(&self) -> Result<String, SerializeError> {
crate::text::encode_with_unknown(self)
}
pub fn from_text(desc: Arc<MessageDescriptor>, text: &str) -> Result<Self, ParseError> {
crate::text::decode(desc, text)
}
pub fn from_text_with_pool(
desc: Arc<MessageDescriptor>,
pool: Option<Arc<DescriptorPool>>,
text: &str,
) -> Result<Self, ParseError> {
crate::text::decode_with_pool(desc, text, pool)
}
pub fn push(&mut self, number: u32, value: Value) {
match self.fields.entry(number) {
std::collections::btree_map::Entry::Occupied(mut e) => match e.get_mut() {
FieldValue::Repeated(v) => v.push(value),
other => *other = FieldValue::Repeated(vec![value]),
},
std::collections::btree_map::Entry::Vacant(e) => {
e.insert(FieldValue::Repeated(vec![value]));
}
}
}
pub fn insert_map(&mut self, number: u32, key: MapKeyValue, value: Value) {
match self.fields.entry(number) {
std::collections::btree_map::Entry::Occupied(mut e) => match e.get_mut() {
FieldValue::Map(m) => {
m.insert(key, value);
}
other => {
let mut m = BTreeMap::new();
m.insert(key, value);
*other = FieldValue::Map(m);
}
},
std::collections::btree_map::Entry::Vacant(e) => {
let mut m = BTreeMap::new();
m.insert(key, value);
e.insert(FieldValue::Map(m));
}
}
}
pub fn clear_field(&mut self, number: u32) {
self.fields.remove(&number);
}
fn merge_bytes(
&mut self,
data: &[u8],
enforce_required: bool,
depth: u32,
) -> Result<(), ParseError> {
if depth > RECURSION_LIMIT {
return Err(ParseError::new("recursion limit exceeded"));
}
let mut pos = 0;
while pos < data.len() {
let (number, wire) = decode_tag(data, &mut pos)?;
if self.desc.message_set_wire_format && number == 1 {
self.merge_message_set_item(data, &mut pos, wire, depth)?;
continue;
}
match self.desc.field(number).cloned() {
None => {
self.unknown
.fields
.push(wire::capture_unknown(data, &mut pos, number, wire)?);
}
Some(field) => self.merge_field(&field, data, &mut pos, wire, depth)?,
}
}
if enforce_required {
for f in self.desc.fields.values() {
if f.cardinality == Cardinality::Required && !self.fields.contains_key(&f.number) {
return Err(ParseError::new("missing required field"));
}
}
}
Ok(())
}
fn merge_field(
&mut self,
field: &FieldDescriptor,
data: &[u8],
pos: &mut usize,
wire: u32,
depth: u32,
) -> Result<(), ParseError> {
let expected = if field.delimited {
WIRE_SGROUP
} else {
field.field_type.default_wire()
};
let packed_ok = field.cardinality == Cardinality::Repeated
&& field.field_type.is_packable()
&& wire == WIRE_LEN;
if wire != expected && !packed_ok && !(field.is_map && wire == WIRE_LEN) {
self.unknown
.fields
.push(wire::capture_unknown(data, pos, field.number, wire)?);
return Ok(());
}
if field.is_map {
let payload = read_len_bytes(data, pos)?;
let entry = field_message_desc(field, self.pool.as_ref())?;
let (k, v) = decode_map_entry(&entry, payload, self.pool.clone(), depth)?;
self.insert_map(field.number, k, v);
return Ok(());
}
if field.cardinality == Cardinality::Repeated {
if packed_ok {
let payload = read_len_bytes(data, pos)?;
let mut p = 0;
let leaf_wire = field.field_type.default_wire();
while p < payload.len() {
let v =
decode_leaf(field, payload, &mut p, leaf_wire, self.pool.clone(), depth)?;
match v {
Value::Enum(n) if is_closed_unknown(field, n) => {
self.unknown.fields.push(UnknownField::Varint {
number: field.number,
value: n as u64,
});
}
value => self.push(field.number, value),
}
}
return Ok(());
}
let v = decode_leaf(field, data, pos, wire, self.pool.clone(), depth)?;
if let Value::Enum(n) = v {
if is_closed_unknown(field, n) {
self.unknown.fields.push(UnknownField::Varint {
number: field.number,
value: n as u64,
});
return Ok(());
}
}
self.push(field.number, v);
return Ok(());
}
let v = decode_leaf(field, data, pos, wire, self.pool.clone(), depth)?;
if let Value::Enum(n) = &v {
if is_closed_unknown(field, *n) {
self.unknown.fields.push(UnknownField::Varint {
number: field.number,
value: *n as u64,
});
return Ok(());
}
}
if let Value::Message(incoming) = v {
match self.fields.get_mut(&field.number) {
Some(FieldValue::Singular(Value::Message(existing))) => {
existing.merge_from_dyn(&incoming);
}
_ => {
self.set(field.number, Value::Message(incoming));
}
}
return Ok(());
}
self.set(field.number, v);
Ok(())
}
pub(crate) fn merge_from_dyn(&mut self, src: &DynamicMessage) {
for (n, val) in &src.fields {
match val {
FieldValue::Singular(Value::Message(child)) => match self.fields.get_mut(n) {
Some(FieldValue::Singular(Value::Message(dst))) => dst.merge_from_dyn(child),
_ => {
self.fields
.insert(*n, FieldValue::Singular(Value::Message(child.clone())));
}
},
FieldValue::Repeated(items) => match self.fields.get_mut(n) {
Some(FieldValue::Repeated(dst)) => dst.extend(items.iter().cloned()),
_ => {
self.fields.insert(*n, FieldValue::Repeated(items.clone()));
}
},
FieldValue::Map(items) => match self.fields.get_mut(n) {
Some(FieldValue::Map(dst)) => {
dst.extend(items.iter().map(|(k, v)| (k.clone(), v.clone())));
}
_ => {
self.fields.insert(*n, FieldValue::Map(items.clone()));
}
},
other => {
self.fields.insert(*n, other.clone());
}
}
}
self.unknown
.fields
.extend(src.unknown.fields.iter().cloned());
}
fn compute_size(&self) -> u64 {
let mut n = 0u64;
for (number, val) in &self.fields {
if let Some(field) = self.desc.field(*number) {
n += field_value_size(field, val);
} else {
n += untyped_size(*number, val);
}
}
n + self.unknown.encoded_len()
}
fn write_to(&self, out: &mut impl crate::wire::WireOut) {
if self.desc.message_set_wire_format {
self.write_message_set(out);
self.unknown.encode(out);
return;
}
for (number, val) in &self.fields {
if let Some(field) = self.desc.field(*number) {
write_field_value(field, val, out);
} else {
write_untyped(*number, val, out);
}
}
self.unknown.encode(out);
}
fn merge_message_set_item(
&mut self,
data: &[u8],
pos: &mut usize,
wire: u32,
depth: u32,
) -> Result<(), ParseError> {
let mut type_id = 0u32;
let mut payload = Vec::new();
if wire == WIRE_LEN {
let inner = read_len_bytes(data, pos)?;
let mut p = 0;
while p < inner.len() {
let (n, w) = decode_tag(inner, &mut p)?;
match (n, w) {
(2, WIRE_VARINT) => type_id = decode_varint(inner, &mut p)? as u32,
(3, WIRE_LEN) => payload = read_len_bytes(inner, &mut p)?.to_vec(),
_ => wire::skip_field(inner, &mut p, w)?,
}
}
} else if wire == WIRE_SGROUP {
loop {
if *pos >= data.len() {
return Err(ParseError::new("truncated message set"));
}
let (n, w) = decode_tag(data, pos)?;
if w == WIRE_EGROUP && n == 1 {
break;
}
match (n, w) {
(2, WIRE_VARINT) => type_id = decode_varint(data, pos)? as u32,
(3, WIRE_LEN) => payload = read_len_bytes(data, pos)?.to_vec(),
_ => self
.unknown
.fields
.push(wire::capture_unknown(data, pos, n, w)?),
}
}
} else {
self.unknown
.fields
.push(wire::capture_unknown(data, pos, 1, wire)?);
return Ok(());
}
if type_id == 0 {
return Ok(());
}
if let Some(field) = self.desc.field(type_id).cloned() {
let mut inner = DynamicMessage::new(field_message_desc(&field, self.pool.as_ref())?);
if let Some(p) = self.pool.clone() {
inner.set_pool(p);
}
inner.merge_bytes(&payload, false, depth + 1)?;
self.set(type_id, Value::Message(inner));
} else {
self.unknown.fields.push(UnknownField::Group {
number: 1,
fields: {
let mut u = UnknownFields::default();
u.fields.push(UnknownField::Varint {
number: 2,
value: u64::from(type_id),
});
u.fields.push(UnknownField::LengthDelimited {
number: 3,
value: payload,
});
u
},
});
}
Ok(())
}
fn write_message_set(&self, out: &mut impl crate::wire::WireOut) {
for (number, val) in &self.fields {
let FieldValue::Singular(Value::Message(m)) = val else {
continue;
};
let mut inner = Vec::new();
m.write_to(&mut inner);
encode_tag(out, 1, WIRE_SGROUP);
encode_tag(out, 2, WIRE_VARINT);
encode_varint(out, u64::from(*number));
encode_len_field(out, 3, &inner);
encode_tag(out, 1, WIRE_EGROUP);
}
}
}
fn is_closed_unknown(field: &FieldDescriptor, n: i32) -> bool {
field
.enum_ty
.as_ref()
.is_some_and(|e| e.closed && !e.values.contains_key(&n))
}
fn field_message_desc(
field: &FieldDescriptor,
pool: Option<&Arc<DescriptorPool>>,
) -> Result<Arc<MessageDescriptor>, ParseError> {
if let (Some(tn), Some(pool)) = (field.type_name.as_deref(), pool) {
if let Some(m) = pool.get_message(tn.trim_start_matches('.')) {
return Ok(m);
}
}
if let Some(m) = &field.message {
return Ok(m.clone());
}
Err(ParseError::new("unresolved message type"))
}
fn decode_leaf(
field: &FieldDescriptor,
data: &[u8],
pos: &mut usize,
wire: u32,
pool: Option<Arc<DescriptorPool>>,
depth: u32,
) -> Result<Value, ParseError> {
if field.delimited || field.field_type == FieldType::Group {
return decode_group(field, data, pos, pool, depth);
}
match field.field_type {
FieldType::Message => {
if wire != WIRE_LEN {
return Err(ParseError::new("bad wire type for message"));
}
let payload = read_len_bytes(data, pos)?;
let desc = field_message_desc(field, pool.as_ref())?;
Ok(Value::Message(DynamicMessage::parse_with_pool_depth(
desc,
pool,
payload,
depth + 1,
true,
)?))
}
FieldType::Group => decode_group(field, data, pos, pool, depth),
FieldType::String => {
if wire != WIRE_LEN {
return Err(ParseError::new("bad wire type for string"));
}
let bytes = read_len_bytes(data, pos)?;
if field.utf8_validate {
std::str::from_utf8(bytes).map_err(|_| ParseError::new("invalid utf-8"))?;
}
Ok(Value::String(ProtoString::from_bytes(bytes)))
}
FieldType::Bytes => {
if wire != WIRE_LEN {
return Err(ParseError::new("bad wire type for bytes"));
}
Ok(Value::Bytes(ProtoBytes::from(read_len_bytes(data, pos)?)))
}
FieldType::Double => Ok(Value::Double(f64::from_bits(read_fixed64(data, pos)?))),
FieldType::Float => Ok(Value::Float(f32::from_bits(read_fixed32(data, pos)?))),
FieldType::Fixed64 => Ok(Value::Uint64(read_fixed64(data, pos)?)),
FieldType::Sfixed64 => Ok(Value::Int64(read_fixed64(data, pos)? as i64)),
FieldType::Fixed32 => Ok(Value::Uint32(read_fixed32(data, pos)?)),
FieldType::Sfixed32 => Ok(Value::Int32(read_fixed32(data, pos)? as i32)),
FieldType::Bool => Ok(Value::Bool(decode_varint(data, pos)? != 0)),
FieldType::Int32 => Ok(Value::Int32(decode_varint(data, pos)? as i32)),
FieldType::Int64 => Ok(Value::Int64(decode_varint(data, pos)? as i64)),
FieldType::Uint32 => Ok(Value::Uint32(decode_varint(data, pos)? as u32)),
FieldType::Uint64 => Ok(Value::Uint64(decode_varint(data, pos)?)),
FieldType::Sint32 => Ok(Value::Int32(wire::decode_zigzag32(decode_varint(
data, pos,
)?))),
FieldType::Sint64 => Ok(Value::Int64(wire::decode_zigzag64(decode_varint(
data, pos,
)?))),
FieldType::Enum => Ok(Value::Enum(decode_varint(data, pos)? as i32)),
}
}
fn decode_group(
field: &FieldDescriptor,
data: &[u8],
pos: &mut usize,
pool: Option<Arc<DescriptorPool>>,
depth: u32,
) -> Result<Value, ParseError> {
if depth + 1 > RECURSION_LIMIT {
return Err(ParseError::new("recursion limit exceeded"));
}
let desc = field_message_desc(field, pool.as_ref())?;
let mut msg = DynamicMessage::new(desc);
msg.pool = pool;
loop {
if *pos >= data.len() {
return Err(ParseError::new("truncated group"));
}
let (n, w) = decode_tag(data, pos)?;
if w == WIRE_EGROUP {
if n != field.number {
return Err(ParseError::new("mismatched end-group"));
}
break;
}
match msg.desc.field(n).cloned() {
None => msg
.unknown
.fields
.push(wire::capture_unknown(data, pos, n, w)?),
Some(f) => msg.merge_field(&f, data, pos, w, depth + 1)?,
}
}
Ok(Value::Message(msg))
}
fn decode_map_entry(
entry: &MessageDescriptor,
payload: &[u8],
pool: Option<Arc<DescriptorPool>>,
depth: u32,
) -> Result<(MapKeyValue, Value), ParseError> {
let msg = DynamicMessage::parse_with_pool_depth(
Arc::new(entry.clone()),
pool.clone(),
payload,
depth + 1,
false,
)?;
let key_field = entry
.field(1)
.ok_or_else(|| ParseError::new("map entry missing key"))?;
let val_field = entry
.field(2)
.ok_or_else(|| ParseError::new("map entry missing value"))?;
let key = match msg.get_singular(1) {
Some(v) => value_to_map_key(v)?,
None => default_map_key(key_field.field_type)?,
};
let value = match msg.get_singular(2) {
Some(v) => v.clone(),
None => default_value(val_field, pool.as_ref())?,
};
Ok((key, value))
}
fn value_to_map_key(v: &Value) -> Result<MapKeyValue, ParseError> {
Ok(match v {
Value::Int32(n) => MapKeyValue::I32(*n),
Value::Int64(n) => MapKeyValue::I64(*n),
Value::Uint32(n) => MapKeyValue::U32(*n),
Value::Uint64(n) => MapKeyValue::U64(*n),
Value::Bool(n) => MapKeyValue::Bool(*n),
Value::String(s) => MapKeyValue::String(s.clone()),
_ => return Err(ParseError::new("invalid map key type")),
})
}
pub(crate) fn default_map_key(ty: FieldType) -> Result<MapKeyValue, ParseError> {
Ok(match ty {
FieldType::Int32 | FieldType::Sint32 | FieldType::Sfixed32 => MapKeyValue::I32(0),
FieldType::Int64 | FieldType::Sint64 | FieldType::Sfixed64 => MapKeyValue::I64(0),
FieldType::Uint32 | FieldType::Fixed32 => MapKeyValue::U32(0),
FieldType::Uint64 | FieldType::Fixed64 => MapKeyValue::U64(0),
FieldType::Bool => MapKeyValue::Bool(false),
FieldType::String => MapKeyValue::String(ProtoString::new()),
_ => return Err(ParseError::new("invalid map key type")),
})
}
pub(crate) fn default_value(
field: &FieldDescriptor,
pool: Option<&Arc<DescriptorPool>>,
) -> Result<Value, ParseError> {
Ok(match field.field_type {
FieldType::Double => Value::Double(0.0),
FieldType::Float => Value::Float(0.0),
FieldType::Int32 | FieldType::Sint32 | FieldType::Sfixed32 => Value::Int32(0),
FieldType::Int64 | FieldType::Sint64 | FieldType::Sfixed64 => Value::Int64(0),
FieldType::Uint32 | FieldType::Fixed32 => Value::Uint32(0),
FieldType::Uint64 | FieldType::Fixed64 => Value::Uint64(0),
FieldType::Bool => Value::Bool(false),
FieldType::String => Value::String(ProtoString::new()),
FieldType::Bytes => Value::Bytes(ProtoBytes::new()),
FieldType::Enum => Value::Enum(0),
FieldType::Message | FieldType::Group => {
let desc = field_message_desc(field, pool)?;
Value::Message(DynamicMessage::new(desc))
}
})
}
fn synthetic(number: u32, v: &Value) -> FieldDescriptor {
let ty = match v {
Value::Double(_) => FieldType::Double,
Value::Float(_) => FieldType::Float,
Value::Int32(_) => FieldType::Int32,
Value::Int64(_) => FieldType::Int64,
Value::Uint32(_) => FieldType::Uint32,
Value::Uint64(_) => FieldType::Uint64,
Value::Bool(_) => FieldType::Bool,
Value::String(_) => FieldType::String,
Value::Bytes(_) => FieldType::Bytes,
Value::Enum(_) => FieldType::Enum,
Value::Message(_) => FieldType::Message,
};
let mut f = FieldDescriptor::new("ext", number, ty, Cardinality::Optional, Presence::Explicit);
if let Value::Message(m) = v {
f.message = Some(m.descriptor().clone());
}
f
}
fn untyped_size(number: u32, val: &FieldValue) -> u64 {
match val {
FieldValue::Singular(v) => field_value_size(&synthetic(number, v), val),
FieldValue::Repeated(items) => items
.iter()
.map(|v| field_value_size(&synthetic(number, v), &FieldValue::Singular(v.clone())))
.sum(),
FieldValue::Map(_) => 0,
}
}
fn write_untyped(number: u32, val: &FieldValue, out: &mut impl crate::wire::WireOut) {
match val {
FieldValue::Singular(v) => write_field_value(&synthetic(number, v), val, out),
FieldValue::Repeated(items) => {
for v in items {
write_field_value(&synthetic(number, v), &FieldValue::Singular(v.clone()), out);
}
}
FieldValue::Map(_) => {}
}
}
fn field_value_size(field: &FieldDescriptor, val: &FieldValue) -> u64 {
match val {
FieldValue::Singular(v) => {
if field.presence == Presence::Implicit && v.is_implicit_default() {
0
} else {
scalar_size(field, v)
}
}
FieldValue::Repeated(items) => {
if field.packed && field.field_type.is_packable() {
let payload: u64 = items
.iter()
.map(|v| packed_scalar_len(field.field_type, v))
.sum();
if payload == 0 {
0
} else {
key_len_value_len(field.number, payload)
}
} else {
items.iter().map(|v| scalar_size(field, v)).sum()
}
}
FieldValue::Map(items) => items
.iter()
.map(|(k, v)| key_len_value_len(field.number, map_entry_len(field, k, v)))
.sum(),
}
}
fn write_field_value(
field: &FieldDescriptor,
val: &FieldValue,
out: &mut impl crate::wire::WireOut,
) {
match val {
FieldValue::Singular(v) => {
if field.presence == Presence::Implicit && v.is_implicit_default() {
return;
}
write_scalar(field, v, out);
}
FieldValue::Repeated(items) => {
if field.packed && field.field_type.is_packable() {
let mut payload = Vec::new();
for v in items {
write_packed_scalar(field.field_type, v, &mut payload);
}
if !payload.is_empty() {
encode_len_field(out, field.number, &payload);
}
} else {
for v in items {
write_scalar(field, v, out);
}
}
}
FieldValue::Map(items) => {
for (k, v) in items {
let mut payload = Vec::new();
write_map_entry(field, k, v, &mut payload);
encode_len_field(out, field.number, &payload);
}
}
}
}
fn map_entry_len(field: &FieldDescriptor, key: &MapKeyValue, value: &Value) -> u64 {
let entry = match field.message.as_ref() {
Some(e) => e,
None => return 0,
};
let mut n = 0u64;
if let Some(kf) = entry.field(1) {
n += scalar_size(kf, &map_key_to_value(key));
}
if let Some(vf) = entry.field(2) {
n += scalar_size(vf, value);
}
n
}
fn write_map_entry(
field: &FieldDescriptor,
key: &MapKeyValue,
value: &Value,
out: &mut impl crate::wire::WireOut,
) {
let kv = map_key_to_value(key);
let mut kf = field
.message
.as_ref()
.and_then(|e| e.field(1).cloned())
.unwrap_or_else(|| synthetic(1, &kv));
kf.delimited = false;
write_scalar(&kf, &kv, out);
let mut vf = field
.message
.as_ref()
.and_then(|e| e.field(2).cloned())
.unwrap_or_else(|| synthetic(2, value));
vf.delimited = false;
write_scalar(&vf, value, out);
}
fn map_key_to_value(key: &MapKeyValue) -> Value {
match key {
MapKeyValue::I32(n) => Value::Int32(*n),
MapKeyValue::I64(n) => Value::Int64(*n),
MapKeyValue::U32(n) => Value::Uint32(*n),
MapKeyValue::U64(n) => Value::Uint64(*n),
MapKeyValue::Bool(n) => Value::Bool(*n),
MapKeyValue::String(s) => Value::String(s.clone()),
}
}
fn scalar_size(field: &FieldDescriptor, v: &Value) -> u64 {
match v {
Value::Message(m) if field.delimited || field.field_type == FieldType::Group => {
tag_len(field.number, WIRE_SGROUP)
+ m.compute_size()
+ tag_len(field.number, WIRE_EGROUP)
}
Value::Message(m) => key_len_value_len(field.number, m.compute_size()),
Value::String(s) => key_len_value_len(field.number, s.as_bytes().len() as u64),
Value::Bytes(b) => key_len_value_len(field.number, b.as_bytes().len() as u64),
other => {
tag_len(field.number, field.field_type.default_wire())
+ packed_scalar_len(field.field_type, other)
}
}
}
fn packed_scalar_len(ty: FieldType, v: &Value) -> u64 {
match (ty, v) {
(FieldType::Double | FieldType::Fixed64 | FieldType::Sfixed64, _) => 8,
(FieldType::Float | FieldType::Fixed32 | FieldType::Sfixed32, _) => 4,
(FieldType::Bool, Value::Bool(b)) => varint_len(u64::from(*b)),
(FieldType::Int32, Value::Int32(n)) => varint_len(*n as u64),
(FieldType::Int64, Value::Int64(n)) => varint_len(*n as u64),
(FieldType::Uint32, Value::Uint32(n)) => varint_len(u64::from(*n)),
(FieldType::Uint64, Value::Uint64(n)) => varint_len(*n),
(FieldType::Sint32, Value::Int32(n)) => varint_len(encode_zigzag32(*n)),
(FieldType::Sint64, Value::Int64(n)) => varint_len(encode_zigzag64(*n)),
(FieldType::Enum, Value::Enum(n)) => varint_len(*n as u64),
(FieldType::String, Value::String(s)) => {
varint_len(s.as_bytes().len() as u64) + s.as_bytes().len() as u64
}
(FieldType::Bytes, Value::Bytes(b)) => {
varint_len(b.as_bytes().len() as u64) + b.as_bytes().len() as u64
}
_ => 0,
}
}
fn write_scalar(field: &FieldDescriptor, v: &Value, out: &mut impl crate::wire::WireOut) {
match v {
Value::Message(m) if field.delimited || field.field_type == FieldType::Group => {
encode_tag(out, field.number, WIRE_SGROUP);
m.write_to(out);
encode_tag(out, field.number, WIRE_EGROUP);
}
Value::Message(m) => {
let mut inner = Vec::new();
m.write_to(&mut inner);
encode_len_field(out, field.number, &inner);
}
Value::String(s) => encode_len_field(out, field.number, s.as_bytes()),
Value::Bytes(b) => encode_len_field(out, field.number, b.as_bytes()),
_ => {
encode_tag(out, field.number, field.field_type.default_wire());
write_packed_scalar(field.field_type, v, out);
}
}
}
fn write_packed_scalar(ty: FieldType, v: &Value, out: &mut impl crate::wire::WireOut) {
match (ty, v) {
(FieldType::Double, Value::Double(n)) => out.extend_from_slice(&n.to_bits().to_le_bytes()),
(FieldType::Float, Value::Float(n)) => out.extend_from_slice(&n.to_bits().to_le_bytes()),
(FieldType::Fixed64, Value::Uint64(n)) => out.extend_from_slice(&n.to_le_bytes()),
(FieldType::Sfixed64, Value::Int64(n)) => out.extend_from_slice(&(*n as u64).to_le_bytes()),
(FieldType::Fixed32, Value::Uint32(n)) => out.extend_from_slice(&n.to_le_bytes()),
(FieldType::Sfixed32, Value::Int32(n)) => out.extend_from_slice(&(*n as u32).to_le_bytes()),
(FieldType::Bool, Value::Bool(b)) => encode_varint(out, u64::from(*b)),
(FieldType::Int32, Value::Int32(n)) => encode_varint(out, *n as u64),
(FieldType::Int64, Value::Int64(n)) => encode_varint(out, *n as u64),
(FieldType::Uint32, Value::Uint32(n)) => encode_varint(out, u64::from(*n)),
(FieldType::Uint64, Value::Uint64(n)) => encode_varint(out, *n),
(FieldType::Sint32, Value::Int32(n)) => encode_varint(out, encode_zigzag32(*n)),
(FieldType::Sint64, Value::Int64(n)) => encode_varint(out, encode_zigzag64(*n)),
(FieldType::Enum, Value::Enum(n)) => encode_varint(out, *n as u64),
(FieldType::String, Value::String(s)) => {
encode_varint(out, s.as_bytes().len() as u64);
out.extend_from_slice(s.as_bytes());
}
(FieldType::Bytes, Value::Bytes(b)) => {
encode_varint(out, b.as_bytes().len() as u64);
out.extend_from_slice(b.as_bytes());
}
_ => {}
}
}
#[derive(Clone, Copy, Debug)]
pub struct DynamicMessageView<'msg> {
inner: &'msg DynamicMessage,
}
impl Default for DynamicMessageView<'_> {
fn default() -> Self {
Self {
inner: crate::gen_support::default_instance_of::<DynamicMessage>(),
}
}
}
pub struct DynamicMessageMut<'msg> {
inner: &'msg mut DynamicMessage,
}
impl SealedInternal for DynamicMessage {}
impl MessageType for DynamicMessage {}
impl Proxied for DynamicMessage {
type View<'msg> = DynamicMessageView<'msg>;
}
impl MutProxied for DynamicMessage {
type Mut<'msg> = DynamicMessageMut<'msg>;
}
impl AsView for DynamicMessage {
type Proxied = Self;
fn as_view(&self) -> DynamicMessageView<'_> {
DynamicMessageView { inner: self }
}
}
impl AsMut for DynamicMessage {
type MutProxied = Self;
fn as_mut(&mut self) -> DynamicMessageMut<'_> {
DynamicMessageMut { inner: self }
}
}
impl SealedInternal for DynamicMessageView<'_> {}
impl AsView for DynamicMessageView<'_> {
type Proxied = DynamicMessage;
fn as_view(&self) -> DynamicMessageView<'_> {
*self
}
}
impl<'msg> IntoView<'msg> for DynamicMessageView<'msg> {
fn into_view<'shorter>(self) -> DynamicMessageView<'shorter>
where
'msg: 'shorter,
{
DynamicMessageView { inner: self.inner }
}
}
impl SealedInternal for DynamicMessageMut<'_> {}
impl AsView for DynamicMessageMut<'_> {
type Proxied = DynamicMessage;
fn as_view(&self) -> DynamicMessageView<'_> {
DynamicMessageView { inner: self.inner }
}
}
impl AsMut for DynamicMessageMut<'_> {
type MutProxied = DynamicMessage;
fn as_mut(&mut self) -> DynamicMessageMut<'_> {
DynamicMessageMut { inner: self.inner }
}
}
impl<'msg> IntoView<'msg> for DynamicMessageMut<'msg> {
fn into_view<'shorter>(self) -> DynamicMessageView<'shorter>
where
'msg: 'shorter,
{
DynamicMessageView { inner: self.inner }
}
}
impl<'msg> IntoMut<'msg> for DynamicMessageMut<'msg> {
fn into_mut<'shorter>(self) -> DynamicMessageMut<'shorter>
where
'msg: 'shorter,
{
DynamicMessageMut { inner: self.inner }
}
}
impl Serialize for DynamicMessage {
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
let mut out = Vec::new();
self.write_to(&mut out);
wire::check_size(out.len() as u64)?;
Ok(out)
}
fn serialized_len(&self) -> usize {
self.compute_size() as usize
}
fn encode(&self, out: &mut impl crate::wire::WireOut) -> Result<(), SerializeError> {
wire::check_size(self.compute_size())?;
self.write_to(out);
Ok(())
}
}
impl Serialize for DynamicMessageView<'_> {
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
self.inner.serialize()
}
fn serialized_len(&self) -> usize {
self.inner.serialized_len()
}
fn encode(&self, out: &mut impl crate::wire::WireOut) -> Result<(), SerializeError> {
self.inner.encode(out)
}
}
impl Serialize for DynamicMessageMut<'_> {
fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
self.inner.serialize()
}
fn serialized_len(&self) -> usize {
self.inner.serialized_len()
}
fn encode(&self, out: &mut impl crate::wire::WireOut) -> Result<(), SerializeError> {
self.inner.encode(out)
}
}
impl Clear for DynamicMessage {
fn clear(&mut self) {
self.fields.clear();
self.unknown.clear();
}
}
impl Clear for DynamicMessageMut<'_> {
fn clear(&mut self) {
self.inner.clear();
}
}
impl ClearAndParse for DynamicMessage {
fn clear_and_parse(&mut self, data: &[u8]) -> Result<(), ParseError> {
self.clear();
self.merge_bytes(data, true, 0)
}
fn clear_and_parse_dont_enforce_required(&mut self, data: &[u8]) -> Result<(), ParseError> {
self.clear();
self.merge_bytes(data, false, 0)
}
fn merge_from_bytes(&mut self, data: &[u8]) -> Result<(), ParseError> {
self.merge_bytes(data, true, 0)
}
fn merge_from_bytes_dont_enforce_required(&mut self, data: &[u8]) -> Result<(), ParseError> {
self.merge_bytes(data, false, 0)
}
}
impl ClearAndParse for DynamicMessageMut<'_> {
fn clear_and_parse(&mut self, data: &[u8]) -> Result<(), ParseError> {
self.inner.clear_and_parse(data)
}
fn clear_and_parse_dont_enforce_required(&mut self, data: &[u8]) -> Result<(), ParseError> {
self.inner.clear_and_parse_dont_enforce_required(data)
}
fn merge_from_bytes(&mut self, data: &[u8]) -> Result<(), ParseError> {
self.inner.merge_from_bytes(data)
}
}
impl CopyFrom for DynamicMessage {
fn copy_from(&mut self, src: impl AsView<Proxied = Self>) {
let src = src.as_view();
*self = src.inner.clone();
}
}
impl CopyFrom for DynamicMessageMut<'_> {
fn copy_from(&mut self, src: impl AsView<Proxied = DynamicMessage>) {
let src = src.as_view();
*self.inner = src.inner.clone();
}
}
impl TakeFrom for DynamicMessage {
fn take_from(&mut self, mut src: impl AsMut<MutProxied = Self>) {
let src = src.as_mut();
*self = std::mem::take(src.inner);
}
}
impl Default for DynamicMessage {
fn default() -> Self {
let desc = Arc::new(MessageDescriptor::builder("_Unset").build());
Self::new(desc)
}
}
impl TakeFrom for DynamicMessageMut<'_> {
fn take_from(&mut self, mut src: impl AsMut<MutProxied = DynamicMessage>) {
let src = src.as_mut();
*self.inner = std::mem::take(src.inner);
}
}
impl MergeFrom for DynamicMessage {
fn merge_from(&mut self, src: impl AsView<Proxied = Self>) {
let src = src.as_view();
self.merge_from_dyn(src.inner);
}
}
impl MergeFrom for DynamicMessageMut<'_> {
fn merge_from(&mut self, src: impl AsView<Proxied = DynamicMessage>) {
let src = src.as_view();
self.inner.merge_from_dyn(src.inner);
}
}
impl Message for DynamicMessage {
type MessageView<'msg> = DynamicMessageView<'msg>;
type MessageMut<'msg> = DynamicMessageMut<'msg>;
}
impl<'msg> MessageView<'msg> for DynamicMessageView<'msg> {
type Message = DynamicMessage;
}
impl<'msg> MessageMut<'msg> for DynamicMessageMut<'msg> {
type Message = DynamicMessage;
}
impl fmt::Debug for DynamicMessageMut<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.inner, f)
}
}
#[derive(Clone, Copy, Debug, Default)]
struct RawFeatures {
presence: u32,
enum_type: u32,
repeated_encoding: u32,
utf8: u32,
message_encoding: u32,
json_format: u32,
naming_style: u32,
default_symbol_visibility: u32,
}
const VISIBILITY_LOCAL: u32 = 1;
const VISIBILITY_EXPORT: u32 = 2;
fn parse_declared_visibility(bytes: &[u8], pos: &mut usize) -> Result<u32, ParseError> {
match decode_varint(bytes, pos)? {
0 => Ok(0),
1 => Ok(VISIBILITY_LOCAL),
2 => Ok(VISIBILITY_EXPORT),
_ => Err(ParseError::new("unknown symbol visibility")),
}
}
fn resolve_visibility(declared: u32, default: u32, nested: bool) -> Result<u32, ParseError> {
match declared {
VISIBILITY_LOCAL | VISIBILITY_EXPORT => Ok(declared),
0 => match default {
1 => Ok(VISIBILITY_EXPORT),
2 if nested => Ok(VISIBILITY_LOCAL),
2 => Ok(VISIBILITY_EXPORT),
3 => Ok(VISIBILITY_LOCAL),
_ => Err(ParseError::new("unresolved default symbol visibility")),
},
_ => Err(ParseError::new("unknown symbol visibility")),
}
}
impl RawFeatures {
fn merge(self, over: Self) -> Self {
Self {
presence: if over.presence != 0 {
over.presence
} else {
self.presence
},
enum_type: if over.enum_type != 0 {
over.enum_type
} else {
self.enum_type
},
repeated_encoding: if over.repeated_encoding != 0 {
over.repeated_encoding
} else {
self.repeated_encoding
},
utf8: if over.utf8 != 0 { over.utf8 } else { self.utf8 },
message_encoding: if over.message_encoding != 0 {
over.message_encoding
} else {
self.message_encoding
},
json_format: if over.json_format != 0 {
over.json_format
} else {
self.json_format
},
naming_style: if over.naming_style != 0 {
over.naming_style
} else {
self.naming_style
},
default_symbol_visibility: if over.default_symbol_visibility != 0 {
over.default_symbol_visibility
} else {
self.default_symbol_visibility
},
}
}
}
fn edition_defaults(syntax: &str, edition: i32) -> RawFeatures {
if syntax == "proto3" || edition == 999 {
RawFeatures {
presence: 2,
enum_type: 1,
repeated_encoding: 1,
utf8: 2,
message_encoding: 1,
json_format: 1,
naming_style: 2,
default_symbol_visibility: 1,
}
} else if edition == 1001 {
RawFeatures {
presence: 1,
enum_type: 1,
repeated_encoding: 1,
utf8: 2,
message_encoding: 1,
json_format: 1,
naming_style: 1,
default_symbol_visibility: 2,
}
} else if syntax == "editions" || edition == 1000 {
RawFeatures {
presence: 1,
enum_type: 1,
repeated_encoding: 1,
utf8: 2,
message_encoding: 1,
json_format: 1,
naming_style: 2,
default_symbol_visibility: 1,
}
} else {
RawFeatures {
presence: 1,
enum_type: 2,
repeated_encoding: 2,
utf8: 3,
message_encoding: 1,
json_format: 2,
naming_style: 2,
default_symbol_visibility: 1,
}
}
}
#[derive(Default)]
struct RawFile {
name: String,
package: String,
syntax: String,
edition: i32,
features: RawFeatures,
messages: Vec<RawMessage>,
enums: Vec<RawEnum>,
extensions: Vec<RawField>,
services: Vec<RawService>,
dependencies: Vec<String>,
public_dependency: Vec<i32>,
weak_dependency: Vec<i32>,
options: Vec<DescriptorOption>,
source_code_info: Option<SourceCodeInfo>,
comments: Comments,
deprecated: bool,
}
#[derive(Default, Clone)]
struct RawService {
name: String,
full_name: String,
methods: Vec<MethodDescriptor>,
method_features: Vec<RawFeatures>,
features: RawFeatures,
comments: Comments,
deprecated: bool,
options: Vec<DescriptorOption>,
}
#[derive(Default, Clone)]
struct RawField {
name: String,
number: u32,
label: i32,
ty: i32,
type_name: String,
json_name: String,
proto3_optional: bool,
packed: Option<bool>,
oneof_index: Option<u32>,
default_value: Option<String>,
extendee: String,
features: RawFeatures,
full_ext_name: String,
file_name: String,
options: Vec<DescriptorOption>,
comments: Comments,
deprecated: bool,
}
#[derive(Default, Clone)]
struct RawMessage {
name: String,
full_name: String,
fields: Vec<RawField>,
nested: Vec<RawMessage>,
is_map_entry: bool,
syntax_proto3: bool,
oneofs: Vec<RawOneof>,
enums: Vec<RawEnum>,
features: RawFeatures,
declared_visibility: u32,
effective_visibility: u32,
extensions: Vec<RawField>,
extension_ranges: Vec<(u32, u32)>,
reserved_names: Vec<String>,
file_name: String,
message_set_wire_format: bool,
options: Vec<DescriptorOption>,
comments: Comments,
deprecated: bool,
}
#[derive(Default, Clone)]
struct RawOneof {
name: String,
features: RawFeatures,
}
#[derive(Default, Clone)]
struct RawEnum {
name: String,
full_name: String,
file_name: String,
values: Vec<(i32, String)>,
value_features: Vec<RawFeatures>,
closed: bool,
features: RawFeatures,
declared_visibility: u32,
effective_visibility: u32,
options: Vec<DescriptorOption>,
comments: Comments,
value_comments: BTreeMap<i32, Comments>,
value_comments_by_name: BTreeMap<String, Comments>,
deprecated: bool,
deprecated_values: BTreeSet<i32>,
}
fn file_name_matches(wanted: &str, file_name: &str) -> bool {
if wanted == file_name {
return true;
}
let w = std::path::Path::new(wanted);
let f = std::path::Path::new(file_name);
w.file_name() == f.file_name() || wanted.ends_with(file_name) || file_name.ends_with(wanted)
}
fn parse_file_descriptor_set(bytes: &[u8]) -> Result<Vec<RawFile>, ParseError> {
let mut files = Vec::new();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
if n == 1 && w == WIRE_LEN {
let payload = read_len_bytes(bytes, &mut pos)?;
files.push(parse_file(payload)?);
} else {
wire::skip_field(bytes, &mut pos, w)?;
}
}
Ok(files)
}
fn parse_file(bytes: &[u8]) -> Result<RawFile, ParseError> {
let mut file = RawFile::default();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
match (n, w) {
(1, WIRE_LEN) => file.name = read_string(bytes, &mut pos)?,
(2, WIRE_LEN) => file.package = read_string(bytes, &mut pos)?,
(3, WIRE_LEN) => file.dependencies.push(read_string(bytes, &mut pos)?),
(10, WIRE_VARINT) => file
.public_dependency
.push(decode_varint(bytes, &mut pos)? as i32),
(11, WIRE_VARINT) => file
.weak_dependency
.push(decode_varint(bytes, &mut pos)? as i32),
(4, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
file.messages.push(parse_descriptor(payload, "")?);
}
(5, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
file.enums.push(parse_enum(payload, false)?);
}
(6, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
file.services.push(parse_service(payload)?);
}
(7, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
file.extensions.push(parse_field(payload)?);
}
(8, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
let (features, deprecated, options) = parse_file_options(payload)?;
file.features = features;
file.deprecated = deprecated;
file.options = options;
}
(9, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
file.source_code_info = Some(parse_source_code_info(payload)?);
}
(12, WIRE_LEN) => file.syntax = read_string(bytes, &mut pos)?,
(14, WIRE_VARINT) => {
file.edition = i32::try_from(decode_varint(bytes, &mut pos)?)
.map_err(|_| ParseError::new("protobuf edition out of range"))?;
}
_ => wire::skip_field(bytes, &mut pos, w)?,
}
}
if (file.edition > 1001 && file.edition != 9999)
|| (file.syntax == "editions" && !matches!(file.edition, 1000 | 1001 | 9999))
|| (file.edition == 1001 && file.syntax != "editions")
{
return Err(ParseError::new("unsupported or missing protobuf edition"));
}
if file.source_code_info.is_some() {
attach_source_code_info(&mut file);
}
let defaults = edition_defaults(&file.syntax, file.edition);
file.features = defaults.merge(file.features);
let proto3 = file.syntax == "proto3" || file.edition == 999;
mark_syntax(&mut file.messages, proto3, file.features, false)?;
prefix_names(&mut file.messages, &file.package);
for e in &mut file.enums {
e.features = file.features.merge(e.features);
e.closed = e.features.enum_type == 2;
e.effective_visibility = resolve_visibility(
e.declared_visibility,
e.features.default_symbol_visibility,
false,
)?;
e.file_name = file.name.clone();
e.full_name = if file.package.is_empty() {
e.name.clone()
} else {
format!("{}.{}", file.package, e.name)
};
}
prefix_enums_in_messages(&mut file.messages)?;
for ext in &mut file.extensions {
if ext.extendee.starts_with('.') {
ext.extendee = ext.extendee.trim_start_matches('.').to_string();
} else if !file.package.is_empty() && !ext.extendee.contains('.') {
ext.extendee = format!("{}.{}", file.package, ext.extendee);
}
ext.full_ext_name = if file.package.is_empty() {
ext.name.clone()
} else {
format!("{}.{}", file.package, ext.name)
};
ext.file_name = file.name.clone();
}
stamp_file(&mut file.messages, &file.name);
for svc in &mut file.services {
svc.full_name = if file.package.is_empty() {
svc.name.clone()
} else {
format!("{}.{}", file.package, svc.name)
};
for m in &mut svc.methods {
m.input_type = m.input_type.trim_start_matches('.').to_string();
m.output_type = m.output_type.trim_start_matches('.').to_string();
}
}
if file.edition == 1001 {
validate_edition2024_file(&file)?;
}
Ok(file)
}
#[derive(Clone, Copy)]
enum Edition2024NameCase {
Title,
LowerSnake,
UpperSnake,
}
fn validate_edition2024_name(
name: &str,
naming_style: u32,
case: Edition2024NameCase,
) -> Result<(), ParseError> {
if naming_style == 2 {
return Ok(());
}
if naming_style != 1 {
return Err(ParseError::new("unresolved Edition 2024 naming style"));
}
let valid = match case {
Edition2024NameCase::Title => {
let mut bytes = name.bytes();
bytes.next().is_some_and(|c| c.is_ascii_uppercase())
&& bytes.all(|c| c.is_ascii_alphanumeric())
}
Edition2024NameCase::LowerSnake => edition2024_snake_case(name, false),
Edition2024NameCase::UpperSnake => edition2024_snake_case(name, true),
};
if valid {
Ok(())
} else {
Err(ParseError::new("invalid Edition 2024 identifier"))
}
}
fn edition2024_snake_case(name: &str, upper: bool) -> bool {
let is_letter = |c: u8| {
if upper {
c.is_ascii_uppercase()
} else {
c.is_ascii_lowercase()
}
};
let mut bytes = name.bytes();
if !bytes.next().is_some_and(is_letter) {
return false;
}
let mut underscore = false;
for c in bytes {
if c == b'_' {
if underscore {
return false;
}
underscore = true;
} else if is_letter(c) {
underscore = false;
} else if c.is_ascii_digit() && !underscore {
} else {
return false;
}
}
!underscore
}
fn validate_edition2024_field(f: &RawField, parent: RawFeatures) -> Result<(), ParseError> {
if !matches!(f.label, 1 | 3)
|| f.number == 0
|| f.number > 536_870_911
|| (19_000..=19_999).contains(&f.number)
|| matches!(FieldType::from_i32(f.ty), None | Some(FieldType::Group))
|| f.proto3_optional
|| f.packed.is_some()
|| f.options.iter().any(|option| option.number == 1)
{
return Err(ParseError::new("unsupported Edition 2024 field"));
}
validate_edition2024_name(
&f.name,
parent.merge(f.features).naming_style,
Edition2024NameCase::LowerSnake,
)
}
fn validate_edition2024_enum(en: &RawEnum) -> Result<(), ParseError> {
validate_edition2024_name(
&en.name,
en.features.naming_style,
Edition2024NameCase::Title,
)?;
for ((_, name), features) in en.values.iter().zip(&en.value_features) {
validate_edition2024_name(
name,
en.features.merge(*features).naming_style,
Edition2024NameCase::UpperSnake,
)?;
}
Ok(())
}
fn validate_edition2024_message(msg: &RawMessage) -> Result<(), ParseError> {
validate_edition2024_name(
&msg.name,
msg.features.naming_style,
Edition2024NameCase::Title,
)?;
for field in msg.fields.iter().chain(&msg.extensions) {
validate_edition2024_field(field, msg.features)?;
if field
.oneof_index
.is_some_and(|index| index as usize >= msg.oneofs.len())
{
return Err(ParseError::new("unresolved Edition 2024 oneof"));
}
}
for oneof in &msg.oneofs {
validate_edition2024_name(
&oneof.name,
msg.features.merge(oneof.features).naming_style,
Edition2024NameCase::LowerSnake,
)?;
}
for en in &msg.enums {
validate_edition2024_enum(en)?;
}
for nested in &msg.nested {
validate_edition2024_message(nested)?;
}
Ok(())
}
fn validate_edition2024_file(file: &RawFile) -> Result<(), ParseError> {
if !file.weak_dependency.is_empty() || file.options.iter().any(|option| option.number == 10) {
return Err(ParseError::new("unsupported Edition 2024 file option"));
}
for msg in &file.messages {
validate_edition2024_message(msg)?;
}
for en in &file.enums {
validate_edition2024_enum(en)?;
}
for ext in &file.extensions {
validate_edition2024_field(ext, file.features)?;
}
for svc in &file.services {
let features = file.features.merge(svc.features);
validate_edition2024_name(&svc.name, features.naming_style, Edition2024NameCase::Title)?;
for (method, method_features) in svc.methods.iter().zip(&svc.method_features) {
validate_edition2024_name(
&method.name,
features.merge(*method_features).naming_style,
Edition2024NameCase::Title,
)?;
}
}
Ok(())
}
fn attach_source_code_info(file: &mut RawFile) {
let Some(sci) = file.source_code_info.clone() else {
return;
};
let mut path_map: BTreeMap<Vec<i32>, Comments> = BTreeMap::new();
for loc in &sci.locations {
let comments = Comments {
leading_comments: loc.leading_comments.clone(),
trailing_comments: loc.trailing_comments.clone(),
leading_detached_comments: loc.leading_detached_comments.clone(),
leading: loc.leading_comments.clone(),
trailing: loc.trailing_comments.clone(),
span: loc.span.clone(),
};
match path_map.entry(loc.path.clone()) {
std::collections::btree_map::Entry::Vacant(e) => {
e.insert(comments);
}
std::collections::btree_map::Entry::Occupied(mut e) => {
let existing = e.get_mut();
if existing.span.is_empty() && !comments.span.is_empty() {
existing.span = comments.span;
}
if existing.leading_comments.is_none() && comments.leading_comments.is_some() {
existing.leading_comments = comments.leading_comments;
existing.leading = comments.leading;
}
if existing.trailing_comments.is_none() && comments.trailing_comments.is_some() {
existing.trailing_comments = comments.trailing_comments;
existing.trailing = comments.trailing;
}
if existing.leading_detached_comments.is_empty()
&& !comments.leading_detached_comments.is_empty()
{
existing.leading_detached_comments = comments.leading_detached_comments;
}
}
}
}
let file_c = lookup_comments(&path_map, &[]);
if !file_c.is_empty() {
file.comments = file_c;
} else {
let syntax_c = lookup_comments(&path_map, &[12]);
if !syntax_c.is_empty() {
file.comments = syntax_c;
} else {
let pkg_c = lookup_comments(&path_map, &[2]);
if !pkg_c.is_empty() {
file.comments = pkg_c;
}
}
}
for (i, msg) in file.messages.iter_mut().enumerate() {
let path = [4, i as i32];
attach_message_comments(msg, &path, &path_map);
}
for (i, e) in file.enums.iter_mut().enumerate() {
let path = [5, i as i32];
attach_enum_comments(e, &path, &path_map);
}
for (i, svc) in file.services.iter_mut().enumerate() {
let path = [6, i as i32];
attach_service_comments(svc, &path, &path_map);
}
for (i, ext) in file.extensions.iter_mut().enumerate() {
let path = [7, i as i32];
ext.comments = lookup_comments(&path_map, &path);
}
}
fn attach_message_comments(
msg: &mut RawMessage,
path: &[i32],
path_map: &BTreeMap<Vec<i32>, Comments>,
) {
msg.comments = lookup_comments(path_map, path);
for (j, field) in msg.fields.iter_mut().enumerate() {
let mut field_path = path.to_vec();
field_path.push(2);
field_path.push(j as i32);
field.comments = lookup_comments(path_map, &field_path);
}
for (j, nested) in msg.nested.iter_mut().enumerate() {
let mut nested_path = path.to_vec();
nested_path.push(3);
nested_path.push(j as i32);
attach_message_comments(nested, &nested_path, path_map);
}
for (j, e) in msg.enums.iter_mut().enumerate() {
let mut enum_path = path.to_vec();
enum_path.push(4);
enum_path.push(j as i32);
attach_enum_comments(e, &enum_path, path_map);
}
for (j, ext) in msg.extensions.iter_mut().enumerate() {
let mut ext_path = path.to_vec();
ext_path.push(6);
ext_path.push(j as i32);
ext.comments = lookup_comments(path_map, &ext_path);
}
}
fn attach_enum_comments(e: &mut RawEnum, path: &[i32], path_map: &BTreeMap<Vec<i32>, Comments>) {
e.comments = lookup_comments(path_map, path);
for (j, val) in e.values.iter().enumerate() {
let mut val_path = path.to_vec();
val_path.push(2);
val_path.push(j as i32);
let comments = lookup_comments(path_map, &val_path);
e.value_comments.insert(val.0, comments.clone());
e.value_comments_by_name.insert(val.1.clone(), comments);
}
}
fn attach_service_comments(
svc: &mut RawService,
path: &[i32],
path_map: &BTreeMap<Vec<i32>, Comments>,
) {
svc.comments = lookup_comments(path_map, path);
for (j, method) in svc.methods.iter_mut().enumerate() {
let mut method_path = path.to_vec();
method_path.push(2);
method_path.push(j as i32);
method.comments = lookup_comments(path_map, &method_path);
}
}
fn lookup_comments(path_map: &BTreeMap<Vec<i32>, Comments>, path: &[i32]) -> Comments {
if let Some(c) = path_map.get(path) {
if !c.is_empty() || !c.span.is_empty() {
let mut res = c.clone();
if res.is_empty() {
let mut name_path = path.to_vec();
name_path.push(1);
if let Some(nc) = path_map.get(&name_path) {
if !nc.is_empty() {
res.leading_comments = nc.leading_comments.clone();
res.trailing_comments = nc.trailing_comments.clone();
res.leading_detached_comments = nc.leading_detached_comments.clone();
res.leading = nc.leading.clone();
res.trailing = nc.trailing.clone();
}
}
}
return res;
}
}
let mut name_path = path.to_vec();
name_path.push(1);
if let Some(c) = path_map.get(&name_path) {
return c.clone();
}
Comments::default()
}
fn parse_source_code_info(bytes: &[u8]) -> Result<SourceCodeInfo, ParseError> {
let mut info = SourceCodeInfo::default();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
match (n, w) {
(1, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
info.locations.push(parse_source_location(payload)?);
}
_ => wire::skip_field(bytes, &mut pos, w)?,
}
}
Ok(info)
}
fn parse_source_location(bytes: &[u8]) -> Result<SourceLocation, ParseError> {
let mut loc = SourceLocation::default();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
match (n, w) {
(1, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
let mut p_pos = 0;
while p_pos < payload.len() {
let v = decode_varint(payload, &mut p_pos)? as i32;
loc.path.push(v);
}
}
(1, WIRE_VARINT) => {
let v = decode_varint(bytes, &mut pos)? as i32;
loc.path.push(v);
}
(2, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
let mut p_pos = 0;
while p_pos < payload.len() {
let v = decode_varint(payload, &mut p_pos)? as i32;
loc.span.push(v);
}
}
(2, WIRE_VARINT) => {
let v = decode_varint(bytes, &mut pos)? as i32;
loc.span.push(v);
}
(3, WIRE_LEN) => {
loc.leading_comments = Some(read_string(bytes, &mut pos)?);
}
(4, WIRE_LEN) => {
loc.trailing_comments = Some(read_string(bytes, &mut pos)?);
}
(6, WIRE_LEN) => {
loc.leading_detached_comments
.push(read_string(bytes, &mut pos)?);
}
_ => wire::skip_field(bytes, &mut pos, w)?,
}
}
Ok(loc)
}
fn parse_service(bytes: &[u8]) -> Result<RawService, ParseError> {
let mut svc = RawService::default();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
match (n, w) {
(1, WIRE_LEN) => svc.name = read_string(bytes, &mut pos)?,
(2, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
let (method, features) = parse_method(payload)?;
svc.methods.push(method);
svc.method_features.push(features);
}
(3, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
let (deprecated, features, options) = parse_service_options(payload)?;
svc.deprecated = deprecated;
svc.features = features;
svc.options = options;
}
_ => wire::skip_field(bytes, &mut pos, w)?,
}
}
Ok(svc)
}
fn parse_method(bytes: &[u8]) -> Result<(MethodDescriptor, RawFeatures), ParseError> {
let mut m = MethodDescriptor::default();
let mut features = RawFeatures::default();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
match (n, w) {
(1, WIRE_LEN) => m.name = read_string(bytes, &mut pos)?,
(2, WIRE_LEN) => m.input_type = read_string(bytes, &mut pos)?,
(3, WIRE_LEN) => m.output_type = read_string(bytes, &mut pos)?,
(5, WIRE_VARINT) => m.client_streaming = decode_varint(bytes, &mut pos)? != 0,
(6, WIRE_VARINT) => m.server_streaming = decode_varint(bytes, &mut pos)? != 0,
(4, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
let (deprecated, method_features, options) = parse_method_options(payload)?;
m.deprecated = deprecated;
features = method_features;
m.options = options;
}
_ => wire::skip_field(bytes, &mut pos, w)?,
}
}
Ok((m, features))
}
fn stamp_file(msgs: &mut [RawMessage], file_name: &str) {
for m in msgs {
m.file_name = file_name.to_string();
stamp_file(&mut m.nested, file_name);
for e in &mut m.enums {
e.file_name = file_name.to_string();
}
for ext in &mut m.extensions {
ext.full_ext_name = format!("{}.{}", m.full_name, ext.name);
ext.file_name = file_name.to_string();
}
}
}
fn prefix_enums_in_messages(msgs: &mut [RawMessage]) -> Result<(), ParseError> {
for m in msgs {
for e in &mut m.enums {
e.features = m.features.merge(e.features);
e.closed = e.features.enum_type == 2;
e.effective_visibility = resolve_visibility(
e.declared_visibility,
e.features.default_symbol_visibility,
true,
)?;
e.full_name = format!("{}.{}", m.full_name, e.name);
}
prefix_enums_in_messages(&mut m.nested)?;
}
Ok(())
}
fn parse_descriptor(bytes: &[u8], _parent: &str) -> Result<RawMessage, ParseError> {
let mut msg = RawMessage::default();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
match (n, w) {
(1, WIRE_LEN) => msg.name = read_string(bytes, &mut pos)?,
(2, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
msg.fields.push(parse_field(payload)?);
}
(3, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
msg.nested.push(parse_descriptor(payload, "")?);
}
(4, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
msg.enums.push(parse_enum(payload, false)?);
}
(5, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
if let Some(range) = parse_extension_range(payload)? {
msg.extension_ranges.push(range);
}
}
(6, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
msg.extensions.push(parse_field(payload)?);
}
(8, WIRE_LEN) => {
msg.oneofs
.push(parse_oneof(read_len_bytes(bytes, &mut pos)?)?);
}
(7, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
let (map_entry, message_set, deprecated, features, options) =
parse_message_options(payload)?;
msg.is_map_entry = map_entry;
msg.message_set_wire_format = message_set;
msg.deprecated = deprecated;
msg.features = features;
msg.options = options;
}
(10, WIRE_LEN) => msg.reserved_names.push(read_string(bytes, &mut pos)?),
(11, WIRE_VARINT) => {
msg.declared_visibility = parse_declared_visibility(bytes, &mut pos)?;
}
(11, _) => return Err(ParseError::new("invalid message visibility wire type")),
_ => wire::skip_field(bytes, &mut pos, w)?,
}
}
Ok(msg)
}
fn parse_oneof(bytes: &[u8]) -> Result<RawOneof, ParseError> {
let mut oneof = RawOneof::default();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
match (n, w) {
(1, WIRE_LEN) => oneof.name = read_string(bytes, &mut pos)?,
(2, WIRE_LEN) => {
let options = read_len_bytes(bytes, &mut pos)?;
let mut options_pos = 0;
while options_pos < options.len() {
let (n, w) = decode_tag(options, &mut options_pos)?;
if n == 1 && w == WIRE_LEN {
oneof.features = oneof.features.merge(parse_features(
read_len_bytes(options, &mut options_pos)?,
FeatureTarget::Oneof,
)?);
} else if n == 1 {
return Err(ParseError::new("invalid OneofOptions.features wire type"));
} else {
wire::skip_field(options, &mut options_pos, w)?;
}
}
}
(2, _) => return Err(ParseError::new("invalid oneof options wire type")),
_ => wire::skip_field(bytes, &mut pos, w)?,
}
}
Ok(oneof)
}
fn parse_field(bytes: &[u8]) -> Result<RawField, ParseError> {
let mut f = RawField::default();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
match (n, w) {
(1, WIRE_LEN) => f.name = read_string(bytes, &mut pos)?,
(2, WIRE_LEN) => f.extendee = read_string(bytes, &mut pos)?,
(3, WIRE_VARINT) => {
f.number = u32::try_from(decode_varint(bytes, &mut pos)?)
.map_err(|_| ParseError::new("field number out of range"))?;
}
(4, WIRE_VARINT) => {
f.label = i32::try_from(decode_varint(bytes, &mut pos)?)
.map_err(|_| ParseError::new("field label out of range"))?;
}
(5, WIRE_VARINT) => {
f.ty = i32::try_from(decode_varint(bytes, &mut pos)?)
.map_err(|_| ParseError::new("field type out of range"))?;
}
(6, WIRE_LEN) => f.type_name = read_string(bytes, &mut pos)?,
(7, WIRE_LEN) => f.default_value = Some(read_string(bytes, &mut pos)?),
(9, WIRE_VARINT) => {
f.oneof_index = Some(
u32::try_from(decode_varint(bytes, &mut pos)?)
.map_err(|_| ParseError::new("oneof index out of range"))?,
);
}
(10, WIRE_LEN) => f.json_name = read_string(bytes, &mut pos)?,
(8, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
let (packed, deprecated, features, options) = parse_field_options(payload)?;
f.packed = packed;
f.deprecated = deprecated;
f.features = features;
f.options = options;
}
(17, WIRE_VARINT) => f.proto3_optional = decode_varint(bytes, &mut pos)? != 0,
_ => wire::skip_field(bytes, &mut pos, w)?,
}
}
Ok(f)
}
fn parse_message_options(
bytes: &[u8],
) -> Result<(bool, bool, bool, RawFeatures, Vec<DescriptorOption>), ParseError> {
let mut map_entry = false;
let mut message_set = false;
let mut deprecated = false;
let mut features = RawFeatures::default();
let mut options = Vec::new();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
match (n, w) {
(1, WIRE_VARINT) => message_set = decode_varint(bytes, &mut pos)? != 0,
(3, WIRE_VARINT) => deprecated = decode_varint(bytes, &mut pos)? != 0,
(7, WIRE_VARINT) => map_entry = decode_varint(bytes, &mut pos)? != 0,
(12, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
features = features.merge(parse_features(payload, FeatureTarget::Message)?);
}
(12, _) => return Err(ParseError::new("invalid MessageOptions.features wire type")),
_ => options.push(DescriptorOption {
number: n,
value: capture_option_value(bytes, &mut pos, w)?,
}),
}
}
Ok((map_entry, message_set, deprecated, features, options))
}
fn parse_field_options(
bytes: &[u8],
) -> Result<(Option<bool>, bool, RawFeatures, Vec<DescriptorOption>), ParseError> {
let mut packed = None;
let mut deprecated = false;
let mut features = RawFeatures::default();
let mut options = Vec::new();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
match (n, w) {
(2, WIRE_VARINT) => packed = Some(decode_varint(bytes, &mut pos)? != 0),
(3, WIRE_VARINT) => deprecated = decode_varint(bytes, &mut pos)? != 0,
(21, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
features = features.merge(parse_features(payload, FeatureTarget::Field)?);
}
(21, _) => return Err(ParseError::new("invalid FieldOptions.features wire type")),
_ => options.push(DescriptorOption {
number: n,
value: capture_option_value(bytes, &mut pos, w)?,
}),
}
}
Ok((packed, deprecated, features, options))
}
fn capture_option_value(bytes: &[u8], pos: &mut usize, w: u32) -> Result<Vec<u8>, ParseError> {
match w {
WIRE_VARINT => {
let v = decode_varint(bytes, pos)?;
let mut out = Vec::new();
encode_varint(&mut out, v);
Ok(out)
}
WIRE_LEN => Ok(read_len_bytes(bytes, pos)?.to_vec()),
WIRE_I32 => {
let v = read_fixed32(bytes, pos)?;
Ok(v.to_le_bytes().to_vec())
}
WIRE_I64 => {
let v = read_fixed64(bytes, pos)?;
Ok(v.to_le_bytes().to_vec())
}
_ => {
wire::skip_field(bytes, pos, w)?;
Ok(Vec::new())
}
}
}
fn parse_file_options(
bytes: &[u8],
) -> Result<(RawFeatures, bool, Vec<DescriptorOption>), ParseError> {
let mut features = RawFeatures::default();
let mut deprecated = false;
let mut options = Vec::new();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
if n == 50 {
if w != WIRE_LEN {
return Err(ParseError::new("invalid FileOptions.features wire type"));
}
let payload = read_len_bytes(bytes, &mut pos)?;
features = features.merge(parse_features(payload, FeatureTarget::File)?);
} else if n == 23 && w == WIRE_VARINT {
deprecated = decode_varint(bytes, &mut pos)? != 0;
} else {
options.push(DescriptorOption {
number: n,
value: capture_option_value(bytes, &mut pos, w)?,
});
}
}
Ok((features, deprecated, options))
}
fn parse_enum_options(
bytes: &[u8],
) -> Result<(bool, RawFeatures, Vec<DescriptorOption>), ParseError> {
let mut deprecated = false;
let mut features = RawFeatures::default();
let mut options = Vec::new();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
if n == 7 {
if w != WIRE_LEN {
return Err(ParseError::new("invalid EnumOptions.features wire type"));
}
features = features.merge(parse_features(
read_len_bytes(bytes, &mut pos)?,
FeatureTarget::Enum,
)?);
} else if n == 2 && w == WIRE_VARINT {
deprecated = decode_varint(bytes, &mut pos)? != 0;
} else {
options.push(DescriptorOption {
number: n,
value: capture_option_value(bytes, &mut pos, w)?,
});
}
}
Ok((deprecated, features, options))
}
fn parse_method_options(
bytes: &[u8],
) -> Result<(bool, RawFeatures, Vec<DescriptorOption>), ParseError> {
let mut deprecated = false;
let mut features = RawFeatures::default();
let mut options = Vec::new();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
if n == 35 {
if w != WIRE_LEN {
return Err(ParseError::new("invalid MethodOptions.features wire type"));
}
features = features.merge(parse_features(
read_len_bytes(bytes, &mut pos)?,
FeatureTarget::Method,
)?);
} else if n == 33 && w == WIRE_VARINT {
deprecated = decode_varint(bytes, &mut pos)? != 0;
} else {
options.push(DescriptorOption {
number: n,
value: capture_option_value(bytes, &mut pos, w)?,
});
}
}
Ok((deprecated, features, options))
}
fn parse_service_options(
bytes: &[u8],
) -> Result<(bool, RawFeatures, Vec<DescriptorOption>), ParseError> {
let mut deprecated = false;
let mut features = RawFeatures::default();
let mut options = Vec::new();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
if n == 34 && w == WIRE_LEN {
features = features.merge(parse_features(
read_len_bytes(bytes, &mut pos)?,
FeatureTarget::Service,
)?);
} else if n == 34 {
return Err(ParseError::new("invalid ServiceOptions.features wire type"));
} else if n == 33 && w == WIRE_VARINT {
deprecated = decode_varint(bytes, &mut pos)? != 0;
} else {
options.push(DescriptorOption {
number: n,
value: capture_option_value(bytes, &mut pos, w)?,
});
}
}
Ok((deprecated, features, options))
}
#[derive(Clone, Copy)]
enum FeatureTarget {
File,
Message,
Field,
Enum,
EnumValue,
Oneof,
ExtensionRange,
Service,
Method,
}
fn parse_features(bytes: &[u8], target: FeatureTarget) -> Result<RawFeatures, ParseError> {
let mut f = RawFeatures::default();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
if (1000..=1004).contains(&n) && w == WIRE_LEN {
wire::skip_field(bytes, &mut pos, w)?;
continue;
}
let allowed = match n {
1 | 3..=5 => matches!(target, FeatureTarget::File | FeatureTarget::Field),
2 => matches!(target, FeatureTarget::File | FeatureTarget::Enum),
6 => matches!(
target,
FeatureTarget::File | FeatureTarget::Message | FeatureTarget::Enum
),
7 => true,
8 => matches!(target, FeatureTarget::File),
_ => return Err(ParseError::new("unrecognized protobuf feature")),
};
if !allowed || w != WIRE_VARINT {
return Err(ParseError::new(
"invalid protobuf feature target or wire type",
));
}
let v = u32::try_from(decode_varint(bytes, &mut pos)?)
.map_err(|_| ParseError::new("protobuf feature value out of range"))?;
let valid = match n {
1 => matches!(v, 1..=3),
2 | 3 | 5 | 6 | 7 => matches!(v, 1 | 2),
4 => matches!(v, 2 | 3),
8 => matches!(v, 1..=3),
_ => false,
};
if !valid {
return Err(ParseError::new("unsupported protobuf feature value"));
}
match n {
1 => f.presence = v,
2 => f.enum_type = v,
3 => f.repeated_encoding = v,
4 => f.utf8 = v,
5 => f.message_encoding = v,
6 => f.json_format = v,
7 => f.naming_style = v,
8 => f.default_symbol_visibility = v,
_ => return Err(ParseError::new("unrecognized protobuf feature")),
}
}
Ok(f)
}
fn parse_extension_range(bytes: &[u8]) -> Result<Option<(u32, u32)>, ParseError> {
let mut start = 0u32;
let mut end = 0u32;
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
match (n, w) {
(1, WIRE_VARINT) => start = decode_varint(bytes, &mut pos)? as u32,
(2, WIRE_VARINT) => end = decode_varint(bytes, &mut pos)? as u32,
(3, WIRE_LEN) => {
let options = read_len_bytes(bytes, &mut pos)?;
let mut options_pos = 0;
while options_pos < options.len() {
let (n, w) = decode_tag(options, &mut options_pos)?;
if n == 50 && w == WIRE_LEN {
let _ = parse_features(
read_len_bytes(options, &mut options_pos)?,
FeatureTarget::ExtensionRange,
)?;
} else if n == 50 {
return Err(ParseError::new("invalid ExtensionRangeOptions.features"));
} else {
wire::skip_field(options, &mut options_pos, w)?;
}
}
}
(3, _) => return Err(ParseError::new("invalid extension range options wire type")),
_ => wire::skip_field(bytes, &mut pos, w)?,
}
}
Ok(if end > start {
Some((start, end))
} else {
None
})
}
fn parse_enum(bytes: &[u8], closed: bool) -> Result<RawEnum, ParseError> {
let mut e = RawEnum {
closed,
..RawEnum::default()
};
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
match (n, w) {
(1, WIRE_LEN) => e.name = read_string(bytes, &mut pos)?,
(2, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
let (num, name, dep, features) = parse_enum_value(payload)?;
e.values.push((num, name));
e.value_features.push(features);
if dep {
e.deprecated_values.insert(num);
}
}
(3, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
let (deprecated, features, options) = parse_enum_options(payload)?;
e.deprecated = deprecated;
e.features = features;
e.options = options;
}
(6, WIRE_VARINT) => {
e.declared_visibility = parse_declared_visibility(bytes, &mut pos)?;
}
(6, _) => return Err(ParseError::new("invalid enum visibility wire type")),
_ => wire::skip_field(bytes, &mut pos, w)?,
}
}
Ok(e)
}
fn parse_enum_value(bytes: &[u8]) -> Result<(i32, String, bool, RawFeatures), ParseError> {
let mut name = String::new();
let mut number = 0i32;
let mut deprecated = false;
let mut features = RawFeatures::default();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
match (n, w) {
(1, WIRE_LEN) => name = read_string(bytes, &mut pos)?,
(2, WIRE_VARINT) => number = decode_varint(bytes, &mut pos)? as i32,
(3, WIRE_LEN) => {
let payload = read_len_bytes(bytes, &mut pos)?;
(deprecated, features) = parse_enum_value_options(payload)?;
}
_ => wire::skip_field(bytes, &mut pos, w)?,
}
}
Ok((number, name, deprecated, features))
}
fn parse_enum_value_options(bytes: &[u8]) -> Result<(bool, RawFeatures), ParseError> {
let mut deprecated = false;
let mut features = RawFeatures::default();
let mut pos = 0;
while pos < bytes.len() {
let (n, w) = decode_tag(bytes, &mut pos)?;
if n == 2 && w == WIRE_LEN {
features = features.merge(parse_features(
read_len_bytes(bytes, &mut pos)?,
FeatureTarget::EnumValue,
)?);
} else if n == 2 {
return Err(ParseError::new(
"invalid EnumValueOptions.features wire type",
));
} else if n == 1 && w == WIRE_VARINT {
deprecated = decode_varint(bytes, &mut pos)? != 0;
} else {
wire::skip_field(bytes, &mut pos, w)?;
}
}
Ok((deprecated, features))
}
fn read_string(bytes: &[u8], pos: &mut usize) -> Result<String, ParseError> {
let b = read_len_bytes(bytes, pos)?;
Ok(String::from_utf8_lossy(b).into_owned())
}
fn mark_syntax(
msgs: &mut [RawMessage],
proto3: bool,
features: RawFeatures,
nested: bool,
) -> Result<(), ParseError> {
for m in msgs {
m.syntax_proto3 = proto3;
m.features = features.merge(m.features);
m.effective_visibility = resolve_visibility(
m.declared_visibility,
m.features.default_symbol_visibility,
nested,
)?;
mark_syntax(&mut m.nested, proto3, m.features, true)?;
}
Ok(())
}
fn prefix_names(msgs: &mut [RawMessage], package: &str) {
for m in msgs {
m.full_name = if package.is_empty() {
m.name.clone()
} else {
format!("{package}.{}", m.name)
};
prefix_names(&mut m.nested, &m.full_name);
}
}
fn collect_raw(
file: &RawFile,
out: &mut BTreeMap<String, RawMessage>,
enums: &mut BTreeMap<String, RawEnum>,
extensions: &mut Vec<(RawFeatures, RawField)>,
) {
fn walk(
m: &RawMessage,
out: &mut BTreeMap<String, RawMessage>,
enums: &mut BTreeMap<String, RawEnum>,
extensions: &mut Vec<(RawFeatures, RawField)>,
) {
out.insert(m.full_name.clone(), m.clone());
for e in &m.enums {
enums.insert(e.full_name.clone(), e.clone());
}
for ext in &m.extensions {
extensions.push((m.features, ext.clone()));
}
for n in &m.nested {
walk(n, out, enums, extensions);
}
}
for e in &file.enums {
enums.insert(e.full_name.clone(), e.clone());
}
for ext in &file.extensions {
extensions.push((file.features, ext.clone()));
}
for m in &file.messages {
walk(m, out, enums, extensions);
}
}
fn check_visible_from_file(
source_file: &str,
target_file: &str,
target_visibility: u32,
) -> Result<(), ParseError> {
if source_file != target_file && target_visibility == VISIBILITY_LOCAL {
Err(ParseError::new("cross-file reference to local symbol"))
} else {
Ok(())
}
}
fn check_symbol_visible_from_file(
source_file: &str,
target_file: &str,
full_name: &str,
metadata: &BTreeMap<String, SymbolMetadata>,
) -> Result<(), ParseError> {
let visibility = metadata
.get(full_name)
.ok_or_else(|| ParseError::new("unresolved symbol visibility"))?;
check_visible_from_file(source_file, target_file, visibility.effective_visibility)
}
fn check_edition2024_reference(
pool: &DescriptorPool,
source_file: &str,
imports: &BTreeSet<String>,
name: &str,
expected_type: FieldType,
) -> Result<(), ParseError> {
let name = name.trim_start_matches('.');
let target_file = match expected_type {
FieldType::Message => pool.messages.get(name).map(|desc| desc.file_name.as_str()),
FieldType::Enum => pool.enums.get(name).map(|desc| desc.file_name.as_str()),
_ => return Err(ParseError::new("unsupported Edition 2024 reference type")),
}
.ok_or_else(|| ParseError::new("unresolved Edition 2024 type reference"))?;
if source_file != target_file {
if !imports.contains(target_file) {
return Err(ParseError::new("Edition 2024 type is not imported"));
}
check_symbol_visible_from_file(source_file, target_file, name, &pool.symbol_metadata)?;
}
Ok(())
}
fn check_edition2024_field_references(
field: &RawField,
source_file: &str,
imports: &BTreeSet<String>,
pool: &DescriptorPool,
) -> Result<(), ParseError> {
match FieldType::from_i32(field.ty) {
Some(ty @ (FieldType::Message | FieldType::Enum)) => {
check_edition2024_reference(pool, source_file, imports, &field.type_name, ty)?;
}
Some(_) if field.type_name.is_empty() => {}
_ => return Err(ParseError::new("invalid Edition 2024 field type reference")),
}
if !field.extendee.is_empty() {
check_edition2024_reference(
pool,
source_file,
imports,
&field.extendee,
FieldType::Message,
)?;
}
Ok(())
}
fn check_edition2024_message_references(
msg: &RawMessage,
source_file: &str,
imports: &BTreeSet<String>,
pool: &DescriptorPool,
) -> Result<(), ParseError> {
for field in msg.fields.iter().chain(&msg.extensions) {
check_edition2024_field_references(field, source_file, imports, pool)?;
}
for nested in &msg.nested {
check_edition2024_message_references(nested, source_file, imports, pool)?;
}
Ok(())
}
fn validate_edition2024_references(
files: &[RawFile],
pool: &DescriptorPool,
) -> Result<(), ParseError> {
let by_name: BTreeMap<&str, &RawFile> = files
.iter()
.map(|file| (file.name.as_str(), file))
.collect();
for file in files.iter().filter(|file| file.edition == 1001) {
let mut imports = BTreeSet::new();
let mut pending = file.dependencies.clone();
while let Some(name) = pending.pop() {
if !imports.insert(name.clone()) {
continue;
}
if let Some(imported) = by_name.get(name.as_str()) {
for index in &imported.public_dependency {
if let Some(dependency) = usize::try_from(*index)
.ok()
.and_then(|index| imported.dependencies.get(index))
{
pending.push(dependency.clone());
}
}
}
}
for msg in &file.messages {
check_edition2024_message_references(msg, &file.name, &imports, pool)?;
}
for field in &file.extensions {
check_edition2024_field_references(field, &file.name, &imports, pool)?;
}
for service in &file.services {
for method in &service.methods {
for name in [&method.input_type, &method.output_type] {
check_edition2024_reference(
pool,
&file.name,
&imports,
name,
FieldType::Message,
)?;
}
}
}
}
Ok(())
}
fn resolve_pool(
raw: BTreeMap<String, RawMessage>,
raw_enums: BTreeMap<String, RawEnum>,
extensions: Vec<(RawFeatures, RawField)>,
edition2024_files: &BTreeSet<String>,
) -> Result<DescriptorPool, ParseError> {
let mut skeletons: BTreeMap<String, MessageDescriptor> = BTreeMap::new();
let mut symbol_metadata = BTreeMap::new();
for (name, raw_msg) in &raw {
symbol_metadata.insert(
name.clone(),
SymbolMetadata {
features: raw_msg.features,
declared_visibility: raw_msg.declared_visibility,
effective_visibility: raw_msg.effective_visibility,
},
);
let mut b = MessageDescriptor::builder(name.clone()).map_entry(raw_msg.is_map_entry);
let mut oneofs: Vec<Vec<u32>> = vec![Vec::new(); raw_msg.oneofs.len()];
for f in &raw_msg.fields {
let fd = raw_field_to_desc(
f,
raw_msg.features,
edition2024_files.contains(&raw_msg.file_name),
);
if let Some(idx) = fd.oneof_index {
if let Some(slot) = oneofs.get_mut(idx as usize) {
slot.push(fd.number);
}
}
b = b.field(fd);
}
let mut built = b.build();
built.oneofs = oneofs;
built.extension_ranges = raw_msg.extension_ranges.clone();
built.reserved_names = raw_msg.reserved_names.iter().cloned().collect();
built.message_set_wire_format = raw_msg.message_set_wire_format;
built.file_name = raw_msg.file_name.clone();
built.options = raw_msg.options.clone();
built.comments = raw_msg.comments.clone();
built.deprecated = raw_msg.deprecated;
skeletons.insert(name.clone(), built);
}
let mut enum_arcs: BTreeMap<String, Arc<EnumDescriptor>> = BTreeMap::new();
for (name, raw_e) in &raw_enums {
symbol_metadata.insert(
name.clone(),
SymbolMetadata {
features: raw_e.features,
declared_visibility: raw_e.declared_visibility,
effective_visibility: raw_e.effective_visibility,
},
);
let mut ed = EnumDescriptor {
name: raw_e.name.clone(),
full_name: name.clone(),
file_name: raw_e.file_name.clone(),
values: BTreeMap::new(),
names: BTreeMap::new(),
listed: raw_e.values.clone(),
closed: raw_e.closed,
options: raw_e.options.clone(),
comments: raw_e.comments.clone(),
value_comments: raw_e.value_comments.clone(),
value_comments_by_name: raw_e.value_comments_by_name.clone(),
deprecated: raw_e.deprecated,
deprecated_values: raw_e.deprecated_values.clone(),
};
for (num, n) in &raw_e.values {
ed.values.entry(*num).or_insert_with(|| n.clone());
ed.names.insert(n.clone(), *num);
}
enum_arcs.insert(name.clone(), Arc::new(ed));
}
let mut ext_index: BTreeMap<String, (String, u32, String)> = BTreeMap::new();
for (parent_feat, ext) in &extensions {
let fd = raw_field_to_desc(
ext,
*parent_feat,
edition2024_files.contains(&ext.file_name),
);
let extendee = fd
.extendee
.as_deref()
.unwrap_or("")
.trim_start_matches('.')
.to_string();
if let Some(type_name) = fd.type_name.as_deref() {
let key = type_name.trim_start_matches('.');
if let Some(target) = skeletons.get(key) {
check_symbol_visible_from_file(
&ext.file_name,
&target.file_name,
key,
&symbol_metadata,
)?;
}
if let Some(target) = enum_arcs.get(key) {
check_symbol_visible_from_file(
&ext.file_name,
&target.file_name,
key,
&symbol_metadata,
)?;
}
}
if let Some(desc) = skeletons.get_mut(&extendee) {
if !ext.file_name.is_empty() {
check_symbol_visible_from_file(
&ext.file_name,
&desc.file_name,
&extendee,
&symbol_metadata,
)?;
}
desc.fields_by_name
.entry(fd.name.clone())
.or_insert(fd.number);
if !fd.json_name.is_empty() {
desc.fields_by_json_name
.entry(fd.json_name.clone())
.or_insert(fd.number);
}
let full = format!("{extendee}.{}", fd.name);
desc.fields_by_name.insert(full, fd.number);
if !ext.full_ext_name.is_empty() {
desc.fields_by_name
.insert(ext.full_ext_name.clone(), fd.number);
let file = if ext.file_name.is_empty() {
desc.file_name.clone()
} else {
ext.file_name.clone()
};
ext_index.insert(
ext.full_ext_name.clone(),
(extendee.clone(), fd.number, file),
);
}
desc.fields.insert(fd.number, fd);
}
}
let lookup: BTreeMap<String, Arc<MessageDescriptor>> = skeletons
.iter()
.map(|(k, v)| (k.clone(), Arc::new(v.clone())))
.collect();
let mut resolved = BTreeMap::new();
for (name, mut d) in skeletons {
for field in d.fields.values_mut() {
if let Some(tn) = &field.type_name {
let key = tn.trim_start_matches('.');
if let Some(target) = lookup.get(key) {
check_symbol_visible_from_file(
&d.file_name,
&target.file_name,
key,
&symbol_metadata,
)?;
field.message = Some(target.clone());
if target.is_map_entry {
field.is_map = true;
field.cardinality = Cardinality::Repeated;
field.packed = false;
field.delimited = false;
}
}
if field.field_type == FieldType::Enum || field.message.is_none() {
if let Some(en) = enum_arcs.get(key) {
check_symbol_visible_from_file(
&d.file_name,
&en.file_name,
key,
&symbol_metadata,
)?;
field.enum_ty = Some(en.clone());
field.field_type = FieldType::Enum;
}
}
}
}
if d.is_map_entry {
for field in d.fields.values_mut() {
field.delimited = false;
}
}
let mut alts = Vec::new();
for field in d.fields.values() {
if field.extension_name.is_some() {
continue;
}
if field.field_type == FieldType::Group || field.delimited {
if let Some(tn) = &field.type_name {
let short = tn.rsplit('.').next().unwrap_or(tn);
alts.push((short.to_string(), field.number));
alts.push((short.to_ascii_lowercase(), field.number));
}
}
}
for (alt, n) in alts {
d.fields_by_name.entry(alt).or_insert(n);
}
resolved.insert(name, Arc::new(d));
}
Ok(DescriptorPool {
messages: resolved,
enums: enum_arcs,
extensions_by_name: ext_index,
services: BTreeMap::new(),
files: BTreeMap::new(),
public_imports: BTreeMap::new(),
file_metadata: BTreeMap::new(),
symbol_metadata,
})
}
fn raw_field_to_desc(f: &RawField, parent: RawFeatures, edition2024: bool) -> FieldDescriptor {
let feat = parent.merge(f.features);
let mut field_type = FieldType::from_i32(f.ty).unwrap_or(FieldType::Message);
if f.ty == 0 && !f.type_name.is_empty() {
field_type = FieldType::Message;
}
let cardinality = match f.label {
3 => Cardinality::Repeated,
2 => Cardinality::Required,
_ if feat.presence == 3 => Cardinality::Required,
_ => Cardinality::Optional,
};
let presence = if cardinality == Cardinality::Repeated
|| field_type == FieldType::Message
|| field_type == FieldType::Group
|| f.proto3_optional
|| f.oneof_index.is_some()
|| feat.presence == 1
|| feat.presence == 3
{
Presence::Explicit
} else {
Presence::Implicit
};
let packed = f.packed.unwrap_or(
cardinality == Cardinality::Repeated
&& field_type.is_packable()
&& feat.repeated_encoding == 1,
);
FieldDescriptor {
name: f.name.clone(),
number: f.number,
field_type,
cardinality,
presence,
packed,
type_name: if f.type_name.is_empty() {
None
} else {
Some(f.type_name.clone())
},
json_name: if f.json_name.is_empty() {
f.name.clone()
} else {
f.json_name.clone()
},
is_map: false,
message: None,
enum_ty: None,
oneof_index: f.oneof_index,
utf8_validate: feat.utf8 == 2 && (!edition2024 || field_type == FieldType::String),
default: f.default_value.clone(),
extendee: if f.extendee.is_empty() {
None
} else {
Some(f.extendee.clone())
},
delimited: field_type == FieldType::Group
|| (feat.message_encoding == 2 && field_type == FieldType::Message),
extension_name: if f.full_ext_name.is_empty() {
None
} else {
Some(f.full_ext_name.clone())
},
options: f.options.clone(),
comments: f.comments.clone(),
deprecated: f.deprecated,
}
}