use crate::error::AspectError;
use std::any::Any;
use std::fmt;
#[derive(Debug, Clone)]
pub struct JoinPoint {
pub function_name: &'static str,
pub module_path: &'static str,
pub location: Location,
}
impl JoinPoint {
pub fn new(
function_name: &'static str,
module_path: &'static str,
location: Location,
) -> Self {
Self {
function_name,
module_path,
location,
}
}
pub fn qualified_name(&self) -> String {
format!("{}::{}", self.module_path, self.function_name)
}
}
impl fmt::Display for JoinPoint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}::{}@{}:{}",
self.module_path, self.function_name, self.location.file, self.location.line
)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Location {
pub file: &'static str,
pub line: u32,
}
impl fmt::Display for Location {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.file, self.line)
}
}
pub struct ProceedingJoinPoint<'a> {
inner: Box<dyn FnOnce() -> Result<Box<dyn Any>, AspectError> + 'a>,
context: JoinPoint,
}
impl<'a> ProceedingJoinPoint<'a> {
pub fn new<F>(f: F, context: JoinPoint) -> Self
where
F: FnOnce() -> Result<Box<dyn Any>, AspectError> + 'a,
{
Self {
inner: Box::new(f),
context,
}
}
pub fn proceed(self) -> Result<Box<dyn Any>, AspectError> {
(self.inner)()
}
pub fn context(&self) -> &JoinPoint {
&self.context
}
}
impl<'a> fmt::Debug for ProceedingJoinPoint<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ProceedingJoinPoint")
.field("context", &self.context)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_joinpoint_qualified_name() {
let jp = JoinPoint {
function_name: "my_func",
module_path: "crate::module",
location: Location {
file: "src/lib.rs",
line: 10,
},
};
assert_eq!(jp.qualified_name(), "crate::module::my_func");
}
#[test]
fn test_joinpoint_display() {
let jp = JoinPoint {
function_name: "test",
module_path: "mod",
location: Location {
file: "test.rs",
line: 42,
},
};
let display = format!("{}", jp);
assert!(display.contains("test"));
assert!(display.contains("mod"));
assert!(display.contains("test.rs"));
assert!(display.contains("42"));
}
#[test]
fn test_proceeding_joinpoint() {
let jp = JoinPoint {
function_name: "test",
module_path: "test",
location: Location {
file: "test.rs",
line: 1,
},
};
let pjp = ProceedingJoinPoint::new(
|| Ok(Box::new(42) as Box<dyn Any>),
jp,
);
assert_eq!(pjp.context().function_name, "test");
let result = pjp.proceed().unwrap();
let value = result.downcast_ref::<i32>().unwrap();
assert_eq!(*value, 42);
}
}