github.com/alexflint/go-memdump@v1.1.0/descriptor.go (about) 1 package memdump 2 3 import ( 4 "fmt" 5 "reflect" 6 ) 7 8 // pointer - type 9 // slice - type 10 // array - type, length 11 // string 12 // int - size 13 // float - size 14 15 // A Descriptor describes a type such that if two types have the 16 // same descriptor then their memory layout is identical. 17 type descriptor []typ 18 19 // a class contains information about a type 20 type typ struct { 21 Kind reflect.Kind // Kind is the kind of this type 22 Size uintptr // Size is the size in bits, as per reflect.Value.Size 23 Elem int // Elem is index of the underlying type for pointers, slices, and arrays 24 Fields []field // Fields contains the fields for structs 25 } 26 27 type field struct { 28 Name string // Name is the name of this field, or its memdump tag if present 29 Offset uintptr // Offset is the position of this field relative to the beginning of the struct 30 Type int // ID is the index of the type of this field in the descripto 31 } 32 33 // descriptorsEqual compares two descriptors 34 func descriptorsEqual(a, b descriptor) bool { 35 if len(a) != len(b) { 36 return false 37 } 38 for i := range a { 39 if a[i].Kind != b[i].Kind { 40 return false 41 } 42 if a[i].Size != b[i].Size { 43 return false 44 } 45 if a[i].Elem != b[i].Elem { 46 return false 47 } 48 if len(a[i].Fields) != len(b[i].Fields) { 49 return false 50 } 51 for j := range a[i].Fields { 52 if a[i].Fields[j].Name != b[i].Fields[j].Name { 53 return false 54 } 55 if a[i].Fields[j].Offset != b[i].Fields[j].Offset { 56 return false 57 } 58 if a[i].Fields[j].Type != b[i].Fields[j].Type { 59 return false 60 } 61 } 62 } 63 return true 64 } 65 66 // describe computes the descriptor for a type 67 func describe(t reflect.Type) descriptor { 68 var nextID int 69 var desc descriptor 70 var queue []reflect.Type 71 seen := make(map[reflect.Type]int) 72 73 push := func(t reflect.Type) int { 74 if id, found := seen[t]; found { 75 return id 76 } 77 id := nextID 78 seen[t] = id 79 nextID++ 80 queue = append(queue, t) 81 return id 82 } 83 84 push(t) 85 for len(queue) > 0 { 86 cur := queue[0] 87 queue = queue[1:] 88 t := typ{ 89 Size: cur.Size(), 90 Kind: cur.Kind(), 91 } 92 93 switch cur.Kind() { 94 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map: 95 panic(fmt.Sprintf("cannot compute descriptor for %v", cur.Kind())) 96 case reflect.Array, reflect.Slice, reflect.Ptr: 97 t.Elem = push(cur.Elem()) 98 case reflect.Struct: 99 for i := 0; i < cur.NumField(); i++ { 100 f := cur.Field(i) 101 if f.Type.Size() == 0 { 102 continue 103 } 104 105 name := f.Name 106 if tag := f.Tag.Get("memdump"); tag != "" { 107 name = tag 108 } 109 t.Fields = append(t.Fields, field{ 110 Name: name, 111 Offset: f.Offset, 112 Type: push(f.Type), 113 }) 114 } 115 } 116 117 desc = append(desc, t) 118 } 119 return desc 120 }