+++ /dev/null
-// Copyright 2020 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package lsp
-
-import (
- "sync"
- "time"
-)
-
-type debounceFunc struct {
- order uint64
- done chan struct{}
-}
-
-type debouncer struct {
- mu sync.Mutex
- funcs map[string]*debounceFunc
-}
-
-func newDebouncer() *debouncer {
- return &debouncer{
- funcs: make(map[string]*debounceFunc),
- }
-}
-
-// debounce waits timeout before running f, if no subsequent call is made with
-// the same key in the intervening time. If a later call to debounce with the
-// same key occurs while the original call is blocking, the original call will
-// return immediately without running its f.
-//
-// If order is specified, it will be used to order calls logically, so calls
-// with lesser order will not cancel calls with greater order.
-func (d *debouncer) debounce(key string, order uint64, timeout time.Duration, f func()) {
- if timeout == 0 {
- // Degenerate case: no debouncing.
- f()
- return
- }
-
- // First, atomically acquire the current func, cancel it, and insert this
- // call into d.funcs.
- d.mu.Lock()
- current, ok := d.funcs[key]
- if ok && current.order > order {
- // If we have a logical ordering of events (as is the case for snapshots),
- // don't overwrite a later event with an earlier event.
- d.mu.Unlock()
- return
- }
- if ok {
- close(current.done)
- }
- done := make(chan struct{})
- next := &debounceFunc{
- order: order,
- done: done,
- }
- d.funcs[key] = next
- d.mu.Unlock()
-
- // Next, wait to be cancelled or for our wait to expire. There is a race here
- // that we must handle: our timer could expire while another goroutine holds
- // d.mu.
- select {
- case <-done:
- case <-time.After(timeout):
- d.mu.Lock()
- if d.funcs[key] != next {
- // We lost the race: another event has arrived for the key and started
- // waiting. We could reasonably choose to run f at this point, but doing
- // nothing is simpler.
- d.mu.Unlock()
- return
- }
- delete(d.funcs, key)
- d.mu.Unlock()
- f()
- }
-}