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