init
This commit is contained in:
commit
9a4987edb7
9
README.md
Normal file
9
README.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Speicher
|
||||
|
||||
WORK IN PROGRESS
|
||||
|
||||
Pronunciation: [[ˈʃpaɪ̯çɐ]](https://upload.wikimedia.org/wikipedia/commons/2/21/De-speicher.ogg)
|
||||
|
||||
Speicher is a lightweight, data store.
|
||||
|
||||

|
119
map.go
Normal file
119
map.go
Normal file
@ -0,0 +1,119 @@
|
||||
package speicher
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type (
|
||||
MemoryMap[T any] struct {
|
||||
data map[string]T
|
||||
location string
|
||||
mut sync.RWMutex
|
||||
}
|
||||
|
||||
Map[T any] interface {
|
||||
Get(key string) (T, bool)
|
||||
Has(key string) bool
|
||||
Set(key string, value T)
|
||||
RangeKV() <-chan MapRangeEl[T]
|
||||
RangeV() <-chan T
|
||||
Save() error
|
||||
Lock()
|
||||
Unlock()
|
||||
RLock()
|
||||
RUnlock()
|
||||
}
|
||||
|
||||
MapRangeEl[T any] struct {
|
||||
Key string
|
||||
Value T
|
||||
}
|
||||
)
|
||||
|
||||
func (m *MemoryMap[T]) Get(key string) (value T, found bool) {
|
||||
value, found = m.data[key]
|
||||
return
|
||||
}
|
||||
|
||||
func (m *MemoryMap[T]) Has(key string) bool {
|
||||
_, ok := m.data[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (m *MemoryMap[T]) Set(key string, value T) {
|
||||
m.data[key] = value
|
||||
}
|
||||
|
||||
func (m *MemoryMap[T]) RangeKV() <-chan MapRangeEl[T] {
|
||||
ch := make(chan MapRangeEl[T])
|
||||
go func() {
|
||||
defer close(ch)
|
||||
for key, value := range m.data {
|
||||
ch <- MapRangeEl[T]{Key: key, Value: value}
|
||||
}
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
func (m *MemoryMap[T]) RangeV() <-chan T {
|
||||
ch := make(chan T)
|
||||
go func() {
|
||||
defer close(ch)
|
||||
for _, value := range m.data {
|
||||
ch <- value
|
||||
}
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
func (m *MemoryMap[T]) Lock() {
|
||||
m.mut.Lock()
|
||||
}
|
||||
func (m *MemoryMap[T]) Unlock() {
|
||||
m.mut.Unlock()
|
||||
_ = m.Save()
|
||||
}
|
||||
|
||||
func (m *MemoryMap[T]) RLock() {
|
||||
m.mut.RLock()
|
||||
}
|
||||
func (m *MemoryMap[T]) RUnlock() {
|
||||
m.mut.RUnlock()
|
||||
}
|
||||
|
||||
func (m *MemoryMap[T]) Save() error {
|
||||
f, err := os.OpenFile(m.location, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
||||
if err != nil {
|
||||
return errors.Join(fmt.Errorf("failed to open file %s", m.location), err)
|
||||
}
|
||||
encoder := json.NewEncoder(f)
|
||||
if err := encoder.Encode(m.data); err != nil {
|
||||
return errors.Join(fmt.Errorf("failed to encode json file %s", m.location), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoadMap[T any](location string) (Map[T], error) {
|
||||
if strings.HasSuffix(location, ".json") {
|
||||
return loadMapFromJsonFile[T](location)
|
||||
}
|
||||
return nil, fmt.Errorf("unable to find loader for %s", location)
|
||||
}
|
||||
|
||||
func loadMapFromJsonFile[T any](location string) (Map[T], error) {
|
||||
f, err := os.OpenFile(location, os.O_RDONLY, 0644)
|
||||
if err != nil {
|
||||
return nil, errors.Join(fmt.Errorf("failed to open file %s", location), err)
|
||||
}
|
||||
decoder := json.NewDecoder(f)
|
||||
m := &MemoryMap[T]{}
|
||||
if err := decoder.Decode(&m.data); err != nil {
|
||||
return nil, errors.Join(fmt.Errorf("failed to decode json file %s", location), err)
|
||||
}
|
||||
return m, nil
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user