-
Notifications
You must be signed in to change notification settings - Fork 8
Description
The CGP computation macros like #[cgp_computer] can be extended to allow function arguments to be extracted from the context instead of from the arguments.
Current State
Currently we can write:
#[cgp_computer]
pub fn rectangle_area(width: f64, height: f64) -> f64 {
width * height
}which would expands to:
#[cgp_impl(new RectangleArea)]
impl<Code> Computer<Code, (f64, f64)> {
fn compute(
&self,
_code: PhantomData<Code>,
(width, height): (f64, f64),
) -> f64 {
rectangle_area(width, height)
}
}Dependency Injection in Function
We should be able to also write something like:
#[cgp_computer]
pub fn rectangle_area(
#[implicit] width: f64,
#[implicit] height: f64,
) -> f64 {
width * height
}which would expands differently to get the dependencies from the context:
#[cgp_impl(new RectangleArea)]
impl<Code> Computer<Code, ()>
where
Self: HasField<Symbol!("width"), Value = f64>
+ HasField<Symbol!("width"), Value = f64>,
{
fn compute(
&self,
_code: PhantomData<Code>,
(width, height): (f64, f64),
) -> f64 {
rectangle_area(
self.get_field(PhantomData::<Symbol!("width")>),
self.get_field(PhantomData::<Symbol!("height")>),
)
}
}Provider Trait Promotion
This would also allow us to later on generate promotion providers to promote a Computer provider to proper traits. For example:
#[cgp_component {
provider: AreaCalculator,
derive_promote: PromoteAreaCalculator,
}]
pub trait HasArea {
fn area(&self) -> f64;
}This would allow a generated PromoteAreaCalculator provider to wrap the RectangleArea provider to implement AreaCalculator:
pub struct Rectangle {
pub width: f64,
pub height: f64,
}
delegate_components! {
Rectangle {
AreaCalculatorComponent:
PromoteAreaCalculator<RectangleArea>,
}
}Direct Function Promotion
We can also promote a function directly to implement a provider trait when defining the function, like:
#[cgp_computer(AreaCalculatorComponent)]
pub fn rectangle_area(
#[field] width: f64,
#[field] height: f64,
) -> f64 {
width * height
}Then it would automatically delegate the component like:
delegate_components! {
RectangleArea {
AreaCalculatorComponent:
PromoteAreaCalculator,
}
}Motivation
The main motivation for this is that Rust developers are much more familiar with function-style dependency injection, as compared to dependency injection via getter traits and where clauses. Frameworks like Axum and Bevy has trained a whole generation of Rust developers that they can just write plain functions and get the values from a context automagically.
For CGP to gain adoption, we need to show developers that they can reuse the same function-style dependency injection that they know well, and also use it to get fields from a context. This should significantly lower the barrier, as they don't need to learn the new syntax to start using CGP.