OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / rjeczalik / notify / watchpoint.go
1 // Copyright (c) 2014-2015 The Notify Authors. All rights reserved.
2 // Use of this source code is governed by the MIT license that can be
3 // found in the LICENSE file.
4
5 package notify
6
7 // EventDiff describes a change to an event set - EventDiff[0] is an old state,
8 // while EventDiff[1] is a new state. If event set has not changed (old == new),
9 // functions typically return the None value.
10 type eventDiff [2]Event
11
12 func (diff eventDiff) Event() Event {
13         return diff[1] &^ diff[0]
14 }
15
16 // Watchpoint
17 //
18 // The nil key holds total event set - logical sum for all registered events.
19 // It speeds up computing EventDiff for Add method.
20 //
21 // The rec key holds an event set for a watchpoints created by RecursiveWatch
22 // for a Watcher implementation which is not natively recursive.
23 type watchpoint map[chan<- EventInfo]Event
24
25 // None is an empty event diff, think null object.
26 var none eventDiff
27
28 // rec is just a placeholder
29 var rec = func() (ch chan<- EventInfo) {
30         ch = make(chan<- EventInfo)
31         close(ch)
32         return
33 }()
34
35 func (wp watchpoint) dryAdd(ch chan<- EventInfo, e Event) eventDiff {
36         if e &^= internal; wp[ch]&e == e {
37                 return none
38         }
39         total := wp[ch] &^ internal
40         return eventDiff{total, total | e}
41 }
42
43 // Add assumes neither c nor e are nil or zero values.
44 func (wp watchpoint) Add(c chan<- EventInfo, e Event) (diff eventDiff) {
45         wp[c] |= e
46         diff[0] = wp[nil]
47         diff[1] = diff[0] | e
48         wp[nil] = diff[1] &^ omit
49         // Strip diff from internal events.
50         diff[0] &^= internal
51         diff[1] &^= internal
52         if diff[0] == diff[1] {
53                 return none
54         }
55         return
56 }
57
58 func (wp watchpoint) Del(c chan<- EventInfo, e Event) (diff eventDiff) {
59         wp[c] &^= e
60         if wp[c] == 0 {
61                 delete(wp, c)
62         }
63         diff[0] = wp[nil]
64         delete(wp, nil)
65         if len(wp) != 0 {
66                 // Recalculate total event set.
67                 for _, e := range wp {
68                         diff[1] |= e
69                 }
70                 wp[nil] = diff[1] &^ omit
71         }
72         // Strip diff from internal events.
73         diff[0] &^= internal
74         diff[1] &^= internal
75         if diff[0] == diff[1] {
76                 return none
77         }
78         return
79 }
80
81 func (wp watchpoint) Dispatch(ei EventInfo, extra Event) {
82         e := eventmask(ei, extra)
83         if !matches(wp[nil], e) {
84                 return
85         }
86         for ch, eset := range wp {
87                 if ch != nil && matches(eset, e) {
88                         select {
89                         case ch <- ei:
90                         default: // Drop event if receiver is too slow
91                                 dbgprintf("dropped %s on %q: receiver too slow", ei.Event(), ei.Path())
92                         }
93                 }
94         }
95 }
96
97 func (wp watchpoint) Total() Event {
98         return wp[nil] &^ internal
99 }
100
101 func (wp watchpoint) IsRecursive() bool {
102         return wp[nil]&recursive != 0
103 }