github.com/dgallion1/notify@v0.9.3-0.20201128171805-931189d936e0/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  }