| // 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")); | |
| } | |
| } |