1package pgtype
2
3import (
4	"database/sql/driver"
5	"encoding/binary"
6	"fmt"
7
8	"github.com/jackc/pgio"
9)
10
11type Varbit struct {
12	Bytes  []byte
13	Len    int32 // Number of bits
14	Status Status
15}
16
17func (dst *Varbit) Set(src interface{}) error {
18	return fmt.Errorf("cannot convert %v to Varbit", src)
19}
20
21func (dst Varbit) Get() interface{} {
22	switch dst.Status {
23	case Present:
24		return dst
25	case Null:
26		return nil
27	default:
28		return dst.Status
29	}
30}
31
32func (src *Varbit) AssignTo(dst interface{}) error {
33	return fmt.Errorf("cannot assign %v to %T", src, dst)
34}
35
36func (dst *Varbit) DecodeText(ci *ConnInfo, src []byte) error {
37	if src == nil {
38		*dst = Varbit{Status: Null}
39		return nil
40	}
41
42	bitLen := len(src)
43	byteLen := bitLen / 8
44	if bitLen%8 > 0 {
45		byteLen++
46	}
47	buf := make([]byte, byteLen)
48
49	for i, b := range src {
50		if b == '1' {
51			byteIdx := i / 8
52			bitIdx := uint(i % 8)
53			buf[byteIdx] = buf[byteIdx] | (128 >> bitIdx)
54		}
55	}
56
57	*dst = Varbit{Bytes: buf, Len: int32(bitLen), Status: Present}
58	return nil
59}
60
61func (dst *Varbit) DecodeBinary(ci *ConnInfo, src []byte) error {
62	if src == nil {
63		*dst = Varbit{Status: Null}
64		return nil
65	}
66
67	if len(src) < 4 {
68		return fmt.Errorf("invalid length for varbit: %v", len(src))
69	}
70
71	bitLen := int32(binary.BigEndian.Uint32(src))
72	rp := 4
73
74	*dst = Varbit{Bytes: src[rp:], Len: bitLen, Status: Present}
75	return nil
76}
77
78func (src Varbit) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
79	switch src.Status {
80	case Null:
81		return nil, nil
82	case Undefined:
83		return nil, errUndefined
84	}
85
86	for i := int32(0); i < src.Len; i++ {
87		byteIdx := i / 8
88		bitMask := byte(128 >> byte(i%8))
89		char := byte('0')
90		if src.Bytes[byteIdx]&bitMask > 0 {
91			char = '1'
92		}
93		buf = append(buf, char)
94	}
95
96	return buf, nil
97}
98
99func (src Varbit) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
100	switch src.Status {
101	case Null:
102		return nil, nil
103	case Undefined:
104		return nil, errUndefined
105	}
106
107	buf = pgio.AppendInt32(buf, src.Len)
108	return append(buf, src.Bytes...), nil
109}
110
111// Scan implements the database/sql Scanner interface.
112func (dst *Varbit) Scan(src interface{}) error {
113	if src == nil {
114		*dst = Varbit{Status: Null}
115		return nil
116	}
117
118	switch src := src.(type) {
119	case string:
120		return dst.DecodeText(nil, []byte(src))
121	case []byte:
122		srcCopy := make([]byte, len(src))
123		copy(srcCopy, src)
124		return dst.DecodeText(nil, srcCopy)
125	}
126
127	return fmt.Errorf("cannot scan %T", src)
128}
129
130// Value implements the database/sql/driver Valuer interface.
131func (src Varbit) Value() (driver.Value, error) {
132	return EncodeValueText(src)
133}
134