func parseTag(tag reflect.StructTag) packopts { var opts packopts bpTag := tag.Get("binpack") for _, t := range strings.Split(string(bpTag), ",") { if t == "-" { opts.skip = true } if strings.HasPrefix(t, "lenprefix=") { opts.lenprefix = strings.TrimPrefix(t, "lenprefix=") } if strings.HasPrefix(t, "endian=") { endian := strings.TrimPrefix(t, "endian=") switch endian { case "little": opts.endian = binary.LittleEndian case "big": opts.endian = binary.BigEndian default: panic("unknown endian type in struct: " + endian) } } } return opts }
func (q *queryParser) parseValue(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error { value = elemOf(value) // no need to handle zero values if !value.IsValid() { return nil } t := tag.Get("type") if t == "" { switch value.Kind() { case reflect.Struct: t = "structure" case reflect.Slice: t = "list" case reflect.Map: t = "map" } } switch t { case "structure": return q.parseStruct(v, value, prefix) case "list": return q.parseList(v, value, prefix, tag) case "map": return q.parseMap(v, value, prefix, tag) default: return q.parseScalar(v, value, prefix, tag) } }
func dump(path string, typ types.Type, st reflect.StructTag) IObj { named, _ := typ.(*types.Named) if named != nil { typ = typ.Underlying() } if strings.Split(st.Get("json"), ",")[0] == "" { if _, ok := typ.(*types.Struct); !ok { if _, ok := typ.(*types.Pointer); !ok { return nil } } } switch u := typ.(type) { case *types.Struct: return Struct(path, st, u, named) case *types.Map: return Map(path, st, u, named) case *types.Slice: return Slice(path, st, u) case *types.Pointer: return Pointer(path, st, u) case *types.Basic: return Basic(path, st, u, named) default: panic("unsupported") } }
func HasFilter(field reflect.StructTag) (k, v string, err error) { tag := field.Get("blueprint") for _, entry := range strings.Split(tag, ",") { if strings.HasPrefix(entry, "filter") { if !strings.HasPrefix(entry, "filter(") || !strings.HasSuffix(entry, ")") { return "", "", fmt.Errorf("unexpected format for filter %q: missing ()", entry) } entry = strings.TrimPrefix(entry, "filter(") entry = strings.TrimSuffix(entry, ")") s := strings.Split(entry, ":") if len(s) != 2 { return "", "", fmt.Errorf("unexpected format for filter %q: expected single ':'", entry) } k = s[0] v, err = strconv.Unquote(s[1]) if err != nil { return "", "", fmt.Errorf("unexpected format for filter %q: %s", entry, err.Error()) } return k, v, nil } } return "", "", nil }
// Iterate struct names and return a slice that contains column names. func ParseColumnNames(val interface{}) ([]string) { t := reflect.ValueOf(val).Elem() typeOfT := t.Type() var structName string = typeOfT.String() if cache, ok := columnNameCache[structName] ; ok { return cache } var columns []string for i := 0; i < t.NumField(); i++ { var tag reflect.StructTag = typeOfT.Field(i).Tag if tag.Get("field") == "-" { continue } var columnName *string = GetColumnNameFromTag(&tag) if columnName == nil { continue } columns = append(columns, *columnName) } columnNameCache[structName] = columns return columns }
// NewParamOptions returns a ParamOptions from a StructTag func NewParamOptions(tags *reflect.StructTag) *ParamOptions { output := &ParamOptions{} // We use the json tag to get the field name jsonOpts := strings.Split(tags.Get("json"), ",") if len(jsonOpts) > 0 { if jsonOpts[0] == "-" { return &ParamOptions{Ignore: true} } output.Name = jsonOpts[0] } // We parse the params opts := strings.Split(tags.Get("params"), ",") nbOptions := len(opts) for i := 0; i < nbOptions; i++ { switch opts[i] { case "required": output.Required = true case "trim": output.Trim = true } } return output }
func generateInput(tag reflect.StructTag, valueField string) (fInput string) { var extras, label string // Ignore "-" form fields if tag.Get("form") == "-" || tag.Get("form") == "" { return } fType := "text" fAttrs := strings.Split(tag.Get("attr"), ";") for _, element := range fAttrs { fAttr := strings.Split(element, ":") ele := strings.ToLower(fAttr[0]) val := "" if len(fAttr) == 2 { val = fAttr[1] } if valueField != "" && val == "input" { val = valueField } if valueField == "" && val == "input" { val = "" } switch ele { case "alt": extras += fmt.Sprintf(" alt=\"%s\"", val) case "autofocus": extras += " autofocus" case "checked": extras += " checked" case "class": extras += fmt.Sprintf(" class=\"%s\"", val) case "label": label = fmt.Sprintf("\t<label for=\"%s\">%s</label>\n", tag.Get("form"), val) case "maxlength": extras += fmt.Sprintf(" maxlength=\"%s\"", val) case "min": extras += fmt.Sprintf(" min=\"%s\"", val) case "placeholder": extras += fmt.Sprintf(" placeholder=\"%s\"", val) case "readonly": extras += " readonly" case "required": extras += " required" case "type": fType = val case "value": extras += fmt.Sprintf(" value=\"%s\"", val) } } if label != "" { fInput += label } fInput += fmt.Sprintf("\t<input type=\"%s\" name=\"%s\" id=\"%s\"%s>\n", fType, tag.Get("form"), tag.Get("form"), extras) return }
// parseTag parses "endpoints" field tag into endpointsTag struct. // // type MyMessage struct { // SomeField int `endpoints:"req,min=0,max=100,desc="Int field"` // WithDefault string `endpoints:"d=Hello gopher"` // } // // - req, required (boolean) // - d=val, default value // - min=val, min value // - max=val, max value // - desc=val, description // // It is an error to specify both default and required. func parseTag(t reflect.StructTag) (*endpointsTag, error) { eTag := &endpointsTag{} if tag := t.Get("endpoints"); tag != "" { parts := strings.Split(tag, ",") for _, k := range parts { switch k { case "req": eTag.required = true default: // key=value format kv := strings.SplitN(k, "=", 2) if len(kv) < 2 { continue } switch kv[0] { case "d": eTag.defaultVal = kv[1] case "min": eTag.minVal = kv[1] case "max": eTag.maxVal = kv[1] case "desc": eTag.desc = kv[1] } } } if eTag.required && eTag.defaultVal != "" { return nil, fmt.Errorf( "Can't have both required and default (%#v)", eTag.defaultVal) } } return eTag, nil }
func parse(r reflect.Value, node *XMLNode, tag reflect.StructTag) error { rtype := r.Type() if rtype.Kind() == reflect.Ptr { rtype = rtype.Elem() // check kind of actual element type } t := tag.Get("type") if t == "" { switch rtype.Kind() { case reflect.Struct: t = "structure" case reflect.Slice: t = "list" case reflect.Map: t = "map" } } switch t { case "structure": if field, ok := rtype.FieldByName("SDKShapeTraits"); ok { tag = field.Tag } return parseStruct(r, node, tag) case "list": return parseList(r, node, tag) case "map": return parseMap(r, node, tag) default: return parseScalar(r, node, tag) } }
func (b *xmlBuilder) buildValue(value reflect.Value, current *XMLNode, tag reflect.StructTag) error { value = elemOf(value) if !value.IsValid() { // no need to handle zero values return nil } else if tag.Get("location") != "" { // don't handle non-body location values return nil } t := tag.Get("type") if t == "" { switch value.Kind() { case reflect.Struct: t = "structure" case reflect.Slice: t = "list" case reflect.Map: t = "map" } } switch t { case "structure": if field, ok := value.Type().FieldByName("SDKShapeTraits"); ok { tag = tag + reflect.StructTag(" ") + field.Tag } return b.buildStruct(value, current, tag) case "list": return b.buildList(value, current, tag) case "map": return b.buildMap(value, current, tag) default: return b.buildScalar(value, current, tag) } }
// parseTag parses the given struct tag attached to the given // field name into a tag structure. func parseTag(rtag reflect.StructTag, fieldName string) (tag, error) { t := tag{ name: fieldName, } tagStr := rtag.Get("httprequest") if tagStr == "" { return t, nil } fields := strings.Split(tagStr, ",") if fields[0] != "" { t.name = fields[0] } for _, f := range fields[1:] { switch f { case "path": t.source = sourcePath case "form": t.source = sourceForm case "body": t.source = sourceBody default: return tag{}, fmt.Errorf("unknown tag flag %q", f) } } return t, nil }
func (source envSource) GetConfig(name string, tag reflect.StructTag) (interface{}, bool) { var varName = tag.Get("env") if varName == "" { return nil, false } return os.Getenv(varName) == "1", true }
func buildStruct(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error { if !value.IsValid() { return nil } // unwrap payloads if payload := tag.Get("payload"); payload != "" { field, _ := value.Type().FieldByName(payload) tag = field.Tag value = elemOf(value.FieldByName(payload)) if !value.IsValid() { return nil } } buf.WriteString("{") t, fields := value.Type(), []*reflect.StructField{} for i := 0; i < t.NumField(); i++ { field := t.Field(i) member := value.FieldByName(field.Name) if (member.Kind() == reflect.Ptr || member.Kind() == reflect.Slice || member.Kind() == reflect.Map) && member.IsNil() { continue // ignore unset fields } if c := field.Name[0:1]; strings.ToLower(c) == c { continue // ignore unexported fields } if field.Tag.Get("location") != "" { continue // ignore non-body elements } fields = append(fields, &field) } for i, field := range fields { member := value.FieldByName(field.Name) // figure out what this field is called name := field.Name if locName := field.Tag.Get("locationName"); locName != "" { name = locName } buf.WriteString(fmt.Sprintf("%q:", name)) err := buildAny(member, buf, field.Tag) if err != nil { return err } if i < len(fields)-1 { buf.WriteString(",") } } buf.WriteString("}") return nil }
func (w *writing) writeType(e ast.Expr, name string, tag reflect.StructTag) { switch e := e.(type) { case *ast.StructType: w.writeStruct(e, name) case *ast.SelectorExpr: pck := e.X.(*ast.Ident).Name s := e.Sel.Name w.writeNamed(pck+"."+s, name, tag) case *ast.StarExpr: w.writeType(e.X, name, tag) case *ast.Ident: w.writeNamed(e.Name, name, tag) case *ast.ArrayType: lT := tag.Get("length") if lT != "remaining" && lT != "" && lT[0] != '@' { w.writeNamed(lT, fmt.Sprintf("%s(len(%s))", lT, name), "") } if i, ok := e.Elt.(*ast.Ident); ok && (i.Name == "byte" || i.Name == "uint8") { fmt.Fprintf(&w.buf, "if _, err = ww.Write(%s); err != nil { return }\n", name) } else { iVar := w.tmp() fmt.Fprintf(&w.buf, "for %s := range %s {\n", iVar, name) w.writeType(e.Elt, fmt.Sprintf("%s[%s]", name, iVar), tag) w.buf.WriteString("}\n") } default: fmt.Fprintf(&w.buf, "// Unhandled %#v\n", e) } }
// Extract column name attribute from struct tag (the first element) of the 'field' tag or // column name from 'json' tag. func GetColumnNameFromTag(tag *reflect.StructTag) *string { var p int var tagStr string if tagStr = tag.Get("field"); len(tagStr) != 0 { // ignore it if it starts with dash if tagStr[0] == "-"[0] { return nil } if p = IndexOfChar(tagStr, ","); p != -1 { if p > 1 { str := tagStr[:p] return &str } } else { return &tagStr } } if tagStr = tag.Get("json"); len(tagStr) == 0 { return nil } if tagStr[0] == "-"[0] { return nil } if p = IndexOfChar(tagStr, ","); p != -1 { if p > 1 { str := tagStr[:p] return &str } return nil } return &tagStr }
// parseTag interprets datastore struct field tags func parseTag(t reflect.StructTag) (name string, keep bool, other interface{}, err error) { s := t.Get("datastore") parts := strings.Split(s, ",") if parts[0] == "-" && len(parts) == 1 { return "", false, nil, nil } if parts[0] != "" && !validPropertyName(parts[0]) { err = fmt.Errorf("datastore: struct tag has invalid property name: %q", parts[0]) return "", false, nil, err } var opts saveOpts if len(parts) > 1 { for _, p := range parts[1:] { switch p { case "flatten": opts.flatten = true case "omitempty": opts.omitEmpty = true case "noindex": opts.noIndex = true default: err = fmt.Errorf("datastore: struct tag has invalid option: %q", p) return "", false, nil, err } } other = opts } return parts[0], true, other, nil }
func (q *queryParser) parseList(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error { // If it's empty, generate an empty value if !value.IsNil() && value.Len() == 0 { v.Set(prefix, "") return nil } // check for unflattened list member if !q.isEC2 && tag.Get("flattened") == "" { prefix += ".member" } for i := 0; i < value.Len(); i++ { slicePrefix := prefix if slicePrefix == "" { slicePrefix = strconv.Itoa(i + 1) } else { slicePrefix = slicePrefix + "." + strconv.Itoa(i+1) } if err := q.parseValue(v, value.Index(i), slicePrefix, ""); err != nil { return err } } return nil }
func parseStrucTag(tag reflect.StructTag) *strucTag { t := &strucTag{ Order: binary.BigEndian, } tagStr := tag.Get("struc") if tagStr == "" { // someone's going to typo this (I already did once) // sorry if you made a module actually using this tag // and you're mad at me now tagStr = tag.Get("struct") } for _, s := range strings.Split(tagStr, ",") { if strings.HasPrefix(s, "sizeof=") { tmp := strings.SplitN(s, "=", 2) t.Sizeof = tmp[1] } else if s == "big" { t.Order = binary.BigEndian } else if s == "little" { t.Order = binary.LittleEndian } else { t.Type = s } } return t }
func (q *queryDecoder) decodeMap(output reflect.Value, prefix string, tag reflect.StructTag) error { // check for unflattened list member if !q.isEC2 && tag.Get("flattened") == "" { prefix += ".entry" } namer := newMapNamer(prefix, tag) mapType := output.Type() output.Set(reflect.MakeMap(mapType)) keyType := mapType.Key() valueType := mapType.Elem() for i := 0; ; i++ { keyName := namer.KeyName(i) if !q.containsPrefix(keyName) { break } key, err := q.getValue(keyName, keyType) if err != nil { return err } val, err := q.getValue(namer.ValueName(i), valueType) if err != nil { return err } output.SetMapIndex(key, val) } return nil }
func (de *Decoder) writeField(t, name string, tag reflect.StructTag) { as := tag.Get("as") if as != "" { switch as { case "json": imports["encoding/json"] = struct{}{} t := de.T() fmt.Fprintf(de.buf, `var %[1]s string if %[1]s, err = packets.ReadString(rr); err != nil { return err } if err = json.Unmarshal([]byte(%[1]s), &%[2]s); err != nil { return err } `, t, name) default: fmt.Fprintf(de.buf, "// Can't 'as' %s\n", as) } return } // TODO: For ints, unwrap binary.Read() trickery to reuse []byte tmp. switch t { case "bool": fmt.Fprintf(de.buf, "if %s, err = packets.ReadBool(rr); err != nil { return err }", name) case "int8", "uint8", "int16", "uint16", "int32", "int64", "float32", "float64": fmt.Fprintf(de.buf, errWrap("binary.Read(rr, %s, %s)", Endianness, name)) case "string": fmt.Fprintf(de.buf, "if %s, err = packets.ReadString(rr); err != nil { return err }", name) case "packets.VarInt": n := de.T() fmt.Fprintf(de.buf, "%s, err := packets.ReadVarint(rr)\n", n) fmt.Fprintf(de.buf, "if err != nil { return err }\n") fmt.Fprintf(de.buf, "%s = packets.VarInt(%s)\n", name, n) case "packets.VarLong": n := de.T() fmt.Fprintf(de.buf, "%s, err := packets.ReadVarint(rr)\n", n) fmt.Fprintf(de.buf, "if err != nil { return err }\n") fmt.Fprintf(de.buf, "%s = packets.VarLong(%s)\n", name, n) case "packets.Position", "packets.Angle": // TODO: Do we need to take &%s so it reads into var? fmt.Fprintf(de.buf, errWrap("binary.Read(rr, %s, %s)", Endianness, name)) case "packets.UUID": fmt.Fprintf(de.buf, errWrap("binary.Read(rr, %s, %s)", Endianness, name)) case "packets.Chat": // Covered by the 'as' switch above. case "packets.Chunk": fallthrough case "packets.Metadata": fallthrough case "packets.Slot": fallthrough case "packets.ObjectData": fallthrough case "packets.NBT": fallthrough default: fmt.Fprintf(de.buf, "// Unable to decode: %s (%s)", name, t) } fmt.Fprintf(de.buf, "\n") }
func (t *tag) parseJSONTag(structTag reflect.StructTag) { tagStr := structTag.Get("json") if len(tagStr) == 0 { return } t.parseTagStr(tagStr) }
func (t *tag) parseAVTag(structTag reflect.StructTag) { tagStr := structTag.Get("dynamodbav") if len(tagStr) == 0 { return } t.parseTagStr(tagStr) }
// Get the first non-empty matching tag value for given variations of a key func getTagValue(tag reflect.StructTag, keys ...string) string { for _, key := range keys { if tag.Get(key) != "" { return tag.Get(key) } } return "" }
// Extract attributes from "field" tag. // Current supported attributes: "required","primary","serial" func GetColumnAttributesFromTag(tag *reflect.StructTag) map[string]bool { fieldTags := strings.Split(tag.Get("field"), ",") attributes := map[string]bool{} for _, tag := range fieldTags[1:] { attributes[tag] = true } return attributes }
// as struct tags can continue multiple values, this gets the first func GetFirstTagValue(tag reflect.StructTag, attr string) (value string) { tagValue := tag.Get(attr) if len(tagValue) == 0 { return } value = strings.Split(tagValue, ",")[0] return }
func (en *Encoder) writeField(t, name string, tag reflect.StructTag) { as := tag.Get("as") if as != "" { switch as { case "json": imports["encoding/json"] = struct{}{} t := en.T() fmt.Fprintf(en.buf, `var %[1]s []byte if %[1]s, err = json.Marshal(&%[2]s); err != nil { return err } if err = packets.WriteString(ww, string(%[1]s)); err != nil { return err } `, t, name) default: fmt.Fprintf(en.buf, "// Can't 'as' %s\n", as) } return } // TODO: For ints, unwrap binary.Write() trickery to reuse []byte tmp. switch t { case "bool": fmt.Fprintf(en.buf, "if err = packets.WriteBool(ww, %s); err != nil { return err }", name) case "int8", "uint8", "int16", "uint16", "int32", "int64", "float32", "float64": fmt.Fprintf(en.buf, errWrap("binary.Write(ww, %s, %s)", Endianness, name)) case "string": fmt.Fprintf(en.buf, "if err = packets.WriteString(ww, %s); err != nil { return err }", name) case "packets.VarInt", "packets.VarLong": x := en.T() // []byte for varint n := en.T() // num of varint bytes // TODO: Is making a new []byte every time efficient? fmt.Fprintf(en.buf, "%s := make([]byte, binary.MaxVarintLen64)\n", x) fmt.Fprintf(en.buf, "%s := packets.PutVarint(%s, int64(%s))\n", n, x, name) fmt.Fprintf(en.buf, errWrap("binary.Write(ww, %s, %s[:%s])", Endianness, x, n)) case "packets.Position", "packets.Angle": // TODO: Do we need to convert these to an appropriate type for binary.Write()? fmt.Fprintf(en.buf, errWrap("binary.Write(ww, %s, %s)", Endianness, name)) case "packets.UUID": fmt.Fprintf(en.buf, errWrap("binary.Write(ww, %s, %s[:])", Endianness, name)) case "packets.Chat": // Covered by the 'as' switch above. case "packets.Chunk": fallthrough case "packets.Metadata": fallthrough case "packets.Slot": fallthrough case "packets.ObjectData": fallthrough case "packets.NBT": fallthrough default: fmt.Fprintf(en.buf, "// Unable to encode: %s (%s)", name, t) } fmt.Fprintf(en.buf, "\n") }
// JSONKeyMapper uses the struct tags on a conversion to determine the key value for // the other side. Use when mapping from a map[string]* to a struct or vice versa. func JSONKeyMapper(key string, sourceTag, destTag reflect.StructTag) (string, string) { if s := destTag.Get("json"); len(s) > 0 { return strings.SplitN(s, ",", 2)[0], key } if s := sourceTag.Get("json"); len(s) > 0 { return key, strings.SplitN(s, ",", 2)[0] } return key, key }
func main13() { // reflect でタグを取得 var ts = TaggedStruct{} var t reflect.Type = reflect.TypeOf(ts) var f reflect.StructField = t.Field(0) var tag reflect.StructTag = f.Tag var val string = tag.Get("json") fmt.Println(tag, val) // json:"emp_name" emp_name }
func encodeBool(b bool, st reflect.StructTag) string { v := strconv.FormatBool(b) tv := st.Get(v) if tv != "" { return tv } return v }
func getStructTag(t reflect.StructTag) (s string) { // check for tags: codec, json, in that order. // this allows seamless support for many configured structs. s = t.Get("codec") if s == "" { s = t.Get("json") } return }