Path: blob/main/vendor/github.com/spf13/viper/encoding.go
2875 views
package viper12import (3"errors"4"strings"5"sync"67"github.com/spf13/viper/internal/encoding/dotenv"8"github.com/spf13/viper/internal/encoding/json"9"github.com/spf13/viper/internal/encoding/toml"10"github.com/spf13/viper/internal/encoding/yaml"11)1213// Encoder encodes Viper's internal data structures into a byte representation.14// It's primarily used for encoding a map[string]any into a file format.15type Encoder interface {16Encode(v map[string]any) ([]byte, error)17}1819// Decoder decodes the contents of a byte slice into Viper's internal data structures.20// It's primarily used for decoding contents of a file into a map[string]any.21type Decoder interface {22Decode(b []byte, v map[string]any) error23}2425// Codec combines [Encoder] and [Decoder] interfaces.26type Codec interface {27Encoder28Decoder29}3031// TODO: consider adding specific errors for not found scenarios3233// EncoderRegistry returns an [Encoder] for a given format.34//35// Format is case-insensitive.36//37// [EncoderRegistry] returns an error if no [Encoder] is registered for the format.38type EncoderRegistry interface {39Encoder(format string) (Encoder, error)40}4142// DecoderRegistry returns an [Decoder] for a given format.43//44// Format is case-insensitive.45//46// [DecoderRegistry] returns an error if no [Decoder] is registered for the format.47type DecoderRegistry interface {48Decoder(format string) (Decoder, error)49}5051// [CodecRegistry] combines [EncoderRegistry] and [DecoderRegistry] interfaces.52type CodecRegistry interface {53EncoderRegistry54DecoderRegistry55}5657// WithEncoderRegistry sets a custom [EncoderRegistry].58func WithEncoderRegistry(r EncoderRegistry) Option {59return optionFunc(func(v *Viper) {60if r == nil {61return62}6364v.encoderRegistry = r65})66}6768// WithDecoderRegistry sets a custom [DecoderRegistry].69func WithDecoderRegistry(r DecoderRegistry) Option {70return optionFunc(func(v *Viper) {71if r == nil {72return73}7475v.decoderRegistry = r76})77}7879// WithCodecRegistry sets a custom [EncoderRegistry] and [DecoderRegistry].80func WithCodecRegistry(r CodecRegistry) Option {81return optionFunc(func(v *Viper) {82if r == nil {83return84}8586v.encoderRegistry = r87v.decoderRegistry = r88})89}9091// DefaultCodecRegistry is a simple implementation of [CodecRegistry] that allows registering custom [Codec]s.92type DefaultCodecRegistry struct {93codecs map[string]Codec9495mu sync.RWMutex96once sync.Once97}9899// NewCodecRegistry returns a new [CodecRegistry], ready to accept custom [Codec]s.100func NewCodecRegistry() *DefaultCodecRegistry {101r := &DefaultCodecRegistry{}102103r.init()104105return r106}107108func (r *DefaultCodecRegistry) init() {109r.once.Do(func() {110r.codecs = map[string]Codec{}111})112}113114// RegisterCodec registers a custom [Codec].115//116// Format is case-insensitive.117func (r *DefaultCodecRegistry) RegisterCodec(format string, codec Codec) error {118r.init()119120r.mu.Lock()121defer r.mu.Unlock()122123r.codecs[strings.ToLower(format)] = codec124125return nil126}127128// Encoder implements the [EncoderRegistry] interface.129//130// Format is case-insensitive.131func (r *DefaultCodecRegistry) Encoder(format string) (Encoder, error) {132encoder, ok := r.codec(format)133if !ok {134return nil, errors.New("encoder not found for this format")135}136137return encoder, nil138}139140// Decoder implements the [DecoderRegistry] interface.141//142// Format is case-insensitive.143func (r *DefaultCodecRegistry) Decoder(format string) (Decoder, error) {144decoder, ok := r.codec(format)145if !ok {146return nil, errors.New("decoder not found for this format")147}148149return decoder, nil150}151152func (r *DefaultCodecRegistry) codec(format string) (Codec, bool) {153r.mu.Lock()154defer r.mu.Unlock()155156format = strings.ToLower(format)157158if r.codecs != nil {159codec, ok := r.codecs[format]160if ok {161return codec, true162}163}164165switch format {166case "yaml", "yml":167return yaml.Codec{}, true168169case "json":170return json.Codec{}, true171172case "toml":173return toml.Codec{}, true174175case "dotenv", "env":176return &dotenv.Codec{}, true177}178179return nil, false180}181182183