github.com/searKing/golang/go@v1.2.117/reflect/truncate.go (about)

     1  // Copyright 2022 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package reflect
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"reflect"
    11  	"strings"
    12  
    13  	bytes_ "github.com/searKing/golang/go/bytes"
    14  	strings_ "github.com/searKing/golang/go/strings"
    15  )
    16  
    17  // TruncateString reset string, useful for dump into log if some field is huge
    18  // v is truncated in place
    19  // return interface{} same as truncated v for stream-like api
    20  func TruncateString(v any, n int) any {
    21  	return Truncate(v, func(v any) bool {
    22  		_, ok := v.(string)
    23  		return ok
    24  	}, n)
    25  }
    26  
    27  // TruncateBytes reset bytes, useful for dump into log if some field is huge
    28  // v is truncated in place
    29  // return interface{} same as truncated v for stream-like api
    30  func TruncateBytes(v any, n int) any {
    31  	return Truncate(v, func(v any) bool {
    32  		_, ok := v.([]byte)
    33  		return ok
    34  	}, n)
    35  }
    36  
    37  // Truncate reset bytes and string at each run of value c satisfying f(c), useful for dump into log if some field is huge
    38  // v is truncated in place
    39  // return interface{} same as truncated v for stream-like api
    40  func Truncate(v any, f func(v any) bool, n int) any {
    41  	truncate(reflect.ValueOf(v), f, n)
    42  	return v
    43  }
    44  
    45  func truncate(v reflect.Value, f func(v any) bool, n int) {
    46  	if !v.IsValid() {
    47  		return
    48  	}
    49  	if IsNilType(v.Type()) {
    50  		return
    51  	}
    52  
    53  	if v.CanInterface() {
    54  		vv := v.Interface()
    55  		if f(vv) {
    56  			// handle v in place, stop visit sons
    57  			if v.CanSet() {
    58  				switch vv := vv.(type) {
    59  				case []byte:
    60  					if len(vv) <= n {
    61  						break
    62  					}
    63  					var buf bytes.Buffer
    64  					buf.WriteString(fmt.Sprintf("size: %d, bytes: ", len(vv)))
    65  					buf.Write(bytes_.Truncate(vv, n))
    66  					v.SetBytes(buf.Bytes())
    67  					return
    68  				case string:
    69  					if len(vv) <= n {
    70  						break
    71  					}
    72  					var buf strings.Builder
    73  					buf.WriteString(fmt.Sprintf("size: %d, string: ", len(vv)))
    74  					buf.WriteString(strings_.Truncate(vv, n))
    75  					v.SetString(buf.String())
    76  					return
    77  				}
    78  			}
    79  			return
    80  		}
    81  	}
    82  
    83  	// handle v's sons
    84  	switch v.Kind() {
    85  	case reflect.Slice, reflect.Array:
    86  		for i := 0; i < v.Len(); i++ {
    87  			truncate(v.Index(i), f, n)
    88  		}
    89  	case reflect.Struct:
    90  		// Scan typ for fields to include.
    91  		for i := 0; i < v.NumField(); i++ {
    92  			truncate(v.Field(i), f, n)
    93  		}
    94  	case reflect.Map:
    95  		iter := v.MapRange()
    96  		for iter.Next() {
    97  			//truncate(iter.Key(), f, n) // Key of Map is not addressable
    98  			truncate(iter.Value(), f, n)
    99  		}
   100  	case reflect.Ptr:
   101  		truncate(reflect.Indirect(v), f, n)
   102  	}
   103  	return
   104  }