github.com/keysonZZZ/kmg@v0.0.0-20151121023212-05317bfd7d39/encoding/kmgYaml/encode.go (about)

     1  package kmgYaml
     2  
     3  import (
     4  	"encoding"
     5  	"reflect"
     6  	"sort"
     7  	"strconv"
     8  	//"fmt"
     9  )
    10  
    11  type encoder struct {
    12  	emitter yaml_emitter_t
    13  	event   yaml_event_t
    14  	out     []byte
    15  	flow    bool
    16  }
    17  
    18  func newEncoder() (e *encoder) {
    19  	e = &encoder{}
    20  	e.must(yaml_emitter_initialize(&e.emitter))
    21  	yaml_emitter_set_output_string(&e.emitter, &e.out)
    22  	e.must(yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING))
    23  	e.emit()
    24  	e.must(yaml_document_start_event_initialize(&e.event, nil, nil, true))
    25  	e.emit()
    26  	return e
    27  }
    28  
    29  func (e *encoder) finish() {
    30  	e.must(yaml_document_end_event_initialize(&e.event, true))
    31  	e.emit()
    32  	e.emitter.open_ended = false
    33  	e.must(yaml_stream_end_event_initialize(&e.event))
    34  	e.emit()
    35  }
    36  
    37  func (e *encoder) destroy() {
    38  	yaml_emitter_delete(&e.emitter)
    39  }
    40  
    41  func (e *encoder) emit() {
    42  	// This will internally delete the e.event value.
    43  	if !yaml_emitter_emit(&e.emitter, &e.event) && e.event.typ != yaml_DOCUMENT_END_EVENT && e.event.typ != yaml_STREAM_END_EVENT {
    44  		e.must(false)
    45  	}
    46  }
    47  
    48  func (e *encoder) must(ok bool) {
    49  	if !ok {
    50  		msg := e.emitter.problem
    51  		if msg == "" {
    52  			msg = "Unknown problem generating YAML content"
    53  		}
    54  		panic(msg)
    55  	}
    56  }
    57  
    58  func (e *encoder) marshal(tag string, in reflect.Value) {
    59  	var value interface{}
    60  	if getter, ok := in.Interface().(Getter); ok {
    61  		tag, value = getter.GetYAML()
    62  		if value == nil {
    63  			e.nilv()
    64  			return
    65  		}
    66  		in = reflect.ValueOf(value)
    67  	}
    68  	if marhsaler, ok := in.Interface().(encoding.TextMarshaler); ok {
    69  		text, err := marhsaler.MarshalText()
    70  		if err != nil {
    71  			panic(err)
    72  		}
    73  		in = reflect.ValueOf(string(text))
    74  	}
    75  	switch in.Kind() {
    76  	case reflect.Interface:
    77  		if in.IsNil() {
    78  			e.nilv()
    79  		} else {
    80  			e.marshal(tag, in.Elem())
    81  		}
    82  	case reflect.Map:
    83  		e.mapv(tag, in)
    84  	case reflect.Ptr:
    85  		if in.IsNil() {
    86  			e.nilv()
    87  		} else {
    88  			e.marshal(tag, in.Elem())
    89  		}
    90  	case reflect.Array:
    91  		e.slicev(tag, in)
    92  	case reflect.Struct:
    93  		e.structv(tag, in)
    94  	case reflect.Slice:
    95  		e.slicev(tag, in)
    96  	case reflect.String:
    97  		e.stringv(tag, in)
    98  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    99  		e.intv(tag, in)
   100  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   101  		e.uintv(tag, in)
   102  	case reflect.Float32, reflect.Float64:
   103  		e.floatv(tag, in)
   104  	case reflect.Bool:
   105  		e.boolv(tag, in)
   106  	default:
   107  		panic("Can't marshal type yet: " + in.Type().String())
   108  	}
   109  }
   110  
   111  func (e *encoder) mapv(tag string, in reflect.Value) {
   112  	e.mappingv(tag, func() {
   113  		keys := keyList(in.MapKeys())
   114  		sort.Sort(keys)
   115  		for _, k := range keys {
   116  			e.marshal("", k)
   117  			e.marshal("", in.MapIndex(k))
   118  		}
   119  	})
   120  }
   121  
   122  func (e *encoder) structv(tag string, in reflect.Value) {
   123  	sinfo, err := getStructInfo(in.Type())
   124  	if err != nil {
   125  		panic(err)
   126  	}
   127  	e.mappingv(tag, func() {
   128  		for _, info := range sinfo.FieldsList {
   129  			var value reflect.Value
   130  			if info.Inline == nil {
   131  				value = in.Field(info.Num)
   132  			} else {
   133  				value = in.FieldByIndex(info.Inline)
   134  			}
   135  			if info.OmitEmpty && isZero(value) {
   136  				continue
   137  			}
   138  			e.marshal("", reflect.ValueOf(info.Key))
   139  			e.flow = info.Flow
   140  			e.marshal("", value)
   141  		}
   142  	})
   143  }
   144  
   145  func (e *encoder) mappingv(tag string, f func()) {
   146  	implicit := tag == ""
   147  	style := yaml_BLOCK_MAPPING_STYLE
   148  	if e.flow {
   149  		e.flow = false
   150  		style = yaml_FLOW_MAPPING_STYLE
   151  	}
   152  	e.must(yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
   153  	e.emit()
   154  	f()
   155  	e.must(yaml_mapping_end_event_initialize(&e.event))
   156  	e.emit()
   157  }
   158  
   159  func (e *encoder) slicev(tag string, in reflect.Value) {
   160  	implicit := tag == ""
   161  	style := yaml_BLOCK_SEQUENCE_STYLE
   162  	if e.flow {
   163  		e.flow = false
   164  		style = yaml_FLOW_SEQUENCE_STYLE
   165  	}
   166  	e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
   167  	e.emit()
   168  	n := in.Len()
   169  	for i := 0; i < n; i++ {
   170  		e.marshal("", in.Index(i))
   171  	}
   172  	e.must(yaml_sequence_end_event_initialize(&e.event))
   173  	e.emit()
   174  }
   175  
   176  func (e *encoder) stringv(tag string, in reflect.Value) {
   177  	var style yaml_scalar_style_t
   178  	s := in.String()
   179  	if rtag, _ := resolve("", s); rtag != "!!str" {
   180  		style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
   181  	} else {
   182  		style = yaml_PLAIN_SCALAR_STYLE
   183  	}
   184  	e.emitScalar(s, "", tag, style)
   185  }
   186  
   187  func (e *encoder) boolv(tag string, in reflect.Value) {
   188  	var s string
   189  	if in.Bool() {
   190  		s = "true"
   191  	} else {
   192  		s = "false"
   193  	}
   194  	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
   195  }
   196  
   197  func (e *encoder) intv(tag string, in reflect.Value) {
   198  	s := strconv.FormatInt(in.Int(), 10)
   199  	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
   200  }
   201  
   202  func (e *encoder) uintv(tag string, in reflect.Value) {
   203  	s := strconv.FormatUint(in.Uint(), 10)
   204  	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
   205  }
   206  
   207  func (e *encoder) floatv(tag string, in reflect.Value) {
   208  	// FIXME: Handle 64 bits here.
   209  	s := strconv.FormatFloat(float64(in.Float()), 'g', -1, 32)
   210  	switch s {
   211  	case "+Inf":
   212  		s = ".inf"
   213  	case "-Inf":
   214  		s = "-.inf"
   215  	case "NaN":
   216  		s = ".nan"
   217  	}
   218  	e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
   219  }
   220  
   221  func (e *encoder) nilv() {
   222  	e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE)
   223  }
   224  
   225  func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) {
   226  	implicit := tag == ""
   227  	if !implicit {
   228  		style = yaml_PLAIN_SCALAR_STYLE
   229  	}
   230  	e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style))
   231  	e.emit()
   232  }