reifydb_core/util/ioc/
resolve_rc.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the AGPL-3.0-or-later, see license.md file
3
4use std::{
5	any::{Any, type_name},
6	cell::OnceCell,
7	rc::Rc,
8};
9
10use reifydb_type::{Result, diagnostic::internal, error};
11
12use super::IocContainer;
13
14/// Single-threaded lazy resolution wrapper using OnceCell
15/// Can be cheaply cloned as it uses Rc internally
16pub struct LazyResolveRc<T> {
17	inner: Rc<LazyResolveInner<T>>,
18}
19
20/// Inner storage for lazy resolution (single-threaded)
21struct LazyResolveInner<T> {
22	value: OnceCell<T>,
23}
24
25#[allow(dead_code)]
26impl<T: Clone> LazyResolveRc<T> {
27	/// Create a new lazy resolve
28	pub fn new() -> Self {
29		Self {
30			inner: Rc::new(LazyResolveInner {
31				value: OnceCell::new(),
32			}),
33		}
34	}
35
36	/// Get or resolve the value from the IoC container
37	/// The resolution happens exactly once, subsequent calls return the
38	/// cached value
39	pub fn get_or_resolve(&self, ioc: &IocContainer) -> Result<&T>
40	where
41		T: Clone + Any + Send + Sync + 'static,
42	{
43		if let Some(value) = self.inner.value.get() {
44			return Ok(value);
45		}
46
47		// Try to resolve and set
48		let resolved = ioc.resolve::<T>()?;
49		match self.inner.value.set(resolved) {
50			Ok(()) => {
51				// We successfully set it, return a reference
52				self.inner.value.get().ok_or_else(|| {
53					error!(internal(format!(
54						"Failed to get value after setting in OnceCell for type {}",
55						type_name::<T>()
56					)))
57				})
58			}
59			Err(_) => {
60				// This shouldn't happen in single-threaded
61				// context
62				Err(error!(internal(format!(
63					"Failed to set value in OnceCell for type {}",
64					type_name::<T>()
65				))))
66			}
67		}
68	}
69
70	/// Get the resolved value if it exists, without attempting to resolve
71	#[allow(dead_code)]
72	pub fn get(&self) -> Option<&T> {
73		self.inner.value.get()
74	}
75
76	/// Check if the value has been resolved
77	#[allow(dead_code)]
78	pub fn is_resolved(&self) -> bool {
79		self.inner.value.get().is_some()
80	}
81}
82
83impl<T: Clone> Clone for LazyResolveRc<T> {
84	fn clone(&self) -> Self {
85		Self {
86			inner: Rc::clone(&self.inner),
87		}
88	}
89}
90
91impl<T: Clone> Default for LazyResolveRc<T> {
92	fn default() -> Self {
93		Self::new()
94	}
95}