mirror of
https://github.com/Luzifer/worktime.git
synced 2024-12-23 22:41:17 +00:00
199 lines
5 KiB
Go
199 lines
5 KiB
Go
|
package toml
|
||
|
|
||
|
// Tools to convert a TomlTree to different representations
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// encodes a string to a TOML-compliant string value
|
||
|
func encodeTomlString(value string) string {
|
||
|
result := ""
|
||
|
for _, rr := range value {
|
||
|
intRr := uint16(rr)
|
||
|
switch rr {
|
||
|
case '\b':
|
||
|
result += "\\b"
|
||
|
case '\t':
|
||
|
result += "\\t"
|
||
|
case '\n':
|
||
|
result += "\\n"
|
||
|
case '\f':
|
||
|
result += "\\f"
|
||
|
case '\r':
|
||
|
result += "\\r"
|
||
|
case '"':
|
||
|
result += "\\\""
|
||
|
case '\\':
|
||
|
result += "\\\\"
|
||
|
default:
|
||
|
if intRr < 0x001F {
|
||
|
result += fmt.Sprintf("\\u%0.4X", intRr)
|
||
|
} else {
|
||
|
result += string(rr)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
// Value print support function for ToString()
|
||
|
// Outputs the TOML compliant string representation of a value
|
||
|
func toTomlValue(item interface{}, indent int) string {
|
||
|
tab := strings.Repeat(" ", indent)
|
||
|
switch value := item.(type) {
|
||
|
case int:
|
||
|
return tab + strconv.FormatInt(int64(value), 10)
|
||
|
case int8:
|
||
|
return tab + strconv.FormatInt(int64(value), 10)
|
||
|
case int16:
|
||
|
return tab + strconv.FormatInt(int64(value), 10)
|
||
|
case int32:
|
||
|
return tab + strconv.FormatInt(int64(value), 10)
|
||
|
case int64:
|
||
|
return tab + strconv.FormatInt(value, 10)
|
||
|
case uint:
|
||
|
return tab + strconv.FormatUint(uint64(value), 10)
|
||
|
case uint8:
|
||
|
return tab + strconv.FormatUint(uint64(value), 10)
|
||
|
case uint16:
|
||
|
return tab + strconv.FormatUint(uint64(value), 10)
|
||
|
case uint32:
|
||
|
return tab + strconv.FormatUint(uint64(value), 10)
|
||
|
case uint64:
|
||
|
return tab + strconv.FormatUint(value, 10)
|
||
|
case float32:
|
||
|
return tab + strconv.FormatFloat(float64(value), 'f', -1, 32)
|
||
|
case float64:
|
||
|
return tab + strconv.FormatFloat(value, 'f', -1, 64)
|
||
|
case string:
|
||
|
return tab + "\"" + encodeTomlString(value) + "\""
|
||
|
case bool:
|
||
|
if value {
|
||
|
return "true"
|
||
|
}
|
||
|
return "false"
|
||
|
case time.Time:
|
||
|
return tab + value.Format(time.RFC3339)
|
||
|
case []interface{}:
|
||
|
result := tab + "[\n"
|
||
|
for _, item := range value {
|
||
|
result += toTomlValue(item, indent+2) + ",\n"
|
||
|
}
|
||
|
return result + tab + "]"
|
||
|
case nil:
|
||
|
return ""
|
||
|
default:
|
||
|
panic(fmt.Sprintf("unsupported value type %T: %v", value, value))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Recursive support function for ToString()
|
||
|
// Outputs a tree, using the provided keyspace to prefix group names
|
||
|
func (t *TomlTree) toToml(indent, keyspace string) string {
|
||
|
result := ""
|
||
|
for k, v := range t.values {
|
||
|
// figure out the keyspace
|
||
|
combinedKey := k
|
||
|
if keyspace != "" {
|
||
|
combinedKey = keyspace + "." + combinedKey
|
||
|
}
|
||
|
// output based on type
|
||
|
switch node := v.(type) {
|
||
|
case []*TomlTree:
|
||
|
for _, item := range node {
|
||
|
if len(item.Keys()) > 0 {
|
||
|
result += fmt.Sprintf("\n%s[[%s]]\n", indent, combinedKey)
|
||
|
}
|
||
|
result += item.toToml(indent+" ", combinedKey)
|
||
|
}
|
||
|
case *TomlTree:
|
||
|
if len(node.Keys()) > 0 {
|
||
|
result += fmt.Sprintf("\n%s[%s]\n", indent, combinedKey)
|
||
|
}
|
||
|
result += node.toToml(indent+" ", combinedKey)
|
||
|
case map[string]interface{}:
|
||
|
sub := TreeFromMap(node)
|
||
|
|
||
|
if len(sub.Keys()) > 0 {
|
||
|
result += fmt.Sprintf("\n%s[%s]\n", indent, combinedKey)
|
||
|
}
|
||
|
result += sub.toToml(indent+" ", combinedKey)
|
||
|
case map[string]string:
|
||
|
sub := TreeFromMap(convertMapStringString(node))
|
||
|
|
||
|
if len(sub.Keys()) > 0 {
|
||
|
result += fmt.Sprintf("\n%s[%s]\n", indent, combinedKey)
|
||
|
}
|
||
|
result += sub.toToml(indent+" ", combinedKey)
|
||
|
case map[interface{}]interface{}:
|
||
|
sub := TreeFromMap(convertMapInterfaceInterface(node))
|
||
|
|
||
|
if len(sub.Keys()) > 0 {
|
||
|
result += fmt.Sprintf("\n%s[%s]\n", indent, combinedKey)
|
||
|
}
|
||
|
result += sub.toToml(indent+" ", combinedKey)
|
||
|
case *tomlValue:
|
||
|
result += fmt.Sprintf("%s%s = %s\n", indent, k, toTomlValue(node.value, 0))
|
||
|
default:
|
||
|
result += fmt.Sprintf("%s%s = %s\n", indent, k, toTomlValue(v, 0))
|
||
|
}
|
||
|
}
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
func convertMapStringString(in map[string]string) map[string]interface{} {
|
||
|
result := make(map[string]interface{}, len(in))
|
||
|
for k, v := range in {
|
||
|
result[k] = v
|
||
|
}
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
func convertMapInterfaceInterface(in map[interface{}]interface{}) map[string]interface{} {
|
||
|
result := make(map[string]interface{}, len(in))
|
||
|
for k, v := range in {
|
||
|
result[k.(string)] = v
|
||
|
}
|
||
|
return result
|
||
|
}
|
||
|
|
||
|
// ToString is an alias for String
|
||
|
func (t *TomlTree) ToString() string {
|
||
|
return t.String()
|
||
|
}
|
||
|
|
||
|
// String generates a human-readable representation of the current tree.
|
||
|
// Output spans multiple lines, and is suitable for ingest by a TOML parser
|
||
|
func (t *TomlTree) String() string {
|
||
|
return t.toToml("", "")
|
||
|
}
|
||
|
|
||
|
// ToMap recursively generates a representation of the current tree using map[string]interface{}.
|
||
|
func (t *TomlTree) ToMap() map[string]interface{} {
|
||
|
result := map[string]interface{}{}
|
||
|
|
||
|
for k, v := range t.values {
|
||
|
switch node := v.(type) {
|
||
|
case []*TomlTree:
|
||
|
var array []interface{}
|
||
|
for _, item := range node {
|
||
|
array = append(array, item.ToMap())
|
||
|
}
|
||
|
result[k] = array
|
||
|
case *TomlTree:
|
||
|
result[k] = node.ToMap()
|
||
|
case map[string]interface{}:
|
||
|
sub := TreeFromMap(node)
|
||
|
result[k] = sub.ToMap()
|
||
|
case *tomlValue:
|
||
|
result[k] = node.value
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result
|
||
|
}
|