Add support for ,inline flag with struct values.

This also adds the code to do inlining of maps, as supported by bson
(the code was copied from mgo/bson), but it's disabled for the moment
as I'll need more time to implement it.
diff --git a/decode.go b/decode.go
index e7fb29b..15f4a04 100644
--- a/decode.go
+++ b/decode.go
@@ -445,7 +445,13 @@
 			continue
 		}
 		if info, ok := fieldsMap[name.String()]; ok {
-			d.unmarshal(n.children[i+1], out.Field(info.Num))
+			var field reflect.Value
+			if info.Inline == nil {
+				field = out.Field(info.Num)
+			} else {
+				field = out.FieldByIndex(info.Inline)
+			}
+			d.unmarshal(n.children[i+1], field)
 		}
 	}
 	return true
diff --git a/decode_test.go b/decode_test.go
index 89a9fdb..965032c 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -317,6 +317,15 @@
 			B int "-"
 		}{1, 0},
 	},
+
+	// Struct inlining
+	{
+		"a: 1\nb: 2\n",
+		&struct {
+			A int
+			C struct{ B int } `yaml:",inline"`
+		}{1, struct{ B int }{2}},
+	},
 }
 
 func (s *S) TestUnmarshal(c *C) {
diff --git a/encode.go b/encode.go
index ad7853c..6a9c8fa 100644
--- a/encode.go
+++ b/encode.go
@@ -115,7 +115,12 @@
 	}
 	e.mappingv(tag, func() {
 		for _, info := range fields.List {
-			value := in.Field(info.Num)
+			var value reflect.Value
+			if info.Inline == nil {
+				value = in.Field(info.Num)
+			} else {
+				value = in.FieldByIndex(info.Inline)
+			}
 			if info.OmitEmpty && isZero(value) {
 				continue
 			}
diff --git a/encode_test.go b/encode_test.go
index 0d34d88..ad44241 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -200,6 +200,15 @@
 		}{1, 2},
 		"a: 1\n",
 	},
+
+	// Struct inlining
+	{
+		&struct {
+			A int
+			C struct{ B int } `yaml:",inline"`
+		}{1, struct{ B int }{2}},
+		"a: 1\nb: 2\n",
+	},
 }
 
 func (s *S) TestMarshal(c *C) {
diff --git a/goyaml.go b/goyaml.go
index 1b71c8e..3981d71 100644
--- a/goyaml.go
+++ b/goyaml.go
@@ -119,6 +119,10 @@
 //     flow         Marshal using a flow style (useful for structs,
 //                  sequences and maps.
 //
+//     inline       Inline the struct it's applied to, so its fields
+//                  are processed as if they were part of the outer
+//                  struct.
+//
 // In addition, if the key is "-", the field is ignored.
 //
 // For example:
@@ -131,7 +135,7 @@
 //     goyaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
 //
 func Marshal(in interface{}) (out []byte, err error) {
-	//defer handleErr(&err)
+	defer handleErr(&err)
 	e := newEncoder()
 	defer e.destroy()
 	e.marshal("", reflect.ValueOf(in))
@@ -146,8 +150,9 @@
 // The code in this section was copied from gobson.
 
 type structFields struct {
-	Map  map[string]fieldInfo
-	List []fieldInfo
+	Map       map[string]fieldInfo
+	List      []fieldInfo
+	InlineMap int
 }
 
 type fieldInfo struct {
@@ -155,6 +160,7 @@
 	Num       int
 	OmitEmpty bool
 	Flow      bool
+	Inline    []int
 }
 
 var fieldMap = make(map[reflect.Type]*structFields)
@@ -176,7 +182,8 @@
 
 	n := st.NumField()
 	fieldsMap := make(map[string]fieldInfo)
-	fieldsList := make([]fieldInfo, n)
+	fieldsList := make([]fieldInfo, 0, n)
+	inlineMap := -1
 	for i := 0; i != n; i++ {
 		field := st.Field(i)
 		if field.PkgPath != "" {
@@ -193,24 +200,7 @@
 			continue
 		}
 
-		// XXX Drop this after a few releases.
-		if s := strings.Index(tag, "/"); s >= 0 {
-			recommend := tag[:s]
-			for _, c := range tag[s+1:] {
-				switch c {
-				case 'c':
-					recommend += ",omitempty"
-				case 'f':
-					recommend += ",flow"
-				default:
-					msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", string([]byte{uint8(c)}), tag, st)
-					panic(externalPanic(msg))
-				}
-			}
-			msg := fmt.Sprintf("Replace tag %q in field %s of type %s by %q", tag, field.Name, st, recommend)
-			panic(externalPanic(msg))
-		}
-
+		inline := false
 		fields := strings.Split(tag, ",")
 		if len(fields) > 1 {
 			for _, flag := range fields[1:] {
@@ -219,6 +209,8 @@
 					info.OmitEmpty = true
 				case "flow":
 					info.Flow = true
+				case "inline":
+					inline = true
 				default:
 					msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)
 					panic(externalPanic(msg))
@@ -227,6 +219,41 @@
 			tag = fields[0]
 		}
 
+		if inline {
+			switch field.Type.Kind() {
+			//case reflect.Map:
+			//	if inlineMap >= 0 {
+			//		return nil, errors.New("Multiple ,inline maps in struct " + st.String())
+			//	}
+			//	if field.Type.Key() != reflect.TypeOf("") {
+			//		return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
+			//	}
+			//	inlineMap = info.Num
+			case reflect.Struct:
+				sfields, err := getStructFields(field.Type)
+				if err != nil {
+					return nil, err
+				}
+				for _, finfo := range sfields.List {
+					if _, found := fieldsMap[finfo.Key]; found {
+						msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
+						return nil, errors.New(msg)
+					}
+					if finfo.Inline == nil {
+						finfo.Inline = []int{i, finfo.Num}
+					} else {
+						finfo.Inline = append([]int{i}, finfo.Inline...)
+					}
+					fieldsMap[finfo.Key] = finfo
+					fieldsList = append(fieldsList, finfo)
+				}
+			default:
+				//panic("Option ,inline needs a struct value or map field")
+				panic("Option ,inline needs a struct value field")
+			}
+			continue
+		}
+
 		if tag != "" {
 			info.Key = tag
 		} else {
@@ -238,11 +265,11 @@
 			return nil, errors.New(msg)
 		}
 
-		fieldsList[len(fieldsMap)] = info
+		fieldsList = append(fieldsList, info)
 		fieldsMap[info.Key] = info
 	}
 
-	fields = &structFields{fieldsMap, fieldsList[:len(fieldsMap)]}
+	fields = &structFields{fieldsMap, fieldsList, inlineMap}
 
 	fieldMapMutex.Lock()
 	fieldMap[st] = fields