aboutsummaryrefslogtreecommitdiff
path: root/core/state_backend.go
blob: cc7e90c2a579960060068cd0a5e7f7bdae79ef2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package core

import (
	"context"
	"encoding/json"
	"fmt"

)

type StateBackend interface {
	// For Framework ===
	// SetCurrentKey will perform in Memory
	SetCurrentKey(key string) error
	// GetCurrentKey will perform in Memory
	GetCurrentKey() string
	SetCurrentNamespace(namespace any) error
	GetCurrentNamespace() any
	Snapshot(checkpointID uint64, targetDir string) error

	// For User ===
	// GetValueState will perform in disk
	GetValueState(ctx context.Context, statename string) (ValueState[any], error)
}

type stateBackendKeyType struct{}

var stateBackendKey stateBackendKeyType

// type adapter
type typedValueState[T any] struct {
	inner ValueState[any]
}

func CastValueType[T any](inner ValueState[any]) ValueState[T] {
	return &typedValueState[T]{inner: inner}
}

func (s *typedValueState[T]) Value(ctx context.Context) (T, error) {
	val, err := s.inner.Value(ctx)
	var zero T
	if err != nil {
		return zero, err
	}
	if val == nil {
		return zero, nil
	}

	if rawBytes, ok := val.([]byte); ok {
		defer PutBuffer(rawBytes)

		var result T
		if err := json.Unmarshal(rawBytes, &result); err != nil {
			return zero, fmt.Errorf("failed to unmarshal state: %w", err)
		}
		return result, nil
	}

	return val.(T), nil
}

func (s *typedValueState[T]) Update(ctx context.Context, newVal T) (T, error) {
	_, err := s.inner.Update(ctx, newVal)
	return newVal, err
}

func (s *typedValueState[T]) Clear(ctx context.Context) error {
	return s.inner.Clear(ctx)
}

func InjectStateBackend(ctx context.Context, state StateBackend) context.Context {
	return context.WithValue(ctx, stateBackendKey, state)
}

func ExtractStateBackend(ctx context.Context) (StateBackend, bool) {
	backend, ok := ctx.Value(stateBackendKey).(StateBackend)
	return backend, ok
}