use super::{ProviderCredentials, ProviderInfo, ProviderUrl, ProviderWithPreflight};
use crate::Result;
#[doc(hidden)]
pub struct ProviderMetadata {
pub info: ProviderInfo,
pub schemes: &'static [&'static str],
pub credential_names: &'static [&'static str],
#[cfg_attr(not(any(feature = "cli", test)), allow(dead_code))]
pub reads: bool,
pub deletes: bool,
}
#[doc(hidden)]
pub struct ProviderRegistration {
pub metadata: &'static ProviderMetadata,
pub factory: fn(&ProviderUrl, ProviderCredentials) -> Result<ProviderWithPreflight>,
}
#[doc(hidden)]
pub const fn declared_flag(values: &[bool]) -> bool {
matches!(values, [true, ..])
}
#[doc(hidden)]
pub const fn declared_read_capability(values: &[bool]) -> bool {
match values {
[reads, ..] => *reads,
[] => true,
}
}
#[doc(hidden)]
#[linkme::distributed_slice]
pub static PROVIDER_REGISTRY: [ProviderRegistration];
#[doc(hidden)]
#[macro_export]
macro_rules! register_disabled_provider {
(
feature: $feature:literal,
metadata: $metadata:expr $(,)?
) => {
const _: () = {
#[linkme::distributed_slice($crate::provider::PROVIDER_REGISTRY)]
#[doc(hidden)]
static PROVIDER_REGISTRATION: $crate::provider::ProviderRegistration =
$crate::provider::ProviderRegistration {
metadata: $metadata,
factory: |_url, _credentials| {
Err($crate::SecretSpecError::ProviderFeatureDisabled {
provider: $metadata.info.name.to_string(),
feature: $feature,
})
},
};
};
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! register_provider {
(
struct: $struct_name:ident,
config: $config_type:ty,
metadata: $metadata:expr $(,)?) => {
$crate::register_provider!(@register
$struct_name, $config_type, $metadata,
|provider| {
Ok($crate::provider::ProviderWithPreflight {
provider: Box::new(provider),
preflight: None,
})
}
);
};
(
struct: $struct_name:ident,
config: $config_type:ty,
metadata: $metadata:expr,
preflight: $preflight:ident $(,)?) => {
$crate::register_provider!(@register
$struct_name, $config_type, $metadata,
|provider| {
let provider = std::sync::Arc::new(provider);
let preflight_provider = std::sync::Arc::clone(&provider);
Ok($crate::provider::ProviderWithPreflight {
provider: Box::new(provider),
preflight: Some(Box::new(move || preflight_provider.$preflight())),
})
}
);
};
(
struct: $struct_name:ident,
config: $config_type:ty,
name: $name:expr,
description: $description:expr,
schemes: [$($scheme:expr),* $(,)?],
examples: [$($example:expr),* $(,)?]
$(, credential_names: [$($credential_name:expr),* $(,)?])?
$(, reads: $reads:literal)?
$(, deletes: $deletes:literal)? $(,)?
) => {
$crate::register_provider!(@register
$struct_name, $config_type,
&$crate::provider::ProviderMetadata {
info: $crate::provider::ProviderInfo {
name: $name,
description: $description,
examples: &[$($example,)*],
},
schemes: &[$($scheme,)*],
credential_names: &[$($($credential_name,)*)?],
reads: $crate::provider::declared_read_capability(&[$($reads,)?]),
deletes: $crate::provider::declared_flag(&[$($deletes,)?]),
},
|provider| {
Ok($crate::provider::ProviderWithPreflight {
provider: Box::new(provider),
preflight: None,
})
}
);
};
(
struct: $struct_name:ident,
config: $config_type:ty,
name: $name:expr,
description: $description:expr,
schemes: [$($scheme:expr),* $(,)?],
examples: [$($example:expr),* $(,)?],
$(credential_names: [$($credential_name:expr),* $(,)?],)?
$(reads: $reads:literal,)?
$(deletes: $deletes:literal,)?
preflight: $preflight:ident $(,)?
) => {
$crate::register_provider!(@register
$struct_name, $config_type,
&$crate::provider::ProviderMetadata {
info: $crate::provider::ProviderInfo {
name: $name,
description: $description,
examples: &[$($example,)*],
},
schemes: &[$($scheme,)*],
credential_names: &[$($($credential_name,)*)?],
reads: $crate::provider::declared_read_capability(&[$($reads,)?]),
deletes: $crate::provider::declared_flag(&[$($deletes,)?]),
},
|provider| {
let provider = std::sync::Arc::new(provider);
let preflight_provider = std::sync::Arc::clone(&provider);
Ok($crate::provider::ProviderWithPreflight {
provider: Box::new(provider),
preflight: Some(Box::new(move || preflight_provider.$preflight())),
})
}
);
};
(@register
$struct_name:ident, $config_type:ty, $metadata:expr,
$wrap:expr
) => {
impl $struct_name {
const PROVIDER_NAME: &'static str = $metadata.info.name;
}
const _: () = {
#[linkme::distributed_slice($crate::provider::PROVIDER_REGISTRY)]
#[doc(hidden)]
static PROVIDER_REGISTRATION: $crate::provider::ProviderRegistration = $crate::provider::ProviderRegistration {
metadata: $metadata,
factory: |url, credentials| {
let config = <$config_type>::try_from(url)?;
let mut provider = <$struct_name>::new(config);
$crate::provider::Provider::with_credentials(&mut provider, credentials);
let wrap: fn($struct_name) -> $crate::Result<$crate::provider::ProviderWithPreflight> = $wrap;
wrap(provider)
},
};
};
};
}