func (e *StructEncoder) val(conv func(unsafe.Pointer, *Buffer)) {
	e.flunk()  
	e.instructions = append(e.instructions, instruction{leapFun: conv, offset: e.f.Offset})
}
val creates an instruction to read from a field we're marshaling
package jingo
import (
	"fmt"
	"reflect"
	"strings"
	"time"
	"unsafe"
)
type instruction struct {
	static  []byte                         
	kind    int                            
	offset  uintptr                        
	leapFun func(unsafe.Pointer, *Buffer)  
	fun     func(unsafe.Pointer, *Buffer)  
}
const (
	kindNormal = iota
	kindStringField
	kindStatic
	kindInt
)
type iface struct {
	Type, Data unsafe.Pointer
}
type StructEncoder struct {
	instructions []instruction        
	f            reflect.StructField  
	t            interface{}          
	i            int                  
	cb           Buffer               
	cpos         int                  
}
func (e *StructEncoder) Marshal(s interface{}, w *Buffer) {
	p := (*(*iface)(unsafe.Pointer(&s))).Data
	for i := 0; i < len(e.instructions); i++ {
		if e.instructions[i].kind == kindStatic {  
			w.Write(e.instructions[i].static)
			continue
		} else if e.instructions[i].kind == kindStringField {  
			ptrStringToBuf(unsafe.Pointer(uintptr(p)+e.instructions[i].offset), w)
			continue
		} else if e.instructions[i].kind == kindInt {  
			ptrIntToBuf(unsafe.Pointer(uintptr(p)+e.instructions[i].offset), w)
			continue
		} else if e.instructions[i].leapFun != nil {  
			e.instructions[i].leapFun(unsafe.Pointer(uintptr(p)+e.instructions[i].offset), w)
			continue
		}
		e.instructions[i].fun(p, w)  
	}
}
func NewStructEncoder(t interface{}) *StructEncoder {
	e := &StructEncoder{}
	e.t = t
	tt := reflect.TypeOf(t)
	e.chunk("{")
	emit := 0  
	for e.i = 0; e.i < tt.NumField(); e.i++ {
		e.f = tt.Field(e.i)
		tag, opts := parseTag(e.f.Tag.Get("json"))  
		if tag == "" {
			continue
		}
		emit++
		if emit > 1 {
			e.chunk(",")
		}
		e.chunk(`"` + tag + `":`)
		switch {
		case opts.Contains("stringer") && reflect.ValueOf(e.t).Field(e.i).MethodByName("String").Kind() != reflect.Invalid:
			e.optInstrStringer()
		case opts.Contains("encoder"):
			e.optInstrEncoder()
		case opts.Contains("raw"):
			e.optInstrRaw()
		case opts.Contains("escape"):
			e.optInstrEscape()
		case e.f.Type == timeType:
			e.chunk(`"`)
			e.val(ptrTimeToBuf)
			e.chunk(`"`)
		case e.f.Type.Kind() == reflect.Ptr && timeType == reflect.TypeOf(e.t).Field(e.i).Type.Elem():
			e.chunk(`"`)
			e.ptrval(ptrTimeToBuf)
			e.chunk(`"`)
		case e.f.Type.Kind() == reflect.Ptr:
			e.valueInst(e.f.Type.Elem().Kind(), e.ptrval)
		default:
			e.valueInst(e.f.Type.Kind(), e.val)
		}
	}
	e.chunk("}")
	e.flunk()
	return e
}
func (e *StructEncoder) appendInstructionFun(fun func(unsafe.Pointer, *Buffer)) {
	e.instructions = append(e.instructions, instruction{fun: fun})
}
func (e *StructEncoder) optInstrStringer() {
	e.chunk(`"`)
	t := reflect.ValueOf(e.t).Field(e.i).Type()
	if e.f.Type.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	conv := func(v unsafe.Pointer, w *Buffer) {
		e, ok := reflect.NewAt(t, v).Interface().(fmt.Stringer)
		if !ok {
			return
		}
		w.WriteString(e.String())
	}
	if e.f.Type.Kind() == reflect.Ptr {
		e.ptrval(conv)
	} else {
		e.val(conv)
	}
	e.chunk(`"`)
}
func (e *StructEncoder) optInstrEncoder() {
	t := reflect.ValueOf(e.t).Field(e.i).Type()
	if e.f.Type.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	conv := func(v unsafe.Pointer, w *Buffer) {
		e, ok := reflect.NewAt(t, v).Interface().(JSONEncoder)
		if !ok {
			w.Write(null)
			return
		}
		e.JSONEncode(w)
	}
	if e.f.Type.Kind() == reflect.Ptr {
		e.ptrval(conv)
	} else {
		e.val(conv)
	}
}
func (e *StructEncoder) optInstrRaw() {
	conv := func(v unsafe.Pointer, w *Buffer) {
		s := *(*string)(v)
		if len(s) == 0 {
			w.Write(null)
			return
		}
		w.WriteString(s)
	}
	if e.f.Type.Kind() == reflect.Ptr {
		e.ptrval(conv)
	} else {
		e.val(conv)
	}
}
func (e *StructEncoder) optInstrEscape() {
	if e.f.Type.Kind() == reflect.Slice {
		e.flunk()
		enc := NewSliceEncoder([]EscapeString{})
		f := e.f
		e.appendInstructionFun(func(v unsafe.Pointer, w *Buffer) {
			var em interface{} = unsafe.Pointer(uintptr(v) + f.Offset)
			enc.Marshal(em, w)
		})
		return
	}
	if e.f.Type.Kind() == reflect.Ptr {
		e.ptrstringval(ptrEscapeStringToBuf)
	} else {
		e.chunk(`"`)
		e.val(ptrEscapeStringToBuf)
		e.chunk(`"`)
	}
}
func (e *StructEncoder) chunk(b string) {
	e.cb.Write([]byte(b))
}
func (e *StructEncoder) flunk() {
	b := e.cb.Bytes
	bs := b[e.cpos:]
	e.cpos = len(b)
	if len(bs) == 0 {
		return
	}
	e.instructions = append(e.instructions, instruction{static: bs, kind: kindStatic})
}
func (e *StructEncoder) valueInst(k reflect.Kind, instr func(func(unsafe.Pointer, *Buffer))) {
	switch k {
	case reflect.Int:
		if e.f.Type.Kind() == reflect.Ptr {
			instr(ptrIntToBuf)
			return
		}
		e.flunk()
		e.instructions = append(e.instructions, instruction{offset: e.f.Offset, kind: kindInt})
	case reflect.Bool,
		reflect.Int8,
		reflect.Int16,
		reflect.Int32,
		reflect.Int64,
		reflect.Uint,
		reflect.Uint8,
		reflect.Uint16,
		reflect.Uint32,
		reflect.Uint64,
		reflect.Float32,
		reflect.Float64:
		conv, ok := typeconv[k]
		if !ok {
			return
		}
		instr(conv)
	case reflect.Array:
		e.chunk("[")
		conv, ok := typeconv[e.f.Type.Elem().Kind()]
		if !ok {
			return
		}
		offset := e.f.Type.Elem().Size()
		for i := 0; i < e.f.Type.Len(); i++ {
			if i > 0 {
				e.chunk(", ")
			}
			e.flunk()
			f := e.f
			i := i
			e.appendInstructionFun(func(v unsafe.Pointer, w *Buffer) {
				conv(unsafe.Pointer(uintptr(v)+f.Offset+(uintptr(i)*offset)), w)
			})
		}
		e.chunk("]")
	case reflect.Slice:
		e.flunk()
		enc := NewSliceEncoder(reflect.ValueOf(e.t).Field(e.i).Interface())
		f := e.f
		e.appendInstructionFun(func(v unsafe.Pointer, w *Buffer) {
			var em interface{} = unsafe.Pointer(uintptr(v) + f.Offset)
			enc.Marshal(em, w)
		})
	case reflect.String:
		if e.f.Type.Kind() == reflect.Ptr {
			e.ptrstringval(ptrStringToBuf)
			return
		}
		e.chunk(`"`)
		/// fast path for strings
		e.flunk() // flush any chunk data we've buffered
		e.instructions = append(e.instructions, instruction{offset: e.f.Offset, kind: kindStringField})
		e.chunk(`"`)
	case reflect.Struct:
		e.flunk()
		if e.f.Type.Kind() == reflect.Ptr {
			var inf = reflect.New(reflect.TypeOf(e.t).Field(e.i).Type.Elem()).Elem().Interface()
			enc := NewStructEncoder(inf)
			f := e.f
			e.appendInstructionFun(func(v unsafe.Pointer, w *Buffer) {
				var em interface{} = unsafe.Pointer(*(*unsafe.Pointer)(unsafe.Pointer(uintptr(v) + f.Offset)))
				if em == unsafe.Pointer(nil) {
					w.Write(null)
					return
				}
				enc.Marshal(em, w)
			})
			return
		}
		enc := NewStructEncoder(reflect.ValueOf(e.t).Field(e.i).Interface())
		f := e.f
		e.appendInstructionFun(func(v unsafe.Pointer, w *Buffer) {
			var em interface{} = unsafe.Pointer(uintptr(v) + f.Offset)
			enc.Marshal(em, w)
		})
		return
	case reflect.Invalid,
		reflect.Map,
		reflect.Interface,
		reflect.Complex64,
		reflect.Complex128,
		reflect.Chan,
		reflect.Func,
		reflect.Uintptr,
		reflect.UnsafePointer:
		panic(fmt.Sprint("unsupported type ", e.f.Type.Kind(), e.f.Name))
	}
}