Skip to main content

oxihuman_core/
observer_list.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5/// Simple observer list with string-keyed callbacks (stored as labels).
6#[allow(dead_code)]
7pub struct ObserverList {
8    observers: Vec<(u64, String)>,
9    next_id: u64,
10    notify_count: u64,
11}
12
13#[allow(dead_code)]
14impl ObserverList {
15    pub fn new() -> Self {
16        Self {
17            observers: Vec::new(),
18            next_id: 1,
19            notify_count: 0,
20        }
21    }
22    pub fn subscribe(&mut self, label: &str) -> u64 {
23        let id = self.next_id;
24        self.next_id += 1;
25        self.observers.push((id, label.to_string()));
26        id
27    }
28    pub fn unsubscribe(&mut self, id: u64) -> bool {
29        if let Some(pos) = self.observers.iter().position(|(i, _)| *i == id) {
30            self.observers.remove(pos);
31            true
32        } else {
33            false
34        }
35    }
36    pub fn notify(&mut self, _event: &str) {
37        self.notify_count += 1;
38    }
39    pub fn count(&self) -> usize {
40        self.observers.len()
41    }
42    pub fn is_empty(&self) -> bool {
43        self.observers.is_empty()
44    }
45    pub fn notify_count(&self) -> u64 {
46        self.notify_count
47    }
48    pub fn labels(&self) -> Vec<&str> {
49        self.observers.iter().map(|(_, l)| l.as_str()).collect()
50    }
51    pub fn has_label(&self, label: &str) -> bool {
52        self.observers.iter().any(|(_, l)| l.as_str() == label)
53    }
54    pub fn clear(&mut self) {
55        self.observers.clear();
56    }
57    pub fn ids(&self) -> Vec<u64> {
58        self.observers.iter().map(|(id, _)| *id).collect()
59    }
60}
61
62impl Default for ObserverList {
63    fn default() -> Self {
64        Self::new()
65    }
66}
67
68#[allow(dead_code)]
69pub fn new_observer_list() -> ObserverList {
70    ObserverList::new()
71}
72#[allow(dead_code)]
73pub fn ol_subscribe(o: &mut ObserverList, label: &str) -> u64 {
74    o.subscribe(label)
75}
76#[allow(dead_code)]
77pub fn ol_unsubscribe(o: &mut ObserverList, id: u64) -> bool {
78    o.unsubscribe(id)
79}
80#[allow(dead_code)]
81pub fn ol_notify(o: &mut ObserverList, event: &str) {
82    o.notify(event);
83}
84#[allow(dead_code)]
85pub fn ol_count(o: &ObserverList) -> usize {
86    o.count()
87}
88#[allow(dead_code)]
89pub fn ol_is_empty(o: &ObserverList) -> bool {
90    o.is_empty()
91}
92#[allow(dead_code)]
93pub fn ol_notify_count(o: &ObserverList) -> u64 {
94    o.notify_count()
95}
96#[allow(dead_code)]
97pub fn ol_clear(o: &mut ObserverList) {
98    o.clear();
99}
100#[allow(dead_code)]
101pub fn ol_has_label(o: &ObserverList, label: &str) -> bool {
102    o.has_label(label)
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108    #[test]
109    fn test_subscribe_count() {
110        let mut o = new_observer_list();
111        ol_subscribe(&mut o, "a");
112        ol_subscribe(&mut o, "b");
113        assert_eq!(ol_count(&o), 2);
114    }
115    #[test]
116    fn test_unsubscribe() {
117        let mut o = new_observer_list();
118        let id = ol_subscribe(&mut o, "x");
119        assert!(ol_unsubscribe(&mut o, id));
120        assert_eq!(ol_count(&o), 0);
121    }
122    #[test]
123    fn test_unsubscribe_missing() {
124        let mut o = new_observer_list();
125        assert!(!ol_unsubscribe(&mut o, 999));
126    }
127    #[test]
128    fn test_notify_count() {
129        let mut o = new_observer_list();
130        ol_subscribe(&mut o, "a");
131        ol_notify(&mut o, "ev");
132        ol_notify(&mut o, "ev2");
133        assert_eq!(ol_notify_count(&o), 2);
134    }
135    #[test]
136    fn test_is_empty() {
137        let o = new_observer_list();
138        assert!(ol_is_empty(&o));
139    }
140    #[test]
141    fn test_has_label() {
142        let mut o = new_observer_list();
143        ol_subscribe(&mut o, "listener");
144        assert!(ol_has_label(&o, "listener"));
145        assert!(!ol_has_label(&o, "other"));
146    }
147    #[test]
148    fn test_clear() {
149        let mut o = new_observer_list();
150        ol_subscribe(&mut o, "a");
151        ol_clear(&mut o);
152        assert!(ol_is_empty(&o));
153    }
154    #[test]
155    fn test_labels() {
156        let mut o = new_observer_list();
157        ol_subscribe(&mut o, "foo");
158        let labels = o.labels();
159        assert!(labels.contains(&"foo"));
160    }
161    #[test]
162    fn test_ids_unique() {
163        let mut o = new_observer_list();
164        let id1 = ol_subscribe(&mut o, "a");
165        let id2 = ol_subscribe(&mut o, "b");
166        assert_ne!(id1, id2);
167    }
168    #[test]
169    fn test_multiple_unsub() {
170        let mut o = new_observer_list();
171        let id = ol_subscribe(&mut o, "a");
172        ol_subscribe(&mut o, "b");
173        ol_unsubscribe(&mut o, id);
174        assert_eq!(ol_count(&o), 1);
175    }
176}