summaryrefslogtreecommitdiff
path: root/vendor/github.com/hashicorp/terraform/helper/shadow/ordered_value.go
blob: 0a43d4d4d434f07057ef8208502db6e5af7c2bcc (plain)
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
package shadow

import (
	"container/list"
	"sync"
)

// OrderedValue is a struct that keeps track of a value in the order
// it is set. Each time Value() is called, it will return the most recent
// calls value then discard it.
//
// This is unlike Value that returns the same value once it is set.
type OrderedValue struct {
	lock    sync.Mutex
	values  *list.List
	waiters *list.List
}

// Value returns the last value that was set, or blocks until one
// is received.
func (w *OrderedValue) Value() interface{} {
	w.lock.Lock()

	// If we have a pending value already, use it
	if w.values != nil && w.values.Len() > 0 {
		front := w.values.Front()
		w.values.Remove(front)
		w.lock.Unlock()
		return front.Value
	}

	// No pending value, create a waiter
	if w.waiters == nil {
		w.waiters = list.New()
	}

	var val Value
	w.waiters.PushBack(&val)
	w.lock.Unlock()

	// Return the value once we have it
	return val.Value()
}

// SetValue sets the latest value.
func (w *OrderedValue) SetValue(v interface{}) {
	w.lock.Lock()
	defer w.lock.Unlock()

	// If we have a waiter, notify it
	if w.waiters != nil && w.waiters.Len() > 0 {
		front := w.waiters.Front()
		w.waiters.Remove(front)

		val := front.Value.(*Value)
		val.SetValue(v)
		return
	}

	// Add it to the list of values
	if w.values == nil {
		w.values = list.New()
	}

	w.values.PushBack(v)
}