...

Source file src/github.com/jackc/pgtype/path.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 Path struct {
    15  	P      []Vec2
    16  	Closed bool
    17  	Status Status
    18  }
    19  
    20  func (dst *Path) Set(src interface{}) error {
    21  	return fmt.Errorf("cannot convert %v to Path", src)
    22  }
    23  
    24  func (dst Path) 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  
    35  func (src *Path) AssignTo(dst interface{}) error {
    36  	return fmt.Errorf("cannot assign %v to %T", src, dst)
    37  }
    38  
    39  func (dst *Path) DecodeText(ci *ConnInfo, src []byte) error {
    40  	if src == nil {
    41  		*dst = Path{Status: Null}
    42  		return nil
    43  	}
    44  
    45  	if len(src) < 7 {
    46  		return fmt.Errorf("invalid length for Path: %v", len(src))
    47  	}
    48  
    49  	closed := src[0] == '('
    50  	points := make([]Vec2, 0)
    51  
    52  	str := string(src[2:])
    53  
    54  	for {
    55  		end := strings.IndexByte(str, ',')
    56  		x, err := strconv.ParseFloat(str[:end], 64)
    57  		if err != nil {
    58  			return err
    59  		}
    60  
    61  		str = str[end+1:]
    62  		end = strings.IndexByte(str, ')')
    63  
    64  		y, err := strconv.ParseFloat(str[:end], 64)
    65  		if err != nil {
    66  			return err
    67  		}
    68  
    69  		points = append(points, Vec2{x, y})
    70  
    71  		if end+3 < len(str) {
    72  			str = str[end+3:]
    73  		} else {
    74  			break
    75  		}
    76  	}
    77  
    78  	*dst = Path{P: points, Closed: closed, Status: Present}
    79  	return nil
    80  }
    81  
    82  func (dst *Path) DecodeBinary(ci *ConnInfo, src []byte) error {
    83  	if src == nil {
    84  		*dst = Path{Status: Null}
    85  		return nil
    86  	}
    87  
    88  	if len(src) < 5 {
    89  		return fmt.Errorf("invalid length for Path: %v", len(src))
    90  	}
    91  
    92  	closed := src[0] == 1
    93  	pointCount := int(binary.BigEndian.Uint32(src[1:]))
    94  
    95  	rp := 5
    96  
    97  	if 5+pointCount*16 != len(src) {
    98  		return fmt.Errorf("invalid length for Path with %d points: %v", pointCount, len(src))
    99  	}
   100  
   101  	points := make([]Vec2, pointCount)
   102  	for i := 0; i < len(points); i++ {
   103  		x := binary.BigEndian.Uint64(src[rp:])
   104  		rp += 8
   105  		y := binary.BigEndian.Uint64(src[rp:])
   106  		rp += 8
   107  		points[i] = Vec2{math.Float64frombits(x), math.Float64frombits(y)}
   108  	}
   109  
   110  	*dst = Path{
   111  		P:      points,
   112  		Closed: closed,
   113  		Status: Present,
   114  	}
   115  	return nil
   116  }
   117  
   118  func (src Path) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
   119  	switch src.Status {
   120  	case Null:
   121  		return nil, nil
   122  	case Undefined:
   123  		return nil, errUndefined
   124  	}
   125  
   126  	var startByte, endByte byte
   127  	if src.Closed {
   128  		startByte = '('
   129  		endByte = ')'
   130  	} else {
   131  		startByte = '['
   132  		endByte = ']'
   133  	}
   134  	buf = append(buf, startByte)
   135  
   136  	for i, p := range src.P {
   137  		if i > 0 {
   138  			buf = append(buf, ',')
   139  		}
   140  		buf = append(buf, fmt.Sprintf(`(%s,%s)`,
   141  			strconv.FormatFloat(p.X, 'f', -1, 64),
   142  			strconv.FormatFloat(p.Y, 'f', -1, 64),
   143  		)...)
   144  	}
   145  
   146  	return append(buf, endByte), nil
   147  }
   148  
   149  func (src Path) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
   150  	switch src.Status {
   151  	case Null:
   152  		return nil, nil
   153  	case Undefined:
   154  		return nil, errUndefined
   155  	}
   156  
   157  	var closeByte byte
   158  	if src.Closed {
   159  		closeByte = 1
   160  	}
   161  	buf = append(buf, closeByte)
   162  
   163  	buf = pgio.AppendInt32(buf, int32(len(src.P)))
   164  
   165  	for _, p := range src.P {
   166  		buf = pgio.AppendUint64(buf, math.Float64bits(p.X))
   167  		buf = pgio.AppendUint64(buf, math.Float64bits(p.Y))
   168  	}
   169  
   170  	return buf, nil
   171  }
   172  
   173  // Scan implements the database/sql Scanner interface.
   174  func (dst *Path) Scan(src interface{}) error {
   175  	if src == nil {
   176  		*dst = Path{Status: Null}
   177  		return nil
   178  	}
   179  
   180  	switch src := src.(type) {
   181  	case string:
   182  		return dst.DecodeText(nil, []byte(src))
   183  	case []byte:
   184  		srcCopy := make([]byte, len(src))
   185  		copy(srcCopy, src)
   186  		return dst.DecodeText(nil, srcCopy)
   187  	}
   188  
   189  	return fmt.Errorf("cannot scan %T", src)
   190  }
   191  
   192  // Value implements the database/sql/driver Valuer interface.
   193  func (src Path) Value() (driver.Value, error) {
   194  	return EncodeValueText(src)
   195  }
   196  

View as plain text