1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//! # An Aspect Toolkit for Rust
//!
//! Aspect-RS is a project aiming to provide common ground for the main Aspect-Oriented use cases in Rust. By leveraging the trait system, declarative and procedural macros, Aspect-RS provides blocks that let you wrap methods with your custom logic.
//!
//! The project has been extracted from the [Metered project](https://github.com/magnet/metered-rs), which uses the technique to build metrics that can work on expressions or methods, whether they're `async` or not. The technique seemed general enough to be in its own crate and see if it is of any interest to other parties.
//!
//! Aspect-RS provides "pointcut" traits when entering or exiting an expression (`OnEnter` and `OnResult`), experimental `Update` and `UpdateRef` traits that can use parameter shadowing to intercept and update method parameters, and weaving constructs useful when building procedural macros. Please look at the [Metered project](https://github.com/magnet/metered-rs) to see Aspect-RS in action.

#![deny(missing_docs)]
#![deny(warnings)]

pub mod update;
pub use aspect_weave::Weave;

/// The `Enter` trait is called when entering in an aspect, before the wrapped expression is called.
pub trait Enter {
    /// The type returned by the `enter` function and carried to `OnResult`
    type E;

    /// `enter` is called when entering in an aspect
    ///
    /// Use it to set-up some context before calling the expression. For instance, the `ResponseTime` metric in the [metered](https://github.com/magnet/metered-rs) crate uses it to get the current time before the invocation, and pass it over to `OnResult` to compute the elapsed time.
    ///
    /// Aspects which don't need enter can simply do nothing and return unit.
    fn enter(&self) -> Self::E;
}

/// An `Advice` describes what the aspect should do on return
pub enum Advice {
    /// Return the expression value
    Return,
    /// Call the expression again.
    ///
    /// Experimental. Use with caution regarding side-effects in the expression and possible loops.
    Retry,
}

/// The `OnResult` trait is implemented on Aspects to get notified when an expression has returned.
pub trait OnResult<R>: Enter {
    /// Called when an expression has returned.
    ///
    /// This function is passed both the enter return value, and the expression return value.
    ///
    /// `on_result` does not get a chance to alter the returned result. Use `OnResultMut` for that purpose.
    fn on_result(&self, _enter: <Self as Enter>::E, _result: &R) -> Advice {
        Advice::Return
    }
}

/// The `OnResult` trait is implemented on Aspects to get notified when an expression has returned, and provide
/// the possibility to alter the result.
pub trait OnResultMut<R>: Enter {
    /// Called when an expression has returned.
    ///
    /// This function is passed both the enter return value, and the expression return value.
    fn on_result(&self, _enter: <Self as Enter>::E, _result: &mut R) -> Advice {
        Advice::Return
    }
}