summaryrefslogtreecommitdiffstats
path: root/examples/lib-dfscq-log
diff options
context:
space:
mode:
Diffstat (limited to 'examples/lib-dfscq-log')
-rw-r--r--examples/lib-dfscq-log/dfscq-log.lua438
1 files changed, 435 insertions, 3 deletions
diff --git a/examples/lib-dfscq-log/dfscq-log.lua b/examples/lib-dfscq-log/dfscq-log.lua
index c54e4f2..b4e2f8e 100644
--- a/examples/lib-dfscq-log/dfscq-log.lua
+++ b/examples/lib-dfscq-log/dfscq-log.lua
@@ -1,7 +1,439 @@
1local diaphragm = require("diaphragm") 1package.cpath = package.cpath .. ";../../target/debug/?.so"
2package.path = package.path .. ";../../lua-bindings/?.lua"
3
4local dia = require("diaphragm")
5
6-- TODO: add a way to have modified prototypes of these functions
7-- e.g.: local my_blocks = Blocks:new({ default_color = my_color })
8-- my_blocks:new({ elements = ... }):draw()
9
10dia.util.eprint("--------------------")
11
12-- TODO: Fanwood has a high baseline, which renders weirdly in the GroupCommit layer,
13-- and "Goudy Bookletter 1911" doesn't work
14-- local serif_family = "Fanwood"
15-- local serif_family = "Latin Modern Math"
16-- local serif_family = "Goudy Bookletter 1911 Normal"
17local serif_family = "OFL Sorts Mill Goudy"
18local mono_family = "Fira Mono"
19
20local active_color = "#5959ff"
21local light_gray = "#cccccc"
22local dark_gray = "#7f7f7f"
23
24local block_unit_width = 24
25local block_height = 36
26local block_stroke_width = 2
27
28local normal_margin = 20
29local small_margin = 10
30
31local function blocks(params)
32 local result = dia.shape(params)
33
34 result.unit_width = result.unit_width or dia.float.new()
35 result.default_color = result.default_color or light_gray
36 result.default_stroke_width = result.default_stroke_width or block_stroke_width
37
38 result.blocks = dia.util.tbl_map(function(el)
39 return dia.rectangle.new({
40 fill_color = el.color or result.default_color,
41 stroke_width = result.default_stroke_width,
42 height = result.height,
43 width = result.unit_width * (el.grow or 1),
44 })
45 end, params.elements)
46
47 function result:draw()
48 local len = #self.elements
49 assert(len >= 1, "Blocks must have at least 1 element")
50
51 local total_grow = 0
52 for _, el in pairs(self.elements) do
53 total_grow = total_grow + (el.grow or 1)
54 end
55
56 dia.constrain(self.width:eq(self.unit_width * total_grow))
57
58 dia.layout
59 .hstack({
60 elements = self.blocks,
61 top_left = self.top_left,
62 bottom_right = self.bottom_right,
63 width = self.width,
64 })
65 :draw()
66 end
2 67
3-- TODO: anyone can use metatable? 68 return result
69end
70
71local function active_txn(params)
72 return blocks(dia.util.tbl_extend({
73 elements = { {}, {}, {}, {}, {} },
74 height = block_height,
75 default_color = active_color,
76 }, params))
77end
78
79local function fixed_blocks(params)
80 local elements = {}
81 for _ = 1, params.count do
82 table.insert(elements, {})
83 end
84 return blocks({
85 elements = elements,
86 height = block_height,
87 unit_width = block_unit_width,
88 default_color = params.color or dark_gray,
89 })
90end
91
92local function block_list(params)
93 local result = dia.shape(params)
94
95 result.delimiter_height = result.delimiter_height or dia.float.new()
96 result.font = result.font or dia.text.font({ family = serif_family })
97
98 function result:draw()
99 local opening_delimiter = dia.text.new({
100 content = "[",
101 height = self.delimiter_height,
102 font = self.font,
103 })
104
105 local closing_delimiter = dia.text.new({
106 content = "]",
107 height = self.delimiter_height,
108 font = self.font,
109 })
110
111 local function comma()
112 return dia.text.new({
113 content = ", ",
114 font = self.font,
115 })
116 end
117
118 local elements = dia.util.list_intersperse_with(comma, self.elements)
119
120 elements = { opening_delimiter, table.unpack(elements) }
121 table.insert(elements, closing_delimiter)
122
123 -- TODO: not really elegant
124 dia.constrain(self.delimiter_height:eq(self.elements[1].height * 2.5))
125
126 dia.layout
127 .hstack({
128 elements = elements,
129 align = "center",
130 top_left = self.top_left,
131 bottom_right = self.bottom_right,
132 })
133 :draw()
134 end
135
136 return result
137end
138
139local function disk_log_legend(params)
140 local result = dia.shape(params)
141
142 local function lines(params)
143 local result = dia.shape(params)
144
145 result.ticks = {}
146 for _, tick in ipairs(params.ticks) do
147 table.insert(result.ticks,
148 dia.straight_path.new({
149 points = {
150 { x = tick, y = result.top },
151 { x = tick, y = result.bottom },
152 }
153 }))
154 end
155
156 result.baseline = dia.straight_path.new({
157 points = { result.middle_left, result.middle_right },
158 width = result.width,
159 })
160
161 function result:draw()
162 for _, tick in ipairs(self.ticks) do
163 tick:draw()
164 end
165 self.baseline:draw()
166 end
167
168 return result
169 end
4 170
171 result.lines = lines({
172 ticks = params.ticks,
173 top_left = result.top_left,
174 height = result.height / 2,
175 width = result.width,
176 })
177
178 result.font = dia.text.font({ family = serif_family })
179
180 result.labels = {}
181 for i = 1, #params.ticks - 1 do
182 local label = dia.text.new({
183 content = params.labels[i],
184 height = (result.height / 2) + result.height / 6,
185 top = result.lines.bottom - result.height / 6,
186 horiz_center = (params.ticks[i] + params.ticks[i + 1]) / 2,
187 font = result.font,
188 })
189 table.insert(result.labels, label)
190 end
191
192 function result:draw()
193 self.lines:draw()
194 for _, label in ipairs(self.labels) do
195 label:draw()
196 end
197 end
198
199 return result
200end
201
202local function disk_log(params)
203 local result = dia.shape(params)
204
205 local anchor_ids = {}
206 local last_group_id = 0
207 local labels = {}
208 local elements = {}
209 for _, global_spec in pairs(params.elements) do
210 for _, spec in pairs(global_spec.elements) do
211 local spec_params = spec.params or {}
212 for _ = 1, spec.count do
213 table.insert(elements, spec_params)
214 end
215 last_group_id = last_group_id + spec.count
216 end
217 table.insert(anchor_ids, last_group_id)
218 table.insert(labels, global_spec.label)
219 end
220 result.blocks = blocks({
221 elements = elements,
222 height = block_height,
223 top_left = result.top_left,
224 width = result.width,
225 })
226 result.anchors = { result.left }
227 for _, id in pairs(anchor_ids) do
228 table.insert(result.anchors, result.blocks.blocks[id].right)
229 end
230
231 result.legend = disk_log_legend({
232 ticks = result.anchors,
233 labels = labels,
234 height = normal_margin * 2,
235 width = result.width,
236 bottom_right = result.bottom_right,
237 })
238 dia.constraint.below(result.legend, result.blocks, normal_margin)
239
240 function result:draw()
241 result.blocks:draw()
242 result.legend:draw()
243 end
244
245 return result
246end
247
248local function layer_entry(params)
249 local result = dia.shape(params)
250
251 result.text = params.text or dia.text.new({
252 content = params.name .. ": ",
253 font = params.font,
254 })
255 result.text_vert_center = params.text_vert_center or params.content.vert_center
256
257 function result:draw()
258 dia.constraint.left_of(self.text, self.content)
259 dia.constrain(self.text.vert_center:eq(self.text_vert_center))
260
261 dia.constrain(self.left:eq(self.text.left))
262 dia.constrain(self.right:eq(self.content.right))
263 dia.constrain(self.top:eq(dia.float.min({ self.text.top, self.content.top })))
264 dia.constrain(self.bottom:eq(dia.float.max({ self.text.bottom, self.content.bottom })))
265
266 self.text:draw()
267 self.content:draw()
268 end
269
270 return result
271end
272
273local function layer(params)
274 local result = dia.shape(params)
275
276 result.name = result.name or "Layer"
277 result.title = dia.text.new({
278 content = result.name,
279 font = result.title_font,
280 top_left = result.top_left + { x = normal_margin, y = normal_margin },
281 })
282 result.content = result.content or dia.rectangle.new({
283 height = 100,
284 width = 100,
285 })
286
287 function result:draw()
288 dia.rectangle
289 .new({
290 top_left = self.top_left,
291 bottom_right = self.bottom_right,
292 fill_color = "#fff",
293 })
294 :draw()
295
296 dia.constrain(self.right:eq(self.content.right + normal_margin))
297 dia.constraint.below(self.content, self.title)
298 dia.constrain(self.left:lt(self.content.left - 150))
299
300 dia.constrain(self.bottom:eq(dia.float.max({ self.title.bottom, self.content.bottom }) + normal_margin))
301
302 self.title:draw()
303 self.content:draw()
304 end
305
306 return result
307end
308
309dia.draw({
310 content = {
311 draw = function()
312 local title_font = dia.text.font({ family = serif_family, size = 50000 })
313 local entry_font = dia.text.font({ family = mono_family, size = 20000 })
314 local action_font = dia.text.font({ family = mono_family, height = normal_margin })
315
316 local function action(name)
317 return dia.layout.margin_top({
318 margin_top = small_margin,
319 content = dia.text.new({
320 content = '<span foreground="' .. active_color .. '">' .. name .. "</span>",
321 font = action_font,
322 height = normal_margin,
323 }),
324 })
325 end
326
327 local layer_right = dia.float.new()
328
329 local log_layer_entry_left = dia.float.new()
330 local group_commit_entry_left = dia.float.new()
331 local disk_log_entry_left = dia.float.new()
332
333 local layers = {
334 layer({
335 name = "LogAPI",
336 title_font = title_font,
337 -- top_left = { x = normal_margin, y = normal_margin },
338 top_left = { x = normal_margin, y = normal_margin },
339 content = dia.layout.margin_right({
340 content = layer_entry({
341 name = "activeTxn",
342 font = entry_font,
343 content = active_txn({
344 unit_width = block_unit_width,
345 left = log_layer_entry_left,
346 }),
347 }),
348 }),
349 }),
350 action("commit"),
351 layer({
352 name = "GroupCommit",
353 title_font = title_font,
354 -- top_left = { x = 20, y = 100 + 40 },
355 -- right = layer_right,
356 content = dia.layout.margin_right({
357 -- HACK: because I know that "GroupCommit" + "commitedTxns:"
358 -- takes the most space
359 margin_right = 0,
360 content = layer_entry({
361 name = "commitedTxns",
362 font = entry_font,
363 content = block_list({
364 elements = {
365 fixed_blocks({ count = 2 }),
366 fixed_blocks({ count = 7 }),
367 fixed_blocks({ count = 4 }),
368 active_txn({ unit_width = block_unit_width }),
369 },
370 left = group_commit_entry_left,
371 }),
372 }),
373 }),
374 }),
375 action("flush"),
376 layer({
377 name = "DiskLog",
378 title_font = title_font,
379 -- top_left = { x = 20, y = 100 + 40 },
380 right = layer_right,
381 content = dia.layout.margin_right({
382 margin_right = 0,
383 content = layer_entry({
384 -- TODO: align to blocks
385 name = "disk log",
386 font = entry_font,
387 content = disk_log({
388 elements = {
389 {
390 -- TODO: seems to fail solving if using other font size within text, or line returns
391 label = "header",
392 elements = {
393 { count = 1, params = { color = "#000", grow = 11 } },
394 },
395 },
396 {
397 label = "data",
398 elements = {
399 { count = 2, params = { color = light_gray, grow = 13 + 5 } },
400 { count = 13, params = { color = dark_gray } },
401 { count = 5, params = { color = active_color } },
402 },
403 },
404 {
405 label = "available",
406 elements = {
407 { count = 1, params = { color = "#fff", grow = 13 + 5 } },
408 },
409 },
410 },
411 left = disk_log_entry_left,
412 }),
413 }),
414 }),
415 }),
416 action("apply"),
417 layer({
418 name = "Applier",
419 title_font = title_font,
420 right = layer_right,
421 }),
422 }
423
424 dia.layout.vstack({ elements = layers, align = "right" }):draw()
425
426 local layer_entries_text_right = dia.float.new()
427 for _, entry_left in pairs({ log_layer_entry_left, group_commit_entry_left, disk_log_entry_left }) do
428 dia.constrain(layer_entries_text_right:eq(entry_left))
429 end
430 end,
431 },
432 output = {},
433})
434
435-- TODO: anyone can use metatable?
436--[[
5local Blocks = diaphragm.Drawable:new() 437local Blocks = diaphragm.Drawable:new()
6Blocks.elements = {} 438Blocks.elements = {}
7Blocks.unit_width = diaphragm.float() 439Blocks.unit_width = diaphragm.float()
@@ -121,4 +553,4 @@ diaphragm.draw(diaphragm.layout.vstack({
121 -- group_commit, 553 -- group_commit,
122 -- disk_log, 554 -- disk_log,
123 -- applier, 555 -- applier,
124})) 556})) ]]