use super::*;
pub trait ComposeWithChild<C, K: ?Sized> {
type Target;
fn with_child(self, child: C) -> Self::Target;
}
pub struct ChildKind<K: ?Sized>(PhantomData<fn() -> K>);
pub struct TmlKind<K: ?Sized>(PhantomData<fn() -> K>);
impl<'c, P, C, K: ?Sized> ComposeWithChild<C, ChildKind<K>> for P
where
P: StateWriter<Value: ComposeChild<'c, Child: RFrom<C, K>>>,
{
type Target = Pair<P, C>;
#[inline]
fn with_child(self, child: C) -> Self::Target { Pair { parent: self, child } }
}
impl<'c, P, C, Builder, K: ?Sized> ComposeWithChild<C, TmlKind<&'c K>> for P
where
P: StateWriter<Value: ComposeChild<'c, Child: Template<Builder = Builder>>>,
Builder: Default + ComposeWithChild<C, K>,
{
type Target = Pair<P, Builder::Target>;
fn with_child(self, child: C) -> Self::Target {
Pair { parent: self, child: Builder::default().with_child(child) }
}
}
pub struct StatelessKind<K: ?Sized>(PhantomData<fn() -> K>);
impl<'c, P, C, K: ?Sized> ComposeWithChild<C, StatelessKind<K>> for P
where
P: ComposeChild<'c>,
Stateful<P>: ComposeWithChild<C, K>,
{
type Target = <Stateful<P> as ComposeWithChild<C, K>>::Target;
fn with_child(self, child: C) -> Self::Target { Stateful::new(self).with_child(child) }
}
impl<P, C, K: ?Sized> ComposeWithChild<C, K> for FatObj<P>
where
P: ComposeWithChild<C, K>,
{
type Target = FatObj<P::Target>;
#[track_caller]
fn with_child(self, child: C) -> Self::Target {
let (host, fat) = self.into_parts();
let child = host.with_child(child);
fat.map(|_| child)
}
}
impl<P, C, Child, K: ?Sized> ComposeWithChild<Child, K> for Pair<P, C>
where
C: ComposeWithChild<Child, K>,
{
type Target = Pair<P, C::Target>;
#[inline]
fn with_child(self, child: Child) -> Self::Target {
let Pair { parent, child: c } = self;
Pair { parent, child: c.with_child(child) }
}
}
pub trait OptionComposeWithChild<'c, C, K: ?Sized> {
fn with_child(self, child: C) -> Widget<'c>;
}
impl<'c, P, C, K> OptionComposeWithChild<'c, C, K> for Option<P>
where
P: ComposeWithChild<C, K>,
C: IntoWidget<'c, K>,
P::Target: IntoWidget<'c, K>,
{
#[inline]
fn with_child(self, child: C) -> Widget<'c> {
if let Some(p) = self { p.with_child(child).into_widget() } else { child.into_widget() }
}
}
pub struct BuildTml;
impl<B: TemplateBuilder> RFrom<B, BuildTml> for B::Target {
#[inline]
fn r_from(from: B) -> Self { from.build_tml() }
}
impl<'w, P, C, K: ?Sized> RFrom<Pair<P, C>, OtherWidget<K>> for Widget<'w>
where
P: StateWriter<Value: ComposeChild<'w, Child: RFrom<C, K>>>,
{
#[inline]
fn r_from(from: Pair<P, C>) -> Self {
let Pair { parent, child } = from;
ComposeChild::compose_child(parent, child.r_into())
}
}
impl<T> Template for Option<T> {
type Builder = OptionBuilder<T>;
#[inline]
fn builder() -> Self::Builder { OptionBuilder(None) }
}
pub struct OptionBuilder<T>(pub Option<T>);
impl<T> Default for OptionBuilder<T> {
fn default() -> Self { Self(None) }
}
impl<T> TemplateBuilder for OptionBuilder<T> {
type Target = Option<T>;
#[inline]
fn build_tml(self) -> Self::Target { self.0 }
}
impl<C, T, K: ?Sized> ComposeWithChild<C, ValueKind<K>> for OptionBuilder<T>
where
C: RInto<T, K>,
{
type Target = Self;
fn with_child(self, child: C) -> Self::Target { self.with_child(Some(child)) }
}
impl<C, T, K: ?Sized> ComposeWithChild<Option<C>, Option<fn() -> K>> for OptionBuilder<T>
where
C: RInto<T, K>,
{
type Target = Self;
fn with_child(mut self, child: Option<C>) -> Self::Target {
debug_assert!(self.0.is_none(), "Option already has a child");
self.0 = child.map(RInto::r_into);
self
}
}
pub struct VecBuilder<T>(Vec<T>);
impl<T> Default for VecBuilder<T> {
fn default() -> Self { Self(vec![]) }
}
impl<T> Template for Vec<T> {
type Builder = VecBuilder<T>;
#[inline]
fn builder() -> Self::Builder { VecBuilder(vec![]) }
}
impl<T> TemplateBuilder for VecBuilder<T> {
type Target = Vec<T>;
#[inline]
fn build_tml(self) -> Self::Target { self.0 }
}
impl<C, T, K: ?Sized> ComposeWithChild<C, std::iter::Once<&'static K>> for VecBuilder<T>
where
C: RInto<T, K>,
{
type Target = Self;
#[inline]
fn with_child(mut self, child: C) -> Self::Target {
self.0.push(child.r_into());
self
}
}
impl<C, T, K: ?Sized> ComposeWithChild<C, dyn Iterator<Item = K>> for VecBuilder<T>
where
C: IntoIterator<Item: RInto<T, K>>,
{
type Target = Self;
#[inline]
fn with_child(mut self, child: C) -> Self::Target {
self
.0
.extend(child.into_iter().map(|v| v.r_into()));
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_helper::{MockBox, MockStack};
#[derive(Template)]
enum PTml {
Void(Void),
}
struct P;
impl ComposeChild<'static> for P {
type Child = PTml;
fn compose_child(_: impl StateWriter<Value = Self>, _: Self::Child) -> Widget<'static> {
Void.into_widget()
}
}
#[declare]
struct XX;
impl<'c> ComposeChild<'c> for XX {
type Child = Widget<'c>;
fn compose_child(_: impl StateWriter<Value = Self>, _: Self::Child) -> Widget<'c> {
Void.into_widget()
}
}
#[test]
fn template_fill_template() { let _ = |_: &BuildCtx| P.with_child(Void).into_widget(); }
#[test]
fn pair_compose_child() {
let _ = |_: &BuildCtx| -> Widget {
MockBox { size: ZERO_SIZE }
.with_child(XX.with_child(Void {}))
.into_widget()
};
}
#[declare]
struct PipeParent;
impl ComposeChild<'static> for PipeParent {
type Child = PipeValue<usize>;
fn compose_child(_: impl StateWriter<Value = Self>, _: Self::Child) -> Widget<'static> {
Void.into_widget()
}
}
#[test]
fn compose_pipe_child() {
let _value_child = fn_widget! {
@PipeParent { @ { 0usize } }
};
let _pipe_child = fn_widget! {
let state = Stateful::new(0usize);
@PipeParent { @ { pipe!(*$read(state)) } }
};
}
#[test]
fn compose_template_enum() {
#[allow(dead_code)]
#[derive(Template)]
enum EnumTml {
Widget(Widget<'static>),
Text(TextValue),
}
#[declare]
struct EnumTest {}
impl ComposeChild<'static> for EnumTest {
type Child = Vec<EnumTml>;
fn compose_child(_: impl StateWriter<Value = Self>, _: Self::Child) -> Widget<'static> {
unreachable!()
}
}
let _ = fn_widget! {
let v = Stateful::new(true);
let w = EnumTml::Widget(fn_widget! { @Void {} }.into_widget());
@EnumTest {
@ Void {}
@ { "test" }
@ { pipe!(*$read(v)).map(|_| fn_widget! { @Void {} }) }
@ MockStack { @Void {} }
@ {w}
}
};
}
#[test]
fn enum_conversion() {
pub struct BuilderX;
struct BuilderAKind<K: ?Sized>(PhantomData<fn() -> K>);
struct BuilderBKind<K: ?Sized>(PhantomData<fn() -> K>);
impl<C, K: ?Sized> RFrom<C, BuilderAKind<K>> for BuilderX
where
C: RInto<Widget<'static>, K>,
{
fn r_from(_: C) -> Self { unreachable!() }
}
impl<C, K: ?Sized> RFrom<C, BuilderBKind<K>> for BuilderX
where
C: RInto<CowArc<str>, K>,
{
fn r_from(_: C) -> Self { unreachable!() }
}
impl<'w, K: ?Sized, C> ComposeWithChild<C, BuilderAKind<K>> for BuilderX
where
C: RInto<Widget<'w>, K>,
{
type Target = Self;
fn with_child(self, _: C) -> Self { unreachable!() }
}
impl<K: ?Sized, C> ComposeWithChild<C, BuilderBKind<K>> for BuilderX
where
C: RInto<CowArc<str>, K>,
{
type Target = Self;
fn with_child(self, _: C) -> Self { unreachable!() }
}
let _ = move || {
let builder = BuilderX;
let builder = builder.with_child("Hello");
let _builder = builder.with_child(Void);
let _builder: BuilderX = "hello".r_into();
let _builder: BuilderX = Void.r_into();
};
}
}