hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

identity.go (3491B)

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