v1.5.0
Added structutils
This commit is contained in:
parent
70d6c2cbb3
commit
b87934e8a9
@ -12,3 +12,5 @@
|
|||||||
|
|
||||||
- DOCS.
|
- DOCS.
|
||||||
-- Done, but flesh out.
|
-- Done, but flesh out.
|
||||||
|
|
||||||
|
- Implement io.Writer interfaces
|
||||||
|
5
structutils/consts.go
Normal file
5
structutils/consts.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package structutils
|
||||||
|
|
||||||
|
const (
|
||||||
|
TagMapTrim tagMapOpt = iota
|
||||||
|
)
|
362
structutils/funcs.go
Normal file
362
structutils/funcs.go
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
/*
|
||||||
|
GoUtils - a library to assist with various Golang-related functions
|
||||||
|
Copyright (C) 2020 Brent Saner
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package structutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
`reflect`
|
||||||
|
`strings`
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
TagToBoolMap takes struct field `field` and tag name `tagName`,
|
||||||
|
optionally with options `opts`, and returns a map of the tag values.
|
||||||
|
The tag value string is assumed to be in the form of:
|
||||||
|
option[,option,option...]
|
||||||
|
and returns a map[string]bool (map[option]true).
|
||||||
|
|
||||||
|
If field does not have tag tagName, m will be nil.
|
||||||
|
|
||||||
|
See the TagMap* constants for opts.
|
||||||
|
*/
|
||||||
|
func TagToBoolMap(field reflect.StructField, tagName string, opts ...tagMapOpt) (m map[string]bool) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var optSplit []string
|
||||||
|
var tagOpts map[tagMapOpt]bool = getTagMapOpts(opts)
|
||||||
|
|
||||||
|
s = field.Tag.Get(tagName)
|
||||||
|
|
||||||
|
if strings.TrimSpace(s) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
optSplit = strings.Split(s, ",")
|
||||||
|
if optSplit == nil || len(optSplit) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m = make(map[string]bool)
|
||||||
|
for _, o := range optSplit {
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
o = strings.TrimSpace(o)
|
||||||
|
}
|
||||||
|
m[o] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TagToBoolMapWithValue is like TagToBoolMap but additionally assumes the first value is an "identifier".
|
||||||
|
The tag value string is assumed to be in the form of:
|
||||||
|
value,option[,option,option...]
|
||||||
|
and returns a map[string]bool (map[option]true) with the value.
|
||||||
|
*/
|
||||||
|
func TagToBoolMapWithValue(field reflect.StructField, tagName string, opts ...tagMapOpt) (value string, m map[string]bool) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var optSplit []string
|
||||||
|
var tagOpts map[tagMapOpt]bool = getTagMapOpts(opts)
|
||||||
|
|
||||||
|
s = field.Tag.Get(tagName)
|
||||||
|
|
||||||
|
if strings.TrimSpace(s) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
optSplit = strings.Split(s, ",")
|
||||||
|
if optSplit == nil || len(optSplit) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m = make(map[string]bool)
|
||||||
|
for idx, o := range optSplit {
|
||||||
|
if idx == 0 {
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
o = strings.TrimSpace(o)
|
||||||
|
}
|
||||||
|
value = o
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
o = strings.TrimSpace(o)
|
||||||
|
}
|
||||||
|
m[o] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TagToMixedMap combines TagToBoolMap and TagToStringMap.
|
||||||
|
It takes struct field `field` and tag name `tagName`,
|
||||||
|
and returns all single-value options in mapBool, and all key/value options in mapString.
|
||||||
|
|
||||||
|
If field does not have tag tagName, m will be nil.
|
||||||
|
|
||||||
|
See the TagMap* constants for opts.
|
||||||
|
*/
|
||||||
|
func TagToMixedMap(field reflect.StructField, tagName string, opts ...tagMapOpt) (mapBool map[string]bool, mapString map[string]string) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var valStr string
|
||||||
|
var split []string
|
||||||
|
var kvSplit []string
|
||||||
|
var valSplit []string
|
||||||
|
var k string
|
||||||
|
var v string
|
||||||
|
var tagOpts map[tagMapOpt]bool = getTagMapOpts(opts)
|
||||||
|
|
||||||
|
s = field.Tag.Get(tagName)
|
||||||
|
|
||||||
|
if strings.TrimSpace(s) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
split = strings.Split(s, ",")
|
||||||
|
if split == nil || len(split) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mapBool = make(map[string]bool)
|
||||||
|
mapString = make(map[string]string)
|
||||||
|
for _, valStr = range split {
|
||||||
|
if strings.Contains(valStr, "=") {
|
||||||
|
kvSplit = strings.SplitN(valStr, "=", 2)
|
||||||
|
if kvSplit == nil || len(kvSplit) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k = valSplit[0]
|
||||||
|
switch len(valSplit) {
|
||||||
|
case 1:
|
||||||
|
v = ""
|
||||||
|
case 2:
|
||||||
|
v = kvSplit[1]
|
||||||
|
}
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
k = strings.TrimSpace(k)
|
||||||
|
v = strings.TrimSpace(v)
|
||||||
|
}
|
||||||
|
mapString[k] = v
|
||||||
|
} else {
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
valStr = strings.TrimSpace(valStr)
|
||||||
|
}
|
||||||
|
mapBool[valStr] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TagToMixedMapWithValue combines TagToBoolMapWithValue and TagToStringMapWithValue.
|
||||||
|
It takes struct field `field` and tag name `tagName`,
|
||||||
|
and returns all single-value options in mapBool, and all key/value options in mapString
|
||||||
|
along with the first single-value option as value..
|
||||||
|
|
||||||
|
If field does not have tag tagName, m will be nil.
|
||||||
|
|
||||||
|
See the TagMap* constants for opts.
|
||||||
|
*/
|
||||||
|
func TagToMixedMapWithValue(field reflect.StructField, tagName string, opts ...tagMapOpt) (value string, mapBool map[string]bool, mapString map[string]string) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var idx int
|
||||||
|
var valStr string
|
||||||
|
var split []string
|
||||||
|
var kvSplit []string
|
||||||
|
var valSplit []string
|
||||||
|
var k string
|
||||||
|
var v string
|
||||||
|
var tagOpts map[tagMapOpt]bool = getTagMapOpts(opts)
|
||||||
|
|
||||||
|
s = field.Tag.Get(tagName)
|
||||||
|
|
||||||
|
if strings.TrimSpace(s) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
split = strings.Split(s, ",")
|
||||||
|
if split == nil || len(split) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mapBool = make(map[string]bool)
|
||||||
|
mapString = make(map[string]string)
|
||||||
|
for idx, valStr = range split {
|
||||||
|
if idx == 0 {
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
valStr = strings.TrimSpace(valStr)
|
||||||
|
}
|
||||||
|
value = valStr
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.Contains(valStr, "=") {
|
||||||
|
kvSplit = strings.SplitN(valStr, "=", 2)
|
||||||
|
if kvSplit == nil || len(kvSplit) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k = valSplit[0]
|
||||||
|
switch len(valSplit) {
|
||||||
|
case 1:
|
||||||
|
v = ""
|
||||||
|
case 2:
|
||||||
|
v = kvSplit[1]
|
||||||
|
}
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
k = strings.TrimSpace(k)
|
||||||
|
v = strings.TrimSpace(v)
|
||||||
|
}
|
||||||
|
mapString[k] = v
|
||||||
|
} else {
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
valStr = strings.TrimSpace(valStr)
|
||||||
|
}
|
||||||
|
mapBool[valStr] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TagToStringMap takes struct field `field` and tag name `tagName`,
|
||||||
|
optionally with options `opts`, and returns a map of the tag values.
|
||||||
|
The tag value string is assumed to be in the form of:
|
||||||
|
key=value[,key=value,key=value...]
|
||||||
|
and returns a map[string]string (map[key]value).
|
||||||
|
It is proccessed in order; later duplicate keys overwrite previous ones.
|
||||||
|
|
||||||
|
If field does not have tag tagName, m will be nil.
|
||||||
|
|
||||||
|
If only a key is provided with no value, the value in the map will be an empty string.
|
||||||
|
(e.g. "foo,bar=baz" => map[string]string{"foo": "", "bar: "baz"}
|
||||||
|
|
||||||
|
See the TagMap* constants for opts.
|
||||||
|
*/
|
||||||
|
func TagToStringMap(field reflect.StructField, tagName string, opts ...tagMapOpt) (m map[string]string) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var kvSplit []string
|
||||||
|
var valSplit []string
|
||||||
|
var k string
|
||||||
|
var v string
|
||||||
|
var tagOpts map[tagMapOpt]bool = getTagMapOpts(opts)
|
||||||
|
|
||||||
|
s = field.Tag.Get(tagName)
|
||||||
|
|
||||||
|
if strings.TrimSpace(s) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
kvSplit = strings.Split(s, ",")
|
||||||
|
if kvSplit == nil || len(kvSplit) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, kv := range kvSplit {
|
||||||
|
valSplit = strings.SplitN(kv, "=", 2)
|
||||||
|
if valSplit == nil || len(valSplit) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k = valSplit[0]
|
||||||
|
switch len(valSplit) {
|
||||||
|
case 1:
|
||||||
|
v = ""
|
||||||
|
case 2:
|
||||||
|
v = valSplit[1]
|
||||||
|
// It's not possible to have more than 2.
|
||||||
|
}
|
||||||
|
if m == nil {
|
||||||
|
m = make(map[string]string)
|
||||||
|
}
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
k = strings.TrimSpace(k)
|
||||||
|
v = strings.TrimSpace(v)
|
||||||
|
}
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TagToStringMapWithValue is like TagToStringMap but additionally assumes the first value is an "identifier".
|
||||||
|
The tag value string is assumed to be in the form of:
|
||||||
|
value,key=value[,key=value,key=value...]
|
||||||
|
and returns a map[string]string (map[key]value) with the value.
|
||||||
|
*/
|
||||||
|
func TagToStringMapWithValue(field reflect.StructField, tagName string, opts ...tagMapOpt) (value string, m map[string]string) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var kvSplit []string
|
||||||
|
var valSplit []string
|
||||||
|
var k string
|
||||||
|
var v string
|
||||||
|
var tagOpts map[tagMapOpt]bool = getTagMapOpts(opts)
|
||||||
|
|
||||||
|
s = field.Tag.Get(tagName)
|
||||||
|
|
||||||
|
if strings.TrimSpace(s) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
kvSplit = strings.Split(s, ",")
|
||||||
|
if kvSplit == nil || len(kvSplit) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for idx, kv := range kvSplit {
|
||||||
|
if idx == 0 {
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
kv = strings.TrimSpace(kv)
|
||||||
|
}
|
||||||
|
value = kv
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
valSplit = strings.SplitN(kv, "=", 2)
|
||||||
|
if valSplit == nil || len(valSplit) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k = valSplit[0]
|
||||||
|
switch len(valSplit) {
|
||||||
|
case 1:
|
||||||
|
v = ""
|
||||||
|
case 2:
|
||||||
|
v = valSplit[1]
|
||||||
|
// It's not possible to have more than 2.
|
||||||
|
}
|
||||||
|
if m == nil {
|
||||||
|
m = make(map[string]string)
|
||||||
|
}
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
k = strings.TrimSpace(k)
|
||||||
|
v = strings.TrimSpace(v)
|
||||||
|
}
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTagMapOpts(opts []tagMapOpt) (optMap map[tagMapOpt]bool) {
|
||||||
|
|
||||||
|
optMap = make(map[tagMapOpt]bool)
|
||||||
|
|
||||||
|
if opts == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
5
structutils/types.go
Normal file
5
structutils/types.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package structutils
|
||||||
|
|
||||||
|
type (
|
||||||
|
tagMapOpt uint8
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user