v1.5.0
Added structutils
This commit is contained in:
		
							parent
							
								
									70d6c2cbb3
								
							
						
					
					
						commit
						ec686d84c2
					
				@ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user