OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE.md file. | |
4 | |
5 library immi; | |
6 | |
7 import 'package:service/dart/struct.dart'; | |
8 | |
9 // TODO(zerny): Can we find a way to depend on the generated builder hierarchy | |
10 // so we can use the actual builder types below? Otherwise, remove the commented | |
11 // builder types. | |
12 | |
13 abstract class Node { | |
14 diff(Node previous); | |
15 void serializeNode(/*NodeData*/Builder builder, ResourceManager manager); | |
16 void unregisterHandlers(ResourceManager manager); | |
17 } | |
18 | |
19 class ResourceManager { | |
20 int _nextEventID = 1; | |
21 Map<int, Function> _eventHandlers = {}; | |
22 Map<Function, int> _eventHandlersInverted = {}; | |
23 void clear() { | |
24 _eventHandlers.clear(); | |
25 _eventHandlersInverted.clear(); | |
26 } | |
27 int addHandler(Function handler) { | |
28 if (handler == null) return 0; | |
29 _eventHandlers[_nextEventID] = handler; | |
30 _eventHandlersInverted[handler] = _nextEventID; | |
31 return _nextEventID++; | |
32 } | |
33 void removeHandler(Function handler) { | |
34 if (handler == null) return; | |
35 int id = _eventHandlersInverted.remove(handler); | |
36 if (id == null) return; | |
37 _eventHandlers.remove(id); | |
38 } | |
39 Function getHandler(int id) { | |
40 if (id == 0) { | |
41 print('Request with invalid event id: 0'); | |
42 return null; | |
43 } | |
44 Function handler = _eventHandlers[id]; | |
45 if (handler == null) { | |
46 print('Request with unallocated event id: $id'); | |
47 return null; | |
48 } | |
49 return handler; | |
50 } | |
51 } | |
52 | |
53 abstract class NodePatch { | |
54 void serializeNode(/*NodePatchData*/Builder builder, ResourceManager manager); | |
55 } | |
56 | |
57 enum ListPatchType { | |
58 AnyNode, | |
59 SpecificNode | |
60 } | |
61 | |
62 class ListPatch { | |
63 final ListPatchType type; | |
64 final List<ListRegionPatch> regions; | |
65 ListPatch(this.type, this.regions); | |
66 void serializeList(/*ListPatchDataBuilder*/ builder, | |
67 ResourceManager manager) { | |
68 builder.type = type.index; | |
69 int length = regions.length; | |
70 List</*ListRegionData*/Builder> builders = builder.initRegions(length); | |
71 for (int i = 0; i < length; ++i) { | |
72 ListRegionPatch region = regions[i]; | |
73 /*ListRegionDataBuilder*/var regionBuilder = builders[i]; | |
74 regionBuilder.index = region.index; | |
75 region.serializeRegion(regionBuilder, manager); | |
76 } | |
77 } | |
78 } | |
79 | |
80 abstract class ListRegionPatch { | |
81 final int index; | |
82 ListRegionPatch(this.index); | |
83 void serializeRegion(/*ListRegionData*/Builder builder, | |
84 ResourceManager manager); | |
85 } | |
86 | |
87 class ListInsertPatch extends ListRegionPatch { | |
88 final int length; | |
89 final List current; | |
90 ListInsertPatch(int index, this.length, this.current) : super(index); | |
91 void serializeRegion(/*ListRegionDataBuilder*/ builder, | |
92 ResourceManager manager) { | |
93 List</*NodeData*/Builder> builders = builder.initInsert(length); | |
94 for (int i = 0; i < length; ++i) { | |
95 current[index + i].serializeNode(builders[i], manager); | |
96 } | |
97 } | |
98 } | |
99 | |
100 class ListRemovePatch extends ListRegionPatch { | |
101 final int length; | |
102 final List previous; | |
103 ListRemovePatch(int index, this.length, this.previous) : super(index); | |
104 void serializeRegion(/*ListRegionDataBuilder*/ builder, | |
105 ResourceManager manager) { | |
106 builder.remove = length; | |
107 for (int i = 0; i < length; ++i) { | |
108 previous[index + i].unregisterHandlers(manager); | |
109 } | |
110 } | |
111 } | |
112 | |
113 class ListUpdatePatch extends ListRegionPatch { | |
114 final List updates; | |
115 ListUpdatePatch(int index, this.updates) : super(index); | |
116 void serializeRegion(/*ListRegionDataBuilder*/ builder, | |
117 ResourceManager manager) { | |
118 int length = updates.length; | |
119 List</*NodePatchData*/Builder> builders = builder.initUpdate(length); | |
120 for (int i = 0; i < length; ++i) { | |
121 updates[i].serializeNode(builders[i], manager); | |
122 } | |
123 } | |
124 } | |
125 | |
126 ListPatch diffList(List current, List previous, ListPatchType type) { | |
127 int currentLength = current.length; | |
128 int previousLength = previous.length; | |
129 if (currentLength == 0 && previousLength == 0) { | |
130 return null; | |
131 } | |
132 if (previousLength == 0) { | |
133 return new ListPatch( | |
134 type, [new ListInsertPatch(0, currentLength, current)]); | |
135 } | |
136 if (currentLength == 0) { | |
137 return new ListPatch( | |
138 type, [new ListRemovePatch(0, previousLength, previous)]); | |
139 } | |
140 | |
141 // TODO(zerny): be more clever about diffing a list. | |
142 int minLength = | |
143 (currentLength < previousLength) ? currentLength : previousLength; | |
144 | |
145 List patches = []; | |
146 | |
147 int regionStart = -1; | |
148 List regionPatches; | |
149 | |
150 for (int i = 0; i < minLength; ++i) { | |
151 // TODO(zerny): Support lists of primitives and lists of Node. | |
152 var patch = current[i].diff(previous[i]); | |
153 if (patch != null) { | |
154 if (regionStart < 0) { | |
155 regionStart = i; | |
156 regionPatches = []; | |
157 } | |
158 regionPatches.add(patch); | |
159 } else if (regionStart >= 0) { | |
160 patches.add(new ListUpdatePatch(regionStart, regionPatches)); | |
161 regionStart = -1; | |
162 } | |
163 } | |
164 if (regionStart >= 0) { | |
165 patches.add(new ListUpdatePatch(regionStart, regionPatches)); | |
166 } | |
167 | |
168 if (currentLength > previousLength) { | |
169 patches.add(new ListInsertPatch( | |
170 previousLength, currentLength - previousLength, current)); | |
171 } else if (currentLength < previousLength) { | |
172 patches.add(new ListRemovePatch( | |
173 currentLength, previousLength - currentLength, previous)); | |
174 } | |
175 | |
176 return patches.isEmpty ? null : new ListPatch(type, patches); | |
177 } | |
OLD | NEW |