1use core::{
2 convert::{identity, Infallible},
3 marker::PhantomData,
4 ptr::NonNull,
5};
6
7use crate::{
8 query::QueryUsing,
9 tag::{Mut, Ref, TagFor, Value},
10 Lt, Query, TagId,
11};
12
13pub trait Provide<L: Lt = ()>: Sized {
18 fn provide(self, query: &mut Query<'_, L>) -> Option<Self>;
22
23 fn request<Tag: TagFor<L>>(self, arg: Tag::ArgValue) -> Result<Tag::Value, Self> {
28 match Query::new_with::<Tag, _>(|q| self.provide(q), arg) {
29 (_, Some(value)) => Ok(value),
30 (Some(this), None) => Err(this),
31 (None, None) => panic!("'self' not returned when 'provide' failed"),
32 }
33 }
34
35 fn request_value<T: 'static>(self) -> Result<T, Self> {
38 self.request::<Value<T>>(())
39 }
40
41 fn request_ref<'x, T: 'static + ?Sized>(self) -> Result<&'x T, Self>
44 where
45 Ref<Value<T>>: TagFor<L, ArgValue = (), Value = &'x T>,
46 {
47 self.request::<Ref<Value<T>>>(())
48 }
49
50 fn request_mut<'x, T: 'static + ?Sized>(self) -> Result<&'x mut T, Self>
53 where
54 Mut<Value<T>>: TagFor<L, ArgValue = (), Value = &'x mut T>,
55 {
56 self.request::<Mut<Value<T>>>(())
57 }
58}
59
60impl<L: Lt, P: Provide<L>> Provide<L> for Option<P> {
61 fn provide(self, query: &mut Query<'_, L>) -> Option<Self> {
62 self.map(|this| this.provide(query))
63 }
64
65 fn request<Tag: TagFor<L>>(self, arg: Tag::ArgValue) -> Result<Tag::Value, Self> {
66 match Query::new_with::<Tag, _>(|q| self?.provide(q), arg) {
67 (_, Some(value)) => Ok(value),
68 (this, None) => Err(this),
69 }
70 }
71}
72
73impl<LTail: Lt, P: ProvideRef<LTail>> ProvideRef<LTail> for &mut Option<P> {
74 fn provide_ref<'this>(&'this self, query: &mut Query<'_, Lt!['this, ..LTail]>) {
75 if let Some(this) = self {
76 this.provide_ref(query);
77 }
78 }
79
80 fn provide_mut<'this>(&'this mut self, query: &mut Query<'_, Lt!['this, ..LTail]>) {
81 if let Some(this) = self {
82 this.provide_mut(query);
83 }
84 }
85}
86
87pub trait ProvideRef<LTail: Lt = ()> {
95 fn provide_ref<'this>(&'this self, query: &mut Query<'_, Lt!['this, ..LTail]>) {
100 let _ = query;
101 }
102
103 fn provide_mut<'this>(&'this mut self, query: &mut Query<'_, Lt!['this, ..LTail]>) {
108 let _ = query;
109 }
110}
111
112impl<'x, P: ?Sized + ProvideRef<LTail>, LTail: Lt> Provide<Lt!['x, ..LTail]> for &'x P {
113 fn provide(self, query: &mut Query<'_, Lt!['x, ..LTail]>) -> Option<Self> {
114 self.provide_ref(query);
115
116 Some(self)
117 }
118}
119
120impl<'x, P: ?Sized + ProvideRef<LTail>, LTail: Lt> Provide<Lt!['x, ..LTail]> for &'x mut P {
121 fn provide(mut self, query: &mut Query<'_, Lt!['x, ..LTail]>) -> Option<Self> {
122 self = provide_mut_with(self, query, |this, q| {
123 this.provide_mut(q);
124 })
125 .1?;
126
127 self = provide_mut_with(self, query, |this, q| {
128 this.provide_ref(q);
129 })
130 .1?;
131
132 Some(self)
133 }
134}
135
136fn provide_mut_with<'x, T: ?Sized, LTail: Lt, R>(
138 in_ref: &'x mut T,
139 query: &mut Query<'_, Lt!['x, ..LTail]>,
140 f: impl for<'y> FnOnce(&'y mut T, &mut Query<'_, Lt!['y, .. LTail]>) -> R,
141) -> (R, Option<&'x mut T>) {
142 let mut in_ref_ptr = NonNull::from(&mut *in_ref);
143
144 let out = unsafe {
148 let short_lived_ref = in_ref_ptr.as_mut();
149 f(short_lived_ref, query)
150 };
151
152 let out_ref = if query.is_fulfilled() {
153 None
156 } else {
157 Some(in_ref)
159 };
160
161 (out, out_ref)
162}
163
164#[derive(Clone, Copy)]
168pub struct FnProvider<T, F> {
169 value: T,
170 f: F,
171}
172
173impl<T: core::fmt::Debug, F> core::fmt::Debug for FnProvider<T, F> {
174 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
175 f.debug_struct("FnProvider")
176 .field("value", &self.value)
177 .finish_non_exhaustive()
178 }
179}
180
181impl<T, F, L: Lt> Provide<L> for FnProvider<T, F>
182where
183 F: for<'q> FnMut(QueryUsing<'q, T, L>) -> QueryUsing<'q, T, L>,
184{
185 fn provide(self, query: &mut Query<'_, L>) -> Option<Self> {
186 let Self { value, mut f } = self;
187
188 f(query.using(value))
189 .finish()
190 .map(|value| Self { value, f })
191 }
192}
193
194impl<T, F> FnProvider<T, F> {
195 pub fn into_inner(self) -> T {
196 self.value
197 }
198}
199
200pub fn provide_with<T, F, L: Lt>(value: T, provide: F) -> FnProvider<T, F>
213where
214 F: for<'q> FnMut(QueryUsing<'q, T, L>) -> QueryUsing<'q, T, L>,
215{
216 FnProvider { value, f: provide }
217}
218
219#[derive(Clone, Copy)]
223pub struct FnRefProvider<T, FRef, FMut> {
224 value: T,
225 f_ref: FRef,
226 f_mut: FMut,
227}
228
229impl<T: core::fmt::Debug, FRef, FMut> core::fmt::Debug for FnRefProvider<T, FRef, FMut> {
230 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
231 f.debug_struct("FnRefProvider")
232 .field("value", &self.value)
233 .finish_non_exhaustive()
234 }
235}
236
237impl<T, FRef, FMut, L: Lt> ProvideRef<L> for FnRefProvider<T, FRef, FMut>
238where
239 FRef:
240 for<'q, 'x> Fn(QueryUsing<'q, &'x T, Lt!['x, ..L]>) -> QueryUsing<'q, &'x T, Lt!['x, ..L]>,
241 FMut: for<'q, 'x> FnMut(
242 QueryUsing<'q, &'x mut T, Lt!['x, ..L]>,
243 ) -> QueryUsing<'q, &'x mut T, Lt!['x, ..L]>,
244{
245 fn provide_ref<'this>(&'this self, query: &mut Query<'_, Lt!['this, ..L]>) {
246 let Self { value, f_ref, .. } = self;
247
248 let _ = f_ref(query.using(value)).finish();
249 }
250
251 fn provide_mut<'this>(&'this mut self, query: &mut Query<'_, Lt!['this, ..L]>) {
252 let Self { value, f_mut, .. } = self;
253
254 let _ = f_mut(query.using(value)).finish();
255 }
256}
257
258impl<T, FRef, FMut> FnRefProvider<T, FRef, FMut> {
259 pub fn into_inner(self) -> T {
260 self.value
261 }
262}
263
264pub fn provide_by_ref_with<T, FRef, FMut, LTail: Lt>(
278 value: T,
279 provide_ref: FRef,
280 provide_mut: FMut,
281) -> FnRefProvider<T, FRef, FMut>
282where
283 FRef: for<'q, 'x> Fn(
284 QueryUsing<'q, &'x T, Lt!['x, ..LTail]>,
285 ) -> QueryUsing<'q, &'x T, Lt!['x, ..LTail]>,
286 FMut: for<'q, 'x> FnMut(
287 QueryUsing<'q, &'x mut T, Lt!['x, ..LTail]>,
288 ) -> QueryUsing<'q, &'x mut T, Lt!['x, ..LTail]>,
289{
290 FnRefProvider {
291 value,
292 f_ref: provide_ref,
293 f_mut: provide_mut,
294 }
295}
296
297impl<L: Lt> Provide<L> for () {
298 fn provide(self, _: &mut Query<'_, L>) -> Option<Self> {
299 Some(self)
300 }
301}
302
303impl<L: Lt> ProvideRef<L> for () {}
304
305impl<L: Lt> ProvideRef<L> for str {
306 fn provide_ref<'x>(&'x self, query: &mut Query<'_, Lt!['x, ..L]>) {
307 let mut query = query.using(self);
308
309 query = query.put_ref(identity).put_ref(str::as_bytes);
310
311 #[cfg(feature = "alloc")]
312 {
313 use alloc::borrow::ToOwned;
314 query = query
315 .put_value(str::to_owned)
316 .put_value(|this| this.to_owned().into_boxed_str())
317 .put_value(|this| this.as_bytes().to_owned())
318 .put_value(|this| this.as_bytes().to_owned().into_boxed_slice());
319 }
320
321 query.finish();
322 }
323}
324
325impl<L: Lt> Provide<L> for Infallible {
326 fn provide(self, _: &mut Query<'_, L>) -> Option<Self> {
327 match self {}
328 }
329}
330
331impl<L: Lt> ProvideRef<L> for Infallible {}
332
333enum WhenProviderState<P, Cx, Out> {
334 Provider { provider: P, context: Cx },
335 Output { out: Out },
336}
337
338pub struct HasContext<Cx>(Cx);
339pub struct NoContext;
340
341#[doc = include_str!("./when_provider.md")]
348pub fn when_provider<L: Lt, P: Provide<L>, Out>(provider: P) -> WhenProvider<L, P, NoContext, Out> {
349 WhenProvider {
350 state: WhenProviderState::Provider {
351 provider,
352 context: NoContext,
353 },
354 _l: PhantomData,
355 }
356}
357
358#[doc = include_str!("./when_provider.md")]
362pub struct WhenProvider<L, P, Cx, Out> {
363 state: WhenProviderState<P, Cx, Out>,
364 _l: PhantomData<L>,
365}
366
367macro_rules! impl_when_provider_methods {
368 (has_context = $has_context:ident) => {
369 pub fn has<Tag: TagFor<L>>(
371 mut self,
372 arg: Tag::ArgValue,
373 transform: transform_type!(has_context = $has_context, arg = Tag::Value),
374 ) -> Self {
375 if let WhenProviderState::Provider {
376 provider,
377 context: _context,
378 } = self.state
379 {
380 self.state = match provider.request::<Tag>(arg) {
381 Ok(out) => WhenProviderState::Output {
382 out: transform_call!(
383 has_context = $has_context,
384 transform = transform,
385 out = out,
386 context = _context
387 ),
388 },
389 Err(provider) => WhenProviderState::Provider {
390 provider,
391 context: _context,
392 },
393 }
394 }
395
396 self
397 }
398
399 pub fn has_value<T: 'static>(
401 self,
402 transform: transform_type!(has_context = $has_context, arg = T),
403 ) -> Self {
404 self.has::<Value<T>>((), transform)
405 }
406 };
407 (ref/has_context = $has_context:ident) => {
408 pub fn has_ref<T: 'static + ?Sized>(
411 self,
412 transform: transform_type!(has_context = $has_context, arg = &'x T),
413 ) -> Self {
414 self.has::<Ref<Value<T>>>((), transform)
415 }
416
417 pub fn has_mut<T: 'static + ?Sized>(
420 self,
421 transform: transform_type!(has_context = $has_context, arg = &'x mut T),
422 ) -> Self {
423 self.has::<Mut<Value<T>>>((), transform)
424 }
425 };
426}
427
428macro_rules! transform_type {
429 (has_context = true, arg = $Arg:ty) => {
430 impl FnOnce($Arg, Cx) -> Out
431 };
432 (has_context = false, arg = $Arg:ty) => {
433 impl FnOnce($Arg) -> Out
434 };
435}
436
437macro_rules! transform_call {
438 (has_context = true, transform = $transform:ident, out = $out:ident, context = $context:ident) => {
439 $transform($out, $context.0)
440 };
441 (has_context = false, transform = $transform:ident, out = $out:ident, context = $context:ident) => {
442 $transform($out)
443 };
444}
445
446impl<L: Lt, P: Provide<L>, Out> WhenProvider<L, P, NoContext, Out> {
447 pub fn finish(self) -> Result<Out, P> {
450 match self.state {
451 WhenProviderState::Provider {
452 provider,
453 context: NoContext,
454 } => Err(provider),
455 WhenProviderState::Output { out } => Ok(out),
456 }
457 }
458
459 pub fn or_else(self, f: impl FnOnce(P) -> Out) -> Out {
462 self.finish().unwrap_or_else(f)
463 }
464
465 pub fn with<Cx>(self, context: Cx) -> WhenProvider<L, P, HasContext<Cx>, Out> {
468 WhenProvider {
469 state: match self.state {
470 WhenProviderState::Provider {
471 provider,
472 context: NoContext,
473 } => WhenProviderState::Provider {
474 provider,
475 context: HasContext(context),
476 },
477 WhenProviderState::Output { out } => WhenProviderState::Output { out },
478 },
479 _l: PhantomData,
480 }
481 }
482
483 impl_when_provider_methods!(has_context = false);
484}
485
486impl<'x, L: Lt, P: Provide<Lt!['x, ..L]>, Out> WhenProvider<Lt!['x, ..L], P, NoContext, Out> {
487 impl_when_provider_methods!(ref/has_context = false);
488}
489
490impl<L: Lt, P: Provide<L>, Cx, Out> WhenProvider<L, P, HasContext<Cx>, Out> {
491 pub fn finish(self) -> Result<Out, (P, Cx)> {
494 match self.state {
495 WhenProviderState::Provider {
496 provider,
497 context: HasContext(context),
498 } => Err((provider, context)),
499 WhenProviderState::Output { out } => Ok(out),
500 }
501 }
502
503 pub fn or_else(self, f: impl FnOnce(P, Cx) -> Out) -> Out {
506 self.finish()
507 .unwrap_or_else(|(provider, cx)| f(provider, cx))
508 }
509
510 impl_when_provider_methods!(has_context = true);
511}
512
513impl<'x, L: Lt, P: Provide<Lt!['x, ..L]>, Cx, Out>
514 WhenProvider<Lt!['x, ..L], P, HasContext<Cx>, Out>
515{
516 impl_when_provider_methods!(ref/has_context = true);
517}
518
519pub fn for_each_provided_tag_id<L: Lt, P: Provide<L>>(
523 provider: P,
524 on_provide_attempt: impl FnMut(TagId),
525) -> P {
526 Query::capture_tag_ids(|q| provider.provide(q), on_provide_attempt).unwrap()
527}
528
529#[cfg_attr(
532 feature = "alloc",
533 doc = r#"
534```
535use dynamic_provider::{Lt, Mut, Ref, TagId, Value};
536
537let provider = String::from("Hello, world!");
538
539let tag_ids = dynamic_provider::get_provided_tag_ids::<Lt!['_], Vec<_>>(&provider);
540
541assert!(tag_ids.contains(&TagId::of::<Ref<Value<str>>>()));
542assert!(tag_ids.contains(&TagId::of::<Ref<Value<[u8]>>>()));
543assert!(tag_ids.contains(&TagId::of::<Value<String>>()));
544```
545"#
546)]
547pub fn get_provided_tag_ids<L: Lt, Out>(provider: impl Provide<L>) -> Out
548where
549 Out: Default + Extend<TagId>,
550{
551 let mut out = Out::default();
552 for_each_provided_tag_id(provider, |tag_id| out.extend([tag_id]));
553 out
554}