...

Source file src/github.com/jackc/pgtype/polygon.go

Documentation: github.com/jackc/pgtype

     1  package pgtype
     2  
     3  import (
     4  	"database/sql/driver"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"math"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/jackc/pgio"
    12  )
    13  
    14  type Polygon struct {
    15  	P      []Vec2
    16  	Status Status
    17  }
    18  
    19  // Set converts src to dest.
    20  //
    21  // src can be nil, string, []float64, and []pgtype.Vec2.
    22  //
    23  // If src is string the format must be ((x1,y1),(x2,y2),...,(xn,yn)).
    24  // Important that there are no spaces in it.
    25  func (dst *Polygon) Set(src interface{}) error {
    26  	if src == nil {
    27  		dst.Status = Null
    28  		return nil
    29  	}
    30  	err := fmt.Errorf("cannot convert %v to Polygon", src)
    31  	var p *Polygon
    32  	switch value := src.(type) {
    33  	case string:
    34  		p, err = stringToPolygon(value)
    35  	case []Vec2:
    36  		p = &Polygon{Status: Present, P: value}
    37  		err = nil
    38  	case []float64:
    39  		p, err = float64ToPolygon(value)
    40  	default:
    41  		return err
    42  	}
    43  	if err != nil {
    44  		return err
    45  	}
    46  	*dst = *p
    47  	return nil
    48  }
    49  
    50  func stringToPolygon(src string) (*Polygon, error) {
    51  	p := &Polygon{}
    52  	err := p.DecodeText(nil, []byte(src))
    53  	return p, err
    54  }
    55  
    56  func float64ToPolygon(src []float64) (*Polygon, error) {
    57  	p := &Polygon{Status: Null}
    58  	if len(src) == 0 {
    59  		return p, nil
    60  	}
    61  	if len(src)%2 != 0 {
    62  		p.Status = Undefined
    63  		return p, fmt.Errorf("invalid length for polygon: %v", len(src))
    64  	}
    65  	p.Status = Present
    66  	p.P = make([]Vec2, 0)
    67  	for i := 0; i < len(src); i += 2 {
    68  		p.P = append(p.P, Vec2{X: src[i], Y: src[i+1]})
    69  	}
    70  	return p, nil
    71  }
    72  
    73  func (dst Polygon) Get() interface{} {
    74  	switch dst.Status {
    75  	case Present:
    76  		return dst
    77  	case Null:
    78  		return nil
    79  	default:
    80  		return dst.Status
    81  	}
    82  }
    83  
    84  func (src *Polygon) AssignTo(dst interface{}) error {
    85  	return fmt.Errorf("cannot assign %v to %T", src, dst)
    86  }
    87  
    88  func (dst *Polygon) DecodeText(ci *ConnInfo, src []byte) error {
    89  	if src == nil {
    90  		*dst = Polygon{Status: Null}
    91  		return nil
    92  	}
    93  
    94  	if len(src) < 7 {
    95  		return fmt.Errorf("invalid length for Polygon: %v", len(src))
    96  	}
    97  
    98  	points := make([]Vec2, 0)
    99  
   100  	str := string(src[2:])
   101  
   102  	for {
   103  		end := strings.IndexByte(str, ',')
   104  		x, err := strconv.ParseFloat(str[:end], 64)
   105  		if err != nil {
   106  			return err
   107  		}
   108  
   109  		str = str[end+1:]
   110  		end = strings.IndexByte(str, ')')
   111  
   112  		y, err := strconv.ParseFloat(str[:end], 64)
   113  		if err != nil {
   114  			return err
   115  		}
   116  
   117  		points = append(points, Vec2{x, y})
   118  
   119  		if end+3 < len(str) {
   120  			str = str[end+3:]
   121  		} else {
   122  			break
   123  		}
   124  	}
   125  
   126  	*dst = Polygon{P: points, Status: Present}
   127  	return nil
   128  }
   129  
   130  func (dst *Polygon) DecodeBinary(ci *ConnInfo, src []byte) error {
   131  	if src == nil {
   132  		*dst = Polygon{Status: Null}
   133  		return nil
   134  	}
   135  
   136  	if len(src) < 5 {
   137  		return fmt.Errorf("invalid length for Polygon: %v", len(src))
   138  	}
   139  
   140  	pointCount := int(binary.BigEndian.Uint32(src))
   141  	rp := 4
   142  
   143  	if 4+pointCount*16 != len(src) {
   144  		return fmt.Errorf("invalid length for Polygon with %d points: %v", pointCount, len(src))
   145  	}
   146  
   147  	points := make([]Vec2, pointCount)
   148  	for i := 0; i < len(points); i++ {
   149  		x := binary.BigEndian.Uint64(src[rp:])
   150  		rp += 8
   151  		y := binary.BigEndian.Uint64(src[rp:])
   152  		rp += 8
   153  		points[i] = Vec2{math.Float64frombits(x), math.Float64frombits(y)}
   154  	}
   155  
   156  	*dst = Polygon{
   157  		P:      points,
   158  		Status: Present,
   159  	}
   160  	return nil
   161  }
   162  
   163  func (src Polygon) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
   164  	switch src.Status {
   165  	case Null:
   166  		return nil, nil
   167  	case Undefined:
   168  		return nil, errUndefined
   169  	}
   170  
   171  	buf = append(buf, '(')
   172  
   173  	for i, p := range src.P {
   174  		if i > 0 {
   175  			buf = append(buf, ',')
   176  		}
   177  		buf = append(buf, fmt.Sprintf(`(%s,%s)`,
   178  			strconv.FormatFloat(p.X, 'f', -1, 64),
   179  			strconv.FormatFloat(p.Y, 'f', -1, 64),
   180  		)...)
   181  	}
   182  
   183  	return append(buf, ')'), nil
   184  }
   185  
   186  func (src Polygon) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
   187  	switch src.Status {
   188  	case Null:
   189  		return nil, nil
   190  	case Undefined:
   191  		return nil, errUndefined
   192  	}
   193  
   194  	buf = pgio.AppendInt32(buf, int32(len(src.P)))
   195  
   196  	for _, p := range src.P {
   197  		buf = pgio.AppendUint64(buf, math.Float64bits(p.X))
   198  		buf = pgio.AppendUint64(buf, math.Float64bits(p.Y))
   199  	}
   200  
   201  	return buf, nil
   202  }
   203  
   204  // Scan implements the database/sql Scanner interface.
   205  func (dst *Polygon) Scan(src interface{}) error {
   206  	if src == nil {
   207  		*dst = Polygon{Status: Null}
   208  		return nil
   209  	}
   210  
   211  	switch src := src.(type) {
   212  	case string:
   213  		return dst.DecodeText(nil, []byte(src))
   214  	case []byte:
   215  		srcCopy := make([]byte, len(src))
   216  		copy(srcCopy, src)
   217  		return dst.DecodeText(nil, srcCopy)
   218  	}
   219  
   220  	return fmt.Errorf("cannot scan %T", src)
   221  }
   222  
   223  // Value implements the database/sql/driver Valuer interface.
   224  func (src Polygon) Value() (driver.Value, error) {
   225  	return EncodeValueText(src)
   226  }
   227  

View as plain text