Skip to content

Commit 786e5cb

Browse files
committed
Replace keyframe Into<ExactSizeItterator> API
With recent changes to improve the `set_chain` and `start_at` logic in `timeline.rs` the locgic wasn't iterating immedialy. This meant that we had to collect the iterator into a vec in `set_chain`. Which meant we were heap allocating twice for each keyframe in the chain. By using `vec!` and passign a vector to build `struct Chain`, that allocation can be reused. Meaning only one heap allocation.
1 parent f471ff8 commit 786e5cb

File tree

9 files changed

+317
-428
lines changed

9 files changed

+317
-428
lines changed

src/keyframes/button.rs

Lines changed: 44 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -60,37 +60,53 @@ impl Chain {
6060
}
6161
}
6262

63-
impl<T> From<Chain> for crate::timeline::Chain<T>
64-
where
65-
T: ExactSizeIterator<Item = Option<Frame>> + std::fmt::Debug,
66-
Vec<T>: From<Vec<Button>>,
67-
{
63+
impl From<Chain> for crate::timeline::Chain {
6864
fn from(chain: Chain) -> Self {
69-
crate::timeline::Chain::new(chain.id.into(), chain.repeat, chain.links.into())
65+
crate::timeline::Chain::new(
66+
chain.id.into(),
67+
chain.repeat,
68+
chain
69+
.links
70+
.into_iter()
71+
.map(|b| b.into())
72+
.collect::<Vec<_>>(),
73+
)
7074
}
7175
}
7276

7377
#[must_use = "Keyframes are intended to be used in an animation chain."]
7478
#[derive(Debug, Clone, Copy)]
7579
pub struct Button {
76-
index: usize,
7780
at: MovementType,
7881
ease: Ease,
7982
width: Option<Length>,
8083
height: Option<Length>,
8184
padding: Option<Padding>,
85+
is_eager: bool,
8286
}
8387

8488
impl Button {
8589
pub fn new(at: impl Into<MovementType>) -> Button {
8690
let at = at.into();
8791
Button {
88-
index: 0,
8992
at,
9093
ease: Linear::InOut.into(),
9194
width: None,
9295
height: None,
9396
padding: None,
97+
is_eager: true,
98+
}
99+
}
100+
101+
pub fn lazy(at: impl Into<MovementType>) -> Button {
102+
let at = at.into();
103+
Button {
104+
at,
105+
ease: Linear::InOut.into(),
106+
width: None,
107+
height: None,
108+
padding: None,
109+
is_eager: false,
94110
}
95111
}
96112

@@ -137,47 +153,25 @@ impl Button {
137153
}
138154
}
139155

140-
// 0 = width
141-
// 1 = height
142-
// 2 = padding[1] (top)
143-
// 3 = padding[2] (right)
144-
// 4 = padding[3] (bottom)
145-
// 5 = padding[4] (left)
146-
impl Iterator for Button {
147-
type Item = Option<Frame>;
148-
149-
fn next(&mut self) -> Option<Option<Frame>> {
150-
self.index += 1;
151-
match self.index - 1 {
152-
0 => Some(
153-
as_f32(self.width).map(|w| Frame::eager(self.at, w, self.ease)),
154-
),
155-
1 => Some(
156-
as_f32(self.height).map(|h| Frame::eager(self.at, h, self.ease)),
157-
),
158-
2 => Some(
159-
self.padding
160-
.map(|p| Frame::eager(self.at, p.top, self.ease)),
161-
),
162-
3 => Some(
163-
self.padding
164-
.map(|p| Frame::eager(self.at, p.right, self.ease)),
165-
),
166-
4 => Some(
167-
self.padding
168-
.map(|p| Frame::eager(self.at, p.bottom, self.ease)),
169-
),
170-
5 => Some(
171-
self.padding
172-
.map(|p| Frame::eager(self.at, p.left, self.ease)),
173-
),
174-
_ => None,
175-
}
176-
}
177-
}
178-
179-
impl ExactSizeIterator for Button {
180-
fn len(&self) -> usize {
181-
6 - self.index
156+
#[rustfmt::skip]
157+
impl From<Button> for Vec<Option<Frame>> {
158+
fn from(button: Button) -> Vec<Option<Frame>> {
159+
if button.is_eager {
160+
vec![as_f32(button.width).map(|w| Frame::eager(button.at, w, button.ease)), // 0 = width
161+
as_f32(button.height).map(|h| Frame::eager(button.at, h, button.ease)), // 1 = height
162+
button.padding.map(|p| Frame::eager(button.at, p.top, button.ease)), // 2 = padding[0] (top)
163+
button.padding.map(|p| Frame::eager(button.at, p.right, button.ease)), // 3 = padding[1] (right)
164+
button.padding.map(|p| Frame::eager(button.at, p.bottom, button.ease)), // 4 = padding[2] (bottom)
165+
button.padding.map(|p| Frame::eager(button.at, p.left, button.ease)), // 5 = padding[3] (left)
166+
]
167+
} else {
168+
vec![Some(Frame::lazy(button.at, 0., button.ease)), // 0 = width
169+
Some(Frame::lazy(button.at, 0., button.ease)), // 1 = height
170+
Some(Frame::lazy(button.at, 5., button.ease)), // 2 = padding[0] (top)
171+
Some(Frame::lazy(button.at, 5., button.ease)), // 3 = padding[1] (right)
172+
Some(Frame::lazy(button.at, 5., button.ease)), // 4 = padding[2] (bottom)
173+
Some(Frame::lazy(button.at, 5., button.ease)), // 5 = padding[3] (left)
174+
]
175+
}
182176
}
183177
}

src/keyframes/column.rs

Lines changed: 39 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ pub struct Column {
8080
padding: Option<Padding>,
8181
width: Option<Length>,
8282
height: Option<Length>,
83+
is_eager: bool,
8384
}
8485

8586
impl Column {
@@ -94,6 +95,22 @@ impl Column {
9495
padding: None,
9596
max_width: None,
9697
max_height: None,
98+
is_eager: true,
99+
}
100+
}
101+
102+
pub fn lazy(at: impl Into<MovementType>) -> Column {
103+
let at = at.into();
104+
Column {
105+
index: 0,
106+
at,
107+
ease: Linear::InOut.into(),
108+
width: None,
109+
height: None,
110+
padding: None,
111+
max_width: None,
112+
max_height: None,
113+
is_eager: false,
97114
}
98115
}
99116

@@ -107,23 +124,22 @@ impl Column {
107124
Renderer::Theme: widget::container::StyleSheet,
108125
{
109126
let id: widget::Id = id.into();
110-
let now = Instant::now();
111127

112128
widget::Column::new(content)
113129
.spacing(
114130
timeline
115-
.get(&id, &now, 0)
131+
.get(&id, 0)
116132
.map(|m| m.value)
117133
.unwrap_or(0.),
118134
)
119135
.padding([
120-
timeline.get(&id, &now, 1).map(|m| m.value).unwrap_or(0.),
121-
timeline.get(&id, &now, 2).map(|m| m.value).unwrap_or(0.),
122-
timeline.get(&id, &now, 3).map(|m| m.value).unwrap_or(0.),
123-
timeline.get(&id, &now, 4).map(|m| m.value).unwrap_or(0.),
136+
timeline.get(&id, 1).map(|m| m.value).unwrap_or(0.),
137+
timeline.get(&id, 2).map(|m| m.value).unwrap_or(0.),
138+
timeline.get(&id, 3).map(|m| m.value).unwrap_or(0.),
139+
timeline.get(&id, 4).map(|m| m.value).unwrap_or(0.),
124140
])
125-
.width(get_length(&id, timeline, &now, 5, Length::Shrink))
126-
.height(get_length(&id, timeline, &now, 6, Length::Shrink))
141+
.width(get_length(&id, timeline, 5, Length::Shrink))
142+
.height(get_length(&id, timeline, 6, Length::Shrink))
127143
}
128144

129145
pub fn spacing(mut self, spacing: impl Into<Pixels>) -> Self {
@@ -152,45 +168,20 @@ impl Column {
152168
}
153169
}
154170

155-
// 0 = spacing
156-
// 1 = padding[1] (top)
157-
// 2 = padding[2] (right)
158-
// 3 = padding[3] (bottom)
159-
// 4 = padding[4] (left)
160-
// 5 = width
161-
// 6 = height
162-
impl Iterator for Column {
163-
type Item = Option<DurFrame>;
164-
165-
fn next(&mut self) -> Option<Option<DurFrame>> {
166-
self.index += 1;
167-
match self.index - 1 {
168-
0 => Some(self.spacing.map(|s| DurFrame::new(self.at, s, self.ease))),
169-
1 => Some(
170-
self.padding
171-
.map(|p| DurFrame::new(self.at, p.top, self.ease)),
172-
),
173-
2 => Some(
174-
self.padding
175-
.map(|p| DurFrame::new(self.at, p.right, self.ease)),
176-
),
177-
3 => Some(
178-
self.padding
179-
.map(|p| DurFrame::new(self.at, p.bottom, self.ease)),
180-
),
181-
4 => Some(
182-
self.padding
183-
.map(|p| DurFrame::new(self.at, p.left, self.ease)),
184-
),
185-
5 => Some(as_f32(self.width).map(|w| DurFrame::new(self.at, w, self.ease))),
186-
6 => Some(as_f32(self.height).map(|h| DurFrame::new(self.at, h, self.ease))),
187-
_ => None,
188-
}
189-
}
190-
}
191-
192-
impl ExactSizeIterator for Column {
193-
fn len(&self) -> usize {
194-
7 - self.index
171+
#[rustfmt::skip]
172+
impl From<Column> for Vec<Option<Frame>> {
173+
fn from(column: Column) -> Vec<Option<Frame>> {
174+
if column.is_eager {
175+
vec![self.spacing.map(|s| Frame::eager(column.at, s, column.ease)), // 0 = spacing
176+
column.padding.map(|p| Frame::eager(column.at, p.top, column.ease)), // 1 = padding[0] (top)
177+
column.padding.map(|p| Frame::eager(column.at, p.right, column.ease)), // 2 = padding[1] (right)
178+
column.padding.map(|p| Frame::eager(column.at, p.bottom, column.ease)), // 3 = padding[2] (bottom)
179+
column.padding.map(|p| Frame::eager(column.at, p.left, column.ease)), // 4 = padding[3] (left)
180+
as_f32(column.width).map(|w| Frame::eager(column.at, w, column.ease)), // 5 = width
181+
as_f32(column.height).map(|h| Frame::eager(column.at, h, column.ease)), // 6 = height
182+
]
183+
} else {
184+
vec![Some(Frame::lazy(column.at, 0., column.ease)); 7] // lazy evaluates for all values
185+
}
195186
}
196187
}

src/keyframes/container.rs

Lines changed: 42 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -60,41 +60,59 @@ impl Chain {
6060
}
6161
}
6262

63-
impl<T> From<Chain> for crate::timeline::Chain<T>
64-
where
65-
T: ExactSizeIterator<Item = Option<Frame>> + std::fmt::Debug,
66-
Vec<T>: From<Vec<Container>>,
67-
{
63+
impl From<Chain> for crate::timeline::Chain {
6864
fn from(chain: Chain) -> Self {
69-
crate::timeline::Chain::new(chain.id.into(), chain.repeat, chain.links.into())
65+
crate::timeline::Chain::new(
66+
chain.id.into(),
67+
chain.repeat,
68+
chain
69+
.links
70+
.into_iter()
71+
.map(|b| b.into())
72+
.collect::<Vec<_>>(),
73+
)
7074
}
7175
}
7276

7377
#[must_use = "Keyframes are intended to be used in an animation chain."]
7478
#[derive(Debug, Clone, Copy)]
7579
pub struct Container {
76-
index: usize,
7780
at: MovementType,
7881
ease: Ease,
7982
width: Option<Length>,
8083
height: Option<Length>,
8184
padding: Option<Padding>,
8285
max_width: Option<f32>,
8386
max_height: Option<f32>,
87+
is_eager: bool,
8488
}
8589

8690
impl Container {
8791
pub fn new(at: impl Into<MovementType>) -> Container {
8892
let at = at.into();
8993
Container {
90-
index: 0,
9194
at,
9295
ease: Linear::InOut.into(),
9396
width: None,
9497
height: None,
9598
padding: None,
9699
max_width: None,
97100
max_height: None,
101+
is_eager: true,
102+
}
103+
}
104+
105+
pub fn lazy(at: impl Into<MovementType>) -> Container {
106+
let at = at.into();
107+
Container {
108+
at,
109+
ease: Linear::InOut.into(),
110+
width: None,
111+
height: None,
112+
padding: None,
113+
max_width: None,
114+
max_height: None,
115+
is_eager: false,
98116
}
99117
}
100118

@@ -163,57 +181,21 @@ impl Container {
163181
}
164182
}
165183

166-
// 0 = width
167-
// 1 = height
168-
// 2 = padding[1] (top)
169-
// 3 = padding[2] (right)
170-
// 4 = padding[3] (bottom)
171-
// 5 = padding[4] (left)
172-
// 6 = max_width
173-
// 7 = max_height
174-
impl Iterator for Container {
175-
type Item = Option<Frame>;
176-
177-
fn next(&mut self) -> Option<Option<Frame>> {
178-
self.index += 1;
179-
match self.index - 1 {
180-
0 => Some(
181-
as_f32(self.width).map(|w| Frame::eager(self.at, w, self.ease)),
182-
),
183-
1 => Some(
184-
as_f32(self.height).map(|h| Frame::eager(self.at, h, self.ease)),
185-
),
186-
2 => Some(
187-
self.padding
188-
.map(|p| Frame::eager(self.at, p.top, self.ease)),
189-
),
190-
3 => Some(
191-
self.padding
192-
.map(|p| Frame::eager(self.at, p.right, self.ease)),
193-
),
194-
4 => Some(
195-
self.padding
196-
.map(|p| Frame::eager(self.at, p.bottom, self.ease)),
197-
),
198-
5 => Some(
199-
self.padding
200-
.map(|p| Frame::eager(self.at, p.left, self.ease)),
201-
),
202-
6 => Some(
203-
self.max_width
204-
.map(|w| Frame::eager(self.at, w, self.ease)),
205-
),
206-
7 => Some(
207-
self.max_height
208-
.map(|h| Frame::eager(self.at, h, self.ease)),
209-
),
210-
_ => None,
211-
}
212-
}
213-
}
214-
215-
impl ExactSizeIterator for Container {
216-
fn len(&self) -> usize {
217-
8 - self.index
184+
#[rustfmt::skip]
185+
impl From<Container> for Vec<Option<Frame>> {
186+
fn from(container: Container) -> Vec<Option<Frame>> {
187+
if container.is_eager {
188+
vec![as_f32(container.width).map(|w| Frame::eager(container.at, w, container.ease)), // 0 = width
189+
as_f32(container.height).map(|h| Frame::eager(container.at, h, container.ease)), // 1 = height
190+
container.padding.map(|p| Frame::eager(container.at, p.top, container.ease)), // 2 = padding[0] (top)
191+
container.padding.map(|p| Frame::eager(container.at, p.right, container.ease)), // 3 = padding[1] (right)
192+
container.padding.map(|p| Frame::eager(container.at, p.bottom, container.ease)), // 4 = padding[2] (bottom)
193+
container.padding.map(|p| Frame::eager(container.at, p.left, container.ease)), // 5 = padding[3] (left)
194+
container.max_width.map(|w| Frame::eager(container.at, w, container.ease)), // 6 = max_width
195+
container.max_height.map(|h| Frame::eager(container.at, h, container.ease)), // 7 = max_height
196+
]
197+
} else {
198+
vec![Some(Frame::lazy(container.at, 0., container.ease)); 8] // lazy evaluates for all values
199+
}
218200
}
219201
}

0 commit comments

Comments
 (0)