github.com/misseven0/notify@v0.0.0-20230519123055-c1422e46da05/watchpoint.go (about) 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 }