|  | // 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; | 
|  |  | 
|  | use crate::map; | 
|  | pub use crate::r#enum::Enum; | 
|  | use crate::repeated; | 
|  | pub use crate::ProtoStr; | 
|  | use crate::Proxied; | 
|  | pub use std::fmt::Debug; | 
|  |  | 
|  | #[cfg(all(bzl, cpp_kernel))] | 
|  | #[path = "cpp.rs"] | 
|  | pub mod runtime; | 
|  | #[cfg(any(not(bzl), upb_kernel))] | 
|  | #[path = "upb.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 {} | 
|  |  | 
|  | /// A trait used by the proto_eq() gtest macro. | 
|  | pub trait MatcherEq: SealedInternal + Debug { | 
|  | fn matches(&self, o: &Self) -> bool; | 
|  | } | 
|  |  | 
|  | /// Used by the proto! macro to get a default value for a repeated field. | 
|  | pub fn get_repeated_default_value<T: repeated::ProxiedInRepeated + Default>( | 
|  | _: Private, | 
|  | _: repeated::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: Proxied, V: map::ProxiedInMapValue<K> + Default>( | 
|  | _: Private, | 
|  | _: map::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, but the exception is that we consider gencode at 4.32 and older to | 
|  | // be incompatible no matter what. | 
|  | #[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 < 4 || (gencode.0 == 4 && gencode.1 <= 32) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | 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. | 
|  | /// | 
|  | /// 4.33 is the first stable release, so any gencode older than that is not | 
|  | /// compatible going forward. | 
|  | /// | 
|  | /// If you are seeing this fail, it means that your generated code was built | 
|  | /// with a protoc version newer than the runtime crate version (or you have | 
|  | /// pre-4.33 gencode). | 
|  | #[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), | 
|  | "Gencode version is not compatible with runtime 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() { | 
|  | // Pre-4.33 gencode is never considered compatible. | 
|  | expect_false!(are_versions_compatible("4.32.0", "4.32.1")); | 
|  | expect_false!(are_versions_compatible("3.32.0", "3.32.0")); | 
|  |  | 
|  | // Otherwise, exact matches are always fine. | 
|  | expect_true!(are_versions_compatible("4.33.0-rc.1", "4.33.0-rc.1")); | 
|  | expect_true!(are_versions_compatible("4.33.1", "4.33.1")); | 
|  |  | 
|  | // Gencode older than the runtime is also fine. | 
|  | expect_true!(are_versions_compatible("4.33.0", "5.34.0")); | 
|  | expect_true!(are_versions_compatible("4.33.0", "4.34.0")); | 
|  | expect_true!(are_versions_compatible("4.33.0", "4.33.1")); | 
|  | expect_true!(are_versions_compatible("4.33.0-rc.1", "4.33.0-rc.2")); | 
|  | expect_true!(are_versions_compatible("4.33.0-rc.2", "4.33.0")); | 
|  |  | 
|  | // Gencode newer than the runtime is not allowed. | 
|  | expect_false!(are_versions_compatible("5.34.0", "4.33.0")); | 
|  | expect_false!(are_versions_compatible("4.34.0", "4.33.0")); | 
|  | expect_false!(are_versions_compatible("4.33.1", "4.33.0")); | 
|  | expect_false!(are_versions_compatible("4.33.0-rc.2", "4.33.0-rc.1")); | 
|  | expect_false!(are_versions_compatible("4.33.0", "4.33.0-rc.2")); | 
|  | } | 
|  | } |