aspect_core/lib.rs
1//! # aspect-core
2//!
3//! Core abstractions for aspect-oriented programming in Rust.
4//!
5//! This crate provides the fundamental traits and types for building and using
6//! aspects in Rust. Aspects help modularize cross-cutting concerns like logging,
7//! performance monitoring, caching, security, and more.
8//!
9//! ## Core Concepts
10//!
11//! - **Aspect**: A module that encapsulates a cross-cutting concern
12//! - **JoinPoint**: A point in program execution where an aspect can be applied
13//! - **Advice**: The action taken by an aspect at a joinpoint
14//!
15//! ## Example
16//!
17//! ```rust
18//! use aspect_core::prelude::*;
19//! use std::any::Any;
20//!
21//! // Define an aspect
22//! #[derive(Default)]
23//! struct Logger;
24//!
25//! impl Aspect for Logger {
26//! fn before(&self, ctx: &JoinPoint) {
27//! println!("[ENTRY] {}", ctx.function_name);
28//! }
29//!
30//! fn after(&self, ctx: &JoinPoint, _result: &dyn Any) {
31//! println!("[EXIT] {}", ctx.function_name);
32//! }
33//! }
34//! ```
35//!
36//! ## Advice Types
37//!
38//! - **before**: Runs before the target function
39//! - **after**: Runs after successful execution
40//! - **after_error**: Runs when an error occurs
41//! - **around**: Wraps the entire function execution
42//!
43//! ## Thread Safety
44//!
45//! All aspects must implement `Send + Sync` to be used across thread boundaries.
46
47#![deny(missing_docs)]
48
49pub mod aspect;
50pub mod error;
51pub mod joinpoint;
52pub mod pointcut;
53
54// Re-export core types
55pub use aspect::Aspect;
56pub use error::AspectError;
57pub use joinpoint::{JoinPoint, Location, ProceedingJoinPoint};
58
59/// Prelude module for convenient imports
60pub mod prelude {
61 pub use crate::aspect::Aspect;
62 pub use crate::joinpoint::{JoinPoint, Location, ProceedingJoinPoint};
63 pub use crate::error::AspectError;
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69 use std::any::Any;
70 use std::sync::{Arc, Mutex};
71
72 #[derive(Clone)]
73 struct TestAspect {
74 called: Arc<Mutex<Vec<String>>>,
75 }
76
77 impl Default for TestAspect {
78 fn default() -> Self {
79 Self {
80 called: Arc::new(Mutex::new(Vec::new())),
81 }
82 }
83 }
84
85 impl Aspect for TestAspect {
86 fn before(&self, ctx: &JoinPoint) {
87 self.called
88 .lock()
89 .unwrap()
90 .push(format!("before:{}", ctx.function_name));
91 }
92
93 fn after(&self, ctx: &JoinPoint, _result: &dyn Any) {
94 self.called
95 .lock()
96 .unwrap()
97 .push(format!("after:{}", ctx.function_name));
98 }
99 }
100
101 #[test]
102 fn test_aspect_trait() {
103 let aspect = TestAspect::default();
104 let ctx = JoinPoint {
105 function_name: "test_function",
106 module_path: "test::module",
107 location: Location {
108 file: "test.rs",
109 line: 42,
110 },
111 };
112
113 aspect.before(&ctx);
114 aspect.after(&ctx, &42);
115
116 let calls = aspect.called.lock().unwrap();
117 assert_eq!(calls.len(), 2);
118 assert_eq!(calls[0], "before:test_function");
119 assert_eq!(calls[1], "after:test_function");
120 }
121
122 #[test]
123 fn test_joinpoint_creation() {
124 let jp = JoinPoint {
125 function_name: "my_function",
126 module_path: "my::module",
127 location: Location {
128 file: "src/lib.rs",
129 line: 100,
130 },
131 };
132
133 assert_eq!(jp.function_name, "my_function");
134 assert_eq!(jp.module_path, "my::module");
135 assert_eq!(jp.location.file, "src/lib.rs");
136 assert_eq!(jp.location.line, 100);
137 }
138}