116 lines
2.1 KiB
Go
116 lines
2.1 KiB
Go
package memory
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"reflect"
|
|
"sync"
|
|
"time"
|
|
|
|
"errors"
|
|
)
|
|
|
|
var (
|
|
ErrWongType = errors.New("val must be a pointer")
|
|
ErrNotExists = errors.New("not exists")
|
|
ErrAaddressable = errors.New("cannot set value: val is not addressable")
|
|
)
|
|
|
|
type memCache struct {
|
|
opts Options
|
|
|
|
items map[string]Item
|
|
sync.RWMutex
|
|
}
|
|
|
|
func (c *memCache) Load(ctx context.Context, key string, val any) error {
|
|
c.RWMutex.RLock()
|
|
defer c.RWMutex.RUnlock()
|
|
|
|
item, found := c.items[key]
|
|
if !found {
|
|
return ErrNotExists
|
|
}
|
|
if item.Expired() {
|
|
return ErrNotExists
|
|
}
|
|
refValue := reflect.ValueOf(val)
|
|
if refValue.Type().Kind() != reflect.Ptr {
|
|
return ErrWongType
|
|
}
|
|
refElem := refValue.Elem()
|
|
if !refElem.CanSet() {
|
|
return ErrAaddressable
|
|
}
|
|
targetValue := reflect.Indirect(reflect.ValueOf(item.Value))
|
|
if targetValue.Type() != refElem.Type() {
|
|
return fmt.Errorf("type mismatch: expected %v, got %v", refElem.Type(), targetValue.Type())
|
|
}
|
|
refElem.Set(targetValue)
|
|
return nil
|
|
}
|
|
|
|
func (c *memCache) Exists(ctx context.Context, key string) (bool, error) {
|
|
c.RWMutex.RLock()
|
|
defer c.RWMutex.RUnlock()
|
|
item, found := c.items[key]
|
|
if !found {
|
|
return false, nil
|
|
}
|
|
if item.Expired() {
|
|
return false, nil
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (c *memCache) Store(ctx context.Context, key string, val any, d time.Duration) error {
|
|
var e int64
|
|
if d == DefaultExpiration {
|
|
d = c.opts.Expiration
|
|
}
|
|
if d > 0 {
|
|
e = time.Now().Add(d).UnixNano()
|
|
}
|
|
|
|
c.RWMutex.Lock()
|
|
defer c.RWMutex.Unlock()
|
|
|
|
c.items[key] = Item{
|
|
Value: val,
|
|
Expiration: e,
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *memCache) Delete(ctx context.Context, key string) error {
|
|
c.RWMutex.Lock()
|
|
defer c.RWMutex.Unlock()
|
|
|
|
_, found := c.items[key]
|
|
if !found {
|
|
return ErrNotExists
|
|
}
|
|
delete(c.items, key)
|
|
return nil
|
|
}
|
|
|
|
func (m *memCache) String() string {
|
|
return "memory"
|
|
}
|
|
|
|
// NewCache returns a new cache.
|
|
func NewCache(opts ...Option) *memCache {
|
|
options := NewOptions(opts...)
|
|
items := make(map[string]Item)
|
|
|
|
if len(options.Items) > 0 {
|
|
items = options.Items
|
|
}
|
|
|
|
return &memCache{
|
|
opts: options,
|
|
items: items,
|
|
}
|
|
}
|