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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
//! Layout nodes.
use std::any::Any;
use std::fmt::{self, Debug, Formatter};
use std::ops::Deref;
use super::*;
/// A self-contained, styled layout node.
#[derive(Clone, PartialEq)]
pub enum LayoutNode {
/// A spacing node.
Spacing(Spacing),
/// A text node.
Text(Text),
/// A dynamic that can implement custom layouting behaviour.
Dyn(Dynamic),
}
impl LayoutNode {
/// Create a new model node form a type implementing `DynNode`.
pub fn dynamic<T: DynNode>(inner: T) -> Self {
Self::Dyn(Dynamic::new(inner))
}
}
impl Debug for LayoutNode {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Spacing(spacing) => spacing.fmt(f),
Self::Text(text) => text.fmt(f),
Self::Dyn(boxed) => boxed.fmt(f),
}
}
}
#[async_trait(?Send)]
impl Layout for LayoutNode {
async fn layout(
&self,
ctx: &mut LayoutContext,
constraints: LayoutConstraints,
) -> Vec<LayoutItem> {
match self {
Self::Spacing(spacing) => spacing.layout(ctx, constraints).await,
Self::Text(text) => text.layout(ctx, constraints).await,
Self::Dyn(boxed) => boxed.layout(ctx, constraints).await,
}
}
}
/// A wrapper around a boxed dynamic node.
///
/// _Note_: This is needed because the compiler can't `derive(PartialEq)` for
/// [`LayoutNode`] when directly putting the boxed node in there, see
/// the [Rust Issue].
///
/// [`LayoutNode`]: enum.LayoutNode.html
/// [Rust Issue]: https://github.com/rust-lang/rust/issues/31740
pub struct Dynamic(pub Box<dyn DynNode>);
impl Dynamic {
/// Wrap a type implementing `DynNode`.
pub fn new<T: DynNode>(inner: T) -> Self {
Self(Box::new(inner))
}
}
impl Deref for Dynamic {
type Target = dyn DynNode;
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
impl Debug for Dynamic {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl Clone for Dynamic {
fn clone(&self) -> Self {
Self(self.0.dyn_clone())
}
}
impl PartialEq for Dynamic {
fn eq(&self, other: &Self) -> bool {
self.0.dyn_eq(other.0.as_ref())
}
}
impl From<Dynamic> for LayoutNode {
fn from(dynamic: Dynamic) -> Self {
Self::Dyn(dynamic)
}
}
/// A dynamic node, which can implement custom layouting behaviour.
///
/// This trait just combines the requirements for types to qualify as dynamic
/// nodes. The interesting part happens in the inherited trait [`Layout`].
///
/// The trait itself also contains three helper methods to make `Box<dyn
/// DynNode>` able to implement `Clone` and `PartialEq`. However, these are
/// automatically provided by a blanket impl as long as the type in question
/// implements[`Layout`], `Debug`, `PartialEq`, `Clone` and is `'static`.
///
/// [`Layout`]: ../trait.Layout.html
pub trait DynNode: Debug + Layout + 'static {
/// Convert into a `dyn Any` to enable downcasting.
fn as_any(&self) -> &dyn Any;
/// Check for equality with another trait object.
fn dyn_eq(&self, other: &dyn DynNode) -> bool;
/// Clone into a trait object.
fn dyn_clone(&self) -> Box<dyn DynNode>;
}
impl<T> DynNode for T
where
T: Debug + Layout + PartialEq + Clone + 'static,
{
fn as_any(&self) -> &dyn Any {
self
}
fn dyn_eq(&self, other: &dyn DynNode) -> bool {
if let Some(other) = other.as_any().downcast_ref::<Self>() {
self == other
} else {
false
}
}
fn dyn_clone(&self) -> Box<dyn DynNode> {
Box::new(self.clone())
}
}
|