package pgtype
import (
"bytes"
"encoding/binary"
"fmt"
)
type BoundType byte
const (
Inclusive = BoundType ('i' )
Exclusive = BoundType ('e' )
Unbounded = BoundType ('U' )
Empty = BoundType ('E' )
)
func (bt BoundType ) String () string {
return string (bt )
}
type untypedTextRange struct {
Lower string
Upper string
LowerType BoundType
UpperType BoundType
}
func parseUntypedTextRange(src string ) (*untypedTextRange , error ) {
utr := &untypedTextRange {}
if src == "empty" {
utr .LowerType = Empty
utr .UpperType = Empty
return utr , nil
}
buf := bytes .NewBufferString (src )
skipWhitespace (buf )
r , _ , err := buf .ReadRune ()
if err != nil {
return nil , fmt .Errorf ("invalid lower bound: %v" , err )
}
switch r {
case '(' :
utr .LowerType = Exclusive
case '[' :
utr .LowerType = Inclusive
default :
return nil , fmt .Errorf ("missing lower bound, instead got: %v" , string (r ))
}
r , _, err = buf .ReadRune ()
if err != nil {
return nil , fmt .Errorf ("invalid lower value: %v" , err )
}
buf .UnreadRune ()
if r == ',' {
utr .LowerType = Unbounded
} else {
utr .Lower , err = rangeParseValue (buf )
if err != nil {
return nil , fmt .Errorf ("invalid lower value: %v" , err )
}
}
r , _, err = buf .ReadRune ()
if err != nil {
return nil , fmt .Errorf ("missing range separator: %v" , err )
}
if r != ',' {
return nil , fmt .Errorf ("missing range separator: %v" , r )
}
r , _, err = buf .ReadRune ()
if err != nil {
return nil , fmt .Errorf ("invalid upper value: %v" , err )
}
if r == ')' || r == ']' {
utr .UpperType = Unbounded
} else {
buf .UnreadRune ()
utr .Upper , err = rangeParseValue (buf )
if err != nil {
return nil , fmt .Errorf ("invalid upper value: %v" , err )
}
r , _, err = buf .ReadRune ()
if err != nil {
return nil , fmt .Errorf ("missing upper bound: %v" , err )
}
switch r {
case ')' :
utr .UpperType = Exclusive
case ']' :
utr .UpperType = Inclusive
default :
return nil , fmt .Errorf ("missing upper bound, instead got: %v" , string (r ))
}
}
skipWhitespace (buf )
if buf .Len () > 0 {
return nil , fmt .Errorf ("unexpected trailing data: %v" , buf .String ())
}
return utr , nil
}
func rangeParseValue(buf *bytes .Buffer ) (string , error ) {
r , _ , err := buf .ReadRune ()
if err != nil {
return "" , err
}
if r == '"' {
return rangeParseQuotedValue (buf )
}
buf .UnreadRune ()
s := &bytes .Buffer {}
for {
r , _ , err := buf .ReadRune ()
if err != nil {
return "" , err
}
switch r {
case '\\' :
r , _, err = buf .ReadRune ()
if err != nil {
return "" , err
}
case ',' , '[' , ']' , '(' , ')' :
buf .UnreadRune ()
return s .String (), nil
}
s .WriteRune (r )
}
}
func rangeParseQuotedValue(buf *bytes .Buffer ) (string , error ) {
s := &bytes .Buffer {}
for {
r , _ , err := buf .ReadRune ()
if err != nil {
return "" , err
}
switch r {
case '\\' :
r , _, err = buf .ReadRune ()
if err != nil {
return "" , err
}
case '"' :
r , _, err = buf .ReadRune ()
if err != nil {
return "" , err
}
if r != '"' {
buf .UnreadRune ()
return s .String (), nil
}
}
s .WriteRune (r )
}
}
type untypedBinaryRange struct {
Lower []byte
Upper []byte
LowerType BoundType
UpperType BoundType
}
const emptyMask = 1
const lowerInclusiveMask = 2
const upperInclusiveMask = 4
const lowerUnboundedMask = 8
const upperUnboundedMask = 16
func parseUntypedBinaryRange(src []byte ) (*untypedBinaryRange , error ) {
ubr := &untypedBinaryRange {}
if len (src ) == 0 {
return nil , fmt .Errorf ("range too short: %v" , len (src ))
}
rangeType := src [0 ]
rp := 1
if rangeType &emptyMask > 0 {
if len (src [rp :]) > 0 {
return nil , fmt .Errorf ("unexpected trailing bytes parsing empty range: %v" , len (src [rp :]))
}
ubr .LowerType = Empty
ubr .UpperType = Empty
return ubr , nil
}
if rangeType &lowerInclusiveMask > 0 {
ubr .LowerType = Inclusive
} else if rangeType &lowerUnboundedMask > 0 {
ubr .LowerType = Unbounded
} else {
ubr .LowerType = Exclusive
}
if rangeType &upperInclusiveMask > 0 {
ubr .UpperType = Inclusive
} else if rangeType &upperUnboundedMask > 0 {
ubr .UpperType = Unbounded
} else {
ubr .UpperType = Exclusive
}
if ubr .LowerType == Unbounded && ubr .UpperType == Unbounded {
if len (src [rp :]) > 0 {
return nil , fmt .Errorf ("unexpected trailing bytes parsing unbounded range: %v" , len (src [rp :]))
}
return ubr , nil
}
if len (src [rp :]) < 4 {
return nil , fmt .Errorf ("too few bytes for size: %v" , src [rp :])
}
valueLen := int (binary .BigEndian .Uint32 (src [rp :]))
rp += 4
val := src [rp : rp +valueLen ]
rp += valueLen
if ubr .LowerType != Unbounded {
ubr .Lower = val
} else {
ubr .Upper = val
if len (src [rp :]) > 0 {
return nil , fmt .Errorf ("unexpected trailing bytes parsing range: %v" , len (src [rp :]))
}
return ubr , nil
}
if ubr .UpperType != Unbounded {
if len (src [rp :]) < 4 {
return nil , fmt .Errorf ("too few bytes for size: %v" , src [rp :])
}
valueLen := int (binary .BigEndian .Uint32 (src [rp :]))
rp += 4
ubr .Upper = src [rp : rp +valueLen ]
rp += valueLen
}
if len (src [rp :]) > 0 {
return nil , fmt .Errorf ("unexpected trailing bytes parsing range: %v" , len (src [rp :]))
}
return ubr , nil
}
type Range [T any ] struct {
Lower T
Upper T
LowerType BoundType
UpperType BoundType
Valid bool
}
func (r Range [T ]) IsNull () bool {
return !r .Valid
}
func (r Range [T ]) BoundTypes () (lower , upper BoundType ) {
return r .LowerType , r .UpperType
}
func (r Range [T ]) Bounds () (lower , upper any ) {
return &r .Lower , &r .Upper
}
func (r *Range [T ]) ScanNull () error {
*r = Range [T ]{}
return nil
}
func (r *Range [T ]) ScanBounds () (lowerTarget , upperTarget any ) {
return &r .Lower , &r .Upper
}
func (r *Range [T ]) SetBoundTypes (lower , upper BoundType ) error {
if lower == Unbounded || lower == Empty {
var zero T
r .Lower = zero
}
if upper == Unbounded || upper == Empty {
var zero T
r .Upper = zero
}
r .LowerType = lower
r .UpperType = upper
r .Valid = true
return nil
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .