-
Notifications
You must be signed in to change notification settings - Fork 0
/
textcodec.go
76 lines (63 loc) · 1.53 KB
/
textcodec.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package aurum
import (
"encoding"
"fmt"
"os"
"reflect"
"github.com/hansmi/aurum/internal/codecutil"
)
// TextCodec stores values in plain-text files. Supports strings, byte slices,
// rune slices and values implementing [encoding.TextUnmarshaler].
type TextCodec struct {
// Codec to use for unsupported types.
Fallback Codec
}
var _ Codec = (*TextCodec)(nil)
func (t TextCodec) Marshal(v any) ([]byte, error) {
rv, _, err := codecutil.PrepareMarshalValue(v)
if err != nil {
return nil, err
}
if tm, ok := rv.Interface().(encoding.TextMarshaler); ok {
return tm.MarshalText()
}
if v := rv.Elem().Interface(); v != nil {
switch v := v.(type) {
case []byte:
return v, nil
case string:
return []byte(v), nil
case []rune:
return []byte(string(v)), nil
}
}
if t.Fallback == nil {
return nil, fmt.Errorf("%w: marshalling %T as text is not supported", os.ErrInvalid, v)
}
return t.Fallback.Marshal(v)
}
func (t TextCodec) Unmarshal(data []byte, v any) error {
rv, m, err := codecutil.PrepareUnmarshalDest(v)
if err != nil {
return err
}
if m == nil {
switch v := reflect.Indirect(rv).Interface().(type) {
case *[]byte:
*v = append([]byte(nil), data...)
return nil
case *string:
*v = string(data)
return nil
case *[]rune:
*v = []rune(string(data))
return nil
case encoding.TextUnmarshaler:
return v.UnmarshalText(data)
}
}
if t.Fallback == nil {
return fmt.Errorf("%w: unmarshalling text into %T is not supported", os.ErrInvalid, v)
}
return t.Fallback.Unmarshal(data, v)
}