commit 2b2505cbba02b5d85ee24d4472e0c9901c6374f0
parent 92b0585b4e1e5dd6dd536e49a4a6efee69de20d7
Author: triesap <tyson@radroots.org>
Date: Sat, 15 Aug 2026 23:37:15 +0000
service-contracts: validate text before allocation
Diffstat:
16 files changed, 498 insertions(+), 423 deletions(-)
diff --git a/contracts/api_baselines/radroots_runtime_paths.txt b/contracts/api_baselines/radroots_runtime_paths.txt
@@ -4,24 +4,8 @@ pub radroots_runtime_paths::RadrootsPathProfile::InteractiveUser
pub radroots_runtime_paths::RadrootsPathProfile::MobileNative
pub radroots_runtime_paths::RadrootsPathProfile::RepoLocal
pub radroots_runtime_paths::RadrootsPathProfile::ServiceHost
-impl core::clone::Clone for radroots_runtime_paths::RadrootsPathProfile
-pub fn radroots_runtime_paths::RadrootsPathProfile::clone(&self) -> radroots_runtime_paths::RadrootsPathProfile
-impl core::cmp::Eq for radroots_runtime_paths::RadrootsPathProfile
-impl core::cmp::PartialEq for radroots_runtime_paths::RadrootsPathProfile
-pub fn radroots_runtime_paths::RadrootsPathProfile::eq(&self, &radroots_runtime_paths::RadrootsPathProfile) -> bool
-impl core::fmt::Debug for radroots_runtime_paths::RadrootsPathProfile
-pub fn radroots_runtime_paths::RadrootsPathProfile::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::fmt::Display for radroots_runtime_paths::RadrootsPathProfile
pub fn radroots_runtime_paths::RadrootsPathProfile::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::Copy for radroots_runtime_paths::RadrootsPathProfile
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::RadrootsPathProfile
-impl core::marker::Freeze for radroots_runtime_paths::RadrootsPathProfile
-impl core::marker::Send for radroots_runtime_paths::RadrootsPathProfile
-impl core::marker::Sync for radroots_runtime_paths::RadrootsPathProfile
-impl core::marker::Unpin for radroots_runtime_paths::RadrootsPathProfile
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::RadrootsPathProfile
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::RadrootsPathProfile
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::RadrootsPathProfile
pub enum radroots_runtime_paths::RadrootsPlatform
pub radroots_runtime_paths::RadrootsPlatform::Android
pub radroots_runtime_paths::RadrootsPlatform::Ios
@@ -32,24 +16,8 @@ pub radroots_runtime_paths::RadrootsPlatform::Windows
impl radroots_runtime_paths::RadrootsPlatform
pub fn radroots_runtime_paths::RadrootsPlatform::current() -> Self
pub fn radroots_runtime_paths::RadrootsPlatform::is_unix_like(self) -> bool
-impl core::clone::Clone for radroots_runtime_paths::RadrootsPlatform
-pub fn radroots_runtime_paths::RadrootsPlatform::clone(&self) -> radroots_runtime_paths::RadrootsPlatform
-impl core::cmp::Eq for radroots_runtime_paths::RadrootsPlatform
-impl core::cmp::PartialEq for radroots_runtime_paths::RadrootsPlatform
-pub fn radroots_runtime_paths::RadrootsPlatform::eq(&self, &radroots_runtime_paths::RadrootsPlatform) -> bool
-impl core::fmt::Debug for radroots_runtime_paths::RadrootsPlatform
-pub fn radroots_runtime_paths::RadrootsPlatform::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::fmt::Display for radroots_runtime_paths::RadrootsPlatform
pub fn radroots_runtime_paths::RadrootsPlatform::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::Copy for radroots_runtime_paths::RadrootsPlatform
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::RadrootsPlatform
-impl core::marker::Freeze for radroots_runtime_paths::RadrootsPlatform
-impl core::marker::Send for radroots_runtime_paths::RadrootsPlatform
-impl core::marker::Sync for radroots_runtime_paths::RadrootsPlatform
-impl core::marker::Unpin for radroots_runtime_paths::RadrootsPlatform
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::RadrootsPlatform
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::RadrootsPlatform
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::RadrootsPlatform
pub enum radroots_runtime_paths::RadrootsRuntimePathsError
pub radroots_runtime_paths::RadrootsRuntimePathsError::InvalidHomeDir
pub radroots_runtime_paths::RadrootsRuntimePathsError::InvalidHomeDir::platform: radroots_runtime_paths::RadrootsPlatform
@@ -64,94 +32,20 @@ pub radroots_runtime_paths::RadrootsRuntimePathsError::SharedAccountsDataRootMis
pub radroots_runtime_paths::RadrootsRuntimePathsError::UnsupportedProfilePlatform
pub radroots_runtime_paths::RadrootsRuntimePathsError::UnsupportedProfilePlatform::platform: radroots_runtime_paths::RadrootsPlatform
pub radroots_runtime_paths::RadrootsRuntimePathsError::UnsupportedProfilePlatform::profile: radroots_runtime_paths::RadrootsPathProfile
-impl core::clone::Clone for radroots_runtime_paths::RadrootsRuntimePathsError
-pub fn radroots_runtime_paths::RadrootsRuntimePathsError::clone(&self) -> radroots_runtime_paths::RadrootsRuntimePathsError
-impl core::cmp::Eq for radroots_runtime_paths::RadrootsRuntimePathsError
-impl core::cmp::PartialEq for radroots_runtime_paths::RadrootsRuntimePathsError
-pub fn radroots_runtime_paths::RadrootsRuntimePathsError::eq(&self, &radroots_runtime_paths::RadrootsRuntimePathsError) -> bool
-impl core::error::Error for radroots_runtime_paths::RadrootsRuntimePathsError
-impl core::fmt::Debug for radroots_runtime_paths::RadrootsRuntimePathsError
-pub fn radroots_runtime_paths::RadrootsRuntimePathsError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::fmt::Display for radroots_runtime_paths::RadrootsRuntimePathsError
-pub fn radroots_runtime_paths::RadrootsRuntimePathsError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::RadrootsRuntimePathsError
-impl core::marker::Freeze for radroots_runtime_paths::RadrootsRuntimePathsError
-impl core::marker::Send for radroots_runtime_paths::RadrootsRuntimePathsError
-impl core::marker::Sync for radroots_runtime_paths::RadrootsRuntimePathsError
-impl core::marker::Unpin for radroots_runtime_paths::RadrootsRuntimePathsError
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::RadrootsRuntimePathsError
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::RadrootsRuntimePathsError
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::RadrootsRuntimePathsError
pub enum radroots_runtime_paths::RuntimeContextError
pub radroots_runtime_paths::RuntimeContextError::InvalidBootstrapBinding
pub radroots_runtime_paths::RuntimeContextError::PathSelection
-impl core::clone::Clone for radroots_runtime_paths::RuntimeContextError
-pub fn radroots_runtime_paths::RuntimeContextError::clone(&self) -> radroots_runtime_paths::RuntimeContextError
-impl core::cmp::Eq for radroots_runtime_paths::RuntimeContextError
-impl core::cmp::PartialEq for radroots_runtime_paths::RuntimeContextError
-pub fn radroots_runtime_paths::RuntimeContextError::eq(&self, &radroots_runtime_paths::RuntimeContextError) -> bool
-impl core::error::Error for radroots_runtime_paths::RuntimeContextError
-impl core::fmt::Debug for radroots_runtime_paths::RuntimeContextError
-pub fn radroots_runtime_paths::RuntimeContextError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::fmt::Display for radroots_runtime_paths::RuntimeContextError
-pub fn radroots_runtime_paths::RuntimeContextError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::Copy for radroots_runtime_paths::RuntimeContextError
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::RuntimeContextError
-impl core::marker::Freeze for radroots_runtime_paths::RuntimeContextError
-impl core::marker::Send for radroots_runtime_paths::RuntimeContextError
-impl core::marker::Sync for radroots_runtime_paths::RuntimeContextError
-impl core::marker::Unpin for radroots_runtime_paths::RuntimeContextError
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::RuntimeContextError
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::RuntimeContextError
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::RuntimeContextError
pub enum radroots_runtime_paths::RuntimeContextSource
pub radroots_runtime_paths::RuntimeContextSource::BootstrapCli
pub radroots_runtime_paths::RuntimeContextSource::DerivedPath
pub radroots_runtime_paths::RuntimeContextSource::SafeDefault
pub radroots_runtime_paths::RuntimeContextSource::Toml
-impl core::clone::Clone for radroots_runtime_paths::RuntimeContextSource
-pub fn radroots_runtime_paths::RuntimeContextSource::clone(&self) -> radroots_runtime_paths::RuntimeContextSource
-impl core::cmp::Eq for radroots_runtime_paths::RuntimeContextSource
-impl core::cmp::PartialEq for radroots_runtime_paths::RuntimeContextSource
-pub fn radroots_runtime_paths::RuntimeContextSource::eq(&self, &radroots_runtime_paths::RuntimeContextSource) -> bool
-impl core::fmt::Debug for radroots_runtime_paths::RuntimeContextSource
-pub fn radroots_runtime_paths::RuntimeContextSource::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::Copy for radroots_runtime_paths::RuntimeContextSource
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::RuntimeContextSource
-impl serde_core::ser::Serialize for radroots_runtime_paths::RuntimeContextSource
-pub fn radroots_runtime_paths::RuntimeContextSource::serialize<__S>(&self, __S) -> core::result::Result<<__S as serde_core::ser::Serializer>::Ok, <__S as serde_core::ser::Serializer>::Error> where __S: serde_core::ser::Serializer
-impl core::marker::Freeze for radroots_runtime_paths::RuntimeContextSource
-impl core::marker::Send for radroots_runtime_paths::RuntimeContextSource
-impl core::marker::Sync for radroots_runtime_paths::RuntimeContextSource
-impl core::marker::Unpin for radroots_runtime_paths::RuntimeContextSource
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::RuntimeContextSource
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::RuntimeContextSource
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::RuntimeContextSource
pub enum radroots_runtime_paths::ServiceCredentialArtifactNameError
pub radroots_runtime_paths::ServiceCredentialArtifactNameError::Empty
pub radroots_runtime_paths::ServiceCredentialArtifactNameError::InvalidBoundary
pub radroots_runtime_paths::ServiceCredentialArtifactNameError::InvalidCharacter
pub radroots_runtime_paths::ServiceCredentialArtifactNameError::TooLong
pub radroots_runtime_paths::ServiceCredentialArtifactNameError::TooLong::maximum: usize
-impl core::clone::Clone for radroots_runtime_paths::ServiceCredentialArtifactNameError
-pub fn radroots_runtime_paths::ServiceCredentialArtifactNameError::clone(&self) -> radroots_runtime_paths::ServiceCredentialArtifactNameError
-impl core::cmp::Eq for radroots_runtime_paths::ServiceCredentialArtifactNameError
-impl core::cmp::PartialEq for radroots_runtime_paths::ServiceCredentialArtifactNameError
-pub fn radroots_runtime_paths::ServiceCredentialArtifactNameError::eq(&self, &radroots_runtime_paths::ServiceCredentialArtifactNameError) -> bool
-impl core::error::Error for radroots_runtime_paths::ServiceCredentialArtifactNameError
-impl core::fmt::Debug for radroots_runtime_paths::ServiceCredentialArtifactNameError
-pub fn radroots_runtime_paths::ServiceCredentialArtifactNameError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::fmt::Display for radroots_runtime_paths::ServiceCredentialArtifactNameError
-pub fn radroots_runtime_paths::ServiceCredentialArtifactNameError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::Copy for radroots_runtime_paths::ServiceCredentialArtifactNameError
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::ServiceCredentialArtifactNameError
-impl core::marker::Freeze for radroots_runtime_paths::ServiceCredentialArtifactNameError
-impl core::marker::Send for radroots_runtime_paths::ServiceCredentialArtifactNameError
-impl core::marker::Sync for radroots_runtime_paths::ServiceCredentialArtifactNameError
-impl core::marker::Unpin for radroots_runtime_paths::ServiceCredentialArtifactNameError
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::ServiceCredentialArtifactNameError
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::ServiceCredentialArtifactNameError
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::ServiceCredentialArtifactNameError
pub enum radroots_runtime_paths::ServiceIdentityError
pub radroots_runtime_paths::ServiceIdentityError::Empty
pub radroots_runtime_paths::ServiceIdentityError::Empty::kind: radroots_runtime_paths::ServiceIdentityKind
@@ -162,60 +56,16 @@ pub radroots_runtime_paths::ServiceIdentityError::InvalidCharacter::kind: radroo
pub radroots_runtime_paths::ServiceIdentityError::TooLong
pub radroots_runtime_paths::ServiceIdentityError::TooLong::kind: radroots_runtime_paths::ServiceIdentityKind
pub radroots_runtime_paths::ServiceIdentityError::TooLong::maximum: usize
-impl core::clone::Clone for radroots_runtime_paths::ServiceIdentityError
-pub fn radroots_runtime_paths::ServiceIdentityError::clone(&self) -> radroots_runtime_paths::ServiceIdentityError
-impl core::cmp::Eq for radroots_runtime_paths::ServiceIdentityError
-impl core::cmp::PartialEq for radroots_runtime_paths::ServiceIdentityError
-pub fn radroots_runtime_paths::ServiceIdentityError::eq(&self, &radroots_runtime_paths::ServiceIdentityError) -> bool
-impl core::error::Error for radroots_runtime_paths::ServiceIdentityError
-impl core::fmt::Debug for radroots_runtime_paths::ServiceIdentityError
-pub fn radroots_runtime_paths::ServiceIdentityError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::fmt::Display for radroots_runtime_paths::ServiceIdentityError
-pub fn radroots_runtime_paths::ServiceIdentityError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::Copy for radroots_runtime_paths::ServiceIdentityError
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::ServiceIdentityError
-impl core::marker::Freeze for radroots_runtime_paths::ServiceIdentityError
-impl core::marker::Send for radroots_runtime_paths::ServiceIdentityError
-impl core::marker::Sync for radroots_runtime_paths::ServiceIdentityError
-impl core::marker::Unpin for radroots_runtime_paths::ServiceIdentityError
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::ServiceIdentityError
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::ServiceIdentityError
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::ServiceIdentityError
pub enum radroots_runtime_paths::ServiceIdentityKind
pub radroots_runtime_paths::ServiceIdentityKind::Instance
pub radroots_runtime_paths::ServiceIdentityKind::Service
-impl core::clone::Clone for radroots_runtime_paths::ServiceIdentityKind
-pub fn radroots_runtime_paths::ServiceIdentityKind::clone(&self) -> radroots_runtime_paths::ServiceIdentityKind
-impl core::cmp::Eq for radroots_runtime_paths::ServiceIdentityKind
-impl core::cmp::PartialEq for radroots_runtime_paths::ServiceIdentityKind
-pub fn radroots_runtime_paths::ServiceIdentityKind::eq(&self, &radroots_runtime_paths::ServiceIdentityKind) -> bool
-impl core::fmt::Debug for radroots_runtime_paths::ServiceIdentityKind
-pub fn radroots_runtime_paths::ServiceIdentityKind::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::fmt::Display for radroots_runtime_paths::ServiceIdentityKind
pub fn radroots_runtime_paths::ServiceIdentityKind::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::Copy for radroots_runtime_paths::ServiceIdentityKind
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::ServiceIdentityKind
-impl core::marker::Freeze for radroots_runtime_paths::ServiceIdentityKind
-impl core::marker::Send for radroots_runtime_paths::ServiceIdentityKind
-impl core::marker::Sync for radroots_runtime_paths::ServiceIdentityKind
-impl core::marker::Unpin for radroots_runtime_paths::ServiceIdentityKind
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::ServiceIdentityKind
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::ServiceIdentityKind
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::ServiceIdentityKind
pub struct radroots_runtime_paths::InstanceId(_)
impl radroots_runtime_paths::InstanceId
pub fn radroots_runtime_paths::InstanceId::as_str(&self) -> &str
pub fn radroots_runtime_paths::InstanceId::into_string(self) -> alloc::string::String
-pub fn radroots_runtime_paths::InstanceId::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_runtime_paths::ServiceIdentityError>
-impl core::clone::Clone for radroots_runtime_paths::InstanceId
-pub fn radroots_runtime_paths::InstanceId::clone(&self) -> radroots_runtime_paths::InstanceId
-impl core::cmp::Eq for radroots_runtime_paths::InstanceId
-impl core::cmp::Ord for radroots_runtime_paths::InstanceId
-pub fn radroots_runtime_paths::InstanceId::cmp(&self, &radroots_runtime_paths::InstanceId) -> core::cmp::Ordering
-impl core::cmp::PartialEq for radroots_runtime_paths::InstanceId
-pub fn radroots_runtime_paths::InstanceId::eq(&self, &radroots_runtime_paths::InstanceId) -> bool
-impl core::cmp::PartialOrd for radroots_runtime_paths::InstanceId
-pub fn radroots_runtime_paths::InstanceId::partial_cmp(&self, &radroots_runtime_paths::InstanceId) -> core::option::Option<core::cmp::Ordering>
+pub fn radroots_runtime_paths::InstanceId::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_runtime_paths::ServiceIdentityError>
impl core::convert::AsRef<str> for radroots_runtime_paths::InstanceId
pub fn radroots_runtime_paths::InstanceId::as_ref(&self) -> &str
impl core::convert::From<radroots_runtime_paths::InstanceId> for alloc::string::String
@@ -223,13 +73,8 @@ pub fn alloc::string::String::from(radroots_runtime_paths::InstanceId) -> Self
impl core::convert::TryFrom<alloc::string::String> for radroots_runtime_paths::InstanceId
pub type radroots_runtime_paths::InstanceId::Error = radroots_runtime_paths::ServiceIdentityError
pub fn radroots_runtime_paths::InstanceId::try_from(alloc::string::String) -> core::result::Result<Self, Self::Error>
-impl core::fmt::Debug for radroots_runtime_paths::InstanceId
-pub fn radroots_runtime_paths::InstanceId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::fmt::Display for radroots_runtime_paths::InstanceId
pub fn radroots_runtime_paths::InstanceId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::hash::Hash for radroots_runtime_paths::InstanceId
-pub fn radroots_runtime_paths::InstanceId::hash<__H: core::hash::Hasher>(&self, &mut __H)
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::InstanceId
impl core::str::traits::FromStr for radroots_runtime_paths::InstanceId
pub type radroots_runtime_paths::InstanceId::Err = radroots_runtime_paths::ServiceIdentityError
pub fn radroots_runtime_paths::InstanceId::from_str(&str) -> core::result::Result<Self, Self::Err>
@@ -237,13 +82,6 @@ impl serde_core::ser::Serialize for radroots_runtime_paths::InstanceId
pub fn radroots_runtime_paths::InstanceId::serialize<S>(&self, S) -> core::result::Result<<S as serde_core::ser::Serializer>::Ok, <S as serde_core::ser::Serializer>::Error> where S: serde_core::ser::Serializer
impl<'de> serde_core::de::Deserialize<'de> for radroots_runtime_paths::InstanceId
pub fn radroots_runtime_paths::InstanceId::deserialize<D>(D) -> core::result::Result<Self, <D as serde_core::de::Deserializer>::Error> where D: serde_core::de::Deserializer<'de>
-impl core::marker::Freeze for radroots_runtime_paths::InstanceId
-impl core::marker::Send for radroots_runtime_paths::InstanceId
-impl core::marker::Sync for radroots_runtime_paths::InstanceId
-impl core::marker::Unpin for radroots_runtime_paths::InstanceId
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::InstanceId
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::InstanceId
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::InstanceId
pub struct radroots_runtime_paths::RadrootsHostEnvironment
pub radroots_runtime_paths::RadrootsHostEnvironment::appdata_dir: core::option::Option<std::path::PathBuf>
pub radroots_runtime_paths::RadrootsHostEnvironment::home_dir: core::option::Option<std::path::PathBuf>
@@ -253,63 +91,18 @@ pub radroots_runtime_paths::RadrootsHostEnvironment::xdg_config_home: core::opti
pub radroots_runtime_paths::RadrootsHostEnvironment::xdg_data_home: core::option::Option<std::path::PathBuf>
pub radroots_runtime_paths::RadrootsHostEnvironment::xdg_runtime_dir: core::option::Option<std::path::PathBuf>
pub radroots_runtime_paths::RadrootsHostEnvironment::xdg_state_home: core::option::Option<std::path::PathBuf>
-impl core::clone::Clone for radroots_runtime_paths::RadrootsHostEnvironment
-pub fn radroots_runtime_paths::RadrootsHostEnvironment::clone(&self) -> radroots_runtime_paths::RadrootsHostEnvironment
-impl core::cmp::Eq for radroots_runtime_paths::RadrootsHostEnvironment
-impl core::cmp::PartialEq for radroots_runtime_paths::RadrootsHostEnvironment
-pub fn radroots_runtime_paths::RadrootsHostEnvironment::eq(&self, &radroots_runtime_paths::RadrootsHostEnvironment) -> bool
-impl core::default::Default for radroots_runtime_paths::RadrootsHostEnvironment
-pub fn radroots_runtime_paths::RadrootsHostEnvironment::default() -> radroots_runtime_paths::RadrootsHostEnvironment
-impl core::fmt::Debug for radroots_runtime_paths::RadrootsHostEnvironment
-pub fn radroots_runtime_paths::RadrootsHostEnvironment::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::RadrootsHostEnvironment
-impl core::marker::Freeze for radroots_runtime_paths::RadrootsHostEnvironment
-impl core::marker::Send for radroots_runtime_paths::RadrootsHostEnvironment
-impl core::marker::Sync for radroots_runtime_paths::RadrootsHostEnvironment
-impl core::marker::Unpin for radroots_runtime_paths::RadrootsHostEnvironment
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::RadrootsHostEnvironment
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::RadrootsHostEnvironment
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::RadrootsHostEnvironment
pub struct radroots_runtime_paths::RadrootsPathResolver
impl radroots_runtime_paths::RadrootsPathResolver
pub fn radroots_runtime_paths::RadrootsPathResolver::new(radroots_runtime_paths::RadrootsPlatform, radroots_runtime_paths::RadrootsHostEnvironment) -> Self
pub fn radroots_runtime_paths::RadrootsPathResolver::platform(&self) -> radroots_runtime_paths::RadrootsPlatform
-impl core::clone::Clone for radroots_runtime_paths::RadrootsPathResolver
-pub fn radroots_runtime_paths::RadrootsPathResolver::clone(&self) -> radroots_runtime_paths::RadrootsPathResolver
-impl core::cmp::Eq for radroots_runtime_paths::RadrootsPathResolver
-impl core::cmp::PartialEq for radroots_runtime_paths::RadrootsPathResolver
-pub fn radroots_runtime_paths::RadrootsPathResolver::eq(&self, &radroots_runtime_paths::RadrootsPathResolver) -> bool
-impl core::fmt::Debug for radroots_runtime_paths::RadrootsPathResolver
-pub fn radroots_runtime_paths::RadrootsPathResolver::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::RadrootsPathResolver
-impl core::marker::Freeze for radroots_runtime_paths::RadrootsPathResolver
-impl core::marker::Send for radroots_runtime_paths::RadrootsPathResolver
-impl core::marker::Sync for radroots_runtime_paths::RadrootsPathResolver
-impl core::marker::Unpin for radroots_runtime_paths::RadrootsPathResolver
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::RadrootsPathResolver
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::RadrootsPathResolver
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::RadrootsPathResolver
pub struct radroots_runtime_paths::RadrootsServiceInstanceArtifacts
impl radroots_runtime_paths::RadrootsServiceInstanceArtifacts
pub fn radroots_runtime_paths::RadrootsServiceInstanceArtifacts::admin_socket(&self) -> &std::path::Path
pub fn radroots_runtime_paths::RadrootsServiceInstanceArtifacts::config(&self) -> &std::path::Path
pub fn radroots_runtime_paths::RadrootsServiceInstanceArtifacts::state_database(&self) -> &std::path::Path
pub fn radroots_runtime_paths::RadrootsServiceInstanceArtifacts::state_lock(&self) -> &std::path::Path
-impl core::clone::Clone for radroots_runtime_paths::RadrootsServiceInstanceArtifacts
-pub fn radroots_runtime_paths::RadrootsServiceInstanceArtifacts::clone(&self) -> radroots_runtime_paths::RadrootsServiceInstanceArtifacts
-impl core::cmp::Eq for radroots_runtime_paths::RadrootsServiceInstanceArtifacts
-impl core::cmp::PartialEq for radroots_runtime_paths::RadrootsServiceInstanceArtifacts
-pub fn radroots_runtime_paths::RadrootsServiceInstanceArtifacts::eq(&self, &radroots_runtime_paths::RadrootsServiceInstanceArtifacts) -> bool
impl core::fmt::Debug for radroots_runtime_paths::RadrootsServiceInstanceArtifacts
pub fn radroots_runtime_paths::RadrootsServiceInstanceArtifacts::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::RadrootsServiceInstanceArtifacts
-impl core::marker::Freeze for radroots_runtime_paths::RadrootsServiceInstanceArtifacts
-impl core::marker::Send for radroots_runtime_paths::RadrootsServiceInstanceArtifacts
-impl core::marker::Sync for radroots_runtime_paths::RadrootsServiceInstanceArtifacts
-impl core::marker::Unpin for radroots_runtime_paths::RadrootsServiceInstanceArtifacts
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::RadrootsServiceInstanceArtifacts
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::RadrootsServiceInstanceArtifacts
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::RadrootsServiceInstanceArtifacts
pub struct radroots_runtime_paths::RadrootsServiceInstancePaths
impl radroots_runtime_paths::RadrootsServiceInstancePaths
pub fn radroots_runtime_paths::RadrootsServiceInstancePaths::cache(&self) -> &std::path::Path
@@ -318,21 +111,6 @@ pub fn radroots_runtime_paths::RadrootsServiceInstancePaths::logs(&self) -> &std
pub fn radroots_runtime_paths::RadrootsServiceInstancePaths::run(&self) -> &std::path::Path
pub fn radroots_runtime_paths::RadrootsServiceInstancePaths::secrets(&self) -> &std::path::Path
pub fn radroots_runtime_paths::RadrootsServiceInstancePaths::state(&self) -> &std::path::Path
-impl core::clone::Clone for radroots_runtime_paths::RadrootsServiceInstancePaths
-pub fn radroots_runtime_paths::RadrootsServiceInstancePaths::clone(&self) -> radroots_runtime_paths::RadrootsServiceInstancePaths
-impl core::cmp::Eq for radroots_runtime_paths::RadrootsServiceInstancePaths
-impl core::cmp::PartialEq for radroots_runtime_paths::RadrootsServiceInstancePaths
-pub fn radroots_runtime_paths::RadrootsServiceInstancePaths::eq(&self, &radroots_runtime_paths::RadrootsServiceInstancePaths) -> bool
-impl core::fmt::Debug for radroots_runtime_paths::RadrootsServiceInstancePaths
-pub fn radroots_runtime_paths::RadrootsServiceInstancePaths::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::RadrootsServiceInstancePaths
-impl core::marker::Freeze for radroots_runtime_paths::RadrootsServiceInstancePaths
-impl core::marker::Send for radroots_runtime_paths::RadrootsServiceInstancePaths
-impl core::marker::Sync for radroots_runtime_paths::RadrootsServiceInstancePaths
-impl core::marker::Unpin for radroots_runtime_paths::RadrootsServiceInstancePaths
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::RadrootsServiceInstancePaths
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::RadrootsServiceInstancePaths
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::RadrootsServiceInstancePaths
pub struct radroots_runtime_paths::RuntimeContext
impl radroots_runtime_paths::RuntimeContext
pub fn radroots_runtime_paths::RuntimeContext::instance(&self) -> &radroots_runtime_paths::InstanceId
@@ -341,42 +119,16 @@ pub fn radroots_runtime_paths::RuntimeContext::profile(&self) -> radroots_runtim
pub fn radroots_runtime_paths::RuntimeContext::resolve(&radroots_runtime_paths::RadrootsPathResolver, radroots_runtime_paths::RuntimeContextBootstrap, radroots_runtime_paths::ServiceId, radroots_runtime_paths::InstanceId) -> core::result::Result<Self, radroots_runtime_paths::RuntimeContextError>
pub fn radroots_runtime_paths::RuntimeContext::service(&self) -> &radroots_runtime_paths::ServiceId
pub fn radroots_runtime_paths::RuntimeContext::sources(&self) -> &radroots_runtime_paths::RuntimeContextSources
-impl core::clone::Clone for radroots_runtime_paths::RuntimeContext
-pub fn radroots_runtime_paths::RuntimeContext::clone(&self) -> radroots_runtime_paths::RuntimeContext
-impl core::cmp::Eq for radroots_runtime_paths::RuntimeContext
-impl core::cmp::PartialEq for radroots_runtime_paths::RuntimeContext
-pub fn radroots_runtime_paths::RuntimeContext::eq(&self, &radroots_runtime_paths::RuntimeContext) -> bool
impl core::fmt::Debug for radroots_runtime_paths::RuntimeContext
pub fn radroots_runtime_paths::RuntimeContext::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::RuntimeContext
impl serde_core::ser::Serialize for radroots_runtime_paths::RuntimeContext
pub fn radroots_runtime_paths::RuntimeContext::serialize<S>(&self, S) -> core::result::Result<<S as serde_core::ser::Serializer>::Ok, <S as serde_core::ser::Serializer>::Error> where S: serde_core::ser::Serializer
-impl core::marker::Freeze for radroots_runtime_paths::RuntimeContext
-impl core::marker::Send for radroots_runtime_paths::RuntimeContext
-impl core::marker::Sync for radroots_runtime_paths::RuntimeContext
-impl core::marker::Unpin for radroots_runtime_paths::RuntimeContext
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::RuntimeContext
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::RuntimeContext
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::RuntimeContext
pub struct radroots_runtime_paths::RuntimeContextBootstrap
impl radroots_runtime_paths::RuntimeContextBootstrap
pub fn radroots_runtime_paths::RuntimeContextBootstrap::new(radroots_runtime_paths::RadrootsPathProfile, core::option::Option<std::path::PathBuf>, radroots_runtime_paths::RuntimeContextSource, radroots_runtime_paths::RuntimeContextSource) -> core::result::Result<Self, radroots_runtime_paths::RuntimeContextError>
pub fn radroots_runtime_paths::RuntimeContextBootstrap::profile(&self) -> radroots_runtime_paths::RadrootsPathProfile
-impl core::clone::Clone for radroots_runtime_paths::RuntimeContextBootstrap
-pub fn radroots_runtime_paths::RuntimeContextBootstrap::clone(&self) -> radroots_runtime_paths::RuntimeContextBootstrap
-impl core::cmp::Eq for radroots_runtime_paths::RuntimeContextBootstrap
-impl core::cmp::PartialEq for radroots_runtime_paths::RuntimeContextBootstrap
-pub fn radroots_runtime_paths::RuntimeContextBootstrap::eq(&self, &radroots_runtime_paths::RuntimeContextBootstrap) -> bool
impl core::fmt::Debug for radroots_runtime_paths::RuntimeContextBootstrap
pub fn radroots_runtime_paths::RuntimeContextBootstrap::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::RuntimeContextBootstrap
-impl core::marker::Freeze for radroots_runtime_paths::RuntimeContextBootstrap
-impl core::marker::Send for radroots_runtime_paths::RuntimeContextBootstrap
-impl core::marker::Sync for radroots_runtime_paths::RuntimeContextBootstrap
-impl core::marker::Unpin for radroots_runtime_paths::RuntimeContextBootstrap
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::RuntimeContextBootstrap
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::RuntimeContextBootstrap
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::RuntimeContextBootstrap
pub struct radroots_runtime_paths::RuntimeContextSources
impl radroots_runtime_paths::RuntimeContextSources
pub fn radroots_runtime_paths::RuntimeContextSources::instance(&self) -> radroots_runtime_paths::RuntimeContextSource
@@ -384,64 +136,19 @@ pub fn radroots_runtime_paths::RuntimeContextSources::paths(&self) -> radroots_r
pub fn radroots_runtime_paths::RuntimeContextSources::profile(&self) -> radroots_runtime_paths::RuntimeContextSource
pub fn radroots_runtime_paths::RuntimeContextSources::repo_local_root(&self) -> core::option::Option<radroots_runtime_paths::RuntimeContextSource>
pub fn radroots_runtime_paths::RuntimeContextSources::service(&self) -> radroots_runtime_paths::RuntimeContextSource
-impl core::clone::Clone for radroots_runtime_paths::RuntimeContextSources
-pub fn radroots_runtime_paths::RuntimeContextSources::clone(&self) -> radroots_runtime_paths::RuntimeContextSources
-impl core::cmp::Eq for radroots_runtime_paths::RuntimeContextSources
-impl core::cmp::PartialEq for radroots_runtime_paths::RuntimeContextSources
-pub fn radroots_runtime_paths::RuntimeContextSources::eq(&self, &radroots_runtime_paths::RuntimeContextSources) -> bool
-impl core::fmt::Debug for radroots_runtime_paths::RuntimeContextSources
-pub fn radroots_runtime_paths::RuntimeContextSources::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::RuntimeContextSources
-impl serde_core::ser::Serialize for radroots_runtime_paths::RuntimeContextSources
-pub fn radroots_runtime_paths::RuntimeContextSources::serialize<__S>(&self, __S) -> core::result::Result<<__S as serde_core::ser::Serializer>::Ok, <__S as serde_core::ser::Serializer>::Error> where __S: serde_core::ser::Serializer
-impl core::marker::Freeze for radroots_runtime_paths::RuntimeContextSources
-impl core::marker::Send for radroots_runtime_paths::RuntimeContextSources
-impl core::marker::Sync for radroots_runtime_paths::RuntimeContextSources
-impl core::marker::Unpin for radroots_runtime_paths::RuntimeContextSources
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::RuntimeContextSources
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::RuntimeContextSources
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::RuntimeContextSources
pub struct radroots_runtime_paths::ServiceCredentialArtifactName(_)
impl radroots_runtime_paths::ServiceCredentialArtifactName
pub fn radroots_runtime_paths::ServiceCredentialArtifactName::as_str(&self) -> &str
-pub fn radroots_runtime_paths::ServiceCredentialArtifactName::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_runtime_paths::ServiceCredentialArtifactNameError>
-impl core::clone::Clone for radroots_runtime_paths::ServiceCredentialArtifactName
-pub fn radroots_runtime_paths::ServiceCredentialArtifactName::clone(&self) -> radroots_runtime_paths::ServiceCredentialArtifactName
-impl core::cmp::Eq for radroots_runtime_paths::ServiceCredentialArtifactName
-impl core::cmp::Ord for radroots_runtime_paths::ServiceCredentialArtifactName
-pub fn radroots_runtime_paths::ServiceCredentialArtifactName::cmp(&self, &radroots_runtime_paths::ServiceCredentialArtifactName) -> core::cmp::Ordering
-impl core::cmp::PartialEq for radroots_runtime_paths::ServiceCredentialArtifactName
-pub fn radroots_runtime_paths::ServiceCredentialArtifactName::eq(&self, &radroots_runtime_paths::ServiceCredentialArtifactName) -> bool
-impl core::cmp::PartialOrd for radroots_runtime_paths::ServiceCredentialArtifactName
-pub fn radroots_runtime_paths::ServiceCredentialArtifactName::partial_cmp(&self, &radroots_runtime_paths::ServiceCredentialArtifactName) -> core::option::Option<core::cmp::Ordering>
+pub fn radroots_runtime_paths::ServiceCredentialArtifactName::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_runtime_paths::ServiceCredentialArtifactNameError>
impl core::convert::AsRef<str> for radroots_runtime_paths::ServiceCredentialArtifactName
pub fn radroots_runtime_paths::ServiceCredentialArtifactName::as_ref(&self) -> &str
impl core::fmt::Debug for radroots_runtime_paths::ServiceCredentialArtifactName
pub fn radroots_runtime_paths::ServiceCredentialArtifactName::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::hash::Hash for radroots_runtime_paths::ServiceCredentialArtifactName
-pub fn radroots_runtime_paths::ServiceCredentialArtifactName::hash<__H: core::hash::Hasher>(&self, &mut __H)
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::ServiceCredentialArtifactName
-impl core::marker::Freeze for radroots_runtime_paths::ServiceCredentialArtifactName
-impl core::marker::Send for radroots_runtime_paths::ServiceCredentialArtifactName
-impl core::marker::Sync for radroots_runtime_paths::ServiceCredentialArtifactName
-impl core::marker::Unpin for radroots_runtime_paths::ServiceCredentialArtifactName
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::ServiceCredentialArtifactName
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::ServiceCredentialArtifactName
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::ServiceCredentialArtifactName
pub struct radroots_runtime_paths::ServiceId(_)
impl radroots_runtime_paths::ServiceId
pub fn radroots_runtime_paths::ServiceId::as_str(&self) -> &str
pub fn radroots_runtime_paths::ServiceId::into_string(self) -> alloc::string::String
-pub fn radroots_runtime_paths::ServiceId::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_runtime_paths::ServiceIdentityError>
-impl core::clone::Clone for radroots_runtime_paths::ServiceId
-pub fn radroots_runtime_paths::ServiceId::clone(&self) -> radroots_runtime_paths::ServiceId
-impl core::cmp::Eq for radroots_runtime_paths::ServiceId
-impl core::cmp::Ord for radroots_runtime_paths::ServiceId
-pub fn radroots_runtime_paths::ServiceId::cmp(&self, &radroots_runtime_paths::ServiceId) -> core::cmp::Ordering
-impl core::cmp::PartialEq for radroots_runtime_paths::ServiceId
-pub fn radroots_runtime_paths::ServiceId::eq(&self, &radroots_runtime_paths::ServiceId) -> bool
-impl core::cmp::PartialOrd for radroots_runtime_paths::ServiceId
-pub fn radroots_runtime_paths::ServiceId::partial_cmp(&self, &radroots_runtime_paths::ServiceId) -> core::option::Option<core::cmp::Ordering>
+pub fn radroots_runtime_paths::ServiceId::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_runtime_paths::ServiceIdentityError>
impl core::convert::AsRef<str> for radroots_runtime_paths::ServiceId
pub fn radroots_runtime_paths::ServiceId::as_ref(&self) -> &str
impl core::convert::From<radroots_runtime_paths::ServiceId> for alloc::string::String
@@ -449,13 +156,8 @@ pub fn alloc::string::String::from(radroots_runtime_paths::ServiceId) -> Self
impl core::convert::TryFrom<alloc::string::String> for radroots_runtime_paths::ServiceId
pub type radroots_runtime_paths::ServiceId::Error = radroots_runtime_paths::ServiceIdentityError
pub fn radroots_runtime_paths::ServiceId::try_from(alloc::string::String) -> core::result::Result<Self, Self::Error>
-impl core::fmt::Debug for radroots_runtime_paths::ServiceId
-pub fn radroots_runtime_paths::ServiceId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::fmt::Display for radroots_runtime_paths::ServiceId
pub fn radroots_runtime_paths::ServiceId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
-impl core::hash::Hash for radroots_runtime_paths::ServiceId
-pub fn radroots_runtime_paths::ServiceId::hash<__H: core::hash::Hasher>(&self, &mut __H)
-impl core::marker::StructuralPartialEq for radroots_runtime_paths::ServiceId
impl core::str::traits::FromStr for radroots_runtime_paths::ServiceId
pub type radroots_runtime_paths::ServiceId::Err = radroots_runtime_paths::ServiceIdentityError
pub fn radroots_runtime_paths::ServiceId::from_str(&str) -> core::result::Result<Self, Self::Err>
@@ -463,13 +165,6 @@ impl serde_core::ser::Serialize for radroots_runtime_paths::ServiceId
pub fn radroots_runtime_paths::ServiceId::serialize<S>(&self, S) -> core::result::Result<<S as serde_core::ser::Serializer>::Ok, <S as serde_core::ser::Serializer>::Error> where S: serde_core::ser::Serializer
impl<'de> serde_core::de::Deserialize<'de> for radroots_runtime_paths::ServiceId
pub fn radroots_runtime_paths::ServiceId::deserialize<D>(D) -> core::result::Result<Self, <D as serde_core::de::Deserializer>::Error> where D: serde_core::de::Deserializer<'de>
-impl core::marker::Freeze for radroots_runtime_paths::ServiceId
-impl core::marker::Send for radroots_runtime_paths::ServiceId
-impl core::marker::Sync for radroots_runtime_paths::ServiceId
-impl core::marker::Unpin for radroots_runtime_paths::ServiceId
-impl core::marker::UnsafeUnpin for radroots_runtime_paths::ServiceId
-impl core::panic::unwind_safe::RefUnwindSafe for radroots_runtime_paths::ServiceId
-impl core::panic::unwind_safe::UnwindSafe for radroots_runtime_paths::ServiceId
pub const radroots_runtime_paths::DEFAULT_CONFIG_FILE_NAME: &str
pub const radroots_runtime_paths::DEFAULT_SHARED_GEONAMES_NAMESPACE: &str
pub const radroots_runtime_paths::DEFAULT_SHARED_GEONAMES_NAMESPACE_KIND: &str
diff --git a/contracts/api_baselines/radroots_service_host.txt b/contracts/api_baselines/radroots_service_host.txt
@@ -643,7 +643,7 @@ pub fn radroots_service_host::AdminContractVersionError::fmt(&self, &mut core::f
pub struct radroots_service_host::AdminCorrelationId(_)
impl radroots_service_host::AdminCorrelationId
pub fn radroots_service_host::AdminCorrelationId::as_str(&self) -> &str
-pub fn radroots_service_host::AdminCorrelationId::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_service_host::AdminIdentifierError>
+pub fn radroots_service_host::AdminCorrelationId::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_service_host::AdminIdentifierError>
impl core::fmt::Display for radroots_service_host::AdminCorrelationId
pub fn radroots_service_host::AdminCorrelationId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl serde_core::ser::Serialize for radroots_service_host::AdminCorrelationId
@@ -659,7 +659,7 @@ pub const fn radroots_service_host::AdminError::new(radroots_service_host::Admin
pub struct radroots_service_host::AdminErrorCode(_)
impl radroots_service_host::AdminErrorCode
pub fn radroots_service_host::AdminErrorCode::as_str(&self) -> &str
-pub fn radroots_service_host::AdminErrorCode::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_service_host::AdminErrorCodeError>
+pub fn radroots_service_host::AdminErrorCode::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_service_host::AdminErrorCodeError>
impl core::fmt::Display for radroots_service_host::AdminErrorCode
pub fn radroots_service_host::AdminErrorCode::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl serde_core::ser::Serialize for radroots_service_host::AdminErrorCode
@@ -669,7 +669,7 @@ pub fn radroots_service_host::AdminErrorCode::deserialize<D>(D) -> core::result:
pub struct radroots_service_host::AdminErrorMessage(_)
impl radroots_service_host::AdminErrorMessage
pub fn radroots_service_host::AdminErrorMessage::as_str(&self) -> &str
-pub fn radroots_service_host::AdminErrorMessage::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_service_host::AdminErrorMessageError>
+pub fn radroots_service_host::AdminErrorMessage::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_service_host::AdminErrorMessageError>
impl core::fmt::Display for radroots_service_host::AdminErrorMessage
pub fn radroots_service_host::AdminErrorMessage::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl serde_core::ser::Serialize for radroots_service_host::AdminErrorMessage
@@ -696,7 +696,7 @@ pub fn radroots_service_host::AdminMutationRequest<T>::fmt(&self, &mut core::fmt
pub struct radroots_service_host::AdminOperationId(_)
impl radroots_service_host::AdminOperationId
pub fn radroots_service_host::AdminOperationId::as_str(&self) -> &str
-pub fn radroots_service_host::AdminOperationId::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_service_host::AdminIdentifierError>
+pub fn radroots_service_host::AdminOperationId::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_service_host::AdminIdentifierError>
impl core::fmt::Display for radroots_service_host::AdminOperationId
pub fn radroots_service_host::AdminOperationId::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl serde_core::ser::Serialize for radroots_service_host::AdminOperationId
@@ -736,11 +736,11 @@ pub fn radroots_service_host::AdminRouteOutcome::fmt(&self, &mut core::fmt::Form
pub struct radroots_service_host::AdminRoutePath
impl radroots_service_host::AdminRoutePath
pub fn radroots_service_host::AdminRoutePath::as_str(&self) -> &str
-pub fn radroots_service_host::AdminRoutePath::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_service_host::AdminRoutePathError>
+pub fn radroots_service_host::AdminRoutePath::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_service_host::AdminRoutePathError>
pub struct radroots_service_host::AdminRouter
impl radroots_service_host::AdminRouter
pub fn radroots_service_host::AdminRouter::new() -> Self
-pub fn radroots_service_host::AdminRouter::route<F, Fut>(&mut self, radroots_service_host::AdminHttpMethod, impl core::convert::Into<alloc::string::String>, F) -> core::result::Result<(), radroots_service_host::AdminRouteRegistrationError> where F: core::ops::function::Fn(radroots_service_host::AdminRequest) -> Fut + core::marker::Send + core::marker::Sync + 'static, Fut: core::future::future::Future<Output = radroots_service_host::AdminRouteOutcome> + core::marker::Send + 'static
+pub fn radroots_service_host::AdminRouter::route<F, Fut>(&mut self, radroots_service_host::AdminHttpMethod, impl core::convert::AsRef<str>, F) -> core::result::Result<(), radroots_service_host::AdminRouteRegistrationError> where F: core::ops::function::Fn(radroots_service_host::AdminRequest) -> Fut + core::marker::Send + core::marker::Sync + 'static, Fut: core::future::future::Future<Output = radroots_service_host::AdminRouteOutcome> + core::marker::Send + 'static
impl core::fmt::Debug for radroots_service_host::AdminRouter
pub fn radroots_service_host::AdminRouter::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
pub struct radroots_service_host::AdminServer
@@ -876,7 +876,7 @@ impl core::fmt::Display for radroots_service_host::ConfigDocumentError
pub fn radroots_service_host::ConfigDocumentError::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
pub struct radroots_service_host::ConfigDocumentExpectation
impl radroots_service_host::ConfigDocumentExpectation
-pub fn radroots_service_host::ConfigDocumentExpectation::new(impl core::convert::Into<alloc::boxed::Box<str>>, u32) -> core::result::Result<Self, radroots_service_host::ConfigDocumentExpectationError>
+pub fn radroots_service_host::ConfigDocumentExpectation::new(impl core::convert::AsRef<str>, u32) -> core::result::Result<Self, radroots_service_host::ConfigDocumentExpectationError>
pub fn radroots_service_host::ConfigDocumentExpectation::schema(&self) -> &str
pub const fn radroots_service_host::ConfigDocumentExpectation::schema_version(&self) -> u32
impl core::fmt::Debug for radroots_service_host::ConfigDocumentExpectation
@@ -916,14 +916,14 @@ pub fn radroots_service_host::HostError::fmt(&self, &mut core::fmt::Formatter<'_
pub struct radroots_service_host::MetricComponentId(_)
impl radroots_service_host::MetricComponentId
pub fn radroots_service_host::MetricComponentId::as_str(&self) -> &str
-pub fn radroots_service_host::MetricComponentId::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_service_host::MetricsContractError>
+pub fn radroots_service_host::MetricComponentId::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_service_host::MetricsContractError>
pub struct radroots_service_host::MetricDescriptor
impl radroots_service_host::MetricDescriptor
pub const fn radroots_service_host::MetricDescriptor::group(&self) -> radroots_service_host::CommonMetricGroup
pub const fn radroots_service_host::MetricDescriptor::kind(&self) -> radroots_service_host::MetricKind
pub fn radroots_service_host::MetricDescriptor::label_keys(&self) -> &[radroots_service_host::MetricLabelKey]
pub fn radroots_service_host::MetricDescriptor::name(&self) -> &radroots_service_host::MetricName
-pub fn radroots_service_host::MetricDescriptor::new(radroots_service_host::CommonMetricGroup, radroots_service_host::MetricName, impl core::convert::Into<alloc::string::String>, radroots_service_host::MetricKind, impl core::iter::traits::collect::IntoIterator<Item = radroots_service_host::MetricLabelKey>) -> core::result::Result<Self, radroots_service_host::MetricsContractError>
+pub fn radroots_service_host::MetricDescriptor::new(radroots_service_host::CommonMetricGroup, radroots_service_host::MetricName, impl core::convert::AsRef<str>, radroots_service_host::MetricKind, impl core::iter::traits::collect::IntoIterator<Item = radroots_service_host::MetricLabelKey>) -> core::result::Result<Self, radroots_service_host::MetricsContractError>
impl core::fmt::Debug for radroots_service_host::MetricDescriptor
pub fn radroots_service_host::MetricDescriptor::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
pub struct radroots_service_host::MetricLabel
@@ -945,7 +945,7 @@ pub fn radroots_service_host::MetricLabel::fmt(&self, &mut core::fmt::Formatter<
pub struct radroots_service_host::MetricName(_)
impl radroots_service_host::MetricName
pub fn radroots_service_host::MetricName::as_str(&self) -> &str
-pub fn radroots_service_host::MetricName::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_service_host::MetricsContractError>
+pub fn radroots_service_host::MetricName::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_service_host::MetricsContractError>
pub struct radroots_service_host::MetricSample
impl radroots_service_host::MetricSample
pub fn radroots_service_host::MetricSample::labels(&self) -> &[radroots_service_host::MetricLabel]
@@ -1062,7 +1062,7 @@ pub const fn radroots_service_host::Readiness::is_ready(self) -> bool
pub struct radroots_service_host::ReasonCode(_)
impl radroots_service_host::ReasonCode
pub fn radroots_service_host::ReasonCode::as_str(&self) -> &str
-pub fn radroots_service_host::ReasonCode::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_service_host::StatusContractError>
+pub fn radroots_service_host::ReasonCode::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_service_host::StatusContractError>
impl core::convert::From<radroots_service_host::CommonReasonCode> for radroots_service_host::ReasonCode
pub fn radroots_service_host::ReasonCode::from(radroots_service_host::CommonReasonCode) -> Self
impl core::fmt::Display for radroots_service_host::ReasonCode
@@ -1108,7 +1108,7 @@ pub fn radroots_service_host::ServiceStatus<D>::serialize<S>(&self, S) -> core::
pub struct radroots_service_host::Sha256Digest(_)
impl radroots_service_host::Sha256Digest
pub fn radroots_service_host::Sha256Digest::as_str(&self) -> &str
-pub fn radroots_service_host::Sha256Digest::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_service_host::StatusModelError>
+pub fn radroots_service_host::Sha256Digest::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_service_host::StatusModelError>
pub struct radroots_service_host::ShutdownPhaseFailure
impl radroots_service_host::ShutdownPhaseFailure
pub const fn radroots_service_host::ShutdownPhaseFailure::error(&self) -> &radroots_service_host::HostError
@@ -1126,12 +1126,12 @@ pub const fn radroots_service_host::ShutdownSummary::disposition(self) -> radroo
pub struct radroots_service_host::StableRelayId(_)
impl radroots_service_host::StableRelayId
pub fn radroots_service_host::StableRelayId::as_str(&self) -> &str
-pub fn radroots_service_host::StableRelayId::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_service_host::MetricsContractError>
+pub fn radroots_service_host::StableRelayId::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_service_host::MetricsContractError>
pub struct radroots_service_host::StatusBuildInfo<'a>
pub struct radroots_service_host::StatusId(_)
impl radroots_service_host::StatusId
pub fn radroots_service_host::StatusId::as_str(&self) -> &str
-pub fn radroots_service_host::StatusId::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_service_host::StatusModelError>
+pub fn radroots_service_host::StatusId::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_service_host::StatusModelError>
pub struct radroots_service_host::StatusPublisherDropped
impl core::error::Error for radroots_service_host::StatusPublisherDropped
impl core::fmt::Display for radroots_service_host::StatusPublisherDropped
@@ -1176,7 +1176,7 @@ pub const fn radroots_service_host::TaskMetadata::shutdown_phase(&self) -> core:
pub struct radroots_service_host::TaskName(_)
impl radroots_service_host::TaskName
pub fn radroots_service_host::TaskName::as_str(&self) -> &str
-pub fn radroots_service_host::TaskName::new(impl core::convert::Into<alloc::string::String>) -> core::result::Result<Self, radroots_service_host::TaskMetadataError>
+pub fn radroots_service_host::TaskName::new(impl core::convert::AsRef<str>) -> core::result::Result<Self, radroots_service_host::TaskMetadataError>
impl core::fmt::Display for radroots_service_host::TaskName
pub fn radroots_service_host::TaskName::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
pub struct radroots_service_host::TaskSupervisor
diff --git a/crates/runtime_paths/README b/crates/runtime_paths/README
@@ -9,6 +9,9 @@ environment.
- Validated service and instance identifiers define the sole canonical
`services/<service>/<instance>` namespace.
+- Bounded service, instance, and credential artifact names are validated as
+ borrowed UTF-8 before the crate creates their retained strings; Serde identity
+ decoding uses the same boundary without a second prevalidation copy.
- Callers inject the platform, host-environment roots, profile, and typed
bootstrap provenance.
- A sealed `RuntimeContext` is the only public service-instance path
diff --git a/crates/runtime_paths/src/conventions.rs b/crates/runtime_paths/src/conventions.rs
@@ -25,8 +25,8 @@ pub const DEFAULT_SHARED_RUNTIME_STORE_DB_FILE_NAME: &str = "runtime_store.sqlit
pub struct ServiceCredentialArtifactName(String);
impl ServiceCredentialArtifactName {
- pub fn new(value: impl Into<String>) -> Result<Self, ServiceCredentialArtifactNameError> {
- let value = value.into();
+ pub fn new(value: impl AsRef<str>) -> Result<Self, ServiceCredentialArtifactNameError> {
+ let value = value.as_ref();
if value.is_empty() {
return Err(ServiceCredentialArtifactNameError::Empty);
}
@@ -46,7 +46,7 @@ impl ServiceCredentialArtifactName {
{
return Err(ServiceCredentialArtifactNameError::InvalidCharacter);
}
- Ok(Self(value))
+ Ok(Self(value.to_owned()))
}
#[must_use]
@@ -330,6 +330,12 @@ mod tests {
maximum: SERVICE_CREDENTIAL_ARTIFACT_NAME_MAX_BYTES,
})
);
+ assert_eq!(
+ ServiceCredentialArtifactName::new("a".repeat(4 * 1024 * 1024)),
+ Err(ServiceCredentialArtifactNameError::TooLong {
+ maximum: SERVICE_CREDENTIAL_ARTIFACT_NAME_MAX_BYTES,
+ })
+ );
for invalid in [
".",
"..",
diff --git a/crates/runtime_paths/src/identifier.rs b/crates/runtime_paths/src/identifier.rs
@@ -78,8 +78,13 @@ macro_rules! service_identity {
impl $name {
/// Parses and validates a canonical identifier.
- pub fn new(value: impl Into<String>) -> Result<Self, ServiceIdentityError> {
- let value = value.into();
+ pub fn new(value: impl AsRef<str>) -> Result<Self, ServiceIdentityError> {
+ let value = value.as_ref();
+ validate(value, $kind, $maximum)?;
+ Ok(Self(value.to_owned()))
+ }
+
+ fn from_string(value: String) -> Result<Self, ServiceIdentityError> {
validate(&value, $kind, $maximum)?;
Ok(Self(value))
}
@@ -121,7 +126,7 @@ macro_rules! service_identity {
type Error = ServiceIdentityError;
fn try_from(value: String) -> Result<Self, Self::Error> {
- Self::new(value)
+ Self::from_string(value)
}
}
@@ -145,8 +150,31 @@ macro_rules! service_identity {
where
D: Deserializer<'de>,
{
- let value = String::deserialize(deserializer)?;
- Self::new(value).map_err(serde::de::Error::custom)
+ struct Visitor;
+
+ impl<'de> serde::de::Visitor<'de> for Visitor {
+ type Value = $name;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a bounded canonical service identity")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ $name::new(value).map_err(E::custom)
+ }
+
+ fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ $name::from_string(value).map_err(E::custom)
+ }
+ }
+
+ deserializer.deserialize_str(Visitor)
}
}
};
@@ -212,6 +240,26 @@ mod tests {
maximum: INSTANCE_ID_MAX_BYTES,
})
);
+ let very_large = "a".repeat(4 * 1024 * 1024);
+ assert!(matches!(
+ ServiceId::new(&very_large),
+ Err(ServiceIdentityError::TooLong {
+ kind: ServiceIdentityKind::Service,
+ maximum: SERVICE_ID_MAX_BYTES,
+ })
+ ));
+ assert!(matches!(
+ InstanceId::new(&very_large),
+ Err(ServiceIdentityError::TooLong {
+ kind: ServiceIdentityKind::Instance,
+ maximum: INSTANCE_ID_MAX_BYTES,
+ })
+ ));
+
+ let service_json = serde_json::to_string(&very_large).expect("large service JSON");
+ assert!(serde_json::from_str::<ServiceId>(&service_json).is_err());
+ let instance_json = serde_json::to_string(&very_large).expect("large instance JSON");
+ assert!(serde_json::from_str::<InstanceId>(&instance_json).is_err());
for invalid in ["Myc", "café", "a.b", "a:b", "a b", "a%b", "a/b", r"a\b"] {
assert!(ServiceId::new(invalid).is_err(), "accepted `{invalid}`");
diff --git a/crates/runtime_paths/tests/package_boundary.rs b/crates/runtime_paths/tests/package_boundary.rs
@@ -51,7 +51,22 @@ fn runtime_paths_is_unpublished_lint_governed_and_dependency_bounded() {
for source in SOURCES {
let production = source.split("#[cfg(test)]").next().unwrap_or(source);
assert!(!production.contains("std::env"));
+ for forbidden in [
+ "impl Into<String>",
+ "let value = value.into();",
+ "String::deserialize",
+ ] {
+ assert!(
+ !production.contains(forbidden),
+ "bounded runtime-path text boundary still contains `{forbidden}`"
+ );
+ }
}
+ assert!(
+ SOURCES
+ .iter()
+ .any(|source| source.contains("deserializer.deserialize_str(Visitor)"))
+ );
}
#[test]
@@ -128,6 +143,7 @@ fn reviewed_api_requires_the_typed_runtime_context_boundary() {
"## Support Caveats",
"## Public API Baseline",
"The final reviewed root-only API",
+ "validated as\n borrowed UTF-8 before the crate creates their retained strings",
"```rust",
"| Linux `ServiceHost` | `/etc/radroots` | `/var/lib/radroots` | `/var/cache/radroots` | `/var/log/radroots` | `/run/radroots` | `/etc/radroots/secrets` |",
"| Linux `InteractiveUser` | `$XDG_CONFIG_HOME/radroots` | `$XDG_DATA_HOME/radroots` | `$XDG_CACHE_HOME/radroots` | `$XDG_STATE_HOME/radroots/logs` | `$XDG_RUNTIME_DIR/radroots` | `$XDG_CONFIG_HOME/radroots/secrets` |",
diff --git a/crates/service_host/README.md b/crates/service_host/README.md
@@ -101,6 +101,11 @@ or streamed directly into the capped response writer; validation does not
materialize an intermediate `serde_json::Value` tree. Recursive null rejection
and duplicate or unknown field rejection remain fail closed.
+Every bounded text constructor validates borrowed UTF-8 before it creates the
+retained string. Bounded wire strings use validating Serde visitors, so the
+host does not create a second prevalidation copy of identifiers, safe messages,
+reason codes, task names, routes, or metric vocabulary.
+
## Process and runtime ownership
The crate does not parse a CLI, read configuration from environment variables,
diff --git a/crates/service_host/src/admin/model.rs b/crates/service_host/src/admin/model.rs
@@ -49,8 +49,19 @@ macro_rules! admin_identifier {
pub struct $name(String);
impl $name {
- pub fn new(value: impl Into<String>) -> Result<Self, AdminIdentifierError> {
- let value = value.into();
+ pub fn new(value: impl AsRef<str>) -> Result<Self, AdminIdentifierError> {
+ let value = value.as_ref();
+ let field = $field;
+ if value.is_empty() {
+ return Err(AdminIdentifierError::Empty { field });
+ }
+ if value.len() > field.maximum_utf8_bytes() {
+ return Err(AdminIdentifierError::TooLong { field });
+ }
+ Ok(Self(value.to_owned()))
+ }
+
+ fn from_string(value: String) -> Result<Self, AdminIdentifierError> {
let field = $field;
if value.is_empty() {
return Err(AdminIdentifierError::Empty { field });
@@ -87,8 +98,31 @@ macro_rules! admin_identifier {
where
D: Deserializer<'de>,
{
- let value = String::deserialize(deserializer)?;
- Self::new(value).map_err(de::Error::custom)
+ struct Visitor;
+
+ impl<'de> de::Visitor<'de> for Visitor {
+ type Value = $name;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a bounded admin identifier")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ $name::new(value).map_err(E::custom)
+ }
+
+ fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ $name::from_string(value).map_err(E::custom)
+ }
+ }
+
+ deserializer.deserialize_str(Visitor)
}
}
};
@@ -116,20 +150,14 @@ impl Error for AdminErrorCodeError {}
pub struct AdminErrorCode(String);
impl AdminErrorCode {
- pub fn new(value: impl Into<String>) -> Result<Self, AdminErrorCodeError> {
- let value = value.into();
- if value.is_empty() {
- return Err(AdminErrorCodeError::Empty);
- }
- if value.len() > ADMIN_ERROR_CODE_MAX_UTF8_BYTES {
- return Err(AdminErrorCodeError::TooLong);
- }
- let mut bytes = value.bytes();
- if !matches!(bytes.next(), Some(b'a'..=b'z'))
- || !bytes.all(|byte| matches!(byte, b'a'..=b'z' | b'0'..=b'9' | b'_'))
- {
- return Err(AdminErrorCodeError::InvalidCharacter);
- }
+ pub fn new(value: impl AsRef<str>) -> Result<Self, AdminErrorCodeError> {
+ let value = value.as_ref();
+ validate_admin_error_code(value)?;
+ Ok(Self(value.to_owned()))
+ }
+
+ fn from_string(value: String) -> Result<Self, AdminErrorCodeError> {
+ validate_admin_error_code(&value)?;
Ok(Self(value))
}
@@ -143,6 +171,22 @@ impl AdminErrorCode {
}
}
+fn validate_admin_error_code(value: &str) -> Result<(), AdminErrorCodeError> {
+ if value.is_empty() {
+ return Err(AdminErrorCodeError::Empty);
+ }
+ if value.len() > ADMIN_ERROR_CODE_MAX_UTF8_BYTES {
+ return Err(AdminErrorCodeError::TooLong);
+ }
+ let mut bytes = value.bytes();
+ if !matches!(bytes.next(), Some(b'a'..=b'z'))
+ || !bytes.all(|byte| matches!(byte, b'a'..=b'z' | b'0'..=b'9' | b'_'))
+ {
+ return Err(AdminErrorCodeError::InvalidCharacter);
+ }
+ Ok(())
+}
+
impl fmt::Display for AdminErrorCode {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
@@ -163,8 +207,31 @@ impl<'de> Deserialize<'de> for AdminErrorCode {
where
D: Deserializer<'de>,
{
- let value = String::deserialize(deserializer)?;
- Self::new(value).map_err(de::Error::custom)
+ struct Visitor;
+
+ impl<'de> de::Visitor<'de> for Visitor {
+ type Value = AdminErrorCode;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a bounded lowercase admin error code")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ AdminErrorCode::new(value).map_err(E::custom)
+ }
+
+ fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ AdminErrorCode::from_string(value).map_err(E::custom)
+ }
+ }
+
+ deserializer.deserialize_str(Visitor)
}
}
@@ -1290,17 +1357,14 @@ fn checked_non_null(value: &impl Serialize) -> Result<(), AdminPayloadError> {
pub struct AdminErrorMessage(String);
impl AdminErrorMessage {
- pub fn new(value: impl Into<String>) -> Result<Self, AdminErrorMessageError> {
- let value = value.into();
- if value.is_empty() {
- return Err(AdminErrorMessageError::Empty);
- }
- if value.len() > ADMIN_ERROR_MESSAGE_MAX_UTF8_BYTES {
- return Err(AdminErrorMessageError::TooLong);
- }
- if value.chars().any(char::is_control) {
- return Err(AdminErrorMessageError::ControlCharacter);
- }
+ pub fn new(value: impl AsRef<str>) -> Result<Self, AdminErrorMessageError> {
+ let value = value.as_ref();
+ validate_admin_error_message(value)?;
+ Ok(Self(value.to_owned()))
+ }
+
+ fn from_string(value: String) -> Result<Self, AdminErrorMessageError> {
+ validate_admin_error_message(&value)?;
Ok(Self(value))
}
@@ -1314,6 +1378,19 @@ impl AdminErrorMessage {
}
}
+fn validate_admin_error_message(value: &str) -> Result<(), AdminErrorMessageError> {
+ if value.is_empty() {
+ return Err(AdminErrorMessageError::Empty);
+ }
+ if value.len() > ADMIN_ERROR_MESSAGE_MAX_UTF8_BYTES {
+ return Err(AdminErrorMessageError::TooLong);
+ }
+ if value.chars().any(char::is_control) {
+ return Err(AdminErrorMessageError::ControlCharacter);
+ }
+ Ok(())
+}
+
impl fmt::Display for AdminErrorMessage {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
@@ -1334,8 +1411,31 @@ impl<'de> Deserialize<'de> for AdminErrorMessage {
where
D: Deserializer<'de>,
{
- let value = String::deserialize(deserializer)?;
- Self::new(value).map_err(de::Error::custom)
+ struct Visitor;
+
+ impl<'de> de::Visitor<'de> for Visitor {
+ type Value = AdminErrorMessage;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a bounded safe admin error message")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ AdminErrorMessage::new(value).map_err(E::custom)
+ }
+
+ fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ AdminErrorMessage::from_string(value).map_err(E::custom)
+ }
+ }
+
+ deserializer.deserialize_str(Visitor)
}
}
@@ -1989,6 +2089,7 @@ mod tests {
assert!(AdminCorrelationId::new("é".repeat(64)).is_ok());
assert!(AdminCorrelationId::new(format!("{}x", "é".repeat(64))).is_err());
assert!(AdminErrorCode::new("valid_code_2").is_ok());
+ assert!(AdminErrorCode::new("x".repeat(ADMIN_ERROR_CODE_MAX_UTF8_BYTES)).is_ok());
assert!(AdminErrorCode::new("Invalid-Code").is_err());
assert!(AdminErrorCode::new("valid-code").is_err());
assert!(AdminErrorMessage::new("x".repeat(ADMIN_ERROR_MESSAGE_MAX_UTF8_BYTES)).is_ok());
@@ -1997,6 +2098,17 @@ mod tests {
);
assert!(AdminErrorMessage::new("unsafe\nmessage").is_err());
+ let very_large = "x".repeat(4 * 1024 * 1024);
+ assert!(AdminOperationId::new(&very_large).is_err());
+ assert!(AdminCorrelationId::new(&very_large).is_err());
+ assert!(AdminErrorCode::new(&very_large).is_err());
+ assert!(AdminErrorMessage::new(&very_large).is_err());
+ let very_large_json = serde_json::to_string(&very_large).expect("large admin JSON string");
+ assert!(serde_json::from_str::<AdminOperationId>(&very_large_json).is_err());
+ assert!(serde_json::from_str::<AdminCorrelationId>(&very_large_json).is_err());
+ assert!(serde_json::from_str::<AdminErrorCode>(&very_large_json).is_err());
+ assert!(serde_json::from_str::<AdminErrorMessage>(&very_large_json).is_err());
+
let wrong_success: Result<AdminSuccessResponse<ExampleResult>, _> = serde_json::from_str(
r#"{"contract_version":1,"ok":false,"correlation_id":"safe-correlation","result":{"state":"committed"}}"#,
);
diff --git a/crates/service_host/src/admin/server.rs b/crates/service_host/src/admin/server.rs
@@ -89,8 +89,8 @@ enum AdminRouteSegment {
}
impl AdminRoutePath {
- pub fn new(value: impl Into<String>) -> Result<Self, AdminRoutePathError> {
- let value = value.into();
+ pub fn new(value: impl AsRef<str>) -> Result<Self, AdminRoutePathError> {
+ let value = value.as_ref();
if value.is_empty() {
return Err(AdminRoutePathError::Empty);
}
@@ -102,7 +102,6 @@ impl AdminRoutePath {
}
let mut parameter_names = BTreeSet::new();
let mut literal_count = 0;
- let mut segments = Vec::new();
for segment in value[1..].split('/') {
if segment.is_empty() {
return Err(AdminRoutePathError::EmptySegment);
@@ -114,10 +113,9 @@ impl AdminRoutePath {
if !valid_parameter_name(parameter) {
return Err(AdminRoutePathError::InvalidParameter);
}
- if !parameter_names.insert(parameter.to_owned()) {
+ if !parameter_names.insert(parameter) {
return Err(AdminRoutePathError::DuplicateParameter);
}
- segments.push(AdminRouteSegment::Parameter(parameter.to_owned()));
} else {
if !segment
.bytes()
@@ -126,11 +124,22 @@ impl AdminRoutePath {
return Err(AdminRoutePathError::InvalidCharacter);
}
literal_count += 1;
- segments.push(AdminRouteSegment::Literal(segment.to_owned()));
}
}
+ let segments = value[1..]
+ .split('/')
+ .map(|segment| {
+ segment
+ .strip_prefix('{')
+ .and_then(|segment| segment.strip_suffix('}'))
+ .map_or_else(
+ || AdminRouteSegment::Literal(segment.to_owned()),
+ |parameter| AdminRouteSegment::Parameter(parameter.to_owned()),
+ )
+ })
+ .collect();
Ok(Self {
- canonical: value,
+ canonical: value.to_owned(),
segments,
literal_count,
})
@@ -587,7 +596,7 @@ impl AdminRouter {
pub fn route<F, Fut>(
&mut self,
method: AdminHttpMethod,
- path: impl Into<String>,
+ path: impl AsRef<str>,
handler: F,
) -> Result<(), AdminRouteRegistrationError>
where
@@ -2153,6 +2162,16 @@ mod tests {
for (path, expected) in invalid_paths {
assert_eq!(AdminRoutePath::new(path).unwrap_err(), expected);
}
+ let exact_maximum = format!(
+ "/v1/{}",
+ "x".repeat(ADMIN_ROUTE_PATH_MAX_UTF8_BYTES - "/v1/".len())
+ );
+ assert_eq!(
+ AdminRoutePath::new(&exact_maximum)
+ .expect("exact maximum route")
+ .as_str(),
+ exact_maximum
+ );
assert_eq!(
AdminRoutePath::new(format!(
"/v1/{}",
@@ -2161,6 +2180,10 @@ mod tests {
.unwrap_err(),
AdminRoutePathError::TooLong
);
+ assert_eq!(
+ AdminRoutePath::new(format!("/v1/{}", "x".repeat(4 * 1024 * 1024))),
+ Err(AdminRoutePathError::TooLong)
+ );
assert_eq!(
AdminHttpMethod::from_http(&Method::GET),
diff --git a/crates/service_host/src/config/document.rs b/crates/service_host/src/config/document.rs
@@ -23,18 +23,18 @@ pub struct ConfigDocumentExpectation {
impl ConfigDocumentExpectation {
/// Creates an exact expected document identity.
pub fn new(
- schema: impl Into<Box<str>>,
+ schema: impl AsRef<str>,
schema_version: u32,
) -> Result<Self, ConfigDocumentExpectationError> {
- let schema = schema.into();
- if !valid_schema_id(&schema) {
+ let schema = schema.as_ref();
+ if !valid_schema_id(schema) {
return Err(ConfigDocumentExpectationError::InvalidSchema);
}
if schema_version == 0 {
return Err(ConfigDocumentExpectationError::InvalidSchemaVersion);
}
Ok(Self {
- schema,
+ schema: schema.to_owned().into_boxed_str(),
schema_version,
})
}
@@ -645,12 +645,19 @@ mod tests {
ConfigDocumentExpectation::new("bad schema", 1).unwrap_err(),
ConfigDocumentExpectationError::InvalidSchema
);
+ assert!(
+ ConfigDocumentExpectation::new("a".repeat(CONFIG_SCHEMA_ID_MAX_UTF8_BYTES), 1).is_ok()
+ );
assert_eq!(
ConfigDocumentExpectation::new("a".repeat(CONFIG_SCHEMA_ID_MAX_UTF8_BYTES + 1), 1,)
.unwrap_err(),
ConfigDocumentExpectationError::InvalidSchema
);
assert_eq!(
+ ConfigDocumentExpectation::new("a".repeat(4 * 1024 * 1024), 1).unwrap_err(),
+ ConfigDocumentExpectationError::InvalidSchema
+ );
+ assert_eq!(
ConfigDocumentExpectation::new("radroots.example.config", 0).unwrap_err(),
ConfigDocumentExpectationError::InvalidSchemaVersion
);
diff --git a/crates/service_host/src/config/value.rs b/crates/service_host/src/config/value.rs
@@ -1,6 +1,7 @@
//! Validated service-neutral configuration leaf values.
use core::fmt;
+use core::marker::PhantomData;
use core::str::FromStr;
use core::time::Duration;
use std::error::Error;
@@ -107,9 +108,7 @@ impl<'de> Deserialize<'de> for PositiveDuration {
where
D: Deserializer<'de>,
{
- String::deserialize(deserializer)?
- .parse()
- .map_err(D::Error::custom)
+ deserialize_from_str(deserializer)
}
}
@@ -209,9 +208,7 @@ impl<'de> Deserialize<'de> for ByteLimit {
where
D: Deserializer<'de>,
{
- String::deserialize(deserializer)?
- .parse()
- .map_err(D::Error::custom)
+ deserialize_from_str(deserializer)
}
}
@@ -355,9 +352,7 @@ impl<'de> Deserialize<'de> for LoggingFormat {
where
D: Deserializer<'de>,
{
- String::deserialize(deserializer)?
- .parse()
- .map_err(D::Error::custom)
+ deserialize_from_str(deserializer)
}
}
@@ -478,9 +473,7 @@ impl<'de> Deserialize<'de> for OptionalOperationsBind {
where
D: Deserializer<'de>,
{
- String::deserialize(deserializer)?
- .parse()
- .map_err(D::Error::custom)
+ deserialize_from_str(deserializer)
}
}
@@ -505,6 +498,43 @@ enum HumanQuantityError {
Overflow,
}
+fn deserialize_from_str<'de, D, T>(deserializer: D) -> Result<T, D::Error>
+where
+ D: Deserializer<'de>,
+ T: FromStr,
+ T::Err: fmt::Display,
+{
+ struct FromStrVisitor<T>(PhantomData<T>);
+
+ impl<'de, T> serde::de::Visitor<'de> for FromStrVisitor<T>
+ where
+ T: FromStr,
+ T::Err: fmt::Display,
+ {
+ type Value = T;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a canonical bounded configuration string")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ value.parse().map_err(E::custom)
+ }
+
+ fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ value.parse().map_err(E::custom)
+ }
+ }
+
+ deserializer.deserialize_str(FromStrVisitor(PhantomData))
+}
+
fn parse_human_quantity(value: &str, units: &[(&str, u64)]) -> Result<u64, HumanQuantityError> {
let Some((number, multiplier)) = units.iter().find_map(|(unit, multiplier)| {
value.strip_suffix(unit).map(|number| (number, *multiplier))
diff --git a/crates/service_host/src/lifecycle/task.rs b/crates/service_host/src/lifecycle/task.rs
@@ -12,12 +12,12 @@ pub const TASK_NAME_MAX_BYTES: usize = 64;
pub struct TaskName(String);
impl TaskName {
- pub fn new(value: impl Into<String>) -> Result<Self, TaskMetadataError> {
- let value = value.into();
- if !valid_task_name(&value) {
+ pub fn new(value: impl AsRef<str>) -> Result<Self, TaskMetadataError> {
+ let value = value.as_ref();
+ if !valid_task_name(value) {
return Err(TaskMetadataError::InvalidTaskName);
}
- Ok(Self(value))
+ Ok(Self(value.to_owned()))
}
#[must_use]
@@ -184,6 +184,10 @@ mod tests {
);
}
assert!(TaskName::new("a".repeat(TASK_NAME_MAX_BYTES + 1)).is_err());
+ assert_eq!(
+ TaskName::new("a".repeat(4 * 1024 * 1024)),
+ Err(TaskMetadataError::InvalidTaskName)
+ );
}
#[test]
diff --git a/crates/service_host/src/operations/metrics.rs b/crates/service_host/src/operations/metrics.rs
@@ -63,8 +63,8 @@ pub enum MetricLabelKey {
pub struct MetricComponentId(String);
impl MetricComponentId {
- pub fn new(value: impl Into<String>) -> Result<Self, MetricsContractError> {
- let value = value.into();
+ pub fn new(value: impl AsRef<str>) -> Result<Self, MetricsContractError> {
+ let value = value.as_ref();
if value.is_empty()
|| value.len() > METRIC_LABEL_VALUE_MAX_BYTES
|| !value.bytes().enumerate().all(|(index, byte)| {
@@ -77,7 +77,7 @@ impl MetricComponentId {
{
return Err(MetricsContractError::InvalidComponentId);
}
- Ok(Self(value))
+ Ok(Self(value.to_owned()))
}
#[must_use]
@@ -173,12 +173,12 @@ impl MetricLabelKey {
pub struct MetricName(String);
impl MetricName {
- pub fn new(value: impl Into<String>) -> Result<Self, MetricsContractError> {
- let value = value.into();
- if value.is_empty() || value.len() > METRIC_NAME_MAX_BYTES || !valid_metric_name(&value) {
+ pub fn new(value: impl AsRef<str>) -> Result<Self, MetricsContractError> {
+ let value = value.as_ref();
+ if value.is_empty() || value.len() > METRIC_NAME_MAX_BYTES || !valid_metric_name(value) {
return Err(MetricsContractError::InvalidMetricName);
}
- Ok(Self(value))
+ Ok(Self(value.to_owned()))
}
#[must_use]
@@ -192,8 +192,8 @@ impl MetricName {
pub struct StableRelayId(String);
impl StableRelayId {
- pub fn new(value: impl Into<String>) -> Result<Self, MetricsContractError> {
- let value = value.into();
+ pub fn new(value: impl AsRef<str>) -> Result<Self, MetricsContractError> {
+ let value = value.as_ref();
if value.is_empty()
|| value.len() > STABLE_RELAY_ID_MAX_BYTES
|| !value.bytes().enumerate().all(|(index, byte)| {
@@ -208,7 +208,7 @@ impl StableRelayId {
{
return Err(MetricsContractError::InvalidStableRelayId);
}
- Ok(Self(value))
+ Ok(Self(value.to_owned()))
}
#[must_use]
@@ -221,8 +221,8 @@ impl StableRelayId {
struct MetricLabelValue(String);
impl MetricLabelValue {
- fn new(value: impl Into<String>) -> Result<Self, MetricsContractError> {
- let value = value.into();
+ fn new(value: impl AsRef<str>) -> Result<Self, MetricsContractError> {
+ let value = value.as_ref();
if value.is_empty()
|| value.len() > METRIC_LABEL_VALUE_MAX_BYTES
|| !value.bytes().enumerate().all(|(index, byte)| {
@@ -235,7 +235,7 @@ impl MetricLabelValue {
{
return Err(MetricsContractError::InvalidLabelValue);
}
- Ok(Self(value))
+ Ok(Self(value.to_owned()))
}
fn as_str(&self) -> &str {
@@ -292,17 +292,17 @@ impl MetricLabel {
#[must_use]
pub fn storage(storage: MetricComponentId) -> Self {
- Self::fixed(MetricLabelKey::Storage, storage.0)
+ Self::fixed_owned(MetricLabelKey::Storage, storage.0)
}
#[must_use]
pub fn transport(transport: MetricComponentId) -> Self {
- Self::fixed(MetricLabelKey::Transport, transport.0)
+ Self::fixed_owned(MetricLabelKey::Transport, transport.0)
}
#[must_use]
pub fn relay_id(value: StableRelayId) -> Self {
- Self::fixed(MetricLabelKey::RelayId, value.0)
+ Self::fixed_owned(MetricLabelKey::RelayId, value.0)
}
#[must_use]
@@ -332,10 +332,17 @@ impl MetricLabel {
})
}
- fn fixed(key: MetricLabelKey, value: impl Into<String>) -> Self {
+ fn fixed(key: MetricLabelKey, value: &'static str) -> Self {
Self {
key,
- value: MetricLabelValue(value.into()),
+ value: MetricLabelValue(value.to_owned()),
+ }
+ }
+
+ fn fixed_owned(key: MetricLabelKey, value: String) -> Self {
+ Self {
+ key,
+ value: MetricLabelValue(value),
}
}
}
@@ -364,11 +371,11 @@ impl MetricDescriptor {
pub fn new(
group: CommonMetricGroup,
name: MetricName,
- help: impl Into<String>,
+ help: impl AsRef<str>,
kind: MetricKind,
label_keys: impl IntoIterator<Item = MetricLabelKey>,
) -> Result<Self, MetricsContractError> {
- let help = help.into();
+ let help = help.as_ref();
if help.is_empty()
|| help.len() > METRIC_HELP_MAX_BYTES
|| help
@@ -394,7 +401,7 @@ impl MetricDescriptor {
Ok(Self {
group,
name,
- help,
+ help: help.to_owned(),
kind,
label_keys,
})
@@ -1286,6 +1293,7 @@ mod tests {
));
assert!(MetricName::new("_metric").is_ok());
assert!(MetricName::new(":metric9").is_ok());
+ assert!(MetricName::new("a".repeat(METRIC_NAME_MAX_BYTES)).is_ok());
assert_eq!(
MetricName::new("").unwrap_err(),
MetricsContractError::InvalidMetricName
@@ -1302,10 +1310,57 @@ mod tests {
StableRelayId::new("x".repeat(STABLE_RELAY_ID_MAX_BYTES + 1)),
Err(MetricsContractError::InvalidStableRelayId)
);
+ assert!(StableRelayId::new("x".repeat(STABLE_RELAY_ID_MAX_BYTES)).is_ok());
assert_eq!(
MetricComponentId::new("x".repeat(METRIC_LABEL_VALUE_MAX_BYTES + 1)),
Err(MetricsContractError::InvalidComponentId)
);
+ assert!(MetricComponentId::new("x".repeat(METRIC_LABEL_VALUE_MAX_BYTES)).is_ok());
+ assert!(MetricLabelValue::new("x".repeat(METRIC_LABEL_VALUE_MAX_BYTES)).is_ok());
+ assert!(matches!(
+ MetricLabelValue::new("x".repeat(METRIC_LABEL_VALUE_MAX_BYTES + 1)),
+ Err(MetricsContractError::InvalidLabelValue)
+ ));
+
+ let exact_help = "x".repeat(METRIC_HELP_MAX_BYTES);
+ assert!(
+ MetricDescriptor::new(
+ CommonMetricGroup::Phase,
+ name("radroots_exact_help"),
+ &exact_help,
+ MetricKind::Gauge,
+ [MetricLabelKey::Phase],
+ )
+ .is_ok()
+ );
+
+ let very_large = "x".repeat(4 * 1024 * 1024);
+ assert_eq!(
+ MetricName::new(&very_large),
+ Err(MetricsContractError::InvalidMetricName)
+ );
+ assert_eq!(
+ StableRelayId::new(&very_large),
+ Err(MetricsContractError::InvalidStableRelayId)
+ );
+ assert_eq!(
+ MetricComponentId::new(&very_large),
+ Err(MetricsContractError::InvalidComponentId)
+ );
+ assert!(matches!(
+ MetricLabelValue::new(&very_large),
+ Err(MetricsContractError::InvalidLabelValue)
+ ));
+ assert_eq!(
+ MetricDescriptor::new(
+ CommonMetricGroup::Phase,
+ name("radroots_very_large_help"),
+ &very_large,
+ MetricKind::Gauge,
+ [MetricLabelKey::Phase],
+ ),
+ Err(MetricsContractError::InvalidHelp)
+ );
for error in [
MetricsContractError::InvalidMetricName.to_string(),
diff --git a/crates/service_host/src/status/reason.rs b/crates/service_host/src/status/reason.rs
@@ -51,8 +51,15 @@ impl CommonReasonCode {
pub struct ReasonCode(String);
impl ReasonCode {
- pub fn new(value: impl Into<String>) -> Result<Self, StatusContractError> {
- let value = value.into();
+ pub fn new(value: impl AsRef<str>) -> Result<Self, StatusContractError> {
+ let value = value.as_ref();
+ if !valid_reason_code(value) {
+ return Err(StatusContractError::InvalidReasonCode);
+ }
+ Ok(Self(value.to_owned()))
+ }
+
+ fn from_string(value: String) -> Result<Self, StatusContractError> {
if !valid_reason_code(&value) {
return Err(StatusContractError::InvalidReasonCode);
}
@@ -99,7 +106,31 @@ impl<'de> Deserialize<'de> for ReasonCode {
where
D: Deserializer<'de>,
{
- Self::new(String::deserialize(deserializer)?).map_err(serde::de::Error::custom)
+ struct ReasonCodeVisitor;
+
+ impl<'de> serde::de::Visitor<'de> for ReasonCodeVisitor {
+ type Value = ReasonCode;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("a bounded canonical reason code")
+ }
+
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ ReasonCode::new(value).map_err(E::custom)
+ }
+
+ fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ ReasonCode::from_string(value).map_err(E::custom)
+ }
+ }
+
+ deserializer.deserialize_str(ReasonCodeVisitor)
}
}
@@ -234,6 +265,14 @@ mod tests {
);
}
assert!(ReasonCode::new("a".repeat(REASON_CODE_MAX_BYTES + 1)).is_err());
+
+ let very_large = "a".repeat(4 * 1024 * 1024);
+ assert_eq!(
+ ReasonCode::new(&very_large),
+ Err(StatusContractError::InvalidReasonCode)
+ );
+ let encoded = serde_json::to_string(&very_large).expect("large reason JSON");
+ assert!(serde_json::from_str::<ReasonCode>(&encoded).is_err());
}
#[test]
diff --git a/crates/service_host/src/status/service.rs b/crates/service_host/src/status/service.rs
@@ -21,12 +21,12 @@ pub const STATUS_ID_MAX_BYTES: usize = 128;
pub struct StatusId(String);
impl StatusId {
- pub fn new(value: impl Into<String>) -> Result<Self, StatusModelError> {
- let value = value.into();
- if !valid_status_id(&value) {
+ pub fn new(value: impl AsRef<str>) -> Result<Self, StatusModelError> {
+ let value = value.as_ref();
+ if !valid_status_id(value) {
return Err(StatusModelError::InvalidStatusId);
}
- Ok(Self(value))
+ Ok(Self(value.to_owned()))
}
#[must_use]
@@ -41,8 +41,8 @@ impl StatusId {
pub struct Sha256Digest(String);
impl Sha256Digest {
- pub fn new(value: impl Into<String>) -> Result<Self, StatusModelError> {
- let value = value.into();
+ pub fn new(value: impl AsRef<str>) -> Result<Self, StatusModelError> {
+ let value = value.as_ref();
if value.len() != 64
|| !value
.bytes()
@@ -50,7 +50,7 @@ impl Sha256Digest {
{
return Err(StatusModelError::InvalidSha256Digest);
}
- Ok(Self(value))
+ Ok(Self(value.to_owned()))
}
#[must_use]
@@ -615,8 +615,18 @@ mod tests {
}
assert!(StatusId::new("a".repeat(STATUS_ID_MAX_BYTES)).is_ok());
assert!(StatusId::new("a".repeat(STATUS_ID_MAX_BYTES + 1)).is_err());
+ let very_large = "a".repeat(4 * 1024 * 1024);
+ assert_eq!(
+ StatusId::new(&very_large),
+ Err(StatusModelError::InvalidStatusId)
+ );
assert!(Sha256Digest::new("a".repeat(63)).is_err());
+ assert!(Sha256Digest::new("a".repeat(64)).is_ok());
assert!(Sha256Digest::new("A".repeat(64)).is_err());
+ assert_eq!(
+ Sha256Digest::new(&very_large),
+ Err(StatusModelError::InvalidSha256Digest)
+ );
let myc = ServiceId::new("myc").unwrap();
assert_eq!(
validate_configuration_binding(
diff --git a/crates/service_host/tests/package_boundary.rs b/crates/service_host/tests/package_boundary.rs
@@ -94,6 +94,7 @@ fn service_host_is_unpublished_lint_governed_and_dependency_bounded() {
for required in [
".take(REASON_CODES_MAX_ITEMS + 1)",
"deserialize_seq(ReasonCodesVisitor)",
+ "deserializer.deserialize_str(ReasonCodeVisitor)",
] {
assert!(STATUS_SOURCE.contains(required));
}
@@ -111,6 +112,26 @@ fn service_host_is_unpublished_lint_governed_and_dependency_bounded() {
] {
assert!(!ADMIN_SOURCE.contains(forbidden));
}
+ for source in [
+ CONFIG_DOCUMENT_SOURCE,
+ CONFIG_VALUE_SOURCE,
+ ADMIN_SOURCE,
+ STATUS_SOURCE,
+ LIFECYCLE_SOURCE,
+ OPERATIONS_PRIMITIVES_SOURCE,
+ ] {
+ for forbidden in [
+ "impl Into<String>",
+ "impl Into<Box<str>>",
+ "let value = value.into();",
+ "String::deserialize",
+ ] {
+ assert!(
+ !source.contains(forbidden),
+ "bounded text boundary still contains `{forbidden}`"
+ );
+ }
+ }
for forbidden in ["tokio::signal", "ctrl_c", "signal_hook"] {
assert!(!LIFECYCLE_SOURCE.contains(forbidden));
}
@@ -150,6 +171,7 @@ fn documentation_and_reviewed_public_api_are_complete_and_dependency_safe() {
"cached_service_state(CachedServiceState::new",
"parent.child_token()",
"streamed directly into the capped response writer",
+ "validates borrowed UTF-8 before it creates the",
] {
assert!(README.contains(required), "README is missing `{required}`");
}