Repository: goccy/go-yaml
Pull request #173 (2020-11-11 10:31:43)

Support MarshalWithContext and UnmarshalWithContext for passing context.Context to MarshalYAML and UnmarshalYAML
Add new APIs for passing `context.Context` to `MarshalYAML` and `UnmarshalYAML` .

- `yaml.MarshalWithContext(ctx context.Context, v interface{}, opts ...EncodeOption) ([]byte, error)`
- `yaml.UnmarshalWithContext(ctx context.Context, b []byte, v interface{}, opts ...DecodeOption) error`




Patch:
diff --git a/decode.go b/decode.go
index e310d8e..4c9fff1 100644
--- a/decode.go
+++ b/decode.go
@@ -2,6 +2,7 @@ package yaml
 
 import (
 	"bytes"
+	"context"
 	"encoding"
 	"encoding/base64"
 	"fmt"
@@ -493,26 +494,67 @@ type jsonUnmarshaler interface {
 	UnmarshalJSON([]byte) error
 }
 
-func (d *Decoder) decodeValue(dst reflect.Value, src ast.Node) error {
-	if src.Type() == ast.AnchorType {
-		anchorName := src.(*ast.AnchorNode).Name.GetToken().Value
-		if _, exists := d.anchorValueMap[anchorName]; !exists {
-			d.anchorValueMap[anchorName] = dst
+func (d *Decoder) canDecodeByUnmarshaler(dst reflect.Value) bool {
+	iface := dst.Addr().Interface()
+	switch iface.(type) {
+	case BytesUnmarshalerContext:
+		return true
+	case BytesUnmarshaler:
+		return true
+	case InterfaceUnmarshalerContext:
+		return true
+	case InterfaceUnmarshaler:
+		return true
+	case *time.Time:
+		return true
+	case encoding.TextUnmarshaler:
+		return true
+	case jsonUnmarshaler:
+		return d.useJSONUnmarshaler
+	}
+	return false
+}
+
+func (d *Decoder) decodeByUnmarshaler(ctx context.Context, dst reflect.Value, src ast.Node) error {
+	iface := dst.Addr().Interface()
+
+	if unmarshaler, ok := iface.(BytesUnmarshalerContext); ok {
+		if err := unmarshaler.UnmarshalYAML(ctx, d.unmarshalableDocument(src)); err != nil {
+			return errors.Wrapf(err, "failed to UnmarshalYAML")
 		}
+		return nil
 	}
-	valueType := dst.Type()
-	if unmarshaler, ok := dst.Addr().Interface().(BytesUnmarshaler); ok {
+
+	if unmarshaler, ok := iface.(BytesUnmarshaler); ok {
 		if err := unmarshaler.UnmarshalYAML(d.unmarshalableDocument(src)); err != nil {
 			return errors.Wrapf(err, "failed to UnmarshalYAML")
 		}
 		return nil
-	} else if unmarshaler, ok := dst.Addr().Interface().(InterfaceUnmarshaler); ok {
+	}
+
+	if unmarshaler, ok := iface.(InterfaceUnmarshalerContext); ok {
+		if err := unmarshaler.UnmarshalYAML(ctx, func(v interface{}) error {
+			rv := reflect.ValueOf(v)
+			if rv.Type().Kind() != reflect.Ptr {
+				return errors.ErrDecodeRequiredPointerType
+			}
+			if err := d.decodeValue(ctx, rv.Elem(), src); err != nil {
+				return errors.Wrapf(err, "failed to decode value")
+			}
+			return nil
+		}); err != nil {
+			return errors.Wrapf(err, "failed to UnmarshalYAML")
+		}
+		return nil
+	}
+
+	if unmarshaler, ok := iface.(InterfaceUnmarshaler); ok {
 		if err := unmarshaler.UnmarshalYAML(func(v interface{}) error {
 			rv := reflect.ValueOf(v)
 			if rv.Type().Kind() != reflect.Ptr {
 				return errors.ErrDecodeRequiredPointerType
 			}
-			if err := d.decodeValue(rv.Elem(), src); err != nil {
+			if err := d.decodeValue(ctx, rv.Elem(), src); err != nil {
 				return errors.Wrapf(err, "failed to decode value")
 			}
 			return nil
@@ -520,9 +562,13 @@ func (d *Decoder) decodeValue(dst reflect.Value, src ast.Node) error {
 			return errors.Wrapf(err, "failed to UnmarshalYAML")
 		}
 		return nil
-	} else if _, ok := dst.Addr().Interface().(*time.Time); ok {
-		return d.decodeTime(dst, src)
-	} else if unmarshaler, isText := dst.Addr().Interface().(encoding.TextUnmarshaler); isText {
+	}
+
+	if _, ok := iface.(*time.Time); ok {
+		return d.decodeTime(ctx, dst, src)
+	}
+
+	if unmarshaler, isText := iface.(encoding.TextUnmarshaler); isText {
 		b, ok := d.unmarshalableText(src)
 		if ok {
 			if err := unmarshaler.UnmarshalText(b); err != nil {
@@ -530,8 +576,10 @@ func (d *Decoder) decodeValue(dst reflect.Value, src ast.Node) error {
 			}
 			return nil
 		}
-	} else if d.useJSONUnmarshaler {
-		if unmarshaler, ok := dst.Addr().Interface().(jsonUnmarshaler); ok {
+	}
+
+	if d.useJSONUnmarshaler {
+		if unmarshaler, ok := iface.(jsonUnmarshaler); ok {
 			jsonBytes, err := YAMLToJSON(d.unmarshalableDocument(src))
 			if err != nil {
 				return errors.Wrapf(err, "failed to convert yaml to json")
@@ -543,6 +591,24 @@ func (d *Decoder) decodeValue(dst reflect.Value, src ast.Node) error {
 			return nil
 		}
 	}
+
+	return xerrors.Errorf("does not implemented Unmarshaler")
+}
+
+func (d *Decoder) decodeValue(ctx context.Context, dst reflect.Value, src ast.Node) error {
+	if src.Type() == ast.AnchorType {
+		anchorName := src.(*ast.AnchorNode).Name.GetToken().Value
+		if _, exists := d.anchorValueMap[anchorName]; !exists {
+			d.anchorValueMap[anchorName] = dst
+		}
+	}
+	if d.canDecodeByUnmarshaler(dst) {
+		if err := d.decodeByUnmarshaler(ctx, dst, src); err != nil {
+			return errors.Wrapf(err, "failed to decode by unmarshaler")
+		}
+		return nil
+	}
+	valueType := dst.Type()
 	switch valueType.Kind() {
 	case reflect.Ptr:
 		if dst.IsNil() {
@@ -554,7 +620,7 @@ func (d *Decoder) decodeValue(dst reflect.Value, src ast.Node) error {
 			return nil
 		}
 		v := d.createDecodableValue(dst.Type())
-		if err := d.decodeValue(v, src); err != nil {
+		if err := d.decodeValue(ctx, v, src); err != nil {
 			return errors.Wrapf(err, "failed to decode ptr value")
 		}
 		dst.Set(d.castToAssignableValue(v, dst.Type()))
@@ -564,19 +630,19 @@ func (d *Decoder) decodeValue(dst reflect.Value, src ast.Node) error {
 			dst.Set(v)
 		}
 	case reflect.Map:
-		return d.decodeMap(dst, src)
+		return d.decodeMap(ctx, dst, src)
 	case reflect.Array:
-		return d.decodeArray(dst, src)
+		return d.decodeArray(ctx, dst, src)
 	case reflect.Slice:
 		if mapSlice, ok := dst.Addr().Interface().(*MapSlice); ok {
-			return d.decodeMapSlice(mapSlice, src)
+			return d.decodeMapSlice(ctx, mapSlice, src)
 		}
-		return d.decodeSlice(dst, src)
+		return d.decodeSlice(ctx, dst, src)
 	case reflect.Struct:
 		if mapItem, ok := dst.Addr().Interface().(*MapItem); ok {
-			return d.decodeMapItem(mapItem, src)
+			return d.decodeMapItem(ctx, mapItem, src)
 		}
-		return d.decodeStruct(dst, src)
+		return d.decodeStruct(ctx, dst, src)
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 		v := d.nodeToValue(src)
 		switch vv := v.(type) {
@@ -663,7 +729,7 @@ func (d *Decoder) castToAssignableValue(value reflect.Value, target reflect.Type
 	return value
 }
 
-func (d *Decoder) createDecodedNewValue(typ reflect.Type, node ast.Node) (reflect.Value, error) {
+func (d *Decoder) createDecodedNewValue(ctx context.Context, typ reflect.Type, node ast.Node) (reflect.Value, error) {
 	if node.Type() == ast.AliasType {
 		aliasName := node.(*ast.AliasNode).Value.GetToken().Value
 		newValue := d.anchorValueMap[aliasName]
@@ -675,7 +741,7 @@ func (d *Decoder) createDecodedNewValue(typ reflect.Type, node ast.Node) (reflec
 		return reflect.Zero(typ), nil
 	}
 	newValue := d.createDecodableValue(typ)
-	if err := d.decodeValue(newValue, node); err != nil {
+	if err := d.decodeValue(ctx, newValue, node); err != nil {
 		return newValue, errors.Wrapf(err, "failed to decode value")
 	}
 	return newValue, nil
@@ -797,7 +863,7 @@ func (d *Decoder) castToTime(src ast.Node) (time.Time, error) {
 	return time.Time{}, nil
 }
 
-func (d *Decoder) decodeTime(dst reflect.Value, src ast.Node) error {
+func (d *Decoder) decodeTime(ctx context.Context, dst reflect.Value, src ast.Node) error {
 	t, err := d.castToTime(src)
 	if err != nil {
 		return err
@@ -826,7 +892,7 @@ func (d *Decoder) getMergeAliasName(src ast.Node) string {
 	return ""
 }
 
-func (d *Decoder) decodeStruct(dst reflect.Value, src ast.Node) error {
+func (d *Decoder) decodeStruct(ctx context.Context, dst reflect.Value, src ast.Node) error {
 	if src == nil {
 		return nil
 	}
@@ -881,7 +947,7 @@ func (d *Decoder) decodeStruct(dst reflect.Value, src ast.Node) error {
 				key := &ast.StringNode{BaseNode: &ast.BaseNode{}, Value: k}
 				mapNode.Values = append(mapNode.Values, ast.MappingValue(nil, key, v))
 			}
-			newFieldValue, err := d.createDecodedNewValue(fieldValue.Type(), mapNode)
+			newFieldValue, err := d.createDecodedNewValue(ctx, fieldValue.Type(), mapNode)
 			if d.disallowUnknownField {
 				var ufe *unknownFieldError
 				if xerrors.As(err, &ufe) {
@@ -928,7 +994,7 @@ func (d *Decoder) decodeStruct(dst reflect.Value, src ast.Node) error {
 			fieldValue.Set(reflect.Zero(fieldValue.Type()))
 			continue
 		}
-		newFieldValue, err := d.createDecodedNewValue(fieldValue.Type(), v)
+		newFieldValue, err := d.createDecodedNewValue(ctx, fieldValue.Type(), v)
 		if err != nil {
 			if foundErr != nil {
 				continue
@@ -981,7 +1047,7 @@ func (d *Decoder) decodeStruct(dst reflect.Value, src ast.Node) error {
 	return nil
 }
 
-func (d *Decoder) decodeArray(dst reflect.Value, src ast.Node) error {
+func (d *Decoder) decodeArray(ctx context.Context, dst reflect.Value, src ast.Node) error {
 	arrayNode, err := d.getArrayNode(src)
 	if err != nil {
 		return errors.Wrapf(err, "failed to get array node")
@@ -1002,7 +1068,7 @@ func (d *Decoder) decodeArray(dst reflect.Value, src ast.Node) error {
 			// set nil value to pointer
 			arrayValue.Index(idx).Set(reflect.Zero(elemType))
 		} else {
-			dstValue, err := d.createDecodedNewValue(elemType, v)
+			dstValue, err := d.createDecodedNewValue(ctx, elemType, v)
 			if err != nil {
 				if foundErr == nil {
 					foundErr = err
@@ -1021,7 +1087,7 @@ func (d *Decoder) decodeArray(dst reflect.Value, src ast.Node) error {
 	return nil
 }
 
-func (d *Decoder) decodeSlice(dst reflect.Value, src ast.Node) error {
+func (d *Decoder) decodeSlice(ctx context.Context, dst reflect.Value, src ast.Node) error {
 	arrayNode, err := d.getArrayNode(src)
 	if err != nil {
 		return errors.Wrapf(err, "failed to get array node")
@@ -1042,7 +1108,7 @@ func (d *Decoder) decodeSlice(dst reflect.Value, src ast.Node) error {
 			sliceValue = reflect.Append(sliceValue, reflect.Zero(elemType))
 			continue
 		}
-		dstValue, err := d.createDecodedNewValue(elemType, v)
+		dstValue, err := d.createDecodedNewValue(ctx, elemType, v)
 		if err != nil {
 			if foundErr == nil {
 				foundErr = err
@@ -1058,7 +1124,7 @@ func (d *Decoder) decodeSlice(dst reflect.Value, src ast.Node) error {
 	return nil
 }
 
-func (d *Decoder) decodeMapItem(dst *MapItem, src ast.Node) error {
+func (d *Decoder) decodeMapItem(ctx context.Context, dst *MapItem, src ast.Node) error {
 	mapNode, err := d.getMapNode(src)
 	if err != nil {
 		return errors.Wrapf(err, "failed to get map node")
@@ -1073,7 +1139,7 @@ func (d *Decoder) decodeMapItem(dst *MapItem, src ast.Node) error {
 	key := mapIter.Key()
 	value := mapIter.Value()
 	if key.Type() == ast.MergeKeyType {
-		if err := d.decodeMapItem(dst, value); err != nil {
+		if err := d.decodeMapItem(ctx, dst, value); err != nil {
 			return errors.Wrapf(err, "failed to decode map with merge key")
 		}
 		return nil
@@ -1099,7 +1165,7 @@ func (d *Decoder) validateDuplicateKey(keyMap map[string]struct{}, key interface
 	return nil
 }
 
-func (d *Decoder) decodeMapSlice(dst *MapSlice, src ast.Node) error {
+func (d *Decoder) decodeMapSlice(ctx context.Context, dst *MapSlice, src ast.Node) error {
 	mapNode, err := d.getMapNode(src)
 	if err != nil {
 		return errors.Wrapf(err, "failed to get map node")
@@ -1115,7 +1181,7 @@ func (d *Decoder) decodeMapSlice(dst *MapSlice, src ast.Node) error {
 		value := mapIter.Value()
 		if key.Type() == ast.MergeKeyType {
 			var m MapSlice
-			if err := d.decodeMapSlice(&m, value); err != nil {
+			if err := d.decodeMapSlice(ctx, &m, value); err != nil {
 				return errors.Wrapf(err, "failed to decode map with merge key")
 			}
 			for _, v := range m {
@@ -1139,7 +1205,7 @@ func (d *Decoder) decodeMapSlice(dst *MapSlice, src ast.Node) error {
 	return nil
 }
 
-func (d *Decoder) decodeMap(dst reflect.Value, src ast.Node) error {
+func (d *Decoder) decodeMap(ctx context.Context, dst reflect.Value, src ast.Node) error {
 	mapNode, err := d.getMapNode(src)
 	if err != nil {
 		return errors.Wrapf(err, "failed to get map node")
@@ -1158,7 +1224,7 @@ func (d *Decoder) decodeMap(dst reflect.Value, src ast.Node) error {
 		key := mapIter.Key()
 		value := mapIter.Value()
 		if key.Type() == ast.MergeKeyType {
-			if err := d.decodeMap(dst, value); err != nil {
+			if err := d.decodeMap(ctx, dst, value); err != nil {
 				return errors.Wrapf(err, "failed to decode map with merge key")
 			}
 			iter := dst.MapRange()
@@ -1184,7 +1250,7 @@ func (d *Decoder) decodeMap(dst reflect.Value, src ast.Node) error {
 			mapValue.SetMapIndex(k, reflect.Zero(valueType))
 			continue
 		}
-		dstValue, err := d.createDecodedNewValue(valueType, value)
+		dstValue, err := d.createDecodedNewValue(ctx, valueType, value)
 		if err != nil {
 			if foundErr == nil {
 				foundErr = err
@@ -1341,7 +1407,7 @@ func (d *Decoder) decodeInit() error {
 	return nil
 }
 
-func (d *Decoder) decode(v reflect.Value) error {
+func (d *Decoder) decode(ctx context.Context, v reflect.Value) error {
 	if len(d.parsedFile.Docs) <= d.streamIndex {
 		return io.EOF
 	}
@@ -1349,7 +1415,7 @@ func (d *Decoder) decode(v reflect.Value) error {
 	if body == nil {
 		return nil
 	}
-	if err := d.decodeValue(v.Elem(), body); err != nil {
+	if err := d.decodeValue(ctx, v.Elem(), body); err != nil {
 		return errors.Wrapf(err, "failed to decode value")
 	}
 	d.streamIndex++
@@ -1362,12 +1428,18 @@ func (d *Decoder) decode(v reflect.Value) error {
 // See the documentation for Unmarshal for details about the
 // conversion of YAML into a Go value.
 func (d *Decoder) Decode(v interface{}) error {
+	return d.DecodeContext(context.Background(), v)
+}
+
+// DecodeContext reads the next YAML-encoded value from its input
+// and stores it in the value pointed to by v with context.Context.
+func (d *Decoder) DecodeContext(ctx context.Context, v interface{}) error {
 	rv := reflect.ValueOf(v)
 	if rv.Type().Kind() != reflect.Ptr {
 		return errors.ErrDecodeRequiredPointerType
 	}
 	if d.isInitialized() {
-		if err := d.decode(rv); err != nil {
+		if err := d.decode(ctx, rv); err != nil {
 			if err == io.EOF {
 				return err
 			}
@@ -1378,7 +1450,7 @@ func (d *Decoder) Decode(v interface{}) error {
 	if err := d.decodeInit(); err != nil {
 		return errors.Wrapf(err, "failed to decodInit")
 	}
-	if err := d.decode(rv); err != nil {
+	if err := d.decode(ctx, rv); err != nil {
 		if err == io.EOF {
 			return err
 		}
diff --git a/encode.go b/encode.go
index 9bcd7ec..d6c53d7 100644
--- a/encode.go
+++ b/encode.go
@@ -1,6 +1,7 @@
 package yaml
 
 import (
+	"context"
 	"encoding"
 	"fmt"
 	"io"
@@ -69,7 +70,12 @@ func (e *Encoder) Close() error {
 //
 // See the documentation for Marshal for details about the conversion of Go values to YAML.
 func (e *Encoder) Encode(v interface{}) error {
-	node, err := e.EncodeToNode(v)
+	return e.EncodeContext(context.Background(), v)
+}
+
+// EncodeContext writes the YAML encoding of v to the stream with context.Context.
+func (e *Encoder) EncodeContext(ctx context.Context, v interface{}) error {
+	node, err := e.EncodeToNodeContext(ctx, v)
 	if err != nil {
 		return errors.Wrapf(err, "failed to encode to node")
 	}
@@ -80,12 +86,17 @@ func (e *Encoder) Encode(v interface{}) error {
 
 // EncodeToNode convert v to ast.Node.
 func (e *Encoder) EncodeToNode(v interface{}) (ast.Node, error) {
+	return e.EncodeToNodeContext(context.Background(), v)
+}
+
+// EncodeToNodeContext convert v to ast.Node with context.Context.
+func (e *Encoder) EncodeToNodeContext(ctx context.Context, v interface{}) (ast.Node, error) {
 	for _, opt := range e.opts {
 		if err := opt(e); err != nil {
 			return nil, errors.Wrapf(err, "failed to run option for encoder")
 		}
 	}
-	node, err := e.encodeValue(reflect.ValueOf(v), 1)
+	node, err := e.encodeValue(ctx, reflect.ValueOf(v), 1)
 	if err != nil {
 		return nil, errors.Wrapf(err, "failed to encode value")
 	}
@@ -123,58 +134,121 @@ type jsonMarshaler interface {
 	MarshalJSON() ([]byte, error)
 }
 
-func (e *Encoder) encodeValue(v reflect.Value, column int) (ast.Node, error) {
-	if e.isInvalidValue(v) {
-		return e.encodeNil(), nil
+func (e *Encoder) canEncodeByMarshaler(v reflect.Value) bool {
+	if !v.CanInterface() {
+		return false
 	}
-	if v.CanInterface() {
-		iface := v.Interface()
-		if marshaler, ok := iface.(BytesMarshaler); ok {
-			doc, err := marshaler.MarshalYAML()
-			if err != nil {
-				return nil, errors.Wrapf(err, "failed to MarshalYAML")
-			}
-			node, err := e.encodeDocument(doc)
-			if err != nil {
-				return nil, errors.Wrapf(err, "failed to encode document")
-			}
-			return node, nil
-		} else if marshaler, ok := iface.(InterfaceMarshaler); ok {
-			marshalV, err := marshaler.MarshalYAML()
+	iface := v.Interface()
+	switch iface.(type) {
+	case BytesMarshalerContext:
+		return true
+	case BytesMarshaler:
+		return true
+	case InterfaceMarshalerContext:
+		return true
+	case InterfaceMarshaler:
+		return true
+	case time.Time:
+		return true
+	case encoding.TextMarshaler:
+		return true
+	case jsonMarshaler:
+		return e.useJSONMarshaler
+	}
+	return false
+}
+
+func (e *Encoder) encodeByMarshaler(ctx context.Context, v reflect.Value, column int) (ast.Node, error) {
+	iface := v.Interface()
+
+	if marshaler, ok := iface.(BytesMarshalerContext); ok {
+		doc, err := marshaler.MarshalYAML(ctx)
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to MarshalYAML")
+		}
+		node, err := e.encodeDocument(doc)
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to encode document")
+		}
+		return node, nil
+	}
+
+	if marshaler, ok := iface.(BytesMarshaler); ok {
+		doc, err := marshaler.MarshalYAML()
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to MarshalYAML")
+		}
+		node, err := e.encodeDocument(doc)
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to encode document")
+		}
+		return node, nil
+	}
+
+	if marshaler, ok := iface.(InterfaceMarshalerContext); ok {
+		marshalV, err := marshaler.MarshalYAML(ctx)
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to MarshalYAML")
+		}
+		return e.encodeValue(ctx, reflect.ValueOf(marshalV), column)
+	}
+
+	if marshaler, ok := iface.(InterfaceMarshaler); ok {
+		marshalV, err := marshaler.MarshalYAML()
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to MarshalYAML")
+		}
+		return e.encodeValue(ctx, reflect.ValueOf(marshalV), column)
+	}
+
+	if t, ok := iface.(time.Time); ok {
+		return e.encodeTime(t, column), nil
+	}
+
+	if marshaler, ok := iface.(encoding.TextMarshaler); ok {
+		doc, err := marshaler.MarshalText()
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to MarshalText")
+		}
+		node, err := e.encodeDocument(doc)
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to encode document")
+		}
+		return node, nil
+	}
+
+	if e.useJSONMarshaler {
+		if marshaler, ok := iface.(jsonMarshaler); ok {
+			jsonBytes, err := marshaler.MarshalJSON()
 			if err != nil {
-				return nil, errors.Wrapf(err, "failed to MarshalYAML")
+				return nil, errors.Wrapf(err, "failed to MarshalJSON")
 			}
-			return e.encodeValue(reflect.ValueOf(marshalV), column)
-		} else if t, ok := iface.(time.Time); ok {
-			return e.encodeTime(t, column), nil
-		} else if marshaler, ok := iface.(encoding.TextMarshaler); ok {
-			doc, err := marshaler.MarshalText()
+			doc, err := JSONToYAML(jsonBytes)
 			if err != nil {
-				return nil, errors.Wrapf(err, "failed to MarshalText")
+				return nil, errors.Wrapf(err, "failed to convert json to yaml")
 			}
 			node, err := e.encodeDocument(doc)
 			if err != nil {
 				return nil, errors.Wrapf(err, "failed to encode document")
 			}
 			return node, nil
-		} else if e.useJSONMarshaler {
-			if marshaler, ok := iface.(jsonMarshaler); ok {
-				jsonBytes, err := marshaler.MarshalJSON()
-				if err != nil {
-					return nil, errors.Wrapf(err, "failed to MarshalJSON")
-				}
-				doc, err := JSONToYAML(jsonBytes)
-				if err != nil {
-					return nil, errors.Wrapf(err, "failed to convert json to yaml")
-				}
-				node, err := e.encodeDocument(doc)
-				if err != nil {
-					return nil, errors.Wrapf(err, "failed to encode document")
-				}
-				return node, nil
-			}
 		}
 	}
+
+	return nil, xerrors.Errorf("does not implemented Marshaler")
+}
+
+func (e *Encoder) encodeValue(ctx context.Context, v reflect.Value, column int) (ast.Node, error) {
+	if e.isInvalidValue(v) {
+		return e.encodeNil(), nil
+	}
+	if e.canEncodeByMarshaler(v) {
+		node, err := e.encodeByMarshaler(ctx, v, column)
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to encode by marshaler")
+		}
+		return node, nil
+	}
 	switch v.Type().Kind() {
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 		return e.encodeInt(v.Int()), nil
@@ -190,30 +264,30 @@ func (e *Encoder) encodeValue(v reflect.Value, column int) (ast.Node, error) {
 			alias.Value = ast.String(token.New(aliasName, aliasName, e.pos(column)))
 			return alias, nil
 		}
-		return e.encodeValue(v.Elem(), column)
+		return e.encodeValue(ctx, v.Elem(), column)
 	case reflect.Interface:
-		return e.encodeValue(v.Elem(), column)
+		return e.encodeValue(ctx, v.Elem(), column)
 	case reflect.String:
 		return e.encodeString(v.String(), column), nil
 	case reflect.Bool:
 		return e.encodeBool(v.Bool()), nil
 	case reflect.Slice:
 		if mapSlice, ok := v.Interface().(MapSlice); ok {
-			return e.encodeMapSlice(mapSlice, column)
+			return e.encodeMapSlice(ctx, mapSlice, column)
 		}
-		return e.encodeSlice(v)
+		return e.encodeSlice(ctx, v)
 	case reflect.Struct:
 		if v.CanInterface() {
 			if mapItem, ok := v.Interface().(MapItem); ok {
-				return e.encodeMapItem(mapItem, column)
+				return e.encodeMapItem(ctx, mapItem, column)
 			}
 			if t, ok := v.Interface().(time.Time); ok {
 				return e.encodeTime(t, column), nil
 			}
 		}
-		return e.encodeStruct(v, column)
+		return e.encodeStruct(ctx, v, column)
 	case reflect.Map:
-		return e.encodeMap(v, column), nil
+		return e.encodeMap(ctx, v, column), nil
 	default:
 		return nil, xerrors.Errorf("unknown value type %s", v.Type().String())
 	}
@@ -284,10 +358,10 @@ func (e *Encoder) encodeBool(v bool) ast.Node {
 	return ast.Bool(token.New(value, value, e.pos(e.column)))
 }
 
-func (e *Encoder) encodeSlice(value reflect.Value) (ast.Node, error) {
+func (e *Encoder) encodeSlice(ctx context.Context, value reflect.Value) (ast.Node, error) {
 	sequence := ast.Sequence(token.New("-", "-", e.pos(e.column)), e.isFlowStyle)
 	for i := 0; i < value.Len(); i++ {
-		node, err := e.encodeValue(value.Index(i), e.column)
+		node, err := e.encodeValue(ctx, value.Index(i), e.column)
 		if err != nil {
 			return nil, errors.Wrapf(err, "failed to encode value for slice")
 		}
@@ -296,10 +370,10 @@ func (e *Encoder) encodeSlice(value reflect.Value) (ast.Node, error) {
 	return sequence, nil
 }
 
-func (e *Encoder) encodeMapItem(item MapItem, column int) (*ast.MappingValueNode, error) {
+func (e *Encoder) encodeMapItem(ctx context.Context, item MapItem, column int) (*ast.MappingValueNode, error) {
 	k := reflect.ValueOf(item.Key)
 	v := reflect.ValueOf(item.Value)
-	value, err := e.encodeValue(v, column)
+	value, err := e.encodeValue(ctx, v, column)
 	if err != nil {
 		return nil, errors.Wrapf(err, "failed to encode MapItem")
 	}
@@ -313,10 +387,10 @@ func (e *Encoder) encodeMapItem(item MapItem, column int) (*ast.MappingValueNode
 	), nil
 }
 
-func (e *Encoder) encodeMapSlice(value MapSlice, column int) (ast.Node, error) {
+func (e *Encoder) encodeMapSlice(ctx context.Context, value MapSlice, column int) (ast.Node, error) {
 	node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
 	for _, item := range value {
-		value, err := e.encodeMapItem(item, column)
+		value, err := e.encodeMapItem(ctx, item, column)
 		if err != nil {
 			return nil, errors.Wrapf(err, "failed to encode MapItem for MapSlice")
 		}
@@ -325,7 +399,7 @@ func (e *Encoder) encodeMapSlice(value MapSlice, column int) (ast.Node, error) {
 	return node, nil
 }
 
-func (e *Encoder) encodeMap(value reflect.Value, column int) ast.Node {
+func (e *Encoder) encodeMap(ctx context.Context, value reflect.Value, column int) ast.Node {
 	node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
 	keys := []string{}
 	for _, k := range value.MapKeys() {
@@ -335,7 +409,7 @@ func (e *Encoder) encodeMap(value reflect.Value, column int) ast.Node {
 	for _, key := range keys {
 		k := reflect.ValueOf(key)
 		v := value.MapIndex(k)
-		value, err := e.encodeValue(v, column)
+		value, err := e.encodeValue(ctx, v, column)
 		if err != nil {
 			return nil
 		}
@@ -424,7 +498,7 @@ func (e *Encoder) encodeAnchor(anchorName string, value ast.Node, fieldValue ref
 	return anchorNode, nil
 }
 
-func (e *Encoder) encodeStruct(value reflect.Value, column int) (ast.Node, error) {
+func (e *Encoder) encodeStruct(ctx context.Context, value reflect.Value, column int) (ast.Node, error) {
 	node := ast.Mapping(token.New("", "", e.pos(column)), e.isFlowStyle)
 	structType := value.Type()
 	structFieldMap, err := structFieldMap(structType)
@@ -444,7 +518,7 @@ func (e *Encoder) encodeStruct(value reflect.Value, column int) (ast.Node, error
 			// omit encoding
 			continue
 		}
-		value, err := e.encodeValue(fieldValue, column)
+		value, err := e.encodeValue(ctx, fieldValue, column)
 		if err != nil {
 			return nil, errors.Wrapf(err, "failed to encode value")
 		}
diff --git a/yaml.go b/yaml.go
index 8f56c71..ad404cf 100644
--- a/yaml.go
+++ b/yaml.go
@@ -2,6 +2,7 @@ package yaml
 
 import (
 	"bytes"
+	"context"
 	"io"
 
 	"github.com/goccy/go-yaml/ast"
@@ -19,22 +20,42 @@ type BytesMarshaler interface {
 	MarshalYAML() ([]byte, error)
 }
 
+// BytesMarshalerContext interface use BytesMarshaler with context.Context.
+type BytesMarshalerContext interface {
+	MarshalYAML(context.Context) ([]byte, error)
+}
+
 // InterfaceMarshaler interface has MarshalYAML compatible with github.com/go-yaml/yaml package.
 type InterfaceMarshaler interface {
 	MarshalYAML() (interface{}, error)
 }
 
+// InterfaceMarshalerContext interface use InterfaceMarshaler with context.Context.
+type InterfaceMarshalerContext interface {
+	MarshalYAML(context.Context) (interface{}, error)
+}
+
 // BytesUnmarshaler interface may be implemented by types to customize their
 // behavior when being unmarshaled from a YAML document.
 type BytesUnmarshaler interface {
 	UnmarshalYAML([]byte) error
 }
 
+// BytesUnmarshalerContext interface use BytesUnmarshaler with context.Context.
+type BytesUnmarshalerContext interface {
+	UnmarshalYAML(context.Context, []byte) error
+}
+
 // InterfaceUnmarshaler interface has UnmarshalYAML compatible with github.com/go-yaml/yaml package.
 type InterfaceUnmarshaler interface {
 	UnmarshalYAML(func(interface{}) error) error
 }
 
+// InterfaceUnmarshalerContext interface use InterfaceUnmarshaler with context.Context.
+type InterfaceUnmarshalerContext interface {
+	UnmarshalYAML(context.Context, func(interface{}) error) error
+}
+
 // MapItem is an item in a MapSlice.
 type MapItem struct {
 	Key, Value interface{}
@@ -109,9 +130,13 @@ func Marshal(v interface{}) ([]byte, error) {
 
 // MarshalWithOptions serializes the value provided into a YAML document with EncodeOptions.
 func MarshalWithOptions(v interface{}, opts ...EncodeOption) ([]byte, error) {
+	return MarshalWithContext(context.Background(), v, opts...)
+}
+
+// MarshalWithContext serializes the value provided into a YAML document with context.Context and EncodeOptions.
+func MarshalWithContext(ctx context.Context, v interface{}, opts ...EncodeOption) ([]byte, error) {
 	var buf bytes.Buffer
-	enc := NewEncoder(&buf, opts...)
-	if err := enc.Encode(v); err != nil {
+	if err := NewEncoder(&buf, opts...).EncodeContext(ctx, v); err != nil {
 		return nil, errors.Wrapf(err, "failed to marshal")
 	}
 	return buf.Bytes(), nil
@@ -157,8 +182,13 @@ func Unmarshal(data []byte, v interface{}) error {
 // UnmarshalWithOptions decodes with DecodeOptions the first document found within the in byte slice
 // and assigns decoded values into the out value.
 func UnmarshalWithOptions(data []byte, v interface{}, opts ...DecodeOption) error {
+	return UnmarshalWithContext(context.Background(), data, v, opts...)
+}
+
+// UnmarshalWithContext decodes with context.Context and DecodeOptions.
+func UnmarshalWithContext(ctx context.Context, data []byte, v interface{}, opts ...DecodeOption) error {
 	dec := NewDecoder(bytes.NewBuffer(data), opts...)
-	if err := dec.Decode(v); err != nil {
+	if err := dec.DecodeContext(ctx, v); err != nil {
 		if err == io.EOF {
 			return nil
 		}


Test patch:
diff --git a/decode_test.go b/decode_test.go
index 01dc335..439988e 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -2,6 +2,7 @@ package yaml_test
 
 import (
 	"bytes"
+	"context"
 	"fmt"
 	"io"
 	"log"
@@ -1641,6 +1642,36 @@ func TestDecoder_UseJSONUnmarshaler(t *testing.T) {
 	}
 }
 
+type unmarshalWithContext struct {
+	v int
+}
+
+func (c *unmarshalWithContext) UnmarshalYAML(ctx context.Context, b []byte) error {
+	v, ok := ctx.Value("k").(int)
+	if !ok {
+		return fmt.Errorf("cannot get valid context")
+	}
+	if v != 1 {
+		return fmt.Errorf("cannot get valid context")
+	}
+	if string(b) != "1" {
+		return fmt.Errorf("cannot get valid bytes")
+	}
+	c.v = v
+	return nil
+}
+
+func Test_UnmarshalerWithContext(t *testing.T) {
+	ctx := context.WithValue(context.Background(), "k", 1)
+	var v unmarshalWithContext
+	if err := yaml.UnmarshalWithContext(ctx, []byte(`1`), &v); err != nil {
+		t.Fatalf("%+v", err)
+	}
+	if v.v != 1 {
+		t.Fatal("cannot call UnmarshalYAML")
+	}
+}
+
 func Example_JSONTags() {
 	yml := `---
 foo: 1
diff --git a/encode_test.go b/encode_test.go
index 4d5cef4..4cf4393 100644
--- a/encode_test.go
+++ b/encode_test.go
@@ -2,6 +2,7 @@ package yaml_test
 
 import (
 	"bytes"
+	"context"
 	"fmt"
 	"math"
 	"strconv"
@@ -932,6 +933,30 @@ func Test_Marshaler(t *testing.T) {
 	t.Logf("%s", buf)
 }
 
+type marshalWithContext struct{}
+
+func (c *marshalWithContext) MarshalYAML(ctx context.Context) ([]byte, error) {
+	v, ok := ctx.Value("k").(int)
+	if !ok {
+		return nil, fmt.Errorf("cannot get valid context")
+	}
+	if v != 1 {
+		return nil, fmt.Errorf("cannot get valid context")
+	}
+	return []byte("1"), nil
+}
+
+func Test_MarshalerWithContext(t *testing.T) {
+	ctx := context.WithValue(context.Background(), "k", 1)
+	bytes, err := yaml.MarshalWithContext(ctx, &marshalWithContext{})
+	if err != nil {
+		t.Fatalf("%+v", err)
+	}
+	if string(bytes) != "1\n" {
+		t.Fatalf("failed marshal: %q", string(bytes))
+	}
+}
+
 type SlowMarshaler struct {
 	A string
 	B int