telar_services_core/
lib.rs1pub mod dialogs;
2pub mod paths;
3#[cfg(feature = "di")]
4mod registry;
5#[cfg(feature = "di")]
6mod scope;
7
8pub use dialogs::{FileDialog, FileDialogs, FileFilter, file_dialogs, set_file_dialogs};
9pub use paths::{AppPathsProvider, NoPaths};
10#[cfg(feature = "di")]
11pub use registry::ServiceError;
12#[cfg(feature = "di")]
13pub use scope::{Scope, ServiceContext, ServiceGuard, provide, try_inject, with_service};
14
15#[cfg(all(test, feature = "di"))]
16mod tests {
17 use std::cell::RefCell;
18 use std::rc::Rc;
19
20 use super::*;
21 use crate::registry::ServiceRegistry;
22
23 #[test]
24 fn registry_insert_get() {
25 let mut reg = ServiceRegistry::new();
26 reg.insert(42u32).unwrap();
27 assert_eq!(reg.get::<u32>(), Some(&42));
28 }
29
30 #[test]
31 fn registry_insert_duplicate_returns_error() {
32 let mut reg = ServiceRegistry::new();
33 assert!(reg.insert(1u32).is_ok());
34 assert_eq!(reg.insert(2u32), Err(ServiceError::AlreadyRegistered));
35 assert_eq!(reg.get::<u32>(), Some(&1));
36 }
37
38 #[test]
39 fn registry_missing_type() {
40 let reg = ServiceRegistry::new();
41 assert_eq!(reg.get::<u32>(), None);
42 }
43
44 #[test]
45 fn scope_provide_inject() {
46 Scope::with(|| {
47 provide(99u32).unwrap();
48 assert_eq!(try_inject::<u32>(), Some(99));
49 });
50 }
51
52 #[test]
53 fn scope_child_inherits_parent() {
54 Scope::with(|| {
55 provide(String::from("from-parent")).unwrap();
56 Scope::with(|| {
57 assert_eq!(try_inject::<String>(), Some(String::from("from-parent")));
58 });
59 });
60 }
61
62 #[test]
63 fn scope_child_shadows_parent() {
64 Scope::with(|| {
65 provide(1u32).unwrap();
66 Scope::with(|| {
67 provide(2u32).unwrap();
68 assert_eq!(try_inject::<u32>(), Some(2));
69 });
70 });
71 }
72
73 #[test]
74 fn scope_drop_restores_parent() {
75 Scope::with(|| {
76 provide(String::from("parent")).unwrap();
77 Scope::with(|| {
78 provide(String::from("child")).unwrap();
79 assert_eq!(try_inject::<String>().as_deref(), Some("child"));
80 });
81 assert_eq!(try_inject::<String>().as_deref(), Some("parent"));
82 });
83 }
84
85 #[test]
86 fn with_service_non_clone() {
87 Scope::with(|| {
88 provide(Rc::new(RefCell::new(vec![1, 2, 3]))).unwrap();
89 let len = with_service(|v: &Rc<RefCell<Vec<i32>>>| v.borrow().len());
90 assert_eq!(len, Some(3));
91 });
92 }
93
94 #[test]
95 fn try_inject_missing_returns_none() {
96 Scope::with(|| {
97 assert_eq!(try_inject::<u64>(), None);
98 });
99 }
100
101 #[test]
102 fn scope_with_provides_service() {
103 Scope::with(|| {
104 provide(42u32).unwrap();
105 assert_eq!(try_inject::<u32>(), Some(42));
106 });
107 assert_eq!(try_inject::<u32>(), None);
108 }
109
110 #[test]
111 fn scope_with_cleans_up_after_closure_returns() {
112 Scope::with(|| {
113 provide(String::from("ephemeral")).unwrap();
114 assert!(try_inject::<String>().is_some());
115 });
116 assert_eq!(
117 try_inject::<String>(),
118 None,
119 "service must not be visible after Scope::with returns"
120 );
121 }
122
123 #[test]
124 fn scope_with_nested() {
125 Scope::with(|| {
126 provide(String::from("outer")).unwrap();
127 Scope::with(|| {
128 provide(String::from("inner")).unwrap();
129 assert_eq!(try_inject::<String>().as_deref(), Some("inner"));
130 });
131 assert_eq!(try_inject::<String>().as_deref(), Some("outer"));
132 });
133 }
134}