67 lines
1.2 KiB
Go
67 lines
1.2 KiB
Go
package encode
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"time"
|
|
)
|
|
|
|
type encoder struct {
|
|
withDuration bool
|
|
}
|
|
|
|
type Encoder interface {
|
|
Encode(v any) any
|
|
}
|
|
|
|
type EncoderOption func(*encoder)
|
|
|
|
// NewEncoder creates a new encoder with the following default conversions:
|
|
// - float NaN/Inf are converted to nil
|
|
// - zero time.Time are converted to nil
|
|
// - durations are converted to seconds using WithDuration()
|
|
// - fmt.Stringer are converted to string
|
|
// - time.Time are converted to RFC3339 string
|
|
func NewEncoder(opt ...EncoderOption) Encoder {
|
|
res := new(encoder)
|
|
for _, o := range opt {
|
|
o(res)
|
|
}
|
|
return res
|
|
}
|
|
|
|
func WithDuration() EncoderOption {
|
|
return func(e *encoder) {
|
|
e.withDuration = true
|
|
}
|
|
}
|
|
|
|
// Encode provides a consumer-friendly default encoding for any type
|
|
func (e encoder) Encode(v any) any {
|
|
switch val := v.(type) {
|
|
case time.Time:
|
|
if val.IsZero() {
|
|
return nil
|
|
}
|
|
return val.Format(time.RFC3339)
|
|
|
|
case time.Duration:
|
|
// must be before stringer to convert to seconds instead of string
|
|
if e.withDuration {
|
|
return int(val.Seconds())
|
|
}
|
|
return val
|
|
|
|
case float64:
|
|
if math.IsNaN(val) || math.IsInf(val, 0) {
|
|
return nil
|
|
}
|
|
return math.Round(val*1e3) / 1e3
|
|
|
|
case fmt.Stringer:
|
|
return val.String()
|
|
|
|
default:
|
|
return val
|
|
}
|
|
}
|