Skip to content
Snippets Groups Projects
Commit f474f2fc authored by Semyon Krestyaninov's avatar Semyon Krestyaninov :dog2:
Browse files

wip

parent ad9e9734
Branches
No related tags found
No related merge requests found
package encode
import "io"
type Codec interface {
NewDecoder(r io.Reader) Decoder
NewEncoder(w io.Writer) Encoder
}
type Decoder interface {
Decode(any) error
}
type Encoder interface {
Encode(any) error
Flush() error
Close() error
}
......@@ -96,7 +96,6 @@ func TestEncode(t *testing.T) {
RoleID: "role_id",
},
}
t.Run("json", func(t *testing.T) {
var buf bytes.Buffer
err := encode.ToJSON[[]*clients.Client](&buf, input)
......
......@@ -11,32 +11,32 @@ import (
// при кодировании или декодировании JSON.
const bufferSize = 4096
// FromJSON декодирует объект JSON из io.Reader.
func FromJSON[T any](r io.Reader) (T, error) {
var entry T
err := jsoniter.NewDecoder(r).Decode(&entry)
return entry, err
var JSON = &jsonCodec{}
type jsonCodec struct{}
func (jsonCodec) NewEncoder(w io.Writer) Encoder {
return NewJSONEncoder(w)
}
// ToJSON кодирует объект в JSON и записывает в io.Writer.
func ToJSON[T any](w io.Writer, entry T) error {
return jsoniter.NewEncoder(w).Encode(entry)
func (jsonCodec) NewDecoder(r io.Reader) Decoder {
return NewJSONDecoder(r)
}
type JSONStreamEncoder struct {
type JSONEncoder struct {
stream *jsoniter.Stream
first bool
}
func NewJSONEncoder(w io.Writer) *JSONStreamEncoder {
enc := &JSONStreamEncoder{
func NewJSONEncoder(w io.Writer) *JSONEncoder {
enc := &JSONEncoder{
stream: jsoniter.NewStream(jsoniter.ConfigDefault, w, bufferSize),
first: true,
}
return enc
}
func (enc *JSONStreamEncoder) Encode(v any) error {
func (enc *JSONEncoder) Encode(v any) error {
if enc.first {
enc.stream.WriteArrayStart()
enc.first = false
......@@ -47,29 +47,29 @@ func (enc *JSONStreamEncoder) Encode(v any) error {
return enc.stream.Error
}
func (enc *JSONStreamEncoder) Flush() error {
func (enc *JSONEncoder) Flush() error {
return enc.stream.Flush()
}
func (enc *JSONStreamEncoder) Close() error {
func (enc *JSONEncoder) Close() error {
enc.stream.WriteArrayEnd()
return enc.stream.Flush()
}
type JSONStreamDecoder struct {
type JSONDecoder struct {
iter *jsoniter.Iterator
isArray bool
}
func NewJSONDecoder(r io.Reader) *JSONStreamDecoder {
dec := &JSONStreamDecoder{
func NewJSONDecoder(r io.Reader) *JSONDecoder {
dec := &JSONDecoder{
iter: jsoniter.Parse(jsoniter.ConfigDefault, r, bufferSize),
}
dec.isArray = dec.iter.WhatIsNext() == jsoniter.ArrayValue
return dec
}
func (dec *JSONStreamDecoder) Decode(v any) error {
func (dec *JSONDecoder) Decode(v any) error {
if dec.isArray && !dec.iter.ReadArray() {
if dec.iter.Error == nil {
return io.EOF
......@@ -78,9 +78,21 @@ func (dec *JSONStreamDecoder) Decode(v any) error {
}
dec.iter.ReadVal(v)
if dec.iter.Error != nil && !errors.Is(dec.iter.Error, io.EOF) {
if err := dec.iter.Error; err != nil && !errors.Is(err, io.EOF) {
return dec.iter.Error
}
return nil
}
// FromJSON декодирует объект JSON из io.Reader.
func FromJSON[T any](r io.Reader) (T, error) {
var entry T
err := jsoniter.NewDecoder(r).Decode(&entry)
return entry, err
}
// ToJSON кодирует объект в JSON и записывает в io.Writer.
func ToJSON[T any](w io.Writer, entry T) error {
return jsoniter.NewEncoder(w).Encode(entry)
}
......@@ -15,7 +15,8 @@ func TestJSONDecoder(t *testing.T) {
Name string `json:"name"`
}
t.Run("primitive", func(t *testing.T) {
dec := encode.NewJSONDecoder(strings.NewReader(`5`))
dec := encode.NewJSONDecoder(strings.NewReader("5"))
var n int
err := dec.Decode(&n)
require.NoError(t, err)
......@@ -23,26 +24,31 @@ func TestJSONDecoder(t *testing.T) {
})
t.Run("struct", func(t *testing.T) {
dec := encode.NewJSONDecoder(strings.NewReader(`{"name": "Gopher"}`))
var u user
err := dec.Decode(&u)
require.NoError(t, err)
assert.Equal(t, user{Name: "Gopher"}, u)
})
t.Run("valid array", func(t *testing.T) {
dec := encode.NewJSONDecoder(strings.NewReader(`[1, 2, 3]`))
dec := encode.NewJSONDecoder(strings.NewReader("[1, 2, 3]"))
var n int
err := dec.Decode(&n)
require.NoError(t, err)
assert.Equal(t, 1, n)
err = dec.Decode(&n)
require.NoError(t, err)
assert.Equal(t, 2, n)
err = dec.Decode(&n)
require.NoError(t, err)
assert.Equal(t, 3, n)
})
t.Run("invalid array", func(t *testing.T) {
dec := encode.NewJSONDecoder(strings.NewReader(`["1", 2, 3]`))
var s int
err := dec.Decode(&s)
require.Error(t, err)
......@@ -56,8 +62,10 @@ func TestJSONEncoder(t *testing.T) {
t.Run("primitive", func(t *testing.T) {
buf := &bytes.Buffer{}
enc := encode.NewJSONEncoder(buf)
err := enc.Encode(5)
require.NoError(t, err)
err = enc.Close()
require.NoError(t, err)
assert.JSONEq(t, "[5]", buf.String())
......@@ -65,8 +73,10 @@ func TestJSONEncoder(t *testing.T) {
t.Run("struct", func(t *testing.T) {
buf := &bytes.Buffer{}
enc := encode.NewJSONEncoder(buf)
err := enc.Encode(user{Name: "Gopher"})
require.NoError(t, err)
err = enc.Close()
require.NoError(t, err)
assert.JSONEq(t, `[{"name": "Gopher"}]`, buf.String())
......@@ -74,14 +84,18 @@ func TestJSONEncoder(t *testing.T) {
t.Run("valid array", func(t *testing.T) {
buf := &bytes.Buffer{}
enc := encode.NewJSONEncoder(buf)
err := enc.Encode(1)
require.NoError(t, err)
err = enc.Encode(2)
require.NoError(t, err)
err = enc.Encode(3)
require.NoError(t, err)
err = enc.Close()
require.NoError(t, err)
assert.JSONEq(t, `[1, 2, 3]`, buf.String())
assert.JSONEq(t, "[1, 2, 3]", buf.String())
})
}
......@@ -5,30 +5,28 @@ import (
"io"
)
type Decoder interface {
Decode(v any) error
}
type Reader[T any] struct {
dec Decoder
current T
err error
}
func NewReader[T any](decoder Decoder) *Reader[T] {
func NewReader[T any](codec Codec, r io.Reader) *Reader[T] {
return &Reader[T]{
dec: decoder,
dec: codec.NewDecoder(r),
}
}
func (r *Reader[T]) Next() bool {
err := r.dec.Decode(&r.current)
var entry T
err := r.dec.Decode(&entry)
if err != nil {
if !errors.Is(err, io.EOF) {
r.err = err
}
return false
}
r.current = entry
return true
}
......
......@@ -15,25 +15,31 @@ func TestReader(t *testing.T) {
}
t.Run("json", func(t *testing.T) {
t.Run("primitive", func(t *testing.T) {
reader := encode.NewReader[int](encode.NewJSONDecoder(strings.NewReader("5")))
reader := encode.NewReader[int](encode.JSON, strings.NewReader("5"))
next := reader.Next()
assert.True(t, next)
err := reader.Err()
require.NoError(t, err)
current := reader.Current()
assert.Equal(t, 5, current)
})
t.Run("struct", func(t *testing.T) {
reader := encode.NewReader[user](encode.NewJSONDecoder(strings.NewReader(`{"name":"Gopher"}`)))
reader := encode.NewReader[user](encode.JSON, strings.NewReader(`{"name":"Gopher"}`))
next := reader.Next()
assert.True(t, next)
err := reader.Err()
require.NoError(t, err)
current := reader.Current()
assert.Equal(t, user{"Gopher"}, current)
})
t.Run("valid array", func(t *testing.T) {
reader := encode.NewReader[int](encode.NewJSONDecoder(strings.NewReader("[1, 2, 3]")))
reader := encode.NewReader[int](encode.JSON, strings.NewReader("[1, 2, 3]"))
var result []int
for reader.Next() {
result = append(result, reader.Current())
......@@ -43,7 +49,7 @@ func TestReader(t *testing.T) {
assert.Equal(t, []int{1, 2, 3}, result)
})
t.Run("invalid array", func(t *testing.T) {
reader := encode.NewReader[int](encode.NewJSONDecoder(strings.NewReader(`[1, 2, "3", 4]`)))
reader := encode.NewReader[int](encode.JSON, strings.NewReader(`[1, 2, "3", 4]`))
var result []int
for reader.Next() {
result = append(result, reader.Current())
......@@ -55,7 +61,7 @@ func TestReader(t *testing.T) {
})
t.Run("yaml", func(t *testing.T) {
t.Run("struct", func(t *testing.T) {
reader := encode.NewReader[user](encode.NewYAMLStreamDecoder(strings.NewReader(`name: "Gopher"`)))
reader := encode.NewReader[user](encode.YAML, strings.NewReader(`name: "Gopher"`))
next := reader.Next()
assert.True(t, next)
err := reader.Err()
......@@ -67,7 +73,7 @@ func TestReader(t *testing.T) {
input := `name: "Gopher"
---
name: "John"`
reader := encode.NewReader[user](encode.NewYAMLStreamDecoder(strings.NewReader(input)))
reader := encode.NewReader[user](encode.YAML, strings.NewReader(input))
var result []user
for reader.Next() {
result = append(result, reader.Current())
......
package encode
type Encoder interface {
Encode(v any) error
Flush() error
Close() error
}
import "io"
type Writer[T any] struct {
enc Encoder
}
func NewWriter[T any](encoder Encoder) *Writer[T] {
func NewWriter[T any](codec Codec, w io.Writer) *Writer[T] {
return &Writer[T]{
enc: encoder,
enc: codec.NewEncoder(w),
}
}
......
......@@ -16,38 +16,49 @@ func TestWriter(t *testing.T) {
t.Run("json", func(t *testing.T) {
t.Run("valid array", func(t *testing.T) {
buf := &bytes.Buffer{}
writer := encode.NewWriter[int](encode.NewJSONEncoder(buf))
writer := encode.NewWriter[int](encode.JSON, buf)
err := writer.Write(1, 2, 3)
require.NoError(t, err)
err = writer.Write(4, 5)
require.NoError(t, err)
err = writer.Close()
require.NoError(t, err)
assert.JSONEq(t, "[1, 2, 3, 4, 5]", buf.String())
})
t.Run("struct", func(t *testing.T) {
buf := &bytes.Buffer{}
writer := encode.NewWriter[user](encode.NewJSONEncoder(buf))
writer := encode.NewWriter[user](encode.JSON, buf)
err := writer.Write(user{"Gopher"}, user{"John"})
require.NoError(t, err)
err = writer.Close()
require.NoError(t, err)
assert.JSONEq(t, `[{"name": "Gopher"}, {"name": "John"}]`, buf.String())
})
})
t.Run("yaml", func(t *testing.T) {
t.Run("valid array", func(t *testing.T) {
buf := &bytes.Buffer{}
writer := encode.NewWriter[user](encode.NewYAMLEncoder(buf))
writer := encode.NewWriter[user](encode.YAML, buf)
err := writer.Write(
user{Name: "Gopher"},
user{Name: "John"},
)
require.NoError(t, err)
err = writer.Write(user{Name: "Stefan"})
require.NoError(t, err)
err = writer.Close()
require.NoError(t, err)
assert.YAMLEq(t, `name: "Gopher"
---
name: "John
......
......@@ -8,6 +8,54 @@ import (
"gopkg.in/yaml.v3"
)
var YAML = &yamlCodec{}
type yamlCodec struct{}
func (yamlCodec) NewEncoder(w io.Writer) Encoder {
return NewYAMLEncoder(w)
}
func (yamlCodec) NewDecoder(r io.Reader) Decoder {
return NewYAMLDecoder(r)
}
type YAMLEncoder struct {
*yaml.Encoder
}
func NewYAMLEncoder(w io.Writer) *YAMLEncoder {
return &YAMLEncoder{
Encoder: yaml.NewEncoder(w),
}
}
func (enc *YAMLEncoder) Encode(v any) error {
return encodeYAML(enc.Encoder, v)
}
func (enc *YAMLEncoder) Flush() error {
return nil
}
func (enc *YAMLEncoder) Close() error {
return enc.Encoder.Close()
}
type YAMLDecoder struct {
*yaml.Decoder
}
func NewYAMLDecoder(r io.Reader) *YAMLDecoder {
return &YAMLDecoder{
Decoder: yaml.NewDecoder(r),
}
}
func (dec *YAMLDecoder) Decode(v any) error {
return decodeYAML(dec.Decoder, v)
}
// FromYAML декодирует объект YAML из io.Reader.
func FromYAML[T any](w io.Reader) ([]T, error) {
var (
......@@ -30,30 +78,6 @@ func FromYAML[T any](w io.Reader) ([]T, error) {
return entries, nil
}
func decodeYAML(dec *yaml.Decoder, v any) error {
var m map[string]any
err := dec.Decode(&m)
if err != nil {
if errors.Is(err, io.EOF) {
return io.EOF
}
return errors.Wrap(err, "failed to decode yaml")
}
jb, err := jsoniter.Marshal(m)
if err != nil {
return errors.Wrap(err, "failed to marshal json")
}
err = jsoniter.Unmarshal(jb, v)
if err != nil {
return errors.Wrap(err, "failed to unmarshal json")
}
return nil
}
// ToYAML кодирует объект в YAML и записывает в io.Writer.
func ToYAML[T any](w io.Writer, entries []T) error {
enc := yaml.NewEncoder(w)
......@@ -87,38 +111,23 @@ func encodeYAML[T any](enc *yaml.Encoder, entry T) error {
return nil
}
type YAMLStreamEncoder struct {
encoder *yaml.Encoder
}
func NewYAMLEncoder(w io.Writer) *YAMLStreamEncoder {
return &YAMLStreamEncoder{
encoder: yaml.NewEncoder(w),
}
}
func (enc *YAMLStreamEncoder) Encode(v any) error {
return encodeYAML(enc.encoder, v)
}
func (enc *YAMLStreamEncoder) Flush() error {
return nil
}
func decodeYAML(dec *yaml.Decoder, v any) error {
var m map[string]any
func (enc *YAMLStreamEncoder) Close() error {
return enc.encoder.Close()
err := dec.Decode(&m)
if err != nil {
return errors.Wrap(err, "decode yaml")
}
type YAMLStreamDecoder struct {
decoder *yaml.Decoder
jb, err := jsoniter.Marshal(m)
if err != nil {
return errors.Wrap(err, "marshal to json")
}
func NewYAMLStreamDecoder(r io.Reader) *YAMLStreamDecoder {
return &YAMLStreamDecoder{
decoder: yaml.NewDecoder(r),
}
err = jsoniter.Unmarshal(jb, v)
if err != nil {
return errors.Wrap(err, "unmarshal from json")
}
func (dec *YAMLStreamDecoder) Decode(v any) error {
return decodeYAML(dec.decoder, v)
return nil
}
......@@ -15,20 +15,23 @@ func TestYAMLDecoder(t *testing.T) {
Name string `json:"name"`
}
t.Run("struct", func(t *testing.T) {
dec := encode.NewYAMLStreamDecoder(strings.NewReader(`name: "Gopher"`))
dec := encode.NewYAMLDecoder(strings.NewReader(`name: "Gopher"`))
var u user
err := dec.Decode(&u)
require.NoError(t, err)
assert.Equal(t, user{Name: "Gopher"}, u)
})
t.Run("valid array", func(t *testing.T) {
dec := encode.NewYAMLStreamDecoder(strings.NewReader(`name: "Gopher"
dec := encode.NewYAMLDecoder(strings.NewReader(`name: "Gopher"
---
name: "John"`))
var u user
err := dec.Decode(&u)
require.NoError(t, err)
assert.Equal(t, user{Name: "Gopher"}, u)
err = dec.Decode(&u)
require.NoError(t, err)
assert.Equal(t, user{Name: "John"}, u)
......@@ -42,21 +45,28 @@ func TestYAMLEncoder(t *testing.T) {
t.Run("struct", func(t *testing.T) {
buf := &bytes.Buffer{}
enc := encode.NewYAMLEncoder(buf)
err := enc.Encode(user{Name: "Gopher"})
require.NoError(t, err)
err = enc.Close()
require.NoError(t, err)
assert.YAMLEq(t, `name: "Gopher"`, buf.String())
})
t.Run("valid array", func(t *testing.T) {
buf := &bytes.Buffer{}
enc := encode.NewYAMLEncoder(buf)
err := enc.Encode(user{Name: "Gopher"})
require.NoError(t, err)
err = enc.Encode(user{Name: "John"})
require.NoError(t, err)
err = enc.Close()
require.NoError(t, err)
assert.YAMLEq(t, `name: "Gopher"
---
name: "John"`, buf.String())
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment