phlow 3.0.0

An engine for scripting reactive browsers in Rust by adding custom views to structures
Documentation
use std::any::Any;

pub use annotate;
use annotate::{Function, Module};
pub use phlow_derive::{RawView, environment, extensions, view};

pub use crate::method::*;
pub use crate::object::*;
pub use crate::views::*;
pub use ctor;

pub mod cloning;
mod method;
mod object;
pub mod printing;
mod views;

#[macro_export]
macro_rules! export_link_macro {
    ($crate_name:ident) => {
        #[macro_export]
        macro_rules! __phlow_generated_link_macro {
            () => {
                const _: () = {
                    #[used]
                    static __PHLOW_GENERATED_LINK: fn() = ::$crate_name::__ensure_linked;
                };
            };
        }

        pub use __phlow_generated_link_macro as link;
    };
}

pub fn extension_modules_of_val<T: 'static>(_value: &T) -> Vec<Module> {
    extension_modules_of_type::<T>()
}

pub fn extension_modules_of_type<T: 'static>() -> Vec<Module> {
    annotate::global_environment().find_modules_such_that(&|module| {
        module.has_attribute_such_that(|attribute| {
            attribute.name() == "tag" && attribute.is_str("phlow-extensions")
        }) && module.has_attribute_such_that(|attribute| {
            attribute.name() == "phlow_type" && attribute.is_type::<T>()
        })
    })
}

pub fn extension_modules_of_any(value: &dyn Any) -> Vec<Module> {
    let type_id = value.type_id();
    annotate::global_environment().find_modules_such_that(&|module| {
        module.has_attribute_such_that(|attribute| {
            attribute.name() == "tag" && attribute.is_str("phlow-extensions")
        }) && module.has_attribute_such_that(|attribute| {
            attribute.name() == "phlow_type" && attribute.is_type_id(&type_id)
        })
    })
}

pub fn view_functions_of_val<T: 'static>(value: &T) -> Vec<DefiningMethod> {
    view_functions_in_modules(&extension_modules_of_val(value))
}

pub fn view_defining_methods_for_type<T: 'static>() -> Vec<DefiningMethod> {
    view_functions_in_modules(&extension_modules_of_type::<T>())
}

pub fn view_functions_of_any(value: &dyn Any) -> Vec<DefiningMethod> {
    view_functions_in_modules(&extension_modules_of_any(value))
}

pub fn vtable_of_type<T: 'static>() -> PhlowVTable {
    vtable_in_modules(&extension_modules_of_type::<T>())
}

pub fn vtable_of_val<T: 'static>(_value: &T) -> PhlowVTable {
    vtable_in_modules(&extension_modules_of_type::<T>())
}

pub fn vtable_of_any(value: &dyn Any) -> PhlowVTable {
    vtable_in_modules(&extension_modules_of_any(value))
}

fn vtable_in_modules(modules: &[Module]) -> PhlowVTable {
    let to_string_fn = functions_in_utility_modules_tagged(modules, "phlow-printing").pop();
    let type_name_fn = functions_in_utility_modules_tagged(modules, "phlow-type-name").pop();
    let as_view_fn = functions_in_utility_modules_tagged(modules, "phlow-as-view").pop();
    let defining_methods_fn =
        functions_in_utility_modules_tagged(modules, "phlow-defining-methods").pop();

    PhlowVTable {
        type_name_fn,
        to_string_fn,
        as_view_fn,
        defining_methods_fn,
    }
}

fn view_functions_in_modules(modules: &[Module]) -> Vec<DefiningMethod> {
    modules
        .iter()
        .flat_map(|module| {
            module.find_functions_such_that(|function| {
                function.has_attribute_such_that(|attribute| {
                    attribute.name() == "tag" && attribute.is_str("phlow-view")
                })
            })
        })
        .map(|each| each.into())
        .collect()
}

fn functions_in_utility_modules_tagged(modules: &[Module], tag: &str) -> Vec<Function> {
    modules
        .iter()
        .flat_map(|module| {
            module.find_functions_such_that(|function| {
                function.has_attribute_such_that(|attribute| {
                    attribute.name() == "tag" && attribute.is_str(tag)
                })
            })
        })
        .collect()
}