use super::ExtensionCapability;
use otel_arrow_dfe_config::ExtensionId;
use std::marker::PhantomData;
#[derive(Debug, thiserror::Error)]
#[error("capability '{capability}' on extension '{extension}' failed")]
#[non_exhaustive]
pub struct CapabilityError {
pub extension: ExtensionId,
pub capability: &'static str,
#[source]
pub source: Box<dyn std::error::Error + Send + Sync + 'static>,
}
pub struct CapabilityErrorSource<C: ExtensionCapability> {
extension: ExtensionId,
_capability: PhantomData<fn() -> C>,
}
impl<C: ExtensionCapability> CapabilityErrorSource<C> {
#[must_use]
pub fn new(extension: ExtensionId) -> Self {
Self {
extension,
_capability: PhantomData,
}
}
pub fn error<E>(&self, source: E) -> CapabilityError
where
E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
{
CapabilityError {
extension: self.extension.clone(),
capability: C::NAME,
source: source.into(),
}
}
}
impl<C: ExtensionCapability> Clone for CapabilityErrorSource<C> {
fn clone(&self) -> Self {
Self {
extension: self.extension.clone(),
_capability: PhantomData,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::capability::auth::bearer_token_provider::BearerTokenProvider;
#[test]
fn stamps_extension_and_capability_identity() {
let source = CapabilityErrorSource::<BearerTokenProvider>::new("azure_identity".into());
let err = source.error("boom");
assert_eq!(err.extension, "azure_identity");
assert_eq!(err.capability, "bearer_token_provider");
assert_eq!(err.source.to_string(), "boom");
}
#[test]
fn clone_preserves_identity_without_c_clone_bound() {
let source = CapabilityErrorSource::<BearerTokenProvider>::new("ext-a".into());
let cloned = source.clone();
assert_eq!(cloned.error("x").extension, "ext-a");
}
}