serde

package
v2.9.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 8, 2024 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package serde contains Pachyderm-specific data structures for marshalling and unmarshalling Go structs and maps to structured text formats (currently just JSON and YAML).

Similar to https://github.com/ghodss/yaml, all implementations of the Format interface marshal and unmarshal data using the following pipeline:

Go struct/map (fully structured)
  <-> JSON document
  <-> map[string]interface{}
  <-> target format document

Despite the redundant round of marshalling and unmarshalling, there are two main advantages to this approach:

  • YAML (and any future storage formats) can re-use existing `json:` struct tags
  • The intermediate map[string]interface{} can be manipulated, making it possible to have flexible converstions between structs and documents. For examples, PPS pipelines may include a full TFJob spec, which is converted to a string and stored in the 'TFJob' field of Pachyderm's CreatePipelineRequest struct.

json_encoder.go is similar to yaml_encoder.go; see its comment on general approach. Because the final output is json, the steps this uses are a little more redundant, but still the reverse of the steps in decoder.go (allowing for future-proof reversability):

  1. Serialize structs to JSON using encoding/json or, in the case of protobufs, using Google's 'protojson' library.
  2. Deserialize that text into a generic interface{}.
  3. Serialize that interface using encoding/json.

Because the data is serialized to JSON twice, this approach seems more redundant in the context of json_encoder.go, but it's symmetrical with the encoding process. TODO(msteffen) src/server/identity/cmds/cmds.go uses this to serialize Pachyderm identity configs. That code could be written to modify the holder (map[string]interface{}) instead of using connectorConfig as an intermediate struct, which must be kept in sync.

yaml_encoder.go is the reverse of decoder.go. It applies the same steps in the opposite order:

  1. Serialize structs to JSON using encoding/json or, in the case of protobufs, using Google's 'protojson' library
  2. Deserialize that text into a generic interface{}
  3. Serialize that interface using gopkg.in/yaml.v3

This allows for correct handling of timestamps and such. It also allows data that has already been deserialized into a generic interface{} to be written out. Finally, it allows for transformations to be applied to the interface{} in a structured way (e.g. if the struct being serialized in step 1 contains embedded json).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Decode

func Decode(yamlData []byte, v interface{}) error

Decode is a convenience function that decodes the serialized YAML in 'yamlData' into the non-proto object 'v'

func EncodeJSON

func EncodeJSON(v interface{}, options ...EncoderOption) ([]byte, error)

EncodeJSON is a convenience function that encodes json data using a JSONEncoder, but can be called inline

func EncodeYAML

func EncodeYAML(v interface{}, options ...EncoderOption) ([]byte, error)

EncodeYAML is a convenience function that encodes yaml data using a YAMLEncoder, but can be called inline

func RoundTrip

func RoundTrip(holder interface{}, dest interface{}) error

RoundTrip is a helper function used by Decode(), as well as PipelineManifestReader in src/internal/ppsutil/decoder.go. It factors steps 2 and 3 (described up top) out of Decode(), as step 1 may be done in different ways. In particular, PipelineManifestReader may call RoundTrip repeatedly, if multiple PipelineSpecs are present in the same YAML doc.

func WithIndent

func WithIndent(numSpaces int) func(d Encoder)

WithIndent is an EncoderOption that causes the returned encoder to use 'numSpaces' spaces as the indentation prefix for embedded messages. If applied to a JSON encoder, it also changes the encoder output to be multi-line (instead of inline).

func WithOrigName

func WithOrigName(origName bool) func(d Encoder)

WithOrigName is an EncoderOption that, if set, encodes proto messages using the name set in the original .proto message definition, rather than the munged version of the generated struct's field name

Types

type Encoder

type Encoder interface {
	// Marshall converts 'v' (a struct or Go map) to a structured-text document
	// and writes it to this Encoder's output stream
	Encode(v interface{}) error

	// EncodeProto is similar to Encode, but instead of converting between the canonicalized
	// JSON and 'v' using 'encoding/json', it does so using
	// 'google.golang.org/protobuf/encoding/protojson'.  This allows callers to take advantage
	// of more sophisticated timestamp parsing and such.
	//
	// TODO(msteffen): We can *almost* avoid the Encode/EncodeProto split by checking if 'v'
	// implements 'proto.Message', except for one case: the kubernetes client library includes
	// structs that are pseudo-protobufs.  Structs in the kubernetes go client implement the
	// 'proto.Message()' interface but are hand-generated and contain embedded structs, which
	// 'jsonpb' can't handle when parsing. If jsonpb is ever extended to be able to parse JSON
	// into embedded structs (even though the protobuf compiler itself never generates such
	// structs) then we could merge this into Encode() and rely on:
	//
	//   if msg, ok := v.(proto.Message); ok {
	//     ... use jsonpb ...
	//   } else {
	//     ... use encoding/json ...
	//   }
	EncodeProto(proto.Message) error

	// EncodeTransform is similar to Encode, but users can manipulate the intermediate
	// map[string]interface generated by Format implementations by passing a function. Note that
	// 'Encode(v)' is equivalent to 'EncodeTransform(v, nil)'
	EncodeTransform(interface{}, func(map[string]interface{}) error) error

	// EncodeProtoTransform is similar to EncodeTransform(), but instead of converting between
	// the canonicalized JSON and 'v' using 'encoding/json', it does so using
	// 'google.golang.org/protobuf/encoding/protojson'.  This allows callers to take advantage
	// advantage of more sophisticated timestamp parsing and such in the 'jsonpb' library.
	//
	// TODO(msteffen) same comment re: proto.Message as for EncodeProto()
	EncodeProtoTransform(proto.Message, func(map[string]interface{}) error) error
}

Encoder is an interface for encoding data to an output stream (every implementation should provide the ability to construct an Encoder tied to an output stream, to which encoded text should be written)

func GetEncoder

func GetEncoder(encoding string, w io.Writer, opts ...EncoderOption) (Encoder, error)

GetEncoder dynamically creates and returns an Encoder for the text format 'encoding' (currently, 'encoding' must be "yaml" or "json"). 'defaultEncoding' specifies the text format that should be used if 'encoding' is "". 'opts' are the list of options that should be applied to any result, if any are applicable. Typically EncoderOptions are encoder-specific (e.g. setting json indentation). If an option is passed to GetEncoder for e.g. a json encoder but a yaml encoder is requested, then the option will be ignored. This makes it possible to pass all options to GetEncoder, but defer the decision about what kind of encoding to use until runtime, like so:

enc, _ := GetEncoder(outputFlag, os.Stdout,

...options to use if json...,
...options to use if yaml...,

) enc.Encode(obj)

type EncoderOption

type EncoderOption func(Encoder)

EncoderOption modifies the behavior of new encoders and can be passed to GetEncoder.

type JSONEncoder

type JSONEncoder struct {
	// contains filtered or unexported fields
}

JSONEncoder is an implementation of serde.Encoder that operates on JSON data

func NewJSONEncoder

func NewJSONEncoder(w io.Writer, options ...EncoderOption) *JSONEncoder

NewJSONEncoder returns a new JSONEncoder that writes to 'w'

func (*JSONEncoder) Encode

func (e *JSONEncoder) Encode(v interface{}) error

Encode implements the corresponding method of serde.Encoder

func (*JSONEncoder) EncodeProto

func (e *JSONEncoder) EncodeProto(v proto.Message) error

EncodeProto implements the corresponding method of serde.Encoder

func (*JSONEncoder) EncodeProtoTransform

func (e *JSONEncoder) EncodeProtoTransform(v proto.Message, f func(map[string]interface{}) error) error

EncodeProtoTransform implements the corresponding method of serde.Encoder

func (*JSONEncoder) EncodeTransform

func (e *JSONEncoder) EncodeTransform(v interface{}, f func(map[string]interface{}) error) error

EncodeTransform implements the corresponding method of serde.Encoder

type YAMLEncoder

type YAMLEncoder struct {
	// contains filtered or unexported fields
}

YAMLEncoder is an implementation of serde.Encoder that operates on YAML data

func NewYAMLEncoder

func NewYAMLEncoder(w io.Writer, options ...EncoderOption) *YAMLEncoder

NewYAMLEncoder returns a new YAMLEncoder that writes to 'w'

func (*YAMLEncoder) Encode

func (e *YAMLEncoder) Encode(v interface{}) error

Encode implements the corresponding method of serde.Encoder

func (*YAMLEncoder) EncodeProto

func (e *YAMLEncoder) EncodeProto(v proto.Message) error

EncodeProto implements the corresponding method of serde.Encoder

func (*YAMLEncoder) EncodeProtoTransform

func (e *YAMLEncoder) EncodeProtoTransform(v proto.Message, f func(map[string]interface{}) error) error

EncodeProtoTransform implements the corresponding method of serde.Encoder

func (*YAMLEncoder) EncodeTransform

func (e *YAMLEncoder) EncodeTransform(v interface{}, f func(map[string]interface{}) error) error

EncodeTransform implements the corresponding method of serde.Encoder

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL