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
|
(ns unheard.time-object
(:require [missionary.core :as m]
[helins.interval.map :as imap]))
;; DESIGN
;; A "time object" is any object with a lifetime that is temporally bounded. The
;; goal of the time object abstraction is to allow for for efficient,
;; low-latency allocation and deallocation of an unlimited number of time
;; objects.
;;
;;It is important that a time tree can be efficiently queried by both a range
;;(for UI) and a point (for a song).
;;
;; IMPLEMENTATION
;; Time objects are stored in an interval tree.
;; Requirements
;; - time objects returned by a timeline range query will include metadata like
;; start time and end time
;; - Flows associated with time objects should only mount or dismount when
;; the result of the query changes. I think the best way to accomplish this
;; is to have the query return a flow of time objects, and then have some
;; separate function responsible for "playing" these time objects.
;;
;; Question:
;; Should time objects take an interval tree as an argument,
;; or should they return a flow of interval information (start, end, value)
;; that can be fed into some kind of reactive interval map bookkeeper?
;; I think the latter.
;;
(def id-counter (atom 0))
(defn time-object
"A time-object takes a start time, and end time, and a value.
Value is a flow that will be consumed when the corresponding
time tree is consumed at a point in time within the time-object's
interval."
[>start >end >metadata >flow]
(let [action (atom nil)
>action (m/watch action)
id (swap! id-counter inc)]
(m/ap
(reset! action
[:add
id
{:start >start
:end >end
:metadata >metadata
:flow >flow}])
(try
(m/?< >action)
(catch missionary.Cancelled _ [:remove id])))))
(comment
(def cancel
((m/reduce prn nil (time-object 1 2 :a (m/ap)))
prn prn))
(cancel))
(defn time-object-collection
"Takes a flow of [diff-action time-object-id time-object], where:
- diff-action is one of either :add or :remove
- time-object-id is a unique identifier
- time-object is the time object in question
Returns a collection of time objects, represented as a flow."
[& time-objects]
(apply m/latest vector time-objects))
(comment
(def cancel
((m/reduce prn nil
(time-object-collection
(time-object 1 2 :a (m/ap))
(time-object 3 4 :a (m/ap)))) prn prn))
(cancel))
;; m/store is an optimization, allowing diffs to be dropped prior to processing
;; by consumer. Think :add 1, :remove 1
(defn merge-tocs
"Merge multiple time-object-collections. Returns a new time-object-collection."
[& time-object-colletion])
(defn timeline
"Primary timeline bookkeeping mehanism."
[time-object-collection]
(m/ap))
(defn point-query
"Query a timeline. Returns a flow of time objects."
[>timeline >at]
(m/ap
(let [[tl at] (m/?< (m/latest vector >timeline >at))]
(get tl at))))
(defn range-query
"Range query. Returns a flow of time objects."
[timeline >range])
(defn run
"Runs the flows associated with a collection of time objects."
;; TODO: "Running" a time object has different meanings for different objects.
;; How should I think about that?
[>query-result])
;; How should a time tree work?
;; Well, we eventually want to end up with a single time tree
;; Is it important to be able to merge time trees together?
;; Part of me thinks "yes"
;; Time objects cannot be composed together - that is, you can't
;; take two time objects and add them together to get a new time object
;; However, you _can_ add two time objects together to get a time tree
;; The alternative to having intermediate time trees would be to have
;; some kind of time-object-collection abstraction.
;; time-object-collection would have a merge function.
;; A time object collection would be responsible for all of the bookkeeping
;; related to the lifetimes of time objects.
;; My suspicion is that this will
|