// 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 SealedInternal for &T {} impl SealedInternal for &mut T {} /// 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(_: 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( _: 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, but the exception is that we consider gencode at 4.33 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 <= 33) { 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.34 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.34 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.34 gencode is never considered compatible. expect_false!(are_versions_compatible("4.33.0", "4.33.1")); expect_false!(are_versions_compatible("3.33.0", "3.33.0")); // Otherwise, 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")); } }