use crate::{AnyView, Environment, components::Metadata, layout::StretchAxis};
use alloc::{boxed::Box, vec::Vec};
use core::any::type_name;
use core::fmt;
#[must_use]
pub trait View: 'static {
fn body(self, _env: &Environment) -> impl View;
#[doc(hidden)]
fn stretch_axis(&self) -> StretchAxis {
StretchAxis::None
}
}
impl<F: 'static + FnOnce() -> V, V: View> View for F {
fn body(self, _env: &Environment) -> impl View {
self()
}
}
impl<V: View, E: View> View for Result<V, E> {
fn body(self, _env: &Environment) -> impl View {
match self {
Ok(view) => AnyView::new(view),
Err(view) => AnyView::new(view),
}
}
}
impl<V: View> View for Option<V> {
fn body(self, _env: &Environment) -> impl View {
self.map_or_else(|| AnyView::new(()), AnyView::new)
}
}
pub trait IntoView {
type Output: View;
fn into_view(self, env: &Environment) -> Self::Output;
}
impl<V: View> IntoView for V {
type Output = V;
fn into_view(self, _env: &Environment) -> Self::Output {
self
}
}
pub trait TupleViews {
fn into_views(self) -> Vec<AnyView>;
}
impl<V: View> TupleViews for Vec<V> {
fn into_views(self) -> Vec<AnyView> {
self.into_iter()
.map(|content| AnyView::new(content))
.collect()
}
}
impl<V: View, const N: usize> TupleViews for [V; N] {
fn into_views(self) -> Vec<AnyView> {
self.into_iter()
.map(|content| AnyView::new(content))
.collect()
}
}
pub trait ConfigurableView: View {
type Config: ViewConfiguration;
fn config(self) -> Self::Config;
}
pub trait ViewConfiguration: 'static {
type View: View;
fn render(self) -> Self::View;
}
type HookFn<C> = Box<dyn Fn(&Environment, C) -> AnyView>;
pub struct Hook<C>(HookFn<C>);
impl<C> fmt::Debug for Hook<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Modifier<{}>(..)", type_name::<C>())
}
}
impl<V, C, F> From<F> for Hook<C>
where
C: ViewConfiguration,
V: View,
F: Fn(&Environment, C) -> V + 'static,
{
fn from(value: F) -> Self {
Self(Box::new(move |env, config| {
let mut env = env.clone();
env.remove::<Self>(); AnyView::new(Metadata::new(value(&env, config), env))
}))
}
}
impl<C> Hook<C>
where
C: ViewConfiguration,
{
pub fn new<V, F>(f: F) -> Self
where
V: View,
F: Fn(&Environment, C) -> V + 'static,
{
Self::from(f)
}
pub fn apply(&self, env: &Environment, config: C) -> AnyView {
(self.0)(env, config)
}
}
impl<C: ViewConfiguration> Hook<C> {}
macro_rules! impl_tuple_views {
($($ty:ident),*) => {
#[allow(non_snake_case)]
#[allow(unused_variables)]
#[allow(unused_parens)]
impl <$($ty:View,)*>TupleViews for ($($ty,)*){
fn into_views(self) -> Vec<AnyView> {
let ($($ty,)*)=self;
alloc::vec![$(AnyView::new($ty)),*]
}
}
};
}
tuples!(impl_tuple_views);
raw_view!(());
impl<V: View> View for (V,) {
fn body(self, _env: &Environment) -> impl View {
self.0
}
}
#[cfg(feature = "nightly")]
impl View for ! {
fn body(self, _env: &Environment) -> impl View {}
}