tuwunel_service/once_services.rs
1use std::{
2 ops::Deref,
3 sync::{Arc, OnceLock},
4};
5
6use crate::Services;
7
8#[derive(Default)]
9pub(crate) struct OnceServices {
10 lock: OnceLock<Arc<Services>>,
11}
12
13impl OnceServices {
14 pub(super) fn set(&self, services: Arc<Services>) -> Arc<Services> {
15 self.lock.get_or_init(move || services).clone()
16 }
17
18 #[inline]
19 pub(crate) fn get(&self) -> &Arc<Services> {
20 self.lock
21 .get()
22 .expect("services must be initialized")
23 }
24}
25
26impl Deref for OnceServices {
27 type Target = Arc<Services>;
28
29 #[inline]
30 fn deref(&self) -> &Self::Target { self.get() }
31}
32
33#[cfg(not(tuwunel_always_prove_sendness))]
34// SAFETY: Services has a lot of circularity inherited from Conduit's original
35// design. This stresses the trait solver which twists itself into a knot
36// proving Sendness. This issue was a lot worse in conduwuit where we used an
37// instance of `Dep` for each Service rather than a single instance of
38// `OnceServices` like now. The problem still exists though greatly reduced, and
39// the same solution now has greater impact because OnceServices is the single
40// unified focal-point for the entire Services call-web.
41//
42// The prior incarnation required this unsafety or it would blow through the
43// recursion_limit; that no longer happens. Nevertheless compile times are
44// still substantially reduced by asserting Sendness here. Prove sendness
45// by simply commenting this out or using `--cfg tuwunel_always_prove_sendness`,
46// it will just take longer.
47unsafe impl Send for OnceServices {}
48
49#[cfg(not(tuwunel_always_prove_syncness))]
50// SAFETY: Similar to Send as explained above, we further reduce compile-times
51// by manually asserting Syncness of this type. The only threading contention
52// concerns for this would be on startup but this server has a very well defined
53// initialization sequence. After that this structure is purely read-only shared
54// without concern.
55//
56// Proof can be verified by using `--cfg tuwunel_always_prove_syncness` at the
57// cost of additional build time.
58unsafe impl Sync for OnceServices {}