1package pgtype
2
3import (
4	"database/sql/driver"
5	"encoding/binary"
6	"fmt"
7	"math"
8	"strconv"
9	"strings"
10
11	"github.com/jackc/pgx/pgio"
12	"github.com/pkg/errors"
13)
14
15type Line struct {
16	A, B, C float64
17	Status  Status
18}
19
20func (dst *Line) Set(src interface{}) error {
21	return errors.Errorf("cannot convert %v to Line", src)
22}
23
24func (dst *Line) Get() interface{} {
25	switch dst.Status {
26	case Present:
27		return dst
28	case Null:
29		return nil
30	default:
31		return dst.Status
32	}
33}
34
35func (src *Line) AssignTo(dst interface{}) error {
36	return errors.Errorf("cannot assign %v to %T", src, dst)
37}
38
39func (dst *Line) DecodeText(ci *ConnInfo, src []byte) error {
40	if src == nil {
41		*dst = Line{Status: Null}
42		return nil
43	}
44
45	if len(src) < 7 {
46		return errors.Errorf("invalid length for Line: %v", len(src))
47	}
48
49	parts := strings.SplitN(string(src[1:len(src)-1]), ",", 3)
50	if len(parts) < 3 {
51		return errors.Errorf("invalid format for line")
52	}
53
54	a, err := strconv.ParseFloat(parts[0], 64)
55	if err != nil {
56		return err
57	}
58
59	b, err := strconv.ParseFloat(parts[1], 64)
60	if err != nil {
61		return err
62	}
63
64	c, err := strconv.ParseFloat(parts[2], 64)
65	if err != nil {
66		return err
67	}
68
69	*dst = Line{A: a, B: b, C: c, Status: Present}
70	return nil
71}
72
73func (dst *Line) DecodeBinary(ci *ConnInfo, src []byte) error {
74	if src == nil {
75		*dst = Line{Status: Null}
76		return nil
77	}
78
79	if len(src) != 24 {
80		return errors.Errorf("invalid length for Line: %v", len(src))
81	}
82
83	a := binary.BigEndian.Uint64(src)
84	b := binary.BigEndian.Uint64(src[8:])
85	c := binary.BigEndian.Uint64(src[16:])
86
87	*dst = Line{
88		A:      math.Float64frombits(a),
89		B:      math.Float64frombits(b),
90		C:      math.Float64frombits(c),
91		Status: Present,
92	}
93	return nil
94}
95
96func (src *Line) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
97	switch src.Status {
98	case Null:
99		return nil, nil
100	case Undefined:
101		return nil, errUndefined
102	}
103
104	buf = append(buf, fmt.Sprintf(`{%s,%s,%s}`,
105		strconv.FormatFloat(src.A, 'f', -1, 64),
106		strconv.FormatFloat(src.B, 'f', -1, 64),
107		strconv.FormatFloat(src.C, 'f', -1, 64),
108	)...)
109
110	return buf, nil
111}
112
113func (src *Line) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
114	switch src.Status {
115	case Null:
116		return nil, nil
117	case Undefined:
118		return nil, errUndefined
119	}
120
121	buf = pgio.AppendUint64(buf, math.Float64bits(src.A))
122	buf = pgio.AppendUint64(buf, math.Float64bits(src.B))
123	buf = pgio.AppendUint64(buf, math.Float64bits(src.C))
124	return buf, nil
125}
126
127// Scan implements the database/sql Scanner interface.
128func (dst *Line) Scan(src interface{}) error {
129	if src == nil {
130		*dst = Line{Status: Null}
131		return nil
132	}
133
134	switch src := src.(type) {
135	case string:
136		return dst.DecodeText(nil, []byte(src))
137	case []byte:
138		srcCopy := make([]byte, len(src))
139		copy(srcCopy, src)
140		return dst.DecodeText(nil, srcCopy)
141	}
142
143	return errors.Errorf("cannot scan %T", src)
144}
145
146// Value implements the database/sql/driver Valuer interface.
147func (src *Line) Value() (driver.Value, error) {
148	return EncodeValueText(src)
149}
150