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 /// Borrow the services if they are initialized, without panicking on the
26 /// pre-init window. Returns `None` only before `set` runs, a state reached
27 /// by unit harnesses that build a service without an initialized graph.
28 #[inline]
29 pub(crate) fn try_get(&self) -> Option<&Arc<Services>> { self.lock.get() }
30}
31
32impl Deref for OnceServices {
33 type Target = Arc<Services>;
34
35 #[inline]
36 fn deref(&self) -> &Self::Target { self.get() }
37}
38
39#[cfg(not(tuwunel_always_prove_sendness))]
40// SAFETY: Services has a lot of circularity inherited from Conduit's original
41// design. This stresses the trait solver which twists itself into a knot
42// proving Sendness. This issue was a lot worse in conduwuit where we used an
43// instance of `Dep` for each Service rather than a single instance of
44// `OnceServices` like now. The problem still exists though greatly reduced, and
45// the same solution now has greater impact because OnceServices is the single
46// unified focal-point for the entire Services call-web.
47//
48// The prior incarnation required this unsafety or it would blow through the
49// recursion_limit; that no longer happens. Nevertheless compile times are
50// still substantially reduced by asserting Sendness here. Prove sendness
51// by simply commenting this out or using `--cfg tuwunel_always_prove_sendness`,
52// it will just take longer.
53unsafe impl Send for OnceServices {}
54
55#[cfg(not(tuwunel_always_prove_syncness))]
56// SAFETY: Similar to Send as explained above, we further reduce compile-times
57// by manually asserting Syncness of this type. The only threading contention
58// concerns for this would be on startup but this server has a very well defined
59// initialization sequence. After that this structure is purely read-only shared
60// without concern.
61//
62// Proof can be verified by using `--cfg tuwunel_always_prove_syncness` at the
63// cost of additional build time.
64unsafe impl Sync for OnceServices {}