github.com/marinho/drone@v0.2.1-0.20140504195434-d3ba962e89a7/Godeps/_workspace/src/launchpad.net/goyaml/encode.go (about)

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