use super::registry::{
Capabilities, CapabilityRegistry, ConsumedTracker, LocalCapabilityEntry, SharedCapabilityEntry,
resolve_bindings,
};
use super::{ExtensionCapability, KNOWN_CAPABILITIES, KnownCapability};
use crate::capability::factory::{LocalInstanceFactory, SharedInstanceFactory};
use otel_arrow_dfe_config::{CapabilityId, ExtensionId};
use std::any::{Any, TypeId};
use std::collections::{HashMap, HashSet};
trait MacroTestCapLocal {
fn value(&self) -> &str;
}
trait MacroTestCapShared: Send + Sync {
fn value(&self) -> &str;
}
struct MacroTestCap;
impl super::private::Sealed for MacroTestCap {}
impl ExtensionCapability for MacroTestCap {
const NAME: &'static str = "macro_test_cap";
type Local = dyn MacroTestCapLocal;
type Shared = dyn MacroTestCapShared;
fn wrap_shared_as_local(shared: Box<Self::Shared>) -> Box<Self::Local> {
struct Adapter(Box<dyn MacroTestCapShared>);
impl MacroTestCapLocal for Adapter {
fn value(&self) -> &str {
self.0.value()
}
}
Box::new(Adapter(shared))
}
}
#[allow(unsafe_code)]
#[linkme::distributed_slice(KNOWN_CAPABILITIES)]
#[linkme(crate = linkme)]
static _MACRO_TEST_CAP: KnownCapability = KnownCapability {
name: "macro_test_cap",
description: "Test capability for extension_capabilities! macro tests",
type_id: || TypeId::of::<MacroTestCap>(),
};
impl MacroTestCap {
fn shared_entry<E>(ext_id: ExtensionId, factory: SharedInstanceFactory) -> SharedCapabilityEntry
where
E: MacroTestCapShared + 'static,
{
let produce = move || -> Box<dyn Any + Send> {
let erased = factory.produce();
let concrete: Box<E> = erased.downcast().expect("instance factory");
let shared: Box<dyn MacroTestCapShared> = concrete;
Box::new(shared) as Box<dyn Any + Send>
};
let adapt_as_local: fn(Box<dyn Any + Send>) -> Box<dyn Any> = |erased| {
let shared: Box<Box<dyn MacroTestCapShared>> = erased.downcast().expect("envelope");
let boxed_local = <MacroTestCap as ExtensionCapability>::wrap_shared_as_local(*shared);
Box::new(boxed_local) as Box<dyn Any>
};
SharedCapabilityEntry::new(ext_id, produce, adapt_as_local)
}
fn local_entry<E>(ext_id: ExtensionId, factory: LocalInstanceFactory) -> LocalCapabilityEntry
where
E: MacroTestCapLocal + 'static,
{
let produce = move || -> Box<dyn Any> {
let erased = factory.produce();
let concrete: Box<E> = erased.downcast().expect("instance factory");
let local: Box<dyn MacroTestCapLocal> = concrete;
Box::new(local) as Box<dyn Any>
};
LocalCapabilityEntry::new(ext_id, produce)
}
}
#[derive(Clone)]
struct Shared(&'static str);
impl MacroTestCapShared for Shared {
fn value(&self) -> &str {
self.0
}
}
#[derive(Clone)]
struct Local(&'static str);
impl MacroTestCapLocal for Local {
fn value(&self) -> &str {
self.0
}
}
fn shared_factory(val: &'static str) -> SharedInstanceFactory {
SharedInstanceFactory::new(move || Box::new(Shared(val)) as Box<dyn Any + Send>)
}
fn local_factory(val: &'static str) -> LocalInstanceFactory {
LocalInstanceFactory::new(move || Box::new(Local(val)) as Box<dyn Any>)
}
fn bindings() -> HashMap<CapabilityId, ExtensionId> {
let mut m = HashMap::new();
let _ = m.insert("macro_test_cap".into(), "ext".into());
m
}
fn known_exts() -> HashSet<ExtensionId> {
let mut s = HashSet::new();
let _ = s.insert("ext".into());
s
}
fn resolve(registry: &CapabilityRegistry) -> Capabilities {
let mut tracker = ConsumedTracker::new();
resolve_bindings(&bindings(), registry, &known_exts(), &mut tracker).expect("resolve_bindings")
}
#[test]
fn macro_shared_only_form() {
let ec = extension_capabilities!(shared: Shared => [MacroTestCap]);
assert_eq!(ec.shared, &["macro_test_cap"]);
assert!(ec.local.is_empty());
let mut registry = CapabilityRegistry::new();
(ec.register_shared)("ext".into(), shared_factory("s-only"), &mut registry)
.expect("register_shared");
(ec.register_local)("ext".into(), local_factory("unused"), &mut registry)
.expect("register_local no-op");
let caps = resolve(®istry);
assert_eq!(
caps.require_shared::<MacroTestCap>().unwrap().value(),
"s-only"
);
let caps = resolve(®istry);
assert_eq!(
caps.require_local::<MacroTestCap>().unwrap().value(),
"s-only"
);
let caps = resolve(®istry);
let _ = caps.require_local::<MacroTestCap>().unwrap();
assert!(matches!(
caps.require_shared::<MacroTestCap>(),
Err(crate::capability::registry::Error::CapabilityAlreadyConsumed { .. })
));
}
#[test]
fn macro_local_only_form() {
let ec = extension_capabilities!(local: Local => [MacroTestCap]);
assert!(ec.shared.is_empty());
assert_eq!(ec.local, &["macro_test_cap"]);
let mut registry = CapabilityRegistry::new();
(ec.register_local)("ext".into(), local_factory("l-only"), &mut registry)
.expect("register_local");
let caps = resolve(®istry);
assert_eq!(
caps.require_local::<MacroTestCap>().unwrap().value(),
"l-only"
);
assert!(caps.require_shared::<MacroTestCap>().is_err());
}
#[test]
fn macro_dual_form() {
let ec = extension_capabilities!(
(shared: Shared, local: Local) => [MacroTestCap]
);
assert_eq!(ec.shared, &["macro_test_cap"]);
assert_eq!(ec.local, &["macro_test_cap"]);
let mut registry = CapabilityRegistry::new();
(ec.register_shared)("ext".into(), shared_factory("s-dual"), &mut registry)
.expect("register_shared");
(ec.register_local)("ext".into(), local_factory("l-dual"), &mut registry)
.expect("register_local");
let caps_shared = resolve(®istry);
assert_eq!(
caps_shared
.require_shared::<MacroTestCap>()
.unwrap()
.value(),
"s-dual"
);
assert!(matches!(
caps_shared.require_local::<MacroTestCap>(),
Err(crate::capability::registry::Error::CapabilityAlreadyConsumed { .. })
));
let caps_local = resolve(®istry);
assert_eq!(
caps_local.require_local::<MacroTestCap>().unwrap().value(),
"l-dual"
);
assert!(matches!(
caps_local.require_shared::<MacroTestCap>(),
Err(crate::capability::registry::Error::CapabilityAlreadyConsumed { .. })
));
let caps = resolve(®istry);
let _ = caps.require_shared::<MacroTestCap>().unwrap();
assert!(matches!(
caps.require_shared::<MacroTestCap>(),
Err(crate::capability::registry::Error::CapabilityAlreadyConsumed { .. })
));
}