1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use std::convert::Infallible;

use rxrust::ops::box_it::BoxOp;

use crate::{context::BuildCtx, pipe::Pipe, prelude::BoxPipe, state::ModifyScope};

/// Trait used to create a widget declarer that can interact with the `BuildCtx`
/// to create a widget.
pub trait Declare {
  type Builder: ObjDeclarer;
  fn declarer() -> Self::Builder;
}

/// An object declarer is a type that can be used to create a object with the
/// given context.
pub trait ObjDeclarer {
  type Target;
  /// Finish the object creation with the given context.
  fn finish(self, ctx: &BuildCtx) -> Self::Target;
}

/// Used to do conversion from a value to the `DeclareInit` type.
pub trait DeclareFrom<V, const M: u8> {
  fn declare_from(value: V) -> Self;
}

/// A value-to-value conversion that consumes the input value. The
/// opposite of [`DeclareFrom`].
pub trait DeclareInto<V, const M: u8> {
  fn declare_into(self) -> DeclareInit<V>;
}

/// The type use to store the init value of the field when declare a object.
pub enum DeclareInit<V> {
  Value(V),
  Pipe(BoxPipe<V>),
}

pub type ValueStream<V> = BoxOp<'static, (ModifyScope, V), Infallible>;

impl<V: 'static> DeclareInit<V> {
  pub fn unzip(self) -> (V, Option<ValueStream<V>>) {
    match self {
      Self::Value(v) => (v, None),
      Self::Pipe(v) => {
        let (v, pipe) = v.into_pipe().unzip();
        (v, Some(pipe))
      }
    }
  }
}

impl<T: Default> Default for DeclareInit<T> {
  #[inline]
  fn default() -> Self { Self::Value(T::default()) }
}

impl<V> DeclareFrom<DeclareInit<V>, 0> for DeclareInit<V> {
  #[inline]
  fn declare_from(value: DeclareInit<V>) -> Self { value }
}

impl<V, U: From<V>> DeclareFrom<V, 1> for DeclareInit<U> {
  #[inline]
  fn declare_from(value: V) -> Self { Self::Value(value.into()) }
}

impl<P, V> DeclareFrom<P, 2> for DeclareInit<V>
where
  P: Pipe + 'static,
  V: From<P::Value> + 'static,
{
  #[inline]
  fn declare_from(value: P) -> Self {
    let pipe = Box::new(value.map(Into::into));
    Self::Pipe(BoxPipe::pipe(pipe))
  }
}

impl<T, V, const M: u8> DeclareInto<V, M> for T
where
  DeclareInit<V>: DeclareFrom<T, M>,
{
  #[inline]
  fn declare_into(self) -> DeclareInit<V> { DeclareInit::declare_from(self) }
}