github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/identity/identity.go (about) 1 // Copyright 2023 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package identity 15 16 import ( 17 "path/filepath" 18 "strings" 19 "sync" 20 "sync/atomic" 21 ) 22 23 // NewManager creates a new Manager starting at id. 24 func NewManager(id Provider) Manager { 25 return &identityManager{ 26 Provider: id, 27 ids: Identities{id.GetIdentity(): id}, 28 } 29 } 30 31 // NewPathIdentity creates a new Identity with the two identifiers 32 // type and path. 33 func NewPathIdentity(typ, pat string) PathIdentity { 34 pat = strings.ToLower(strings.TrimPrefix(filepath.ToSlash(pat), "/")) 35 return PathIdentity{Type: typ, Path: pat} 36 } 37 38 // Identities stores identity providers. 39 type Identities map[Identity]Provider 40 41 func (ids Identities) search(depth int, id Identity) Provider { 42 if v, found := ids[id.GetIdentity()]; found { 43 return v 44 } 45 46 depth++ 47 48 // There may be infinite recursion in templates. 49 if depth > 100 { 50 // Bail out. 51 return nil 52 } 53 54 for _, v := range ids { 55 switch t := v.(type) { 56 case IdentitiesProvider: 57 if nested := t.GetIdentities().search(depth, id); nested != nil { 58 return nested 59 } 60 } 61 } 62 return nil 63 } 64 65 // IdentitiesProvider provides all Identities. 66 type IdentitiesProvider interface { 67 GetIdentities() Identities 68 } 69 70 // Identity represents an thing that can provide an identify. This can be 71 // any Go type, but the Identity returned by GetIdentify must be hashable. 72 type Identity interface { 73 Provider 74 Name() string 75 } 76 77 // Manager manages identities, and is itself a Provider of Identity. 78 type Manager interface { 79 SearchProvider 80 Add(ids ...Provider) 81 Reset() 82 } 83 84 // SearchProvider provides access to the chained set of identities. 85 type SearchProvider interface { 86 Provider 87 IdentitiesProvider 88 Search(id Identity) Provider 89 } 90 91 // A PathIdentity is a common identity identified by a type and a path, e.g. "layouts" and "_default/single.html". 92 type PathIdentity struct { 93 Type string 94 Path string 95 } 96 97 // GetIdentity returns itself. 98 func (id PathIdentity) GetIdentity() Identity { 99 return id 100 } 101 102 // Name returns the Path. 103 func (id PathIdentity) Name() string { 104 return id.Path 105 } 106 107 // A KeyValueIdentity a general purpose identity. 108 type KeyValueIdentity struct { 109 Key string 110 Value string 111 } 112 113 // GetIdentity returns itself. 114 func (id KeyValueIdentity) GetIdentity() Identity { 115 return id 116 } 117 118 // Name returns the Key. 119 func (id KeyValueIdentity) Name() string { 120 return id.Key 121 } 122 123 // Provider provides the comparable Identity. 124 type Provider interface { 125 // GetIdentity is for internal use. 126 GetIdentity() Identity 127 } 128 129 type identityManager struct { 130 sync.Mutex 131 Provider 132 ids Identities 133 } 134 135 func (im *identityManager) Add(ids ...Provider) { 136 im.Lock() 137 for _, id := range ids { 138 im.ids[id.GetIdentity()] = id 139 } 140 im.Unlock() 141 } 142 143 func (im *identityManager) Reset() { 144 im.Lock() 145 id := im.GetIdentity() 146 im.ids = Identities{id.GetIdentity(): id} 147 im.Unlock() 148 } 149 150 // TODO(bep) these identities are currently only read on server reloads 151 // so there should be no concurrency issues, but that may change. 152 func (im *identityManager) GetIdentities() Identities { 153 im.Lock() 154 defer im.Unlock() 155 return im.ids 156 } 157 158 func (im *identityManager) Search(id Identity) Provider { 159 im.Lock() 160 defer im.Unlock() 161 return im.ids.search(0, id.GetIdentity()) 162 } 163 164 // Incrementer increments and returns the value. 165 // Typically used for IDs. 166 type Incrementer interface { 167 Incr() int 168 } 169 170 // IncrementByOne implements Incrementer adding 1 every time Incr is called. 171 type IncrementByOne struct { 172 counter uint64 173 } 174 175 func (c *IncrementByOne) Incr() int { 176 return int(atomic.AddUint64(&c.counter, uint64(1))) 177 }