1use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
7
8const MAX_HINTS: u32 = 3;
10
11static INITIALIZED: AtomicBool = AtomicBool::new(false);
16static HINT_COUNT: AtomicU32 = AtomicU32::new(0);
17
18pub fn mark_initialized() {
22 INITIALIZED.store(true, Ordering::Release);
23}
24
25#[must_use]
27pub fn is_initialized() -> bool {
28 INITIALIZED.load(Ordering::Acquire)
29}
30
31#[must_use]
39pub fn should_show_hint() -> bool {
40 if is_initialized() {
41 return false;
42 }
43
44 let current = HINT_COUNT.fetch_add(1, Ordering::AcqRel);
46 current < MAX_HINTS
47}
48
49#[must_use]
53pub const fn get_hint_message() -> &'static str {
54 "\n\n---\n💡 **Tip**: Call `subcog_init` at session start to load memory context and best practices."
55}
56
57#[cfg(test)]
59pub fn reset() {
60 INITIALIZED.store(false, Ordering::Release);
61 HINT_COUNT.store(0, Ordering::Release);
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn test_initialization_flow() {
70 reset();
71
72 assert!(!is_initialized());
74
75 mark_initialized();
77 assert!(is_initialized());
78 }
79
80 #[test]
81 fn test_hint_limiting() {
82 reset();
83
84 for i in 0..MAX_HINTS {
86 assert!(should_show_hint(), "Should show hint for call {i}");
87 }
88
89 assert!(!should_show_hint(), "Should not show hint after MAX_HINTS");
91 }
92
93 #[test]
94 fn test_no_hints_when_initialized() {
95 reset();
96
97 mark_initialized();
99
100 for _ in 0..10 {
102 assert!(
103 !should_show_hint(),
104 "Should not show hints when initialized"
105 );
106 }
107 }
108
109 #[test]
110 fn test_hint_message_content() {
111 let msg = get_hint_message();
112 assert!(msg.contains("subcog_init"));
113 assert!(msg.contains("session start"));
114 }
115}