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_TITLE};
100/// use rumtk_web::components::title::title;
101/// use rumtk_web::utils::{SharedAppState, RenderedPageComponentsResult};
102/// use rumtk_web::{rumtk_web_register_page, rumtk_web_get_page, rumtk_web_params_map};
103///
104/// pub fn index(app_state: SharedAppState) -> RenderedPageComponentsResult {
105/// let params = rumtk_web_params_map!([(PARAMS_TITLE, "welcome")]);
106/// let title_welcome = title(&[], params.get_inner(), app_state)?.to_string();
107///
108/// Ok(vec![
109/// title_welcome,
110/// ])
111/// }
112///
113/// rumtk_web_register_page!("index", index);
114/// let r = rumtk_format!("{:?}", &rumtk_web_get_page!("index"));
115/// let p = rumtk_format!("{:?}", &rumtk_web_get_page!("index"));
116///
117/// assert_eq!(&r, &p, "{}", rumtk_format!("The registered page does not match the retrieved page!\nGot: {:?}\nExpected: {:?}", &r, &p));
118///
119/// ```
120///
121/// ### With Default Page
122///
123/// ```
124/// use rumtk_core::strings::rumtk_format;
125/// use rumtk_web::defaults::{PARAMS_TITLE};
126/// use rumtk_web::components::title::title;
127/// use rumtk_web::utils::{SharedAppState, RenderedPageComponentsResult};
128/// use rumtk_web::{rumtk_web_register_page, rumtk_web_get_page, rumtk_web_get_default_page, rumtk_web_params_map};
129///
130/// pub fn index(app_state: SharedAppState) -> RenderedPageComponentsResult {
131/// let params = rumtk_web_params_map!([(PARAMS_TITLE, "welcome")]);
132/// let title_welcome = title(&[], params.get_inner(), app_state)?.to_string();
133///
134/// Ok(vec![
135/// title_welcome,
136/// ])
137/// }
138///
139/// let default = rumtk_format!("{:?}", rumtk_web_get_default_page!());
140/// rumtk_web_register_page!("index", index);
141/// let r = rumtk_format!("{:?}", &rumtk_web_get_page!("index"));
142/// let p = rumtk_format!("{:?}", &rumtk_web_get_page!(""));
143///
144/// assert_ne!(&default, &p, "{}", rumtk_format!("The default page matches the retrieved page!\nGot: {:?}\nExpected: {:?}", &r, &p));
145/// assert_eq!(&r, &p, "{}", rumtk_format!("The registered page does not match the retrieved page!\nGot: {:?}\nExpected: {:?}", &r, &p));
146///
147/// ```
148///
149#[macro_export]
150macro_rules! rumtk_web_get_page {
151 ( $key:expr ) => {{
152 use $crate::pages::get_page;
153 get_page($key)
154 }};
155}
156
157///
158/// Returns the default page function that can be used for rendering that page
159///
160#[macro_export]
161macro_rules! rumtk_web_get_default_page {
162 ( ) => {{
163 use $crate::pages::get_default_page;
164 get_default_page()
165 }};
166}
167
168///
169/// Registers a set of pages provided by the user.
170///
171/// ## Example
172///
173///```
174/// use std::ops::Deref;
175/// use rumtk_core::strings::rumtk_format;
176/// use rumtk_web::defaults::{PARAMS_TITLE};
177/// use rumtk_web::components::title::title;
178/// use rumtk_web::utils::{SharedAppState, RenderedPageComponentsResult};
179/// use rumtk_web::{rumtk_web_init_pages, rumtk_web_get_page, rumtk_web_params_map};
180///
181/// use rumtk_web::pages::UserPages;
182///
183/// fn my_page(app_state: SharedAppState) -> RenderedPageComponentsResult {
184/// let params = rumtk_web_params_map!([(PARAMS_TITLE, "welcome")]);
185/// let title_welcome = title(&[], params.get_inner(), app_state)?.to_string();
186///
187/// Ok(vec![
188/// title_welcome,
189/// ])
190/// }
191///
192/// let my_page_name = "my_page";
193///
194/// let pages: UserPages = vec![(my_page_name, my_page)];
195/// rumtk_web_init_pages!(Some(pages));
196///```
197///
198///
199#[macro_export]
200macro_rules! rumtk_web_init_pages {
201 ( $pages:expr ) => {{
202 use $crate::pages::init_pages;
203 init_pages($pages)
204 }};
205}
206
207#[macro_export]
208macro_rules! rumtk_web_collect_page {
209 ( $page:expr, $app_state:expr ) => {{
210 use $crate::rumtk_web_get_page;
211
212 let page = rumtk_web_get_page!(&$page);
213 page($app_state.clone())
214 }};
215}