daab/
utils.rs

1//!
2//! Utility module
3//!
4//! This module contains some utilities which can be useful when working with `daab`.
5//!
6
7use crate::Resolver;
8use crate::Promise;
9use crate::Blueprint;
10use crate::Builder;
11use crate::CanRef;
12use crate::CanStrong;
13use crate::CanSized;
14use crate::Can;
15use crate::Never;
16
17use std::fmt;
18use std::fmt::Debug;
19use std::marker::PhantomData;
20
21
22
23/// A intermediate cached Builder to circumvent failing builders.
24///
25/// In resource loading, a resource might be come unavailable for sometime.
26/// This wrapper builder will cache the result of its inner builder and return
27/// the cached value instead, if the inner builder failed to produce a new
28/// artifact.
29///
30/// **Notice: It is likely a logical error to keep an artifact despite
31/// been invalidate, which is what this wrapper dose!**
32///
33/// Therefore, this wrapper should be used with care and only
34/// with builders, which actually do not have any dependencies (so they might
35/// only been manually invalidate) or having artifacts which are still usable
36/// after any (or all) dependency has been invalidated.
37///
38/// Notice, that once the inner builder faild, and the `RedeemingBuilder` 'built' the _old artifact_
39/// then this will not establish a dependency on the inner builder. So to make the
40/// `RedeemingBuilder` return a 'fresh' artifact from the inner builder, the `RedeemingBuilder`
41/// itself needs to be invalidated. This should otherwise not be an issue, because if the inner
42/// builder still fails, the `RedeemingBuilder` will again retun the _old artifact_.
43///
44/// # Panics
45///
46/// This builder panics in its `build` method if the first build of its inner
47/// builder failed and the `default_value` has been set to `None`.
48///
49#[derive(Debug, Clone)]
50pub struct RedeemingBuilder<AP, ArtBin> {
51	inner: AP,
52	default_value: Option<ArtBin>,
53}
54
55impl<AP, ArtBin> RedeemingBuilder<AP, ArtBin> {
56
57	/// Wrap given Builder and fill missing recreations with a previous value.
58	///
59	/// **Use with care**
60	///
61	pub fn new<ArtCan, BCan, B: ?Sized, T>(
62		inner: AP,
63		default_value: Option<ArtBin>
64	) -> Self
65		where
66			B: Builder<ArtCan, BCan, Artifact=T>,
67			BCan: Can<AP::Builder>,
68			AP: Promise<Builder = B, BCan = BCan>,
69			T: Debug + 'static,
70			ArtCan: Clone + CanSized<T,Bin=ArtBin>,
71			ArtBin: Clone + Debug + 'static,
72			BCan: Clone + CanStrong,
73			BCan: CanSized<Self>,
74	{
75
76		RedeemingBuilder {
77			inner,
78			default_value,
79		}
80	}
81}
82
83impl<ArtCan, AP, B: ?Sized, BCan, ArtBin, T> Builder<ArtCan, BCan> for RedeemingBuilder<AP, ArtBin>
84	where
85		B: Builder<ArtCan, BCan, Artifact=T>,
86		BCan: Can<B>,
87		AP: Promise<Builder = B, BCan = BCan>,
88		T: Debug + 'static,
89		ArtCan: Clone + CanSized<T,Bin=ArtBin>,
90		ArtBin: Clone + Debug + 'static,
91		BCan: Clone + CanStrong,
92	{
93
94	type Artifact = T;
95	type DynState = Option<ArtCan::Bin>;
96	type Err = Never;
97
98	fn build(&self, resolver: &mut Resolver<ArtCan, BCan, Self::DynState>)
99			-> Result<ArtCan::Bin, Never> {
100
101		let value = resolver.resolve(&self.inner);
102
103		if let Ok(v) = value {
104			*resolver.my_state() = Some(v.clone());
105
106			// Return value
107			Ok(v)
108
109		} else {
110			// Try to return cached value. Panics if very first build fails and
111			// no default value was provided.
112			// This is documented behavior.
113			Ok(resolver.my_state().clone().unwrap())
114		}
115	}
116
117	fn init_dyn_state(&self) -> Self::DynState {
118		self.default_value.clone()
119	}
120}
121
122
123
124
125/// Functional leaf builder wrapper.
126///
127/// A functional builder is a builder consisting of a single function
128/// `Fn(&mut S) -> Result<ArtCan::Bin,E>`. Thus this type can be used to wrap a
129/// closure as `Builder` with type `T` as the artifact type, and type `E` as error type.
130/// The closure takes a mutable reference to a `S` (default `()`) which is the DynState
131/// of the builder. However, the closure will not have a `Resolver` thus it can not
132/// depend on other builders, making it a 'leaf' builder. So it is most useful as a
133/// 'provider' builder.
134///
135/// Also see `ConstBuilder` and `ConfigurableBuilder` for alternatives.
136///
137/// # Examples
138///
139/// Basic usage:
140///
141/// ```
142/// use std::rc::Rc;
143/// use daab::utils::FunctionalBuilder;
144/// use daab::rc::Cache;
145/// use daab::rc::Blueprint;
146/// use daab::prelude::*;
147///
148/// let builder = FunctionalBuilder::new(
149///     |_| {
150///         Ok(Rc::new(42))
151///     }
152/// );
153/// let blueprint = Blueprint::new(builder);
154///
155/// let mut cache = Cache::new();
156///
157/// assert_eq!(42_u32, cache.get_cloned(&blueprint).unpack());
158/// ```
159///
160/// Advanced usage with DynState:
161///
162/// ```
163/// use std::rc::Rc;
164/// use daab::utils::FunctionalBuilder;
165/// use daab::rc::Cache;
166/// use daab::rc::Blueprint;
167///
168/// let builder = FunctionalBuilder::with_state(0_u32, |st| {
169///     if *st < 2 {
170///         *st += 1;
171///         Ok(Rc::new(*st))
172///     } else {
173///         Err(false)
174///     }
175/// });
176/// let blueprint = Blueprint::new(builder);
177///
178/// let mut cache = Cache::new();
179///
180/// assert_eq!(Ok(1_u32), cache.get_cloned(&blueprint));
181/// # assert_eq!(Ok(1_u32), cache.get_cloned(&blueprint));
182/// cache.invalidate(&blueprint);
183/// assert_eq!(Ok(2_u32), cache.get_cloned(&blueprint));
184/// cache.invalidate(&blueprint);
185/// assert_eq!(Err(false), cache.get_cloned(&blueprint));
186/// ```
187///
188/// Real world scenario with `File`:
189///
190/// ```
191/// use std::fs::File;
192/// use std::rc::Rc;
193/// use daab::utils::FunctionalBuilder;
194/// use daab::rc::Cache;
195/// use daab::rc::CanType;
196/// use daab::rc::Blueprint;
197///
198/// let builder = FunctionalBuilder::new(
199///     |_| {
200///         File::open("some_path").map(Rc::new)
201///     }
202/// );
203/// let blueprint = Blueprint::new(builder);
204///
205/// let mut cache = Cache::new();
206///
207/// let file = cache.get(&blueprint);
208///
209/// # assert!(file.is_err());
210/// ```
211///
212pub struct FunctionalBuilder<ArtCan, BCan, F, T, S = ()> {
213	inner: F,
214	initial_state: S,
215	_art_can: PhantomData<ArtCan>,
216	_b_can: PhantomData<BCan>,
217	_t: PhantomData<T>,
218}
219
220impl<ArtCan, BCan, F, T, S> Debug for FunctionalBuilder<ArtCan, BCan, F, T, S> {
221	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
222		write!(fmt, "FunctionalBuilder{{...}}")
223	}
224}
225
226impl<ArtCan, BCan, F, E, T> FunctionalBuilder<ArtCan, BCan, F, T, ()>
227	where
228		F: (for<'r> Fn( &'r mut () ) -> Result<ArtCan::Bin,E>) + 'static,
229		E: Debug + 'static,
230		T: Debug + 'static,
231		BCan: CanStrong,
232		ArtCan: Can<T>,
233		ArtCan: Debug + 'static {
234
235	/// Wraps the given closure as Builder.
236	///
237	pub fn new(f: F) -> Self {
238		FunctionalBuilder::with_state( (), f )
239	}
240}
241
242impl<ArtCan, BCan, F, E, T, S> FunctionalBuilder<ArtCan, BCan, F, T, S>
243	where
244		F: (for<'r> Fn(&'r mut S) -> Result<ArtCan::Bin,E>) + 'static,
245		E: Debug + 'static,
246		T: Debug + 'static,
247		S: Clone + Debug + 'static,
248		BCan: CanStrong,
249		ArtCan: Can<T>,
250		ArtCan: Debug + 'static {
251
252	/// Wraps the given closure as Builder.
253	///
254	pub fn with_state(initial_state: S, f: F) -> Self {
255		FunctionalBuilder {
256			inner: f,
257			initial_state,
258			_art_can: PhantomData,
259			_b_can: PhantomData,
260			_t: PhantomData,
261		}
262	}
263}
264
265/*
266/// Convert a 'stateless' closure into a `FunctionalBuilder`
267impl<ArtCan, BCan, F, E, T> From<F> for FunctionalBuilder<ArtCan, BCan, F, ()>
268	where
269		F: (for<'r> Fn( &'r mut () ) -> Result<T,E>) + 'static,
270		E: Debug + 'static,
271		T: Debug + 'static,
272		BCan: CanStrong,
273		BCan: CanSized<FunctionalBuilder<ArtCan, BCan, F, ()>>,
274		ArtCan: Debug + 'static,
275		Self: Builder<ArtCan, BCan> {
276
277	fn from(f: F) -> Self {
278		FunctionalBuilder::with_state((), f)
279	}
280}
281*/
282
283impl<ArtCan, BCan, F, E, T, S> Builder<ArtCan, BCan> for FunctionalBuilder<ArtCan, BCan, F, T, S>
284	where
285		F: (for<'r> Fn( &'r mut S ) -> Result<ArtCan::Bin,E>) + 'static,
286		E: Debug + 'static,
287		T: Debug + 'static,
288		S: Clone + Debug + 'static,
289		BCan: CanStrong,
290		ArtCan: Can<T>,
291		ArtCan: Debug + 'static {
292
293	type Artifact = T;
294	type DynState = S;
295	type Err = E;
296
297	fn build(&self, resolver: &mut Resolver<ArtCan, BCan, Self::DynState>)
298			 -> Result<ArtCan::Bin, Self::Err> {
299
300		let f = &self.inner;
301		let state = resolver.my_state();
302
303		f(state)
304
305	}
306	fn init_dyn_state(&self) -> Self::DynState {
307		self.initial_state.clone()
308	}
309}
310
311
312
313
314/// A static builder.
315///
316/// A builder which always builds a predetermined value as artifact.
317///
318/// Also see `FunctionalBuilder` and `ConfigurableBuilder` for alternatives.
319///
320/// # Examples
321///
322/// Basic usage:
323///
324/// ```
325/// use std::rc::Rc;
326/// use daab::utils::ConstBuilder;
327/// use daab::rc::Cache;
328/// use daab::rc::Blueprint;
329/// use daab::prelude::*;
330///
331/// let builder = ConstBuilder::new(Rc::new(42_u32));
332/// let blueprint = Blueprint::new(builder);
333///
334/// let mut cache = Cache::new();
335///
336/// assert_eq!(42_u32, cache.get_cloned(&blueprint).unpack());
337/// # cache.invalidate(&blueprint);
338/// # assert_eq!(42_u32, cache.get_cloned(&blueprint).unpack());
339/// ```
340///
341pub struct ConstBuilder<ArtCan, BCan, ArtBin, T> {
342	inner: ArtBin,
343	_art_can: PhantomData<ArtCan>,
344	_b_can: PhantomData<BCan>,
345	_t: PhantomData<T>,
346}
347
348impl<ArtCan, BCan, ArtBin: Debug, T> Debug for ConstBuilder<ArtCan, BCan, ArtBin, T> {
349	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
350		write!(fmt, "FunctionalBuilder{{inner: {:?}}}", self.inner)
351	}
352}
353
354impl<ArtCan, BCan, ArtBin, T> ConstBuilder<ArtCan, BCan, ArtBin, T>
355	where
356		BCan: CanStrong,
357		ArtCan: Can<T,Bin=ArtBin>,
358		ArtCan: 'static,
359		ArtBin: Clone + Debug + 'static, {
360
361	/// Wraps the given closure as Builder.
362	///
363	pub fn new(artifact_bin: ArtBin) -> Self {
364
365		ConstBuilder {
366			inner: artifact_bin,
367			_art_can: PhantomData,
368			_b_can: PhantomData,
369			_t: PhantomData,
370		}
371	}
372}
373
374impl<ArtCan, BCan, ArtBin, T> From<T> for Blueprint<ConstBuilder<ArtCan, BCan, ArtBin, T>, BCan>
375	where
376		T: Clone + Debug + 'static,
377		BCan: CanStrong,
378		BCan: CanSized<ConstBuilder<ArtCan, BCan, ArtBin, T>>,
379		ArtCan: CanSized<T,Bin=ArtBin>,
380		ArtCan: 'static,
381		ArtBin: Clone + Debug + 'static, {
382
383	fn from(t: T) -> Self {
384		Blueprint::new(
385			ConstBuilder::new(ArtCan::into_bin(t))
386		)
387	}
388}
389
390impl<ArtCan, BCan, ArtBin, T> Builder<ArtCan, BCan> for ConstBuilder<ArtCan, BCan, ArtBin, T>
391	where
392		T: Debug + 'static,
393		BCan: CanStrong,
394		ArtCan: Can<T,Bin=ArtBin>,
395		ArtCan: 'static,
396		ArtBin: Clone + Debug + 'static, {
397
398	type Artifact = T;
399	type DynState = ();
400	type Err = Never;
401
402	fn build(&self, _resolver: &mut Resolver<ArtCan, BCan>)
403			 -> Result<ArtBin, Never> {
404
405		Ok(self.inner.clone())
406	}
407	fn init_dyn_state(&self) -> Self::DynState {
408		// empty
409	}
410}
411
412
413
414
415/// A dynamic builder.
416///
417/// A `ConfigurableBuilder` is a builder which's artifact can be reconfigured
418/// i.e. changed by changing it's dyn state.
419///
420/// Also see `FunctionalBuilder` and `ConstBuilder` for alternatives.
421///
422/// # Examples
423///
424/// Basic usage:
425///
426/// ```
427/// use daab::utils::ConfigurableBuilder;
428/// use daab::rc::Cache;
429/// use daab::rc::Blueprint;
430/// use daab::prelude::*;
431///
432/// let builder = ConfigurableBuilder::new(0_u32);
433/// let blueprint = Blueprint::new(builder);
434///
435/// let mut cache = Cache::new();
436///
437/// assert_eq!(0_u32, cache.get_cloned(&blueprint).unpack());
438/// *cache.dyn_state_mut(&blueprint) = 42;
439/// assert_eq!(42_u32, cache.get_cloned(&blueprint).unpack());
440/// # cache.invalidate(&blueprint);
441/// # assert_eq!(42_u32, cache.get_cloned(&blueprint).unpack());
442/// ```
443///
444pub struct ConfigurableBuilder<ArtCan, BCan, T> {
445	initial: T,
446	_art_can: PhantomData<ArtCan>,
447	_b_can: PhantomData<BCan>,
448}
449
450impl<ArtCan, BCan, T: Debug> Debug for ConfigurableBuilder<ArtCan, BCan, T> {
451	fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
452		write!(fmt, "FunctionalBuilder{{initial: {:?}}}", self.initial)
453	}
454}
455
456impl<ArtCan, BCan, T> ConfigurableBuilder<ArtCan, BCan, T>
457	where
458		T: Clone + Debug + 'static,
459		BCan: CanStrong,
460		ArtCan: Debug + 'static {
461
462	/// Wraps the given closure as Builder.
463	///
464	pub fn new(artifact: T) -> Self {
465		ConfigurableBuilder {
466			initial: artifact,
467			_art_can: PhantomData,
468			_b_can: PhantomData,
469		}
470	}
471}
472
473impl<ArtCan, BCan, T> From<T> for Blueprint<ConfigurableBuilder<ArtCan, BCan, T>, BCan>
474	where
475		T: Clone + Debug + 'static,
476		BCan: CanStrong,
477		BCan: CanSized<ConfigurableBuilder<ArtCan, BCan, T>>,
478		ArtCan: Debug + 'static {
479
480	fn from(t: T) -> Self {
481		Blueprint::new(
482			ConfigurableBuilder::new(t)
483		)
484	}
485}
486
487impl<ArtCan, BCan, T> Builder<ArtCan, BCan> for ConfigurableBuilder<ArtCan, BCan, T>
488	where
489		T: Clone + Debug + 'static,
490		BCan: CanStrong,
491		ArtCan: CanSized<T>,
492		ArtCan: Debug + 'static {
493
494	type Artifact = T;
495	type DynState = T;
496	type Err = Never;
497
498	fn build(&self, resolver: &mut Resolver<ArtCan, BCan, T>)
499			 -> Result<ArtCan::Bin, Never> {
500
501		Ok(ArtCan::into_bin(resolver.my_state().clone()))
502	}
503	fn init_dyn_state(&self) -> Self::DynState {
504		self.initial.clone()
505	}
506}
507
508
509
510
511/// A intermediate Builder without dyn state.
512///
513/// When different builder shall be hidden behind a `dyn Builder` it is required
514/// that all such builders have the same dyn state type. Thus, often non dyn
515/// state or the `()` unit type as dyn state is used. This wrapper build now
516/// allows to wrap arbitrary builders (e.g. those with a dyn state) into a
517/// builder that dose has the `()` unit type as dyn state. So that it may be
518/// use to create cast it into `dyn Builder` with the `()` unit type as dyn state.
519///
520/// However, in order to create a valid artifact, the artifact type must be
521/// `Clone`. Thus the original and the 'cloned' artifact are not identical.
522///
523/// Also see the `ForwardingBuilder` for an alternative.
524///
525#[derive(Debug, Clone)]
526pub struct ClonedBuilder<AP> {
527	inner: AP,
528}
529
530impl<AP> ClonedBuilder<AP> {
531
532	/// Wrap given Builder cloning its artifact.
533	///
534	pub fn new<ArtCan, BCan, B: ?Sized>(
535		inner: AP,
536	) -> Self
537		where
538			B: Builder<ArtCan, BCan>,
539			B::Artifact: Clone,
540			BCan: Can<AP::Builder>,
541			AP: Promise<Builder = B, BCan = BCan>,
542			ArtCan: CanRef<B::Artifact>,
543			BCan: Clone + CanStrong,
544			BCan: CanSized<Self>,
545	{
546
547		ClonedBuilder {
548			inner,
549		}
550	}
551}
552
553impl<ArtCan, AP, B: ?Sized, BCan> Builder<ArtCan, BCan> for ClonedBuilder<AP>
554	where
555		B: Builder<ArtCan, BCan>,
556		B::Artifact: Clone,
557		BCan: Can<B>,
558		AP: Promise<Builder = B, BCan = BCan>,
559		ArtCan: CanRef<B::Artifact>,
560		BCan: CanStrong,
561	{
562
563	type Artifact = B::Artifact;
564	type DynState = ();
565	type Err = B::Err;
566
567	fn build(&self, resolver: &mut Resolver<ArtCan, BCan, Self::DynState>)
568			-> Result<ArtCan::Bin, Self::Err> {
569
570		resolver.resolve_cloned(&self.inner)
571			.map(ArtCan::into_bin)
572	}
573
574	fn init_dyn_state(&self) -> Self::DynState {
575		// empty
576	}
577}
578
579
580
581/// A intermediate Builder without dyn state.
582///
583/// When different builder shall be hidden behind a `dyn Builder` it is required
584/// that all such builders have the same dyn state type. Thus, often non dyn
585/// state or the `()` unit type as dyn state is used. This wrapper builder now
586/// allows to wrap arbitrary builders (e.g. those with a dyn state) into a
587/// builder that dose has the `()` unit type as dyn state. So that it may be
588/// use to create cast it into `dyn Builder` with the `()` unit type as dyn state.
589///
590/// However, in order to create a valid artifact, the artifact is kept in its bin-state.
591///
592/// Also see the `ClonedBuilder` for an alternative.
593///
594#[derive(Debug, Clone)]
595pub struct ForwardingBuilder<AP> {
596	inner: AP,
597}
598
599impl<AP> ForwardingBuilder<AP> {
600
601	/// Wrap given Builder forwarding its artifact.
602	///
603	pub fn new<ArtCan, BCan, B: ?Sized>(
604		inner: AP,
605	) -> Self
606		where
607			B: Builder<ArtCan, BCan>,
608			BCan: Can<AP::Builder>,
609			AP: Promise<Builder = B, BCan = BCan>,
610			ArtCan: CanSized<B::Artifact>,
611			ArtCan: Clone,
612			BCan: CanStrong,
613			BCan: CanSized<Self>,
614	{
615
616		ForwardingBuilder {
617			inner,
618		}
619	}
620}
621
622impl<ArtCan, AP, B: ?Sized, BCan> Builder<ArtCan, BCan> for ForwardingBuilder<AP>
623	where
624		B: Builder<ArtCan, BCan>,
625		BCan: Can<B>,
626		AP: Promise<Builder = B, BCan = BCan>,
627		ArtCan: CanSized<B::Artifact>,
628		ArtCan: Clone,
629		BCan: CanStrong,
630	{
631
632	type Artifact = B::Artifact;
633	type DynState = ();
634	type Err = B::Err;
635
636	fn build(&self, resolver: &mut Resolver<ArtCan, BCan, Self::DynState>)
637			-> Result<ArtCan::Bin, Self::Err> {
638
639		resolver.resolve(&self.inner)
640	}
641
642	fn init_dyn_state(&self) -> Self::DynState {
643		// empty
644	}
645}
646
647
648
649/// A intermediate Builder which wraps a builder with `Err=Never` with a arbitrary error type.
650///
651#[derive(Debug, Clone)]
652pub struct FeigningBuilder<AP, Err> {
653	inner: AP,
654	_err: PhantomData<Err>,
655}
656
657impl<AP, Err> FeigningBuilder<AP, Err> {
658
659	/// Wrap given Builder forwarding its artifact.
660	///
661	pub fn new<ArtCan, BCan, B>(
662		inner: AP,
663	) -> Self
664		where
665			B: Builder<ArtCan, BCan, Err=Never>,
666			BCan: Can<AP::Builder>,
667			AP: Promise<Builder = B, BCan = BCan>,
668			Err: Debug + 'static,
669			ArtCan: CanSized<B::Artifact>,
670			ArtCan: Clone,
671			BCan: CanStrong,
672			BCan: CanSized<Self>,
673	{
674
675		FeigningBuilder {
676			inner,
677			_err: PhantomData,
678		}
679	}
680}
681
682impl<ArtCan, AP, B: ?Sized, BCan, Err> Builder<ArtCan, BCan> for FeigningBuilder<AP, Err>
683	where
684		B: Builder<ArtCan, BCan, Err=Never>,
685		BCan: Can<B>,
686		AP: Promise<Builder = B, BCan = BCan>,
687		Err: Debug + 'static,
688		ArtCan: CanSized<B::Artifact>,
689		ArtCan: Clone,
690		BCan: CanStrong,
691	{
692
693	type Artifact = B::Artifact;
694	type DynState = ();
695	type Err = Err;
696
697	fn build(&self, resolver: &mut Resolver<ArtCan, BCan, Self::DynState>)
698			-> Result<ArtCan::Bin, Self::Err> {
699
700		resolver.resolve(&self.inner).map_err(|n| n.into_any())
701	}
702
703	fn init_dyn_state(&self) -> Self::DynState {
704		// empty
705	}
706}
707
708
709
710
711