...

Source file src/github.com/jackc/pgx/v5/pgtype/lseg.go

Documentation: github.com/jackc/pgx/v5/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/pgx/v5/internal/pgio"
    12  )
    13  
    14  type LsegScanner interface {
    15  	ScanLseg(v Lseg) error
    16  }
    17  
    18  type LsegValuer interface {
    19  	LsegValue() (Lseg, error)
    20  }
    21  
    22  type Lseg struct {
    23  	P     [2]Vec2
    24  	Valid bool
    25  }
    26  
    27  func (lseg *Lseg) ScanLseg(v Lseg) error {
    28  	*lseg = v
    29  	return nil
    30  }
    31  
    32  func (lseg Lseg) LsegValue() (Lseg, error) {
    33  	return lseg, nil
    34  }
    35  
    36  // Scan implements the database/sql Scanner interface.
    37  func (lseg *Lseg) Scan(src any) error {
    38  	if src == nil {
    39  		*lseg = Lseg{}
    40  		return nil
    41  	}
    42  
    43  	switch src := src.(type) {
    44  	case string:
    45  		return scanPlanTextAnyToLsegScanner{}.Scan([]byte(src), lseg)
    46  	}
    47  
    48  	return fmt.Errorf("cannot scan %T", src)
    49  }
    50  
    51  // Value implements the database/sql/driver Valuer interface.
    52  func (lseg Lseg) Value() (driver.Value, error) {
    53  	if !lseg.Valid {
    54  		return nil, nil
    55  	}
    56  
    57  	buf, err := LsegCodec{}.PlanEncode(nil, 0, TextFormatCode, lseg).Encode(lseg, nil)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	return string(buf), err
    62  }
    63  
    64  type LsegCodec struct{}
    65  
    66  func (LsegCodec) FormatSupported(format int16) bool {
    67  	return format == TextFormatCode || format == BinaryFormatCode
    68  }
    69  
    70  func (LsegCodec) PreferredFormat() int16 {
    71  	return BinaryFormatCode
    72  }
    73  
    74  func (LsegCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
    75  	if _, ok := value.(LsegValuer); !ok {
    76  		return nil
    77  	}
    78  
    79  	switch format {
    80  	case BinaryFormatCode:
    81  		return encodePlanLsegCodecBinary{}
    82  	case TextFormatCode:
    83  		return encodePlanLsegCodecText{}
    84  	}
    85  
    86  	return nil
    87  }
    88  
    89  type encodePlanLsegCodecBinary struct{}
    90  
    91  func (encodePlanLsegCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
    92  	lseg, err := value.(LsegValuer).LsegValue()
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	if !lseg.Valid {
    98  		return nil, nil
    99  	}
   100  
   101  	buf = pgio.AppendUint64(buf, math.Float64bits(lseg.P[0].X))
   102  	buf = pgio.AppendUint64(buf, math.Float64bits(lseg.P[0].Y))
   103  	buf = pgio.AppendUint64(buf, math.Float64bits(lseg.P[1].X))
   104  	buf = pgio.AppendUint64(buf, math.Float64bits(lseg.P[1].Y))
   105  	return buf, nil
   106  }
   107  
   108  type encodePlanLsegCodecText struct{}
   109  
   110  func (encodePlanLsegCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
   111  	lseg, err := value.(LsegValuer).LsegValue()
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	if !lseg.Valid {
   117  		return nil, nil
   118  	}
   119  
   120  	buf = append(buf, fmt.Sprintf(`[(%s,%s),(%s,%s)]`,
   121  		strconv.FormatFloat(lseg.P[0].X, 'f', -1, 64),
   122  		strconv.FormatFloat(lseg.P[0].Y, 'f', -1, 64),
   123  		strconv.FormatFloat(lseg.P[1].X, 'f', -1, 64),
   124  		strconv.FormatFloat(lseg.P[1].Y, 'f', -1, 64),
   125  	)...)
   126  	return buf, nil
   127  }
   128  
   129  func (LsegCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
   130  
   131  	switch format {
   132  	case BinaryFormatCode:
   133  		switch target.(type) {
   134  		case LsegScanner:
   135  			return scanPlanBinaryLsegToLsegScanner{}
   136  		}
   137  	case TextFormatCode:
   138  		switch target.(type) {
   139  		case LsegScanner:
   140  			return scanPlanTextAnyToLsegScanner{}
   141  		}
   142  	}
   143  
   144  	return nil
   145  }
   146  
   147  type scanPlanBinaryLsegToLsegScanner struct{}
   148  
   149  func (scanPlanBinaryLsegToLsegScanner) Scan(src []byte, dst any) error {
   150  	scanner := (dst).(LsegScanner)
   151  
   152  	if src == nil {
   153  		return scanner.ScanLseg(Lseg{})
   154  	}
   155  
   156  	if len(src) != 32 {
   157  		return fmt.Errorf("invalid length for lseg: %v", len(src))
   158  	}
   159  
   160  	x1 := binary.BigEndian.Uint64(src)
   161  	y1 := binary.BigEndian.Uint64(src[8:])
   162  	x2 := binary.BigEndian.Uint64(src[16:])
   163  	y2 := binary.BigEndian.Uint64(src[24:])
   164  
   165  	return scanner.ScanLseg(Lseg{
   166  		P: [2]Vec2{
   167  			{math.Float64frombits(x1), math.Float64frombits(y1)},
   168  			{math.Float64frombits(x2), math.Float64frombits(y2)},
   169  		},
   170  		Valid: true,
   171  	})
   172  }
   173  
   174  type scanPlanTextAnyToLsegScanner struct{}
   175  
   176  func (scanPlanTextAnyToLsegScanner) Scan(src []byte, dst any) error {
   177  	scanner := (dst).(LsegScanner)
   178  
   179  	if src == nil {
   180  		return scanner.ScanLseg(Lseg{})
   181  	}
   182  
   183  	if len(src) < 11 {
   184  		return fmt.Errorf("invalid length for lseg: %v", len(src))
   185  	}
   186  
   187  	str := string(src[2:])
   188  
   189  	var end int
   190  	end = strings.IndexByte(str, ',')
   191  
   192  	x1, err := strconv.ParseFloat(str[:end], 64)
   193  	if err != nil {
   194  		return err
   195  	}
   196  
   197  	str = str[end+1:]
   198  	end = strings.IndexByte(str, ')')
   199  
   200  	y1, err := strconv.ParseFloat(str[:end], 64)
   201  	if err != nil {
   202  		return err
   203  	}
   204  
   205  	str = str[end+3:]
   206  	end = strings.IndexByte(str, ',')
   207  
   208  	x2, err := strconv.ParseFloat(str[:end], 64)
   209  	if err != nil {
   210  		return err
   211  	}
   212  
   213  	str = str[end+1 : len(str)-2]
   214  
   215  	y2, err := strconv.ParseFloat(str, 64)
   216  	if err != nil {
   217  		return err
   218  	}
   219  
   220  	return scanner.ScanLseg(Lseg{P: [2]Vec2{{x1, y1}, {x2, y2}}, Valid: true})
   221  }
   222  
   223  func (c LsegCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
   224  	return codecDecodeToTextFormat(c, m, oid, format, src)
   225  }
   226  
   227  func (c LsegCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
   228  	if src == nil {
   229  		return nil, nil
   230  	}
   231  
   232  	var lseg Lseg
   233  	err := codecScan(c, m, oid, format, src, &lseg)
   234  	if err != nil {
   235  		return nil, err
   236  	}
   237  	return lseg, nil
   238  }
   239  

View as plain text