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