use irys::*;
use std::fmt;
trait DynSerialize {
fn to_string_repr(&self) -> String;
}
impl<T: fmt::Debug> DynSerialize for T {
fn to_string_repr(&self) -> String {
format!("{:?}", self)
}
}
trait Resettable {
fn reset(&mut self);
fn value(&self) -> String;
}
struct DisplayCap;
impl Capability for DisplayCap {
type Handle = dyn fmt::Display;
}
struct DebugCap;
impl Capability for DebugCap {
type Handle = dyn fmt::Debug;
}
struct SerializeCap;
impl Capability for SerializeCap {
type Handle = dyn DynSerialize;
}
struct ResettableCap;
impl Capability for ResettableCap {
type Handle = dyn Resettable;
}
register_capability! {
slot = 0,
cap = DisplayCap,
trait_bound = fmt::Display,
returns = dyn fmt::Display,
}
register_capability! {
slot = 1,
cap = DebugCap,
trait_bound = fmt::Debug,
returns = dyn fmt::Debug,
}
register_capability! {
slot = 2,
cap = SerializeCap,
trait_bound = DynSerialize,
returns = dyn DynSerialize,
}
register_capability! {
slot = 3,
cap = ResettableCap,
trait_bound = Resettable,
returns = dyn Resettable,
}
#[derive(Debug, Clone)]
struct FullType {
name: String,
value: i32,
}
impl fmt::Display for FullType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}={}", self.name, self.value)
}
}
#[derive(Debug)]
struct DebugOnly {
x: u32,
}
struct OpaqueType {
_data: Vec<u8>,
}
struct Counter {
count: u32,
}
impl Resettable for Counter {
fn reset(&mut self) { self.count = 0; }
fn value(&self) -> String { format!("count={}", self.count) }
}
#[test]
fn test_full_type_capabilities() {
let envelope = reflect!(FullType { name: "test".into(), value: 42 });
assert!(envelope.has::<DisplayCap>());
assert!(envelope.has::<DebugCap>());
assert!(envelope.has::<SerializeCap>());
assert!(!envelope.has::<ResettableCap>());
assert_eq!(envelope.capability_count(), 3);
}
#[test]
fn test_debug_only_capabilities() {
let envelope = reflect!(DebugOnly { x: 99 });
assert!(!envelope.has::<DisplayCap>());
assert!(envelope.has::<DebugCap>());
assert!(envelope.has::<SerializeCap>());
assert!(!envelope.has::<ResettableCap>());
}
#[test]
fn test_opaque_no_capabilities() {
let envelope = reflect!(OpaqueType { _data: vec![1, 2, 3] });
assert!(!envelope.has::<DisplayCap>());
assert!(!envelope.has::<DebugCap>());
assert!(!envelope.has::<SerializeCap>());
assert!(!envelope.has::<ResettableCap>());
assert_eq!(envelope.capability_count(), 0);
}
#[test]
fn test_get_returns_working_trait_object() {
let envelope = reflect!(FullType { name: "hello".into(), value: 7 });
let display = envelope.get::<DisplayCap>().unwrap();
assert_eq!(format!("{}", display), "hello=7");
let debug = envelope.get::<DebugCap>().unwrap();
assert_eq!(format!("{:?}", debug), "FullType { name: \"hello\", value: 7 }");
}
#[test]
fn test_get_mut_allows_mutation() {
let mut envelope = reflect!(Counter { count: 42 });
assert!(envelope.has::<ResettableCap>());
let r = envelope.get::<ResettableCap>().unwrap();
assert_eq!(r.value(), "count=42");
envelope.get_mut::<ResettableCap>().unwrap().reset();
let r = envelope.get::<ResettableCap>().unwrap();
assert_eq!(r.value(), "count=0");
}
#[test]
fn test_get_on_missing_capability_returns_none() {
let envelope = reflect!(OpaqueType { _data: vec![] });
assert!(envelope.get::<DisplayCap>().is_none());
assert!(envelope.get::<DebugCap>().is_none());
}
#[test]
fn test_data_access() {
let envelope = reflect!(FullType { name: "original".into(), value: 100 });
let data = envelope.data::<FullType>().unwrap();
assert_eq!(data.name, "original");
assert_eq!(data.value, 100);
}
#[test]
fn test_into_data() {
let envelope = reflect!(FullType { name: "owned".into(), value: 55 });
let data = envelope.into_data::<FullType>().unwrap();
assert_eq!(data.name, "owned");
assert_eq!(data.value, 55);
}
#[test]
fn test_data_wrong_type_returns_none() {
let envelope = reflect!(FullType { name: "x".into(), value: 1 });
assert!(envelope.data::<Counter>().is_none());
}
#[test]
fn test_custom_registry() {
struct MyRegistry;
struct MyDebugCap;
impl Capability for MyDebugCap {
type Handle = dyn fmt::Debug;
}
register_capability! {
registry = MyRegistry,
slot = 0,
cap = MyDebugCap,
trait_bound = fmt::Debug,
returns = dyn fmt::Debug,
}
let envelope = reflect!(FullType { name: "hi".into(), value: 1 }, [{ registry: MyRegistry, slots: 0..5 }]);
assert!(envelope.has::<MyDebugCap>());
assert!(!envelope.has::<DisplayCap>()); assert_eq!(envelope.capability_count(), 1);
}
#[test]
fn test_multiple_registries() {
struct RegA;
struct RegB;
struct CapA;
impl Capability for CapA {
type Handle = dyn fmt::Display;
}
struct CapB;
impl Capability for CapB {
type Handle = dyn fmt::Debug;
}
register_capability! {
registry = RegA,
slot = 0,
cap = CapA,
trait_bound = fmt::Display,
returns = dyn fmt::Display,
}
register_capability! {
registry = RegB,
slot = 0,
cap = CapB,
trait_bound = fmt::Debug,
returns = dyn fmt::Debug,
}
let envelope = reflect!(FullType { name: "multi".into(), value: 9 }, [
{ registry: RegA, slots: 0..5 },
{ registry: RegB, slots: 0..5 },
]);
assert!(envelope.has::<CapA>());
assert!(envelope.has::<CapB>());
assert_eq!(envelope.capability_count(), 2);
}
#[test]
fn test_custom_range() {
let envelope = reflect!(FullType { name: "range".into(), value: 0 }, [
{ registry: DefaultRegistry, slots: 0..2 },
]);
assert!(envelope.has::<DisplayCap>()); assert!(envelope.has::<DebugCap>()); assert!(!envelope.has::<SerializeCap>()); assert!(!envelope.has::<ResettableCap>()); }