github.com/cloudwego/hertz@v0.9.3/pkg/app/server/binding/internal/decoder/reflect.go (about)

     1  /*
     2   * Copyright 2023 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   * MIT License
    16   *
    17   * Copyright (c) 2019-present Fenny and Contributors
    18   *
    19   * Permission is hereby granted, free of charge, to any person obtaining a copy
    20   * of this software and associated documentation files (the "Software"), to deal
    21   * in the Software without restriction, including without limitation the rights
    22   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    23   * copies of the Software, and to permit persons to whom the Software is
    24   * furnished to do so, subject to the following conditions:
    25   *
    26   * The above copyright notice and this permission notice shall be included in all
    27   * copies or substantial portions of the Software.
    28   *
    29   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    30   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    31   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    32   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    33   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    34   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    35   * SOFTWARE.
    36   *
    37   * This file may have been modified by CloudWeGo authors. All CloudWeGo
    38   * Modifications are Copyright 2023 CloudWeGo Authors
    39   */
    40  
    41  package decoder
    42  
    43  import (
    44  	"reflect"
    45  )
    46  
    47  // ReferenceValue convert T to *T, the ptrDepth is the count of '*'.
    48  func ReferenceValue(v reflect.Value, ptrDepth int) reflect.Value {
    49  	switch {
    50  	case ptrDepth > 0:
    51  		for ; ptrDepth > 0; ptrDepth-- {
    52  			vv := reflect.New(v.Type())
    53  			vv.Elem().Set(v)
    54  			v = vv
    55  		}
    56  	case ptrDepth < 0:
    57  		for ; ptrDepth < 0 && v.Kind() == reflect.Ptr; ptrDepth++ {
    58  			v = v.Elem()
    59  		}
    60  	}
    61  	return v
    62  }
    63  
    64  func GetNonNilReferenceValue(v reflect.Value) (reflect.Value, int) {
    65  	var ptrDepth int
    66  	t := v.Type()
    67  	elemKind := t.Kind()
    68  	for elemKind == reflect.Ptr {
    69  		t = t.Elem()
    70  		elemKind = t.Kind()
    71  		ptrDepth++
    72  	}
    73  	val := reflect.New(t).Elem()
    74  	return val, ptrDepth
    75  }
    76  
    77  func GetFieldValue(reqValue reflect.Value, parentIndex []int) reflect.Value {
    78  	// reqValue -> (***bar)(nil) need new a default
    79  	if reqValue.Kind() == reflect.Ptr && reqValue.IsNil() {
    80  		nonNilVal, ptrDepth := GetNonNilReferenceValue(reqValue)
    81  		reqValue = ReferenceValue(nonNilVal, ptrDepth)
    82  	}
    83  	for _, idx := range parentIndex {
    84  		if reqValue.Kind() == reflect.Ptr && reqValue.IsNil() {
    85  			nonNilVal, ptrDepth := GetNonNilReferenceValue(reqValue)
    86  			reqValue.Set(ReferenceValue(nonNilVal, ptrDepth))
    87  		}
    88  		for reqValue.Kind() == reflect.Ptr {
    89  			reqValue = reqValue.Elem()
    90  		}
    91  		reqValue = reqValue.Field(idx)
    92  	}
    93  
    94  	// It is possible that the parent struct is also a pointer,
    95  	// so need to create a non-nil reflect.Value for it at runtime.
    96  	for reqValue.Kind() == reflect.Ptr {
    97  		if reqValue.IsNil() {
    98  			nonNilVal, ptrDepth := GetNonNilReferenceValue(reqValue)
    99  			reqValue.Set(ReferenceValue(nonNilVal, ptrDepth))
   100  		}
   101  		reqValue = reqValue.Elem()
   102  	}
   103  
   104  	return reqValue
   105  }
   106  
   107  func getElemType(t reflect.Type) reflect.Type {
   108  	for t.Kind() == reflect.Ptr {
   109  		t = t.Elem()
   110  	}
   111  
   112  	return t
   113  }