waterui_core/extract.rs
1//! This module provides mechanisms for extracting values from the Environment.
2//!
3//! It defines the `Extractor` trait for types that can be extracted from an
4//! Environment, along with implementations for common types.
5//! The `Use<T>` wrapper provides a convenient way to extract specific types
6//! from the environment.
7
8use core::any::type_name;
9use core::ops::{Deref, DerefMut};
10
11use crate::Environment;
12use alloc::format;
13use anyhow::Error;
14/// A trait for extracting values from an Environment.
15///
16/// Types implementing this trait can be extracted from an Environment instance.
17/// This is useful for dependency injection and accessing shared resources.
18pub trait Extractor: 'static + Sized {
19 /// Attempts to extract an instance of `Self` from the given environment.
20 ///
21 /// # Errors
22 /// Returns an error if extraction fails, for example if the required value is not present in the environment.
23 fn extract(env: &Environment) -> Result<Self, Error>;
24}
25
26/// Wrapper struct for values that need to be used from the Environment.
27///
28/// This wrapper enables extracting values by type from an Environment.
29#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct Use<T: 'static>(pub T);
31
32impl Extractor for Environment {
33 /// Extracts the Environment itself by creating a clone.
34 fn extract(env: &Environment) -> Result<Self, Error> {
35 Ok(env.clone())
36 }
37}
38
39impl<T> Deref for Use<T> {
40 type Target = T;
41
42 fn deref(&self) -> &Self::Target {
43 &self.0
44 }
45}
46
47impl<T> DerefMut for Use<T> {
48 fn deref_mut(&mut self) -> &mut Self::Target {
49 &mut self.0
50 }
51}
52
53impl<T: Extractor> Extractor for Option<T> {
54 /// Converts a regular extraction into an optional extraction.
55 ///
56 /// This implementation allows for graceful handling of extraction failures
57 /// by converting the error case into a `None` value.
58 fn extract(env: &Environment) -> Result<Self, Error> {
59 Ok(Extractor::extract(env).ok())
60 }
61}
62
63impl<T: 'static + Clone> Extractor for Use<T> {
64 /// Extracts a value of type T from the Environment.
65 ///
66 /// # Errors
67 /// Returns an error if the requested type is not present in the Environment.
68 fn extract(env: &Environment) -> Result<Self, Error> {
69 env.get::<T>().map_or_else(
70 || {
71 Err(Error::msg(format!(
72 "Environment value `{}` not found",
73 type_name::<T>()
74 )))
75 },
76 |value| Ok(Self(value.clone())),
77 )
78 }
79}