1use std::collections::HashMap;
4use std::collections::hash_map;
5use std::convert::Infallible;
6use std::fmt::Debug;
7use std::marker::PhantomData;
8use std::sync::Arc;
9use std::sync::RwLock;
10
11use serde::Deserialize;
12use serde::Deserializer;
13use serde::Serialize;
14
15use self::has_diff::HasDiff;
16use crate::is_global::IsGlobal;
17use crate::unwrap_infallible::UnwrapInfallible as _;
18
19#[derive(Default)]
21pub struct DynamicConfig<T, M = mode::RW> {
22 config: std::sync::RwLock<Option<T>>,
23 notify: Arc<Registry<Box<dyn Fn(&T) + Send + Sync + 'static>>>,
24 on_drop: std::sync::Mutex<Vec<Box<dyn FnOnce() + Send + Sync + 'static>>>,
25 _mode: PhantomData<M>,
26}
27
28pub mod mode {
29 pub use super::mode_impl::Mode;
30 pub use super::mode_impl::RO;
31 pub use super::mode_impl::RW;
32}
33
34mod mode_impl {
35 use crate::is_global::IsGlobal;
36
37 pub trait Mode: IsGlobal {
38 fn mode() -> ModeImpl;
39 }
40
41 pub enum RW {}
43
44 pub enum RO {}
47
48 #[derive(Debug, PartialEq, Eq)]
49 pub enum ModeImpl {
50 RW,
51 RO,
52 }
53
54 impl Mode for RW {
55 fn mode() -> ModeImpl {
56 ModeImpl::RW
57 }
58 }
59 impl Mode for RO {
60 fn mode() -> ModeImpl {
61 ModeImpl::RO
62 }
63 }
64}
65
66impl<T> From<T> for DynamicConfig<T, mode::RW> {
67 fn from(config: T) -> Self {
68 from_impl(config)
69 }
70}
71
72fn from_impl<T, M>(config: T) -> DynamicConfig<T, M>
73where
74 M: mode::Mode,
75{
76 DynamicConfig {
77 config: RwLock::new(Some(config)),
78 notify: Default::default(),
79 on_drop: Default::default(),
80 _mode: PhantomData,
81 }
82}
83
84impl<T> DynamicConfig<T, mode::RW> {
85 pub fn add_notify(
89 &self,
90 f: impl Fn(&T) + IsGlobal,
91 ) -> RegistryHandle<Box<dyn Fn(&T) + Send + Sync + 'static>> {
92 add_notify(self, f)
93 }
94}
95
96fn add_notify<T>(
97 this: &DynamicConfig<T, impl mode::Mode>,
98 f: impl Fn(&T) + IsGlobal,
99) -> RegistryHandle<Box<dyn Fn(&T) + Send + Sync + 'static>> {
100 this.notify.add(Box::new(f))
101}
102
103impl<T, M> DynamicConfig<T, M>
104where
105 M: mode::Mode,
106{
107 pub fn get(&self) -> T
111 where
112 T: Clone,
113 {
114 self.with(T::clone)
115 }
116
117 pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
121 f(self
122 .config
123 .read()
124 .expect("read lock")
125 .as_ref()
126 .expect("option not present"))
127 }
128
129 pub fn view_diff<U>(
133 self: &Arc<Self>,
134 to: impl Fn(&T) -> U + IsGlobal,
135 ) -> Arc<DynamicConfig<U, mode::RO>>
136 where
137 T: Clone + IsGlobal,
138 U: Clone + IsGlobal + HasDiff,
139 {
140 derive_impl(self.clone(), to, |_, _| Option::<T>::None, U::is_same)
141 }
142
143 pub fn view<U>(
147 self: &Arc<Self>,
148 to: impl Fn(&T) -> U + IsGlobal,
149 ) -> Arc<DynamicConfig<U, mode::RO>>
150 where
151 T: Clone + IsGlobal,
152 U: Clone + IsGlobal,
153 {
154 derive_impl(self.clone(), to, |_, _| Option::<T>::None, always_changed)
155 }
156
157 pub fn zip<T2, M2>(
158 self: &Arc<Self>,
159 right: &Arc<DynamicConfig<T2, M2>>,
160 ) -> Arc<DynamicConfig<(T, T2), mode::RO>>
161 where
162 T: Clone + IsGlobal,
163 T2: Clone + IsGlobal,
164 M2: mode::Mode,
165 {
166 let left = self;
167 let zipped: Arc<DynamicConfig<(T, T2), mode::RO>> =
168 Arc::new(from_impl((left.get(), right.get())));
169
170 {
171 let on_left_change = add_notify(left, {
172 let zipped_weak = Arc::downgrade(&zipped);
173 move |new_left| {
174 if let Some(zipped_strong) = zipped_weak.upgrade() {
175 zipped_strong
176 .try_set_impl(
177 |(_, right)| Ok((new_left.clone(), right.clone())),
178 always_changed,
179 )
180 .unwrap_infallible();
181 }
182 }
183 });
184 let left = left.clone();
185 zipped.on_drop.lock().unwrap().push(Box::new(move || {
186 drop(on_left_change);
187 drop(left);
188 }));
189 }
190 {
191 let on_right_change = add_notify(right, {
192 let zipped_weak = Arc::downgrade(&zipped);
193 move |new_right| {
194 if let Some(zipped_strong) = zipped_weak.upgrade() {
195 zipped_strong
196 .try_set_impl(
197 |(left, _)| Ok((left.clone(), new_right.clone())),
198 always_changed,
199 )
200 .unwrap_infallible();
201 }
202 }
203 });
204 let right = right.clone();
205 zipped.on_drop.lock().unwrap().push(Box::new(move || {
206 drop(on_right_change);
207 drop(right);
208 }));
209 }
210
211 return zipped;
212 }
213}
214
215impl<T> DynamicConfig<T, mode::RW> {
216 pub fn set(&self, make_new_config: impl FnOnce(&T) -> T)
220 where
221 T: Clone,
222 {
223 self.try_set(|t| Ok::<_, Infallible>(make_new_config(t)))
224 .unwrap_infallible()
225 }
226
227 pub fn try_set<E>(&self, make_new_config: impl FnOnce(&T) -> Result<T, E>) -> Result<(), E>
231 where
232 T: Clone,
233 {
234 self.try_set_impl(make_new_config, always_changed)
235 }
236
237 pub fn silent_set(&self, make_new_config: impl FnOnce(&T) -> T)
241 where
242 T: Clone,
243 {
244 self.silent_try_set(|t| Ok::<_, Infallible>(make_new_config(t)))
245 .unwrap_infallible()
246 }
247
248 pub fn silent_try_set<E>(
252 &self,
253 make_new_config: impl FnOnce(&T) -> Result<T, E>,
254 ) -> Result<(), E>
255 where
256 T: Clone,
257 {
258 {
259 let mut lock = self.config.write().expect("write lock");
260 let new_config = make_new_config(lock.as_ref().expect("option not present"))?;
261 *lock = Some(new_config);
262 }
263
264 #[cfg(debug_assertions)]
265 let _ = self.get();
266
267 Ok(())
268 }
269
270 pub fn derive<U>(
275 self: &Arc<Self>,
276 to: impl Fn(&T) -> U + IsGlobal,
277 from: impl Fn(T, &U) -> Option<T> + IsGlobal,
278 ) -> Arc<DynamicConfig<U, mode::RW>>
279 where
280 T: Clone + IsGlobal,
281 U: Clone + IsGlobal + HasDiff,
282 {
283 derive_impl(self.clone(), to, from, U::is_same)
284 }
285}
286
287fn derive_impl<T, U, MU>(
288 main: Arc<DynamicConfig<T, impl mode::Mode>>,
289 to: impl Fn(&T) -> U + IsGlobal,
290 from: impl Fn(T, &U) -> Option<T> + IsGlobal,
291 is_same: impl FnOnce(&U, &U) -> bool + IsGlobal + Copy,
292) -> Arc<DynamicConfig<U, MU>>
293where
294 T: Clone + IsGlobal,
295 U: Clone + IsGlobal,
296 MU: mode::Mode,
297{
298 let derived: Arc<DynamicConfig<U, MU>> = Arc::new(from_impl(main.with(|m| to(m))));
299 if MU::mode() == mode_impl::ModeImpl::RW {
300 let on_derived_change = add_notify(&derived, {
301 let main_weak = Arc::downgrade(&main);
302 move |d| {
303 if let Some(main) = main_weak.upgrade()
304 && let Some(m) = from(main.get(), d)
305 {
306 main.try_set_impl(|_| Ok(m), always_changed)
307 .unwrap_infallible();
308 }
309 }
310 });
311 main.on_drop
312 .lock()
313 .unwrap()
314 .push(Box::new(move || drop(on_derived_change)));
315 }
316 let on_main_change = add_notify(&main, {
317 let derived_weak = Arc::downgrade(&derived);
318 move |m| {
319 if let Some(derived) = derived_weak.upgrade() {
320 derived
321 .try_set_impl(|_old| Ok(to(m)), is_same)
322 .unwrap_infallible()
323 }
324 }
325 });
326 derived.on_drop.lock().unwrap().push(Box::new(move || {
327 drop(on_main_change);
328 drop(main);
329 }));
330 return derived;
331}
332
333impl<T> DynamicConfig<T> {
334 pub fn if_change<U>(
335 from: impl Fn(&T, &U) -> T + 'static,
336 ) -> impl Fn(T, &U) -> Option<T> + 'static
337 where
338 T: Eq,
339 {
340 move |old_t, u| {
341 let new_t = from(&old_t, u);
342 if new_t != old_t { Some(new_t) } else { None }
343 }
344 }
345
346 pub fn if_ptr_change<U>(
347 from: impl Fn(&Arc<T>, &U) -> Arc<T> + 'static,
348 ) -> impl Fn(Arc<T>, &U) -> Option<Arc<T>> + 'static {
349 move |old_t, u| {
350 let new_t = from(&old_t, u);
351 if !Arc::ptr_eq(&new_t, &old_t) {
352 Some(new_t)
353 } else {
354 None
355 }
356 }
357 }
358}
359
360impl<T, M> DynamicConfig<T, M>
361where
362 M: mode::Mode,
363{
364 fn try_set_impl<E>(
365 &self,
366 make_new_config: impl FnOnce(&T) -> Result<T, E>,
367 is_same: impl FnOnce(&T, &T) -> bool,
368 ) -> Result<(), E>
369 where
370 T: Clone,
371 {
372 let new_config;
373 {
374 let mut lock = self.config.write().expect("write lock");
375 let old_config = lock.as_ref().expect("option not present");
376 new_config = make_new_config(old_config)?;
377 if is_same(old_config, &new_config) {
378 return Ok(());
379 }
380 *lock = Some(new_config.clone());
381 }
382
383 #[cfg(debug_assertions)]
384 let _ = self.get();
385
386 self.notify.with(|notify| {
387 for notify in notify {
388 notify(&new_config);
389 }
390 });
391 Ok(())
392 }
393}
394
395impl<T: Debug, M: mode::Mode> std::fmt::Debug for DynamicConfig<T, M> {
396 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
397 self.with(|config| {
398 f.debug_struct("DynamicConfig")
399 .field("config", config)
400 .finish()
401 })
402 }
403}
404
405impl<T: Serialize> Serialize for DynamicConfig<T> {
406 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
407 where
408 S: serde::Serializer,
409 {
410 self.with(|v| v.serialize(serializer))
411 }
412}
413
414impl<'de, T: Deserialize<'de>> Deserialize<'de> for DynamicConfig<T> {
415 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
416 where
417 D: Deserializer<'de>,
418 {
419 Ok(T::deserialize(deserializer)?.into())
420 }
421}
422
423struct Registry<T>(std::sync::RwLock<RegistryInner<T>>);
424
425struct RegistryInner<T> {
426 next: i32,
427 table: HashMap<i32, T>,
428}
429
430#[must_use]
431pub struct RegistryHandle<T> {
432 registry: Arc<Registry<T>>,
433 key: i32,
434}
435
436impl<T> Registry<T> {
437 fn add(self: &Arc<Self>, value: T) -> RegistryHandle<T> {
438 let mut lock = self.write();
439 let RegistryInner { next, table } = &mut *lock;
440 *next += 1;
441 let prev = table.insert(*next, value);
442 assert!(prev.is_none());
443 return RegistryHandle {
444 registry: self.clone(),
445 key: *next,
446 };
447 }
448
449 fn read(&self) -> std::sync::RwLockReadGuard<'_, RegistryInner<T>> {
450 self.0.read().expect("registry")
451 }
452
453 fn write(&self) -> std::sync::RwLockWriteGuard<'_, RegistryInner<T>> {
454 self.0.write().expect("registry")
455 }
456}
457
458impl<T> Registry<T> {
459 pub fn with<R>(&self, f: impl Fn(hash_map::Values<'_, i32, T>) -> R) -> R {
460 f(self.read().table.values())
461 }
462}
463
464impl<T> Default for Registry<T> {
465 fn default() -> Self {
466 Self(RwLock::new(RegistryInner {
467 next: 0,
468 table: HashMap::new(),
469 }))
470 }
471}
472
473impl<T> Drop for RegistryHandle<T> {
474 fn drop(&mut self) {
475 let mut lock = self.registry.write();
476 let removed = lock.table.remove(&self.key);
477 debug_assert!(removed.is_some());
478 }
479}
480
481pub mod has_diff {
482 use std::ops::Deref;
483 use std::sync::Arc;
484
485 use serde::Deserialize;
486 use serde::Serialize;
487
488 pub trait HasDiff {
489 #[expect(unused)]
490 fn is_same(lhs: &Self, rhs: &Self) -> bool {
491 false
492 }
493
494 fn is_diff(lhs: &Self, rhs: &Self) -> bool {
495 !Self::is_same(lhs, rhs)
496 }
497 }
498
499 impl<T: Eq> HasDiff for T {
500 fn is_same(lhs: &Self, rhs: &Self) -> bool {
501 PartialEq::eq(lhs, rhs)
502 }
503 }
504
505 #[derive(Default, Serialize, Deserialize)]
506 #[serde(transparent)]
507 pub struct DiffArc<T>(Arc<T>);
508
509 impl<T> HasDiff for DiffArc<T> {
510 fn is_same(lhs: &Self, rhs: &Self) -> bool {
511 Arc::ptr_eq(&lhs.0, &rhs.0)
512 }
513 }
514
515 impl<T> From<T> for DiffArc<T> {
516 fn from(value: T) -> Self {
517 Self(value.into())
518 }
519 }
520
521 impl<T> From<Arc<T>> for DiffArc<T> {
522 fn from(value: Arc<T>) -> Self {
523 Self(value)
524 }
525 }
526
527 impl<T> Deref for DiffArc<T> {
528 type Target = T;
529
530 fn deref(&self) -> &Self::Target {
531 &self.0
532 }
533 }
534
535 impl<T> Clone for DiffArc<T> {
536 fn clone(&self) -> Self {
537 Self(self.0.clone())
538 }
539 }
540
541 impl<T: std::fmt::Debug> std::fmt::Debug for DiffArc<T> {
542 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
543 std::fmt::Debug::fmt(&self.0, f)
544 }
545 }
546
547 #[derive(Clone, Serialize, Deserialize)]
548 #[serde(transparent)]
549 pub struct DiffOption<T>(Option<T>);
550
551 impl<T: HasDiff> HasDiff for DiffOption<T> {
552 fn is_same(lhs: &Self, rhs: &Self) -> bool {
553 match (&lhs.0, &rhs.0) {
554 (None, None) => true,
555 (None, Some(_)) => false,
556 (Some(_), None) => false,
557 (Some(lhs), Some(rhs)) => T::is_same(lhs, rhs),
558 }
559 }
560 }
561
562 impl<T> From<T> for DiffOption<T> {
563 fn from(value: T) -> Self {
564 Self(value.into())
565 }
566 }
567
568 impl<T> Default for DiffOption<T> {
569 fn default() -> Self {
570 Self(Option::default())
571 }
572 }
573
574 impl<T> From<Option<T>> for DiffOption<T> {
575 fn from(value: Option<T>) -> Self {
576 Self(value)
577 }
578 }
579
580 impl<T> Deref for DiffOption<T> {
581 type Target = Option<T>;
582
583 fn deref(&self) -> &Self::Target {
584 &self.0
585 }
586 }
587
588 impl<T: std::fmt::Debug> std::fmt::Debug for DiffOption<T> {
589 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
590 std::fmt::Debug::fmt(&self.0, f)
591 }
592 }
593
594 #[derive(Clone, Default, Serialize, Deserialize)]
595 #[serde(transparent)]
596 pub struct DiffItem<T>(T);
597
598 impl<T> HasDiff for DiffItem<T> {}
599
600 impl<T> From<T> for DiffItem<T> {
601 fn from(value: T) -> Self {
602 Self(value)
603 }
604 }
605
606 impl<T> Deref for DiffItem<T> {
607 type Target = T;
608
609 fn deref(&self) -> &Self::Target {
610 &self.0
611 }
612 }
613
614 impl<T: std::fmt::Debug> std::fmt::Debug for DiffItem<T> {
615 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
616 std::fmt::Debug::fmt(&self.0, f)
617 }
618 }
619}
620
621fn always_changed<T>(_: &T, _: &T) -> bool {
622 false
623}
624
625#[cfg(test)]
626mod tests {
627 use std::sync::Arc;
628 use std::sync::Mutex;
629
630 use super::DynamicConfig;
631
632 #[test]
633 fn set() {
634 let cfg = DynamicConfig::from("hello".to_owned());
635 let () = cfg.set(|old| format!("{old} world"));
636 assert_eq!("hello world", cfg.get());
637 }
638
639 #[test]
640 fn try_set() {
641 let cfg = DynamicConfig::from("hello".to_owned());
642 let Ok(()): Result<(), ()> = cfg.try_set(|old| Ok(format!("{old} world"))) else {
643 panic!();
644 };
645 assert_eq!("hello world", cfg.get());
646
647 let Err(()): Result<(), ()> = cfg.try_set(|_| Err(())) else {
648 panic!();
649 };
650 assert_eq!("hello world", cfg.get());
651 }
652
653 #[test]
654 fn add_notify() {
655 let cfg = DynamicConfig::from("hello".to_owned());
656 let last = Arc::new(Mutex::new(None));
657 let last2 = last.clone();
658 let notify =
659 cfg.add_notify(move |current| *last2.lock().unwrap() = Some(current.to_owned()));
660
661 let () = cfg.set(|old| format!("{old} world"));
662 assert_eq!(Some("hello world"), last.lock().unwrap().as_deref());
663 assert_eq!("hello world", cfg.get());
664
665 let () = cfg.set(|old| format!("{old}!"));
666 assert_eq!(Some("hello world!"), last.lock().unwrap().as_deref());
667 assert_eq!("hello world!", cfg.get());
668
669 drop(notify);
670 let () = cfg.set(|old| format!("{old}!!"));
671 assert_eq!(Some("hello world!"), last.lock().unwrap().as_deref());
672 assert_eq!("hello world!!!", cfg.get());
673 }
674
675 #[test]
676 fn derive() {
677 let main = Arc::new(DynamicConfig::from("hello".to_owned()));
678 let derived = main.derive(
679 |main| Box::new(main.to_uppercase()),
680 |m, d| {
681 let new_main = d.to_lowercase();
682 if new_main != m { Some(new_main) } else { None }
683 },
684 );
685 assert_eq!("hello", main.get());
686 assert_eq!("HELLO", *derived.get());
687
688 derived.set(|_| Box::new("HELLO_WORLD".to_owned()));
689 assert_eq!("hello_world", main.get());
690 assert_eq!("HELLO_WORLD", *derived.get());
691
692 assert_eq!(1, main.notify.read().table.len());
693 assert_eq!(1, derived.notify.read().table.len());
694
695 drop(derived);
696 assert_eq!(0, main.notify.read().table.len());
697 }
698
699 #[test]
700 fn view() {
701 let main = Arc::new(DynamicConfig::from("hello".to_owned()));
702 let view = main.view(|main| Box::new(main.to_uppercase()));
703 assert_eq!("hello", main.get());
704 assert_eq!("HELLO", *view.get());
705
706 main.set(|_| "Hello World".to_owned());
707 assert_eq!("Hello World", main.get());
708 assert_eq!("HELLO WORLD", *view.get());
709 }
710
711 #[test]
712 fn derive_eq() {
713 let main = Arc::new(DynamicConfig::from("hello".to_owned()));
714 let derived = main.derive(
715 |main| Box::new(main.to_uppercase()),
716 DynamicConfig::if_change(|_m, d: &Box<String>| d.to_lowercase()),
717 );
718 assert_eq!("hello", main.get());
719 assert_eq!("HELLO", *derived.get());
720
721 derived.set(|_| Box::new("HELLO_WORLD".to_owned()));
722 assert_eq!("hello_world", main.get());
723 assert_eq!("HELLO_WORLD", *derived.get());
724 }
725
726 #[test]
727 fn derive_ptr() {
728 let main = Arc::new(DynamicConfig::from(Arc::new("hello".to_string())));
729 let derived = main.derive(
730 |main| Arc::new(main.to_uppercase()),
731 DynamicConfig::if_ptr_change(|m: &Arc<String>, _| m.clone()),
732 );
733 assert_eq!("hello", *main.get());
734 assert_eq!("HELLO", *derived.get());
735
736 derived.set(|_| Arc::new("HELLO_WORLD".to_owned()));
737 assert_eq!("hello", *main.get());
738 assert_eq!("HELLO_WORLD", *derived.get());
739
740 main.set(|_| Arc::new("hello2".to_owned()));
741 assert_eq!("hello2", *main.get());
742 assert_eq!("HELLO2", *derived.get());
743 }
744
745 #[test]
746 fn zip() {
747 let left = Arc::new(DynamicConfig::from("left"));
748 let right = Arc::new(DynamicConfig::from(22));
749 let zipped = left.zip(&right);
750 assert_eq!(("left", 22), zipped.get());
751
752 left.set(|_| "left2");
753 assert_eq!(("left2", 22), zipped.get());
754
755 right.set(|_| 33);
756 assert_eq!(("left2", 33), zipped.get());
757
758 let concat = zipped.view(|(left, right)| format!("left:{left} right:{right}"));
759 assert_eq!("left:left2 right:33", concat.get());
760
761 left.set(|_| "left3");
762 right.set(|i| i + 1);
763 assert_eq!("left:left3 right:34", concat.get());
764
765 drop(zipped);
766 left.set(|_| "left4");
767 right.set(|i| i + 1);
768 assert_eq!("left:left4 right:35", concat.get());
769
770 let other = Arc::new(DynamicConfig::from("other"));
771 let zipped = concat.zip(&other.view(|other| other.to_uppercase()));
772 assert_eq!(("left:left4 right:35".into(), "OTHER".into()), zipped.get());
773
774 right.set(|_| 40);
775 assert_eq!(("left:left4 right:40".into(), "OTHER".into()), zipped.get());
776
777 other.set(|_| "update");
778 drop(concat);
779 drop(other);
780 right.set(|_| 41);
781 assert_eq!(
782 ("left:left4 right:41".into(), "UPDATE".into()),
783 zipped.get()
784 );
785 }
786}