| 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
 | package ini
import (
	"bytes"
	"sort"
	"strings"
	"github.com/spf13/cast"
	"gopkg.in/ini.v1"
)
// LoadOptions contains all customized options used for load data source(s).
// This type is added here for convenience: this way consumers can import a single package called "ini".
type LoadOptions = ini.LoadOptions
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for INI encoding.
type Codec struct {
	KeyDelimiter string
	LoadOptions  LoadOptions
}
func (c Codec) Encode(v map[string]any) ([]byte, error) {
	cfg := ini.Empty()
	ini.PrettyFormat = false
	flattened := map[string]any{}
	flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
	keys := make([]string, 0, len(flattened))
	for key := range flattened {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	for _, key := range keys {
		sectionName, keyName := "", key
		lastSep := strings.LastIndex(key, ".")
		if lastSep != -1 {
			sectionName = key[:(lastSep)]
			keyName = key[(lastSep + 1):]
		}
		// TODO: is this a good idea?
		if sectionName == "default" {
			sectionName = ""
		}
		cfg.Section(sectionName).Key(keyName).SetValue(cast.ToString(flattened[key]))
	}
	var buf bytes.Buffer
	_, err := cfg.WriteTo(&buf)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
func (c Codec) Decode(b []byte, v map[string]any) error {
	cfg := ini.Empty(c.LoadOptions)
	err := cfg.Append(b)
	if err != nil {
		return err
	}
	sections := cfg.Sections()
	for i := 0; i < len(sections); i++ {
		section := sections[i]
		keys := section.Keys()
		for j := 0; j < len(keys); j++ {
			key := keys[j]
			value := cfg.Section(section.Name()).Key(key.Name()).String()
			deepestMap := deepSearch(v, strings.Split(section.Name(), c.keyDelimiter()))
			// set innermost value
			deepestMap[key.Name()] = value
		}
	}
	return nil
}
func (c Codec) keyDelimiter() string {
	if c.KeyDelimiter == "" {
		return "."
	}
	return c.KeyDelimiter
}
 |