github.com/trevoraustin/hub@v2.2.0-preview1.0.20141105230840-96d8bfc654cc+incompatible/Godeps/_workspace/src/gopkg.in/yaml.v1/encode.go (about)

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