github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/reflectkit/structtag_parser.go (about)

     1  // Copyright 2020 Insolar Network Ltd.
     2  // All rights reserved.
     3  // This material is licensed under the Insolar License version 1.0,
     4  // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md.
     5  
     6  package reflectkit
     7  
     8  import (
     9  	"reflect"
    10  	"strconv"
    11  )
    12  
    13  func ParseStructTag(tag reflect.StructTag, findFn func(name, qvalue string) bool) (string, string, bool) {
    14  	for tag != "" {
    15  		// Skip leading space.
    16  		i := 0
    17  		for i < len(tag) && tag[i] == ' ' {
    18  			i++
    19  		}
    20  		tag = tag[i:]
    21  		if tag == "" {
    22  			break
    23  		}
    24  
    25  		// Scan to colon. A space, a quote or a control character is a syntax error.
    26  		// Strictly speaking, control chars include the range [0x7f, 0x9f], not just
    27  		// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
    28  		// as it is simpler to inspect the tag's bytes than the tag's runes.
    29  		i = 0
    30  		for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
    31  			i++
    32  		}
    33  		if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
    34  			break
    35  		}
    36  		name := string(tag[:i])
    37  		tag = tag[i+1:]
    38  
    39  		// Scan quoted string to find value.
    40  		i = 1
    41  		for i < len(tag) && tag[i] != '"' {
    42  			if tag[i] == '\\' {
    43  				i++
    44  			}
    45  			i++
    46  		}
    47  		if i >= len(tag) {
    48  			break
    49  		}
    50  		qvalue := string(tag[:i+1])
    51  		tag = tag[i+1:]
    52  
    53  		if findFn(name, qvalue) {
    54  			if value, err := strconv.Unquote(qvalue); err == nil {
    55  				return name, value, true
    56  			}
    57  			break
    58  		}
    59  	}
    60  	return "", "", false
    61  }