v1.5.0
Added structutils
This commit is contained in:
parent
70d6c2cbb3
commit
b87934e8a9
@ -12,3 +12,5 @@
|
||||
|
||||
- DOCS.
|
||||
-- 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