github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/identity/identity.go (about)

     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() Identity
   113  }
   114  
   115  type identityManager struct {
   116  	sync.Mutex
   117  	Provider
   118  	ids Identities
   119  }
   120  
   121  func (im *identityManager) Add(ids ...Provider) {
   122  	im.Lock()
   123  	for _, id := range ids {
   124  		im.ids[id.GetIdentity()] = id
   125  	}
   126  	im.Unlock()
   127  }
   128  
   129  func (im *identityManager) Reset() {
   130  	im.Lock()
   131  	id := im.GetIdentity()
   132  	im.ids = Identities{id.GetIdentity(): id}
   133  	im.Unlock()
   134  }
   135  
   136  // TODO(bep) these identities are currently only read on server reloads
   137  // so there should be no concurrency issues, but that may change.
   138  func (im *identityManager) GetIdentities() Identities {
   139  	im.Lock()
   140  	defer im.Unlock()
   141  	return im.ids
   142  }
   143  
   144  func (im *identityManager) Search(id Identity) Provider {
   145  	im.Lock()
   146  	defer im.Unlock()
   147  	return im.ids.search(0, id.GetIdentity())
   148  }
   149  
   150  // Incrementer increments and returns the value.
   151  // Typically used for IDs.
   152  type Incrementer interface {
   153  	Incr() int
   154  }
   155  
   156  // IncrementByOne implements Incrementer adding 1 every time Incr is called.
   157  type IncrementByOne struct {
   158  	counter uint64
   159  }
   160  
   161  func (c *IncrementByOne) Incr() int {
   162  	return int(atomic.AddUint64(&c.counter, uint64(1)))
   163  }