rerust 0.1.0

Reactive programming with dataflow semantics
Documentation
use super::{change_prefix, temp_prefix, val_prefix, Generate, InterfaceTokens};
use crate::analysis::{ChangedNode, Family, FilterNode, FoldNode, MapNode, NodeData, ReNode};
use proc_macro2::{Ident, TokenStream};
use quote::format_ident;
use quote::quote;

impl Generate for MapNode<'_> {
    fn generate_interface(&self, incoming: &Vec<&ReNode>) -> InterfaceTokens {
        let mut ift = InterfaceTokens::default();
        let name = self.ident();
        let args = &self.update_expr.inputs;
        let return_type = &self.update_expr.return_type;
        let body = &self.update_expr.body;
        ift.functions = quote! {
            #[inline]
            fn #name (#args) -> #return_type
                #body
        };

        let family = self.family();
        let (event_condition, var_condition) = generate_condition(incoming.clone(), family);
        let method_args = generate_method_args(incoming.clone());
        let ty = self.ty();
        let change_name = change_prefix(&name);
        let temp_name = temp_prefix(&name);

        if self.pin() {
            if family == Family::Event {
                ift.state_struct = quote! {
                    #name: Event<#ty>,
                };
                ift.initialize_struct = quote! {
                    #name: Event::None,
                };
                ift.update_part = quote! {
                    if_chain! {
                        #event_condition
                        then {
                            state.#name = Event::Some(Self::#name(#method_args));
                        } else {
                            state.#name = Event::None;
                        }
                    }
                    let #name = &state.#name;
                };
            } else {
                ift.state_struct = quote! {
                    #name: Variable<#ty>,
                };
                ift.update_part = quote! {
                    if_chain! {
                        if #var_condition;
                        then {
                            let result = Self::#name(#method_args);
                            if result != state.#name.value {
                                state.#name.value = result;
                                state.#name.change = true;
                            }
                        }
                    }
                    let #name = &state.#name.value;
                    let #change_name = state.#name.change;
                };
                ift.initialize = quote! {
                    let #temp_name = Variable { value: Self::#name(#method_args), change: true };
                    let #name = &#temp_name.value;
                };
                ift.initialize_struct = quote! {
                    #name: #temp_name,
                };
            }
        } else {
            if family == Family::Event {
                ift.update_part = quote! {
                    let #temp_name = if_chain! {
                        #event_condition
                        then {
                            Event::Some(Self::#name(#method_args))
                        } else {
                            Event::None
                        }
                    };
                    let #name = &#temp_name;
                };
            } else {
                ift.initialize = quote! {
                    let #temp_name = Self::#name(#method_args);
                    let #name = &#temp_name;
                };
                ift.update_part = quote! {
                    let #temp_name = Self::#name(#method_args);
                    let #name = &#temp_name;
                    let #change_name = true;
                };
            }
        }
        ift
    }

    fn ident(&self) -> Ident {
        format_ident!("map_{}", self.id())
    }
}

fn generate_condition(mut incoming: Vec<&ReNode>, family: Family) -> (TokenStream, TokenStream) {
    if incoming.len() == 1 {
        let node = incoming[0];
        let name = node.ident();
        let change_name = change_prefix(&name);
        let fam = node.outgoing_family();
        let local_name = val_prefix(&name);
        if family == Family::Event && fam == Family::Variable {
            return (quote! {}, quote! {});
        }
        if fam == Family::Event {
            (
                quote! { if let Event::Some(#local_name) = #name; },
                quote! {},
            )
        } else {
            (quote! {}, quote! { #change_name })
        }
    } else {
        let node = incoming.pop().unwrap();
        let fam = node.outgoing_family();
        let name = node.ident();
        let change_name = change_prefix(&name);
        let local_name = val_prefix(&name);
        let (rest_events, rest_variables) = generate_condition(incoming, family);
        if family == Family::Event && fam == Family::Variable {
            return (rest_events, rest_variables);
        }
        if fam == Family::Event {
            (
                quote! { if let Event::Some(#local_name) = #name; #rest_events },
                rest_variables,
            )
        } else {
            (rest_events, quote! { #change_name || #rest_variables })
        }
    }
}

fn generate_method_args(mut incoming: Vec<&ReNode>) -> TokenStream {
    if incoming.len() == 1 {
        let node = incoming[0];
        let name = node.ident();
        let fam = node.outgoing_family();
        if fam == Family::Event {
            let local_name = val_prefix(&name);
            quote! { #local_name }
        } else {
            quote! { #name }
        }
    } else {
        let node = incoming.pop().unwrap();
        let fam = node.outgoing_family();
        let name = node.ident();
        let rest = generate_method_args(incoming);
        if fam == Family::Event {
            let local_name = val_prefix(&name);
            quote! { #local_name, #rest }
        } else {
            quote! { #name, #rest }
        }
    }
}

impl Generate for FoldNode<'_> {
    fn ident(&self) -> Ident {
        format_ident!("fold_{}", self.id())
    }

    fn generate_interface(&self, incoming: &Vec<&ReNode>) -> InterfaceTokens {
        let mut ift = InterfaceTokens::default();
        let name = self.ident();
        let args = &self.update_expr.inputs;
        let return_type = &self.update_expr.return_type;
        let body = &self.update_expr.body;
        ift.functions = quote! {
            #[inline(always)]
            fn #name (#args) -> #return_type
                #body
        };

        let family = self.family();
        let (event_condition, _var_condition) = generate_condition(incoming.clone(), family);
        let method_args = generate_method_args(incoming.clone());
        let change_name = change_prefix(&name);
        let temp_name = temp_prefix(&name);

        assert!(family == Family::Event);
        ift.update_part = quote! {
            if_chain! {
                #event_condition
                then {
                    let result = Self::#name(state.#name.value.clone(), #method_args);
                    if result != state.#name.value {
                        state.#name.value = result;
                        state.#name.change = true;
                    }
                }
            }
            let #name = &state.#name.value;
            let #change_name = state.#name.change;
        };
        let ty = self.ty();
        ift.state_struct = quote! {
            #name: Variable<#ty>,
        };

        let init_expr = self.initial;
        ift.initialize = quote! {
            let #temp_name = Variable { value: #init_expr, change: true };
            let #name = &#temp_name.value;
        };
        ift.initialize_struct = quote! {
            #name: #temp_name,
        };

        ift
    }
}

impl Generate for FilterNode<'_> {
    fn generate_interface(&self, incoming: &Vec<&ReNode>) -> InterfaceTokens {
        let mut ift = InterfaceTokens::default();
        let name = self.ident();
        let inputs = &self.filter_expr.inputs;
        let body = &self.filter_expr.body;

        ift.functions = quote! {
            #[inline]
            fn #name (#inputs) -> bool
                #body

        };

        let family = self.family();
        let (event_condition, _) = generate_condition(incoming.clone(), family);
        let method_args = generate_method_args(incoming.clone());

        assert!(family == Family::Event);
        if self.pin() {
            let ty = &self.ty();
            ift.state_struct = quote! {
                #name: Event<#ty>,
            };
            ift.initialize_struct = quote! {
                #name: Event::None,
            };
            ift.update_part = quote! {
                if_chain! {
                    #event_condition
                    Self::#name(#method_args);
                    then {
                        state.#name = Event::Some(#method_args.clone());
                    } else {
                        state.#name = Event::None;
                    }
                }
                let #name = &state.#name;
            };
        } else {
            ift.update_part = quote! {
                let #name = if_chain! {
                    #event_condition
                    Self::#name(#method_args);
                    then {
                        Event::Some(#method_args)
                    } else {
                        Event::None
                    }
                };
            };
        }
        ift
    }

    fn ident(&self) -> Ident {
        format_ident!("filter_{}", self.id())
    }
}

impl Generate for ChangedNode {
    fn generate_interface(&self, incoming: &Vec<&ReNode>) -> InterfaceTokens {
        let mut ift = InterfaceTokens::default();
        let name = self.ident();
        let family = self.family();
        let ty = self.ty();
        assert!(incoming.len() == 1);
        assert!(family == Family::Variable);
        let incoming_name = incoming[0].ident();
        if self.pin() {
            ift.update_part = quote! {
                state.#name = if change_name {
                    Event::Some(#incoming_name.clone())
                } else {
                    Event::None
                };
                let #name = &state.#name;
            };
            ift.state_struct = quote! {
                #name: Event<#ty>,
            };
            ift.initialize_struct = quote! {
                #name: Event::None,
            };
        } else {
            ift.update_part = quote! {
                let #name = if change_name {
                    Event::Some(#incoming_name)
                } else {
                    Event::None
                };
            };
        }
        ift
    }

    fn ident(&self) -> Ident {
        format_ident!("changed_{}", self.id())
    }
}