mirror of
https://github.com/protocolbuffers/protobuf
synced 2026-08-26 02:23:14 -04:00
Cherrypick crate fixes from 36.x to main
Closes #29397
COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/29397 from protocolbuffers:forward_port_crate_swap 2b5bb9fe65
PiperOrigin-RevId: 970589358
187 lines
6.7 KiB
Rust
187 lines
6.7 KiB
Rust
// Protocol Buffers - Google's data interchange format
|
|
// Copyright 2023 Google LLC. All rights reserved.
|
|
//
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file or at
|
|
// https://developers.google.com/open-source/licenses/bsd
|
|
|
|
//! Kernel-agnostic logic for the Rust Protobuf runtime that should not be
|
|
//! exposed to through the `protobuf` path but must be public for use by
|
|
//! generated code.
|
|
|
|
// Used by the proto! macro
|
|
pub use paste::paste;
|
|
|
|
pub use crate::codegen_traits::entity_tag;
|
|
pub use crate::codegen_traits::EntityType;
|
|
pub use crate::extension::{new_extension_id, new_message_extension_id, new_repeated_extension_id};
|
|
pub use crate::r#enum::Enum;
|
|
use crate::repeated::RepeatedView;
|
|
use crate::singular::Singular;
|
|
pub use crate::ProtoStr;
|
|
use crate::{MapKey, MapValue, MapView};
|
|
pub use std::fmt::Debug;
|
|
|
|
#[doc(hidden)]
|
|
pub mod ext {
|
|
pub use crate::extension::{ExtAccess, ExtClear, ExtGetMut, ExtHas};
|
|
}
|
|
|
|
#[cfg(all(bzl, cpp_kernel))]
|
|
#[path = "cpp_kernel/mod.rs"]
|
|
pub mod runtime;
|
|
#[cfg(any(not(bzl), upb_kernel))]
|
|
#[path = "upb_kernel/mod.rs"]
|
|
pub mod runtime;
|
|
|
|
/// Used to protect internal-only items from being used accidentally.
|
|
#[derive(Debug)]
|
|
pub struct Private;
|
|
|
|
/// A trait that is used as a subtrait of traits that we intend to be used but
|
|
/// not be implemented by users.
|
|
///
|
|
/// This is slightly less 'sealed' than the typical sealed trait pattern would
|
|
/// permit in other crates; this trait is intended to be available to crates
|
|
/// which were generated by protoc, but not to application code.
|
|
///
|
|
/// We require Sized as a supertrait, because we generally do not want our
|
|
/// traits to support trait objects.
|
|
pub trait SealedInternal: Sized {}
|
|
|
|
impl<T: SealedInternal> SealedInternal for &T {}
|
|
impl<T: SealedInternal> SealedInternal for &mut T {}
|
|
|
|
/// A trait used by the proto_eq() gtest macro.
|
|
pub trait MatcherEq: SealedInternal + Debug {
|
|
fn matches(&self, o: &Self) -> bool;
|
|
fn matches_partially(&self, expected: &Self) -> bool;
|
|
}
|
|
|
|
/// Used by the proto! macro to get a default value for a repeated field.
|
|
pub fn get_repeated_default_value<T: Singular + Default>(_: Private, _: RepeatedView<'_, T>) -> T {
|
|
Default::default()
|
|
}
|
|
|
|
/// Used by the proto! macro to get a default value for a map field.
|
|
pub fn get_map_default_value<K: MapKey, V: MapValue + Default>(
|
|
_: Private,
|
|
_: MapView<'_, K, V>,
|
|
) -> V {
|
|
Default::default()
|
|
}
|
|
|
|
// Given a version string of the form "x.y.z" with an optional "-rc.n" suffix,
|
|
// returns the tuple (x, y, z, n).
|
|
//
|
|
// This function is not fully robust against malformed version strings, but
|
|
// that is fine since we only call it at compile time.
|
|
#[cfg(not(bzl))]
|
|
const fn split_version(version: &str) -> (u32, u32, u32, u32) {
|
|
let version = version.as_bytes();
|
|
let mut result: [u32; 4] = [0, 0, 0, 0];
|
|
|
|
let mut result_index = 0;
|
|
let mut i = 0;
|
|
while result_index < result.len() && i < version.len() {
|
|
if version[i] == b'.' {
|
|
// Done with one component, so let's move on to the next one.
|
|
result_index += 1;
|
|
} else if version[i] >= b'0' && version[i] <= b'9' {
|
|
// Shift the previous digits one decimal place to the left and add
|
|
// this digit.
|
|
result[result_index] = result[result_index] * 10 + (version[i] - b'0') as u32;
|
|
}
|
|
i += 1;
|
|
}
|
|
|
|
(result[0], result[1], result[2], result[3])
|
|
}
|
|
|
|
// Indicates whether the given gencode and runtime versions are compatible with
|
|
// each other. Generally they are compatible if the gencode is no newer than the
|
|
// runtime.
|
|
#[cfg(not(bzl))]
|
|
const fn are_versions_compatible(gencode: &str, runtime: &str) -> bool {
|
|
let gencode = split_version(gencode);
|
|
let runtime = split_version(runtime);
|
|
|
|
if gencode.0 != runtime.0 {
|
|
return gencode.0 < runtime.0;
|
|
}
|
|
if gencode.1 != runtime.1 {
|
|
return gencode.1 < runtime.1;
|
|
}
|
|
if gencode.2 != runtime.2 {
|
|
return gencode.2 < runtime.2;
|
|
}
|
|
|
|
// The last component is the release candidate version, or zero if it is not
|
|
// a release candidate. This is a special case, since zero is logically
|
|
// newer than any other number.
|
|
let gencode_rc = if gencode.3 == 0 { u32::MAX } else { gencode.3 };
|
|
let runtime_rc = if runtime.3 == 0 { u32::MAX } else { runtime.3 };
|
|
|
|
gencode_rc <= runtime_rc
|
|
}
|
|
|
|
/// A function that is used to assert that the generated code is compatible with
|
|
/// the current runtime version. We require that the generated code cannot be
|
|
/// newer than the runtime version.
|
|
///
|
|
/// If you are seeing this fail, it means that your generated code was built
|
|
/// with a protoc version newer than the runtime crate version.
|
|
#[cfg(not(bzl))]
|
|
pub const fn assert_compatible_gencode_version(gencode_version: &'static str) {
|
|
let runtime_version = env!("CARGO_PKG_VERSION");
|
|
assert!(
|
|
are_versions_compatible(gencode_version, runtime_version),
|
|
concat!(
|
|
"Gencode version (see callsite) is not compatible with runtime ",
|
|
"version (runtime is ",
|
|
env!("CARGO_PKG_VERSION"),
|
|
")"
|
|
),
|
|
)
|
|
}
|
|
|
|
/// There is no need for gencode/runtime poison pill when running in bzl; the
|
|
/// gencode using the __internal mod which is not available to checked in
|
|
/// gencode; gencode built from source should always match.
|
|
#[cfg(bzl)]
|
|
pub const fn assert_compatible_gencode_version(_gencode_version: &'static str) {}
|
|
|
|
#[cfg(test)]
|
|
#[cfg(not(bzl))]
|
|
mod tests {
|
|
use super::*;
|
|
use googletest::prelude::*;
|
|
|
|
#[gtest]
|
|
fn test_split_version() {
|
|
expect_that!(split_version("4.33.1"), eq((4, 33, 1, 0)));
|
|
expect_that!(split_version("4.33.0-rc.1"), eq((4, 33, 0, 1)));
|
|
expect_that!(split_version("4.33.0-release"), eq((4, 33, 0, 0)));
|
|
}
|
|
|
|
#[gtest]
|
|
fn test_are_versions_compatible() {
|
|
// Exact matches are always fine.
|
|
expect_true!(are_versions_compatible("4.34.0-rc.1", "4.34.0-rc.1"));
|
|
expect_true!(are_versions_compatible("4.34.1", "4.34.1"));
|
|
|
|
// Gencode older than the runtime is also fine.
|
|
expect_true!(are_versions_compatible("4.34.0", "5.35.0"));
|
|
expect_true!(are_versions_compatible("4.34.0", "4.35.0"));
|
|
expect_true!(are_versions_compatible("4.34.0", "4.34.1"));
|
|
expect_true!(are_versions_compatible("4.34.0-rc.1", "4.34.0-rc.2"));
|
|
expect_true!(are_versions_compatible("4.34.0-rc.2", "4.34.0"));
|
|
|
|
// Gencode newer than the runtime is not allowed.
|
|
expect_false!(are_versions_compatible("5.35.0", "4.34.0"));
|
|
expect_false!(are_versions_compatible("4.35.0", "4.34.0"));
|
|
expect_false!(are_versions_compatible("4.35.1", "4.34.0"));
|
|
expect_false!(are_versions_compatible("4.35.0-rc.2", "4.34.0-rc.1"));
|
|
expect_false!(are_versions_compatible("4.35.0", "4.34.0-rc.2"));
|
|
}
|
|
}
|