func()

in v2/datastore/load.go [63:173]


func (l *propertyLoader) load(codec *structCodec, structValue reflect.Value, p Property, requireSlice bool) string {
	var v reflect.Value
	var sliceIndex int

	name := p.Name

	// If name ends with a '.', the last field is anonymous.
	// In this case, strings.Split will give us "" as the
	// last element of our fields slice, which will match the ""
	// field name in the substruct codec.
	fields := strings.Split(name, ".")

	for len(fields) > 0 {
		var decoder fieldCodec
		var ok bool

		// Cut off the last field (delimited by ".") and find its parent
		// in the codec.
		// eg. for name "A.B.C.D", split off "A.B.C" and try to
		// find a field in the codec with this name.
		// Loop again with "A.B", etc.
		for i := len(fields); i > 0; i-- {
			parent := strings.Join(fields[:i], ".")
			decoder, ok = codec.fields[parent]
			if ok {
				fields = fields[i:]
				break
			}
		}

		// If we never found a matching field in the codec, return
		// error message.
		if !ok {
			return "no such struct field"
		}

		v = initField(structValue, decoder.path)
		if !v.IsValid() {
			return "no such struct field"
		}
		if !v.CanSet() {
			return "cannot set struct field"
		}

		if decoder.structCodec != nil {
			codec = decoder.structCodec
			structValue = v
		}

		if v.Kind() == reflect.Slice && v.Type() != typeOfByteSlice {
			if l.m == nil {
				l.m = make(map[string]int)
			}
			sliceIndex = l.m[p.Name]
			l.m[p.Name] = sliceIndex + 1
			for v.Len() <= sliceIndex {
				v.Set(reflect.Append(v, reflect.New(v.Type().Elem()).Elem()))
			}
			structValue = v.Index(sliceIndex)
			requireSlice = false
		}
	}

	var slice reflect.Value
	if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 {
		slice = v
		v = reflect.New(v.Type().Elem()).Elem()
	} else if requireSlice {
		return "multiple-valued property requires a slice field type"
	}

	// Convert indexValues to a Go value with a meaning derived from the
	// destination type.
	pValue := p.Value
	if iv, ok := pValue.(indexValue); ok {
		meaning := pb.Property_NO_MEANING
		switch v.Type() {
		case typeOfBlobKey:
			meaning = pb.Property_BLOBKEY
		case typeOfByteSlice:
			meaning = pb.Property_BLOB
		case typeOfByteString:
			meaning = pb.Property_BYTESTRING
		case typeOfGeoPoint:
			meaning = pb.Property_GEORSS_POINT
		case typeOfTime:
			meaning = pb.Property_GD_WHEN
		case typeOfEntityPtr:
			meaning = pb.Property_ENTITY_PROTO
		}
		var err error
		pValue, err = propValue(iv.value, meaning)
		if err != nil {
			return err.Error()
		}
	}

	if errReason := setVal(v, pValue); errReason != "" {
		// Set the slice back to its zero value.
		if slice.IsValid() {
			slice.Set(reflect.Zero(slice.Type()))
		}
		return errReason
	}

	if slice.IsValid() {
		slice.Index(sliceIndex).Set(v)
	}

	return ""
}