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