1use crate::traits::FXBuilderWrapper;
2use crate::traits::FXStruct;
3use async_trait::async_trait;
4use std::any;
5use std::cell::RefCell;
6use std::fmt;
7use std::fmt::Debug;
8use std::fmt::Formatter;
9use std::future::Future;
10use std::pin::Pin;
11use std::sync::atomic::AtomicBool;
12use std::sync::atomic::Ordering;
13
14use super::RwLock;
15use super::RwLockReadGuard;
16use super::RwLockWriteGuard;
17
18pub type FXProxyReadGuard<'a, T> = crate::lock_guards::FXProxyReadGuard<RwLockReadGuard<'a, Option<T>>, T>;
19pub type FXProxyWriteGuard<'a, T> = crate::lock_guards::FXProxyWriteGuard<RwLockWriteGuard<'a, Option<T>>, T>;
20
21type FXCallback<S, T> = Box<dyn Fn(&S) -> Pin<Box<dyn Future<Output = T> + Send + '_>> + Send + Sync>;
22
23#[cfg(feature = "async-tokio")]
24type ReadOrInitGuard<'a, T> = tokio::sync::RwLockWriteGuard<'a, T>;
25#[cfg(all(feature = "async-lock", not(docsrs)))]
26type ReadOrInitGuard<'a, T> = async_lock::RwLockUpgradableReadGuard<'a, T>;
27
28#[doc(hidden)]
29#[async_trait]
30pub trait FXBuilderWrapperAsync: FXBuilderWrapper {
31 async fn invoke(&self, owner: &Self::Owner) -> Result<Self::Value, Self::Error>;
32}
33
34#[doc(hidden)]
35pub struct FXBuilderInfallible<S, T> {
36 builder: FXCallback<S, T>,
37}
38
39impl<S, T> FXBuilderInfallible<S, T> {
40 pub fn new(builder: FXCallback<S, T>) -> Self {
41 Self { builder }
42 }
43}
44
45impl<S: FXStruct, T> FXBuilderWrapper for FXBuilderInfallible<S, T> {
46 type Error = ();
47 type Owner = S;
48 type Value = T;
49}
50
51#[async_trait]
52impl<S, T> FXBuilderWrapperAsync for FXBuilderInfallible<S, T>
53where
54 S: Sync + FXStruct,
55{
56 #[inline(always)]
57 async fn invoke(&self, owner: &Self::Owner) -> Result<Self::Value, Self::Error> {
58 Ok((self.builder)(owner).await)
59 }
60}
61
62#[doc(hidden)]
63pub struct FXBuilderFallible<S, T, E> {
64 builder: FXCallback<S, Result<T, E>>,
65}
66
67impl<S, T, E> FXBuilderFallible<S, T, E> {
68 pub fn new(builder: FXCallback<S, Result<T, E>>) -> Self {
69 Self { builder }
70 }
71}
72
73impl<S, T, E: Debug> FXBuilderWrapper for FXBuilderFallible<S, T, E>
74where
75 S: FXStruct,
76{
77 type Error = E;
78 type Owner = S;
79 type Value = T;
80}
81
82#[async_trait]
83impl<S, T, E: Debug> FXBuilderWrapperAsync for FXBuilderFallible<S, T, E>
84where
85 S: FXStruct + Sync,
86{
87 #[inline(always)]
88 async fn invoke(&self, owner: &Self::Owner) -> Result<Self::Value, Self::Error> {
89 (self.builder)(owner).await
90 }
91}
92
93pub struct FXProxy<B>
95where
96 B: FXBuilderWrapperAsync,
97{
98 value: RwLock<Option<B::Value>>,
99 is_set: AtomicBool,
100 builder: RwLock<Option<B>>,
101}
102
103pub struct FXWriter<'a, B>
108where
109 B: FXBuilderWrapperAsync,
110{
111 lock: RefCell<RwLockWriteGuard<'a, Option<B::Value>>>,
112 fxproxy: &'a FXProxy<B>,
113}
114
115impl<B, V> Debug for FXProxy<B>
116where
117 B: FXBuilderWrapperAsync<Value = V>,
118 V: Debug,
119{
120 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
121 #[cfg(feature = "async-tokio")]
122 let vlock = self.value.blocking_read();
123 #[cfg(feature = "async-lock")]
124 let vlock = self.value.read_blocking();
125
126 formatter
127 .debug_struct(any::type_name::<Self>())
128 .field("value", &*vlock)
129 .finish()
130 }
131}
132
133impl<B, E> FXProxy<B>
134where
135 B: FXBuilderWrapperAsync<Error = E>,
136 E: Debug,
137{
138 #[doc(hidden)]
139 pub fn new_default(builder: B, value: Option<B::Value>) -> Self {
140 Self {
141 is_set: AtomicBool::new(value.is_some()),
142 value: RwLock::new(value),
143 builder: RwLock::new(Some(builder)),
144 }
145 }
146
147 pub fn into_inner(self) -> Option<B::Value> {
149 self.value.into_inner()
150 }
151
152 #[inline]
153 fn is_set_raw(&self) -> &AtomicBool {
154 &self.is_set
155 }
156
157 #[inline]
159 pub fn is_set(&self) -> bool {
160 self.is_set_raw().load(Ordering::SeqCst)
161 }
162
163 pub async fn lazy_init(&self, owner: &B::Owner) {
166 let _ = self.read_or_init(owner).await;
167 }
168
169 async fn read_or_init<'a>(&'a self, owner: &B::Owner) -> Result<ReadOrInitGuard<'a, Option<B::Value>>, B::Error> {
170 #[cfg(feature = "async-tokio")]
171 let mut guard = self.value.write().await;
172 #[cfg(feature = "async-lock")]
173 let guard = self.value.upgradable_read().await;
174
175 if (*guard).is_none() {
176 #[cfg(feature = "async-lock")]
177 let mut guard = ReadOrInitGuard::upgrade(guard).await;
178 match *self.builder.read().await {
180 Some(ref builder_cb) => {
181 *guard = Some((*builder_cb).invoke(owner).await?);
182 self.is_set_raw().store(true, Ordering::SeqCst);
183 }
184 None => panic!("Builder is not set"),
185 }
186 #[cfg(feature = "async-lock")]
187 return Ok(RwLockWriteGuard::downgrade_to_upgradable(guard));
188 }
189 Ok(guard)
190 }
191
192 pub async fn read<'a>(&'a self, owner: &B::Owner) -> FXProxyReadGuard<'a, B::Value> {
196 FXProxyReadGuard::new(ReadOrInitGuard::downgrade(self.read_or_init(owner).await.unwrap()))
197 }
198
199 pub async fn read_mut<'a>(&'a self, owner: &B::Owner) -> FXProxyWriteGuard<'a, B::Value> {
203 #[cfg(feature = "async-tokio")]
204 return FXProxyWriteGuard::new(self.read_or_init(owner).await.unwrap());
205 #[cfg(feature = "async-lock")]
206 return FXProxyWriteGuard::new(ReadOrInitGuard::upgrade(self.read_or_init(owner).await.unwrap()).await);
207 }
208
209 pub async fn try_read<'a>(&'a self, owner: &B::Owner) -> Result<FXProxyReadGuard<'a, B::Value>, B::Error> {
213 #[cfg(feature = "async-tokio")]
214 return Ok(FXProxyReadGuard::new(self.read_or_init(owner).await?.downgrade()));
215 #[cfg(feature = "async-lock")]
216 return Ok(FXProxyReadGuard::new(ReadOrInitGuard::downgrade(
217 self.read_or_init(owner).await?,
218 )));
219 }
220
221 pub async fn try_read_mut<'a>(&'a self, owner: &B::Owner) -> Result<FXProxyWriteGuard<'a, B::Value>, B::Error> {
225 #[cfg(feature = "async-tokio")]
226 return Ok(FXProxyWriteGuard::new(self.read_or_init(owner).await?));
227 #[cfg(feature = "async-lock")]
228 return Ok(FXProxyWriteGuard::new(
229 ReadOrInitGuard::upgrade(self.read_or_init(owner).await?).await,
230 ));
231 }
232
233 pub async fn write<'a>(&'a self) -> FXWriter<'a, B> {
235 FXWriter::<'a, B>::new(self.value.write().await, self)
236 }
237
238 fn clear_with_lock(&self, wguard: &mut RwLockWriteGuard<Option<B::Value>>) -> Option<B::Value> {
239 self.is_set_raw().store(false, Ordering::SeqCst);
240 wguard.take()
241 }
242
243 pub async fn clear(&self) -> Option<B::Value> {
245 let mut wguard = self.value.write().await;
246 self.clear_with_lock(&mut wguard)
247 }
248}
249
250#[allow(private_bounds)]
251impl<'a, B> FXWriter<'a, B>
252where
253 B: FXBuilderWrapperAsync,
254{
255 #[doc(hidden)]
256 pub fn new(lock: RwLockWriteGuard<'a, Option<B::Value>>, fxproxy: &'a FXProxy<B>) -> Self {
257 let lock = RefCell::new(lock);
258 Self { lock, fxproxy }
259 }
260
261 pub fn store(&mut self, value: B::Value) -> Option<B::Value> {
263 self.fxproxy.is_set_raw().store(true, Ordering::Release);
264 self.lock.borrow_mut().replace(value)
265 }
266
267 pub fn clear(&self) -> Option<B::Value> {
269 self.fxproxy.clear_with_lock(&mut *self.lock.borrow_mut())
270 }
271}
272
273impl<B> Clone for FXProxy<B>
274where
275 B: FXBuilderWrapperAsync + Clone,
276 B::Value: Clone,
277{
278 fn clone(&self) -> Self {
279 #[cfg(feature = "async-tokio")]
280 let vguard = self.value.blocking_read();
281 #[cfg(feature = "async-tokio")]
282 let bguard = self.builder.blocking_read();
283
284 #[cfg(feature = "async-lock")]
285 let vguard = self.value.read_blocking();
286 #[cfg(feature = "async-lock")]
287 let bguard = self.builder.read_blocking();
288
289 Self {
290 value: RwLock::new((*vguard).as_ref().cloned()),
291 is_set: AtomicBool::new(self.is_set()),
292 builder: RwLock::new((*bguard).clone()),
293 }
294 }
295}