github.com/alexflint/go-memdump@v1.1.0/single.go (about)

     1  package memdump
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"reflect"
     9  )
    10  
    11  // Encode writes a memdump of the provided object to output. You must
    12  // pass a pointer to the object you wish to encode.
    13  func Encode(w io.Writer, obj interface{}) error {
    14  	t := reflect.TypeOf(obj)
    15  	if t.Kind() != reflect.Ptr {
    16  		panic(fmt.Sprintf("expected a pointer but got %T", obj))
    17  	}
    18  
    19  	// write the object data to a temporary buffer
    20  	var buf bytes.Buffer
    21  	mem := newMemEncoder(&buf)
    22  	ptrs, err := mem.Encode(obj)
    23  	if err != nil {
    24  		return fmt.Errorf("error while walking data: %v", err)
    25  	}
    26  
    27  	// write the locations at the top
    28  	err = encodeLocations(w, &locations{Pointers: ptrs})
    29  	if err != nil {
    30  		return fmt.Errorf("error writing location segment: %v", err)
    31  	}
    32  
    33  	// now write the data segment
    34  	_, err = buf.WriteTo(w)
    35  	if err != nil {
    36  		return fmt.Errorf("error writing data segment: %v", err)
    37  	}
    38  
    39  	return nil
    40  }
    41  
    42  // Decode reads an object of the specified type from the input
    43  // and stores a pointer to it at the location specified by ptrptr,
    44  // which must be a pointer to a pointer. If you originally called
    45  // Encode with parameter *T then you should pass **T to Decode.
    46  func Decode(r io.Reader, ptrptr interface{}) error {
    47  	v := reflect.ValueOf(ptrptr)
    48  	t := v.Type()
    49  	if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Ptr {
    50  		panic(fmt.Sprintf("expected a pointer to a pointer but got %v", v.Type()))
    51  	}
    52  
    53  	// read the locations
    54  	var loc locations
    55  	err := decodeLocations(r, &loc)
    56  	if err != nil {
    57  		return fmt.Errorf("error decoding relocation data: %v", err)
    58  	}
    59  
    60  	buf, err := ioutil.ReadAll(r)
    61  	if err != nil {
    62  		return fmt.Errorf("error reading data segment: %v", err)
    63  	}
    64  
    65  	// relocate the data
    66  	out, err := relocate(buf, loc.Pointers, loc.Main, v.Type().Elem().Elem())
    67  	if err != nil {
    68  		return fmt.Errorf("error relocating data: %v", err)
    69  	}
    70  
    71  	v.Elem().Set(reflect.ValueOf(out))
    72  	return nil
    73  }