Skip to main content

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 {}