github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/serializer/serializer.go (about)

     1  // Copyright 2017 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  package serializer
     5  
     6  import (
     7  	"reflect"
     8  	"strings"
     9  
    10  	"fmt"
    11  	"io"
    12  )
    13  
    14  // Write writes Go-syntax representation of v into w.
    15  // This is similar to fmt.Fprintf(w, "%#v", v), but properly handles pointers,
    16  // does not write package names before types, omits struct fields with default values,
    17  // omits type names where possible, etc. On the other hand, it currently does not
    18  // support all types (e.g. channels and maps).
    19  func Write(ww io.Writer, i interface{}) {
    20  	w := writer{ww}
    21  	v := reflect.ValueOf(i)
    22  	if v.Kind() == reflect.Slice && (v.IsNil() || v.Len() == 0) {
    23  		w.typ(v.Type())
    24  		w.string("(nil)")
    25  		return
    26  	}
    27  	w.do(v, false)
    28  }
    29  
    30  func WriteString(i interface{}) string {
    31  	var sb strings.Builder
    32  	Write(&sb, i)
    33  	return sb.String()
    34  }
    35  
    36  type writer struct {
    37  	w io.Writer
    38  }
    39  
    40  func (w *writer) do(v reflect.Value, sliceElem bool) {
    41  	switch v.Kind() {
    42  	case reflect.Ptr:
    43  		w.doPtr(v, sliceElem)
    44  	case reflect.Interface:
    45  		w.doInterface(v)
    46  	case reflect.Slice:
    47  		w.doSlice(v)
    48  	case reflect.Struct:
    49  		w.doStruct(v, sliceElem)
    50  	case reflect.Bool:
    51  		if v.Bool() {
    52  			w.string("true")
    53  		} else {
    54  			w.string("false")
    55  		}
    56  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    57  		fmt.Fprintf(w.w, "%v", v.Int())
    58  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
    59  		fmt.Fprintf(w.w, "%v", v.Uint())
    60  	case reflect.String:
    61  		fmt.Fprintf(w.w, "%q", v.String())
    62  	case reflect.Func:
    63  		if !v.IsNil() {
    64  			panic("no way to serialize funcs")
    65  		}
    66  		fmt.Fprintf(w.w, "nil")
    67  	default:
    68  		panic(fmt.Sprintf("unsupported type: %#v", v.Type().String()))
    69  	}
    70  }
    71  
    72  func (w *writer) doPtr(v reflect.Value, sliceElem bool) {
    73  	if v.IsNil() {
    74  		w.string("nil")
    75  		return
    76  	}
    77  	if !sliceElem {
    78  		w.byte('&')
    79  	}
    80  	if v.Elem().Kind() != reflect.Struct {
    81  		panic(fmt.Sprintf("only pointers to structs are supported, got %v",
    82  			v.Type().Name()))
    83  	}
    84  	w.do(v.Elem(), sliceElem)
    85  }
    86  
    87  func (w *writer) doInterface(v reflect.Value) {
    88  	if v.IsNil() {
    89  		w.string("nil")
    90  		return
    91  	}
    92  	elem := v.Elem()
    93  	// Handling of user types that has underlying primitive types. Consider:
    94  	//	type T int
    95  	//	var obj interface{} = T(42)
    96  	// T has kind reflect.Int. But if we serialize obj as just "42", it will be turned into plain int.
    97  	// Detect this case and serialize obj as "T(42)".
    98  	if (elem.Kind() == reflect.Bool || elem.Kind() == reflect.String ||
    99  		elem.Type().ConvertibleTo(reflect.TypeOf(0))) &&
   100  		strings.Contains(elem.Type().String(), ".") {
   101  		w.string(elem.Type().Name())
   102  		w.byte('(')
   103  		w.do(elem, false)
   104  		w.byte(')')
   105  		return
   106  	}
   107  	w.do(elem, false)
   108  }
   109  
   110  func (w *writer) doSlice(v reflect.Value) {
   111  	if v.IsNil() || v.Len() == 0 {
   112  		w.string("nil")
   113  		return
   114  	}
   115  	w.typ(v.Type())
   116  	sub := v.Type().Elem().Kind()
   117  	if sub == reflect.Ptr || sub == reflect.Interface || sub == reflect.Struct {
   118  		// Elem per-line.
   119  		w.string("{\n")
   120  		for i := 0; i < v.Len(); i++ {
   121  			w.do(v.Index(i), true)
   122  			w.string(",\n")
   123  		}
   124  		w.byte('}')
   125  		return
   126  	}
   127  	// All on one line.
   128  	w.byte('{')
   129  	for i := 0; i < v.Len(); i++ {
   130  		if i > 0 {
   131  			w.byte(',')
   132  		}
   133  		w.do(v.Index(i), true)
   134  	}
   135  	w.byte('}')
   136  }
   137  
   138  func (w *writer) doStruct(v reflect.Value, sliceElem bool) {
   139  	if !sliceElem {
   140  		w.string(v.Type().Name())
   141  	}
   142  	w.byte('{')
   143  	fieldNames := false
   144  	for i := 0; i < v.NumField(); i++ {
   145  		f := v.Field(i)
   146  		if isDefaultValue(f) || !f.CanSet() {
   147  			fieldNames = true
   148  			break
   149  		}
   150  	}
   151  	needComma := false
   152  	for i := 0; i < v.NumField(); i++ {
   153  		f := v.Field(i)
   154  		if fieldNames && (isDefaultValue(f) || !f.CanSet()) {
   155  			continue
   156  		}
   157  		if needComma {
   158  			w.byte(',')
   159  		}
   160  		if fieldNames {
   161  			w.string(v.Type().Field(i).Name)
   162  			w.byte(':')
   163  		}
   164  		w.do(f, false)
   165  		needComma = true
   166  	}
   167  	w.byte('}')
   168  }
   169  
   170  func (w *writer) typ(t reflect.Type) {
   171  	switch t.Kind() {
   172  	case reflect.Ptr:
   173  		w.byte('*')
   174  		w.typ(t.Elem())
   175  	case reflect.Slice:
   176  		w.string("[]")
   177  		w.typ(t.Elem())
   178  	default:
   179  		w.string(t.Name())
   180  	}
   181  }
   182  
   183  func (w *writer) string(v string) {
   184  	io.WriteString(w.w, v)
   185  }
   186  
   187  func (w *writer) byte(v byte) {
   188  	if bw, ok := w.w.(io.ByteWriter); ok {
   189  		bw.WriteByte(v)
   190  	} else {
   191  		w.w.Write([]byte{v})
   192  	}
   193  }
   194  
   195  func isDefaultValue(v reflect.Value) bool {
   196  	switch v.Kind() {
   197  	case reflect.Ptr:
   198  		return v.IsNil()
   199  	case reflect.Interface:
   200  		return v.IsNil()
   201  	case reflect.Slice:
   202  		return v.IsNil() || v.Len() == 0
   203  	case reflect.Struct:
   204  		for i := 0; i < v.NumField(); i++ {
   205  			if !isDefaultValue(v.Field(i)) {
   206  				return false
   207  			}
   208  		}
   209  		return true
   210  	case reflect.Bool:
   211  		return !v.Bool()
   212  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   213  		return v.Int() == 0
   214  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   215  		return v.Uint() == 0
   216  	case reflect.String:
   217  		return v.String() == ""
   218  	case reflect.Func:
   219  		return false
   220  	default:
   221  		return false
   222  	}
   223  }