Skip to main content

rumtk_web/pages/
mod.rs

1/*
2 * rumtk attempts to implement HL7 and medical protocols for interoperability in medicine.
3 * This toolkit aims to be reliable, simple, performant, and standards compliant.
4 * Copyright (C) 2025  Luis M. Santos, M.D. <lsantos@medicalmasses.com>
5 * Copyright (C) 2025  Ethan Dixon
6 * Copyright (C) 2025  MedicalMasses L.L.C. <contact@medicalmasses.com>
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20 */
21pub mod index;
22
23use crate::utils::PageFunction;
24use rumtk_core::cache::{new_cache, LazyRUMCache};
25use rumtk_core::strings::RUMString;
26use rumtk_core::{rumtk_cache_get, rumtk_cache_push};
27use std::ops::Deref;
28
29pub type PageCache = LazyRUMCache<RUMString, PageFunction>;
30pub type PageItem<'a> = (&'a str, PageFunction);
31pub type UserPages<'a> = Vec<PageItem<'a>>;
32pub type PageCacheItem = PageFunction;
33
34static mut PAGE_CACHE: PageCache = new_cache();
35static mut DEFAULT_PAGE: PageFunction = index::index;
36pub const DEFAULT_PAGE_NAME: &str = "index";
37
38pub fn register_page(name: &str, component_fxn: PageFunction) {
39    let key = RUMString::from(name);
40    rumtk_cache_push!(&raw mut PAGE_CACHE, &key, component_fxn);
41
42    if key == DEFAULT_PAGE_NAME {
43        unsafe {
44            DEFAULT_PAGE = component_fxn;
45        }
46    }
47    println!(
48        "  ➡ Registered page {} => page function [{:?}]",
49        name, &component_fxn
50    );
51}
52
53pub fn get_page(name: &str) -> PageCacheItem {
54    match rumtk_cache_get!(
55        &raw mut PAGE_CACHE,
56        &RUMString::from(name)
57    ) {
58        Some(page) => page,
59        None => {
60            unsafe {DEFAULT_PAGE}
61        }
62    }
63}
64
65pub fn get_default_page() -> &'static PageFunction {
66    unsafe { &DEFAULT_PAGE }
67}
68
69pub fn init_pages(user_components: Option<UserPages>) {
70    println!("🗎 Registering user pages! 🗎");
71    /* Init any user prescribed components */
72    for (name, value) in user_components.unwrap_or_default() {
73        register_page(name, value);
74    }
75    println!(
76        "  ➡ Default page => page function [{:?}]",
77        &get_default_page()
78    );
79    println!("🗎 ~~~~~~~~~~~~~~~~~~~~~~ 🗎");
80}
81
82#[macro_export]
83macro_rules! rumtk_web_register_page {
84    ( $key:expr, $fxn:expr ) => {{
85        use $crate::pages::register_page;
86        register_page($key, $fxn)
87    }};
88}
89
90///
91/// Helper function for retrieving pages registered in the global cache using a string key!
92///
93/// ## Example
94///
95/// ### With Named Page
96///
97/// ```
98/// use rumtk_core::strings::rumtk_format;
99/// use rumtk_web::defaults::{PARAMS_TYPE};
100/// use rumtk_web::utils::{SharedAppState, RenderedPageComponentsResult};
101/// use rumtk_web::{rumtk_web_render_component, rumtk_web_register_page, rumtk_web_get_page};
102///
103/// pub fn index(app_state: SharedAppState) -> RenderedPageComponentsResult {
104///     let title_welcome = rumtk_web_render_component!("title", [(PARAMS_TYPE, "welcome")], app_state)?.to_rumstring();
105///
106///     Ok(vec![
107///         title_welcome,
108///     ])
109/// }
110///
111/// rumtk_web_register_page!("index", index);
112/// let r = rumtk_format!("{:?}", &rumtk_web_get_page!("index"));
113/// let p = rumtk_format!("{:?}", &rumtk_web_get_page!("index"));
114///
115///  assert_eq!(&r, &p, "{}", rumtk_format!("The registered page does not match the retrieved page!\nGot: {:?}\nExpected: {:?}", &r, &p));
116///
117/// ```
118///
119/// ### With Default Page
120///
121/// ```
122/// use rumtk_core::strings::rumtk_format;
123/// use rumtk_web::defaults::{PARAMS_TYPE};
124/// use rumtk_web::utils::{SharedAppState, RenderedPageComponentsResult};
125/// use rumtk_web::{rumtk_web_render_component, rumtk_web_register_page, rumtk_web_get_page, rumtk_web_get_default_page};
126///
127/// pub fn index(app_state: SharedAppState) -> RenderedPageComponentsResult {
128///     let title_welcome = rumtk_web_render_component!("title", [(PARAMS_TYPE, "welcome")], app_state)?.to_rumstring();
129///
130///     Ok(vec![
131///         title_welcome,
132///     ])
133/// }
134///
135/// let default = rumtk_format!("{:?}", rumtk_web_get_default_page!());
136/// rumtk_web_register_page!("index", index);
137/// let r = rumtk_format!("{:?}", &rumtk_web_get_page!("index"));
138/// let p = rumtk_format!("{:?}", &rumtk_web_get_page!(""));
139///
140///  assert_ne!(&default, &p, "{}", rumtk_format!("The default page matches the retrieved page!\nGot: {:?}\nExpected: {:?}", &r, &p));
141///  assert_eq!(&r, &p, "{}", rumtk_format!("The registered page does not match the retrieved page!\nGot: {:?}\nExpected: {:?}", &r, &p));
142///
143/// ```
144///
145#[macro_export]
146macro_rules! rumtk_web_get_page {
147    ( $key:expr ) => {{
148        use $crate::pages::get_page;
149        get_page($key)
150    }};
151}
152
153///
154/// Returns the default page function that can be used for rendering that page
155///
156#[macro_export]
157macro_rules! rumtk_web_get_default_page {
158    ( ) => {{
159        use $crate::pages::get_default_page;
160        get_default_page()
161    }};
162}
163
164///
165/// Registers a set of pages provided by the user.
166///
167/// ## Example
168///
169///```
170/// use std::ops::Deref;
171/// use rumtk_core::strings::rumtk_format;
172/// use rumtk_web::defaults::{PARAMS_TYPE};
173/// use rumtk_web::utils::{SharedAppState, RenderedPageComponentsResult};
174/// use rumtk_web::{rumtk_web_render_component, rumtk_web_init_pages, rumtk_web_get_page};
175///
176/// use rumtk_web::pages::UserPages;
177///
178///  fn my_page(app_state: SharedAppState) -> RenderedPageComponentsResult {
179///     let title_welcome = rumtk_web_render_component!("title", [(PARAMS_TYPE, "welcome")], app_state)?.to_rumstring();
180///
181///     Ok(vec![
182///         title_welcome,
183///     ])
184/// }
185///
186/// let my_page_name = "my_page";
187///
188/// let pages: UserPages = vec![(my_page_name, my_page)];
189/// rumtk_web_init_pages!(Some(pages));
190///```
191///
192///
193#[macro_export]
194macro_rules! rumtk_web_init_pages {
195    ( $pages:expr ) => {{
196        use $crate::pages::init_pages;
197        init_pages($pages)
198    }};
199}
200
201#[macro_export]
202macro_rules! rumtk_web_collect_page {
203    ( $page:expr, $app_state:expr ) => {{
204        use $crate::rumtk_web_get_page;
205
206        let page = rumtk_web_get_page!(&$page);
207        page($app_state.clone())
208    }};
209}