Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Context: Rename insert_with_data to insert and the original insert to insert_env #38

Merged
merged 2 commits into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions crates/indicator/src/context/layer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ where

/// Add a [`Insert`] layer with the given [`RefOperator`] constructor
/// (i.e. a function that returns a [`RefOperator`]).
fn insert<R, Out, F>(self, f: F) -> Stack<Self, Insert<F>>
///
/// We use this method to add the output of the operator to the `env` context.
fn insert_env<R, Out, F>(self, f: F) -> Stack<Self, Insert<F>>
where
F: Fn() -> R,
R: for<'a> RefOperator<'a, In, Output = Out>,
Expand All @@ -89,6 +91,8 @@ where

/// Add a [`InsertData`] layer with the given [`RefOperator`] constructor.
/// (i.e. a function that returns a [`RefOperator`]).
///
/// We use this method to add the output of the operator to the `data` context.
fn insert_data<R, Out, F>(self, f: F) -> Stack<Self, InsertData<F>>
where
F: Fn() -> R,
Expand All @@ -101,7 +105,9 @@ where

/// Add a [`InsertWithData`] layer with the given [`RefOperator`] constructor.
/// (i.e. a function that returns a [`RefOperator`]).
fn insert_with_data<R, Env, Data, F>(self, f: F) -> Stack<Self, InsertWithData<F>>
///
/// We use this method to add the output of the operator to the `env` and `data` context simultaneously.
fn insert<R, Env, Data, F>(self, f: F) -> Stack<Self, InsertWithData<F>>
where
F: Fn() -> R,
R: for<'a> RefOperator<'a, In, Output = (Env, Option<Data>)>,
Expand Down
10 changes: 8 additions & 2 deletions crates/indicator/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ pub trait ContextOperatorExt<In>: ContextOperator<In> {

/// Add a [`Insert`] layer with the given [`RefOperator`] constructor
/// (i.e. a function that returns a [`RefOperator`]).
fn insert<R, Out>(self, f: impl Fn() -> R) -> InsertOperator<Self, R>
///
/// We use this method to add the output of the operator to the `env` context.
fn insert_env<R, Out>(self, f: impl Fn() -> R) -> InsertOperator<Self, R>
where
R: for<'a> RefOperator<'a, In, Output = Out>,
Out: Send + Sync + 'static,
Expand All @@ -114,6 +116,8 @@ pub trait ContextOperatorExt<In>: ContextOperator<In> {

/// Add a [`InsertData`] layer with the given [`RefOperator`] constructor.
/// (i.e. a function that returns a [`RefOperator`]).
///
/// We use this method to add the output of the operator to the `data` context.
fn insert_data<R, Out>(self, f: impl Fn() -> R) -> InsertDataOperator<Self, R>
where
R: for<'a> RefOperator<'a, In, Output = Option<Out>>,
Expand All @@ -125,7 +129,9 @@ pub trait ContextOperatorExt<In>: ContextOperator<In> {

/// Add a [`InsertWithData`] layer with the given [`RefOperator`] constructor.
/// (i.e. a function that returns a [`RefOperator`]).
fn insert_with_data<R, Env, Data>(self, f: impl Fn() -> R) -> InsertWithDataOperator<Self, R>
///
/// We use this method to add the output of the operator to the `env` and `data` context simultaneously.
fn insert<R, Env, Data>(self, f: impl Fn() -> R) -> InsertWithDataOperator<Self, R>
where
R: for<'a> RefOperator<'a, In, Output = (Env, Option<Data>)>,
Env: Send + Sync + 'static,
Expand Down
1 change: 1 addition & 0 deletions crates/indicator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ pub mod prelude {
#[cfg(feature = "context")]
pub use crate::context::{
extractor::{Data, Env, In, Prev},
input,
layer::{layer_fn, stack::id_layer, Layer, LayerExt},
output, output_with, ContextOperator, ContextOperatorExt, Value, ValueRef,
};
Expand Down
4 changes: 4 additions & 0 deletions crates/indicator_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ proc-macro2 = "1.0.67"
quote = "1.0.33"
syn = { version = "2.0.37", features = ["full"] }
convert_case = "0.6.0"

[dev-dependencies]
indicator = { path = "../indicator", features = ["context"] }
num = "0.4.1"
60 changes: 60 additions & 0 deletions crates/indicator_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,66 @@ fn indicator() -> TokenStream2 {
}

/// Create a `RefOperator` from a function.
///
/// ## Note
/// - When using with the `generate_out` flag, the output type will be converted to the same
/// as `generate_out_with_data`, i.e. `(OutTy, Option<DataTy>)` where `DataTy = ()`
/// is this case. So that it can be used in `insert` method (but not the `insert_env` method).
/// - But when using with the `generate_data` flag, the output type is kept as `Option<DataTy>`,
/// so that it can be used in `insert_data` method.
///
/// ## Example
/// The following example is a basic usage of `#[operator]` attribute.
/// We use `#[operator]` to create a `RefOperator` that just add two to the input.
/// ```rust
/// use indicator::prelude::*;
/// use num::Num;
///
/// struct AddTwo<T>(T);
///
/// /// An operator that just add two to the input.
/// #[operator(input = T)]
/// fn add_two<T>(In(value): In<&T>) -> AddTwo<T>
/// where
/// T: Num + Clone,
/// T: Send + Sync + 'static,
/// {
/// let two = T::one() + T::one();
/// AddTwo(value.clone() + two)
/// }
///
/// let op = input::<i32>().insert_env(add_two).finish();
/// ```
///
/// We notice that the above example requires us to define a struct `AddTwo` to wrap the output.
/// The same operator can also be created with the following code but in a more generic way.
/// ```rust
/// use indicator::prelude::*;
/// use num::Num;
///
/// /// An operator that just add two to the input.
/// #[operator(input = I, generate_out)]
/// fn add_two<T>(#[input] value: &T) -> T
/// where
/// T: Num + Clone,
/// {
/// let two = T::one() + T::one();
/// value.clone() + two
/// }
///
/// let op = input::<i32>().insert(add_two::<_, _, i32>).finish();
/// ```
/// Here we use the `#[input]` attribute and the `generate_out` to achieve our goal.
/// - The `#[input]` attribute is used to mark the input parameter.
/// It will replace the `value: &T` parameter with `In(value): In<&I>` in the generated code,
/// and introduce a bound `I: Borrow<T>` so that it can be converted back to `&T` before calling.
/// - The `generate_out` flag in the `#[operator]` attribute is used to generate a generic output type.
/// Like what the `#[input]` attribute does, it will introduce a bound `OutTy: From<T>`
/// (here the `OutTy` is the generated output type) so that the output can be converted from `T`.
///
/// Also note that the operator generated with `generate_out` flag is meant to be used with `insert` method,
/// because the output type is wrapped in a tuple `(OutTy, Option<DataTy>)` where `DataTy = ()` is this case.
/// If you want to costomize the `DataTy`, you can use the `generate_out_with_data` flag instead.
#[proc_macro_attribute]
pub fn operator(args: TokenStream, input: TokenStream) -> TokenStream {
match self::operator::generate_operator(args, input) {
Expand Down
4 changes: 2 additions & 2 deletions crates/indicator_derive/src/operator/operator_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ impl OperatorFn {
match self.out {
Some(GenerateOut::Out) => {
quote! {
#call_name (#extractors).into()
((#call_name (#extractors)).into(), None)
}
}
Some(GenerateOut::Data) => {
Expand Down Expand Up @@ -226,7 +226,7 @@ impl OutputTy {
match options.generate_out {
Some(GenerateOut::Out) => {
generics.push(syn::parse2(quote!(OutTy: From<#ty>))?);
ty = syn::parse2(quote!(OutTy))?;
ty = syn::parse2(quote!((OutTy, Option<()>)))?;
}
Some(GenerateOut::Data) => {
let data_ty = get_type_inside_option(&ty)?;
Expand Down
6 changes: 3 additions & 3 deletions examples/context/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ struct Ma<T>(T);
/// An operator that does the following:
/// `x => (x + prev(x)) / 2`
#[operator(input = T)]
fn ma<T>(Env(x): Env<&T>, Prev(prev): Prev<&Ma<T>>) -> Ma<T>
fn ma<T>(Env(x): Env<&AddTwo<T>>, Prev(prev): Prev<&Ma<T>>) -> Ma<T>
where
T: Num + Clone,
T: Send + Sync + 'static,
{
let two = T::one() + T::one();
let prev = prev.map(|v| v.0.clone()).unwrap_or(T::zero());
Ma((x.clone() + prev) / two)
Ma((x.0.clone() + prev) / two)
}

fn main() -> anyhow::Result<()> {
Expand All @@ -41,7 +41,7 @@ fn main() -> anyhow::Result<()> {
println!("AddTwo: {x}");
}
})
.insert(add_two)
.insert_env(add_two)
.cache(1)
.finish();
let data = [dec!(1), dec!(2), dec!(3)];
Expand Down
2 changes: 1 addition & 1 deletion examples/context/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ fn main() -> anyhow::Result<()> {
.from_context::<&str>() // Asserting that the context has a `&str` data.
.provide("This is my data!")
.insert_data(odds_counter)
.insert_with_data(even_signal::<bool, EvenCount>)
.insert(even_signal::<bool, EvenCount>)
.cache(1)
.finish();
let data = [1, 2, 3];
Expand Down
4 changes: 3 additions & 1 deletion examples/context/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ where
T: Num + Clone,
P: ContextOperator<T>,
{
id_layer().insert(ma::<_, N>).provide(Alpha::<_, N>(alhpa))
id_layer()
.insert_env(ma::<_, N>)
.provide(Alpha::<_, N>(alhpa))
}

/// Config for `ma` operator.
Expand Down