summaryrefslogtreecommitdiffstats
path: root/identity/identity.go
blob: 7e03120b496edac3b18b75eaf99bd21544840375 (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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package identity

import (
	"path/filepath"
	"strings"
	"sync"
)

// NewIdentityManager creates a new Manager starting at id.
func NewManager(id Provider) Manager {
	return &identityManager{
		Provider: id,
		ids:      Identities{id.GetIdentity(): id},
	}
}

// NewPathIdentity creates a new Identity with the two identifiers
// type and path.
func NewPathIdentity(typ, pat string) PathIdentity {
	pat = strings.ToLower(strings.TrimPrefix(filepath.ToSlash(pat), "/"))
	return PathIdentity{Type: typ, Path: pat}
}

// Identities stores identity providers.
type Identities map[Identity]Provider

func (ids Identities) search(depth int, id Identity) Provider {

	if v, found := ids[id.GetIdentity()]; found {
		return v
	}

	depth++

	// There may be infinite recursion in templates.
	if depth > 100 {
		// Bail out.
		return nil
	}

	for _, v := range ids {
		switch t := v.(type) {
		case IdentitiesProvider:
			if nested := t.GetIdentities().search(depth, id); nested != nil {
				return nested
			}
		}
	}
	return nil
}

// IdentitiesProvider provides all Identities.
type IdentitiesProvider interface {
	GetIdentities() Identities
}

// Identity represents an thing that can provide an identify. This can be
// any Go type, but the Identity returned by GetIdentify must be hashable.
type Identity interface {
	Provider
	Name() string
}

// Manager manages identities, and is itself a Provider of Identity.
type Manager interface {
	IdentitiesProvider
	Provider
	Add(ids ...Provider)
	Search(id Identity) Provider
	Reset()
}

// A PathIdentity is a common identity identified by a type and a path, e.g. "layouts" and "_default/single.html".
type PathIdentity struct {
	Type string
	Path string
}

// GetIdentity returns itself.
func (id PathIdentity) GetIdentity() Identity {
	return id
}

// Name returns the Path.
func (id PathIdentity) Name() string {
	return id.Path
}

// A KeyValueIdentity a general purpose identity.
type KeyValueIdentity struct {
	Key   string
	Value string
}

// GetIdentity returns itself.
func (id KeyValueIdentity) GetIdentity() Identity {
	return id
}

// Name returns the Key.
func (id KeyValueIdentity) Name() string {
	return id.Key
}

// Provider provides the hashable Identity.
type Provider interface {
	GetIdentity() Identity
}

type identityManager struct {
	sync.Mutex
	Provider
	ids Identities
}

func (im *identityManager) Add(ids ...Provider) {
	im.Lock()
	for _, id := range ids {
		im.ids[id.GetIdentity()] = id
	}
	im.Unlock()
}

func (im *identityManager) Reset() {
	im.Lock()
	id := im.GetIdentity()
	im.ids = Identities{id.GetIdentity(): id}
	im.Unlock()
}

func (im *identityManager) GetIdentities() Identities {
	im.Lock()
	defer im.Unlock()
	return im.ids
}

func (im *identityManager) Search(id Identity) Provider {
	im.Lock()
	defer im.Unlock()
	return im.ids.search(0, id.GetIdentity())
}