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
//! The diff algorithm utilities.
//!
//! When applying list update,
//! the framework tries to figure out which items should be added, removed, or moved.
//! For example, in the following component:
//!
//! ```rust
//! use maomi::prelude::*;
//!
//! #[component]
//! struct MyComponent {
//! template: template! {
//! for item in self.list.iter() {
//! /* ... */
//! }
//! },
//! list: Vec<usize>,
//! }
//! ```
//!
//! This requires an algorithm to compare the current `list` and the `list` that used to do previous update,
//! and decide which items should be added, removed, or moved.
//!
//! By default, the [keyless](./keyless) algorithm is used.
//! This algorithm compares items one by one,
//! and adds or removes items at the ends of the list.
//! For example:
//! * if the `list` in the previous update is `[30, 40, 50]` while the current `list` is `[30, 40, 50, 60]` ,
//! then the forth item with item data `60` is added;
//! * if the `list` in the previous update is `[30, 40, 50]` while the current `list` is `[30, 50]` ,
//! then the second item is updated with item data `50` , and the third item is removed.
//! This algorithm is very fast if the items at the start and the middle of the list will not be removed or inserted,
//! but it is pretty slow if that happens.
//!
//! For lists that often randomly changes, the [key](./key) algorithm is a better option.
//! To use this algorithm, the `AsListKey` trait must be implemented for the item data,
//! and the `use` instruction should be added in the template `for` expression.
//! The example code above should be changed:
//!
//! ```rust
//! use maomi::prelude::*;
//!
//! struct ListData {
//! id: usize,
//! }
//!
//! impl AsListKey for ListData {
//! type ListKey = usize;
//!
//! fn as_list_key(&self) -> &usize {
//! &self.id
//! }
//! }
//!
//! #[component]
//! struct MyComponent {
//! template: template! {
//! // add a `use` list key
//! for item in self.list.iter() use usize {
//! /* ... */
//! }
//! },
//! list: Vec<ListData>,
//! }
//! ```
//!
//! The `ListKey` is used for list comparison.
//! * if the `ListKey` list in the previous update is `[30, 40, 50]` while the current is `[30, 50]` ,
//! then the second item is removed.
//! * if the `ListKey` list in the previous update is `[30, 40, 50]` while the current is `[30, 40, 60, 50]` ,
//! then the third item with item data 60 is inserted;
//! This algorithm has a balanced performance on lists that dynamically changes,
//! while it has a small overhead no matter the list is changed or not.
use crate::;