File: context.go

package info (click to toggle)
golang-github-viant-toolbox 0.33.2-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, sid, trixie
  • size: 1,280 kB
  • sloc: makefile: 16
file content (140 lines) | stat: -rw-r--r-- 3,869 bytes parent folder | download | duplicates (2)
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package toolbox

import (
	"fmt"
	"reflect"
)

//Context represents type safe map.
type Context interface {

	//GetRequired returns a value for a target type of error if it does not exist
	GetRequired(targetType interface{}) (interface{}, error)

	//GetOptional  returns a value for a target type
	GetOptional(targetType interface{}) interface{}

	//GetOptional into sets requested context value into target, returns true if value was found
	GetInto(targetType interface{}, target interface{}) bool

	//Put puts target type value to the context, or error if value exists,  is nil or incompatible with target type
	Put(targetType interface{}, value interface{}) error

	//Replace repaces value in the context
	Replace(targetType interface{}, value interface{}) error

	//Remove removes value from the context
	Remove(targetType interface{}) interface{}

	//Contains chekcs if a value of a terget type is in contet
	Contains(targetType interface{}) bool

	//Clone create a shallow copy of a context
	Clone() Context
}

type contextImpl struct {
	context map[string]interface{}
}

func (c *contextImpl) getReflectType(targetType interface{}) reflect.Type {
	var reflectType reflect.Type
	var ok bool
	reflectType, ok = targetType.(reflect.Type)
	if !ok {
		reflectType = reflect.TypeOf(targetType)
	}
	return reflectType
}

func (c *contextImpl) getKey(targetType interface{}) string {
	var reflectType = c.getReflectType(targetType)
	return reflectType.String()
}

func (c *contextImpl) GetRequired(targetType interface{}) (interface{}, error) {
	if !c.Contains(targetType) {
		key := c.getKey(targetType)
		return nil, fmt.Errorf("failed to lookup key:" + key)
	}
	return c.GetOptional(targetType), nil
}

func (c *contextImpl) GetOptional(targetType interface{}) interface{} {
	key := c.getKey(targetType)
	if result, ok := c.context[key]; ok {
		return result
	}
	return nil
}

func (c *contextImpl) GetInto(targetType, target interface{}) bool {
	key := c.getKey(targetType)
	if result, ok := c.context[key]; ok {
		reflect.ValueOf(target).Elem().Set(reflect.ValueOf(result))
		return true
	}
	return false
}

func (c *contextImpl) Put(targetType interface{}, value interface{}) error {
	if c.Contains(targetType) {
		key := c.getKey(targetType)
		return fmt.Errorf("failed to put key - already exist: " + key)
	}
	return c.Replace(targetType, value)
}

func (c *contextImpl) Replace(targetType interface{}, value interface{}) error {
	key := c.getKey(targetType)
	targetReflectType := c.getReflectType(targetType)
	valueReflectType := reflect.TypeOf(value)
	if valueReflectType == targetReflectType {
		c.context[key] = value
		return nil
	}

	if targetReflectType.Kind() == reflect.Ptr {
		converted := reflect.ValueOf(value).Elem().Convert(targetReflectType.Elem())
		convertedPointer := reflect.New(targetReflectType.Elem())
		convertedPointer.Elem().Set(converted)
		value = convertedPointer.Interface()

	} else {
		if !valueReflectType.AssignableTo(targetReflectType) {
			return fmt.Errorf("value of type %v is not assignable to %v", valueReflectType, targetReflectType)
		}
		value = reflect.ValueOf(value).Convert(targetReflectType).Interface()
	}
	c.context[key] = value
	return nil
}

func (c *contextImpl) Remove(targetType interface{}) interface{} {
	key := c.getKey(targetType)
	result := c.GetOptional(targetType)
	delete(c.context, key)
	return result
}

func (c *contextImpl) Contains(targetType interface{}) bool {
	key := c.getKey(targetType)
	if _, ok := c.context[key]; ok {
		return true
	}
	return false
}

func (c *contextImpl) Clone() Context {
	var result = &contextImpl{context: make(map[string]interface{})}
	for k, v := range c.context {
		result.context[k] = v
	}
	return result
}

//NewContext creates a new context
func NewContext() Context {
	var result Context = &contextImpl{context: make(map[string]interface{})}
	return result
}