gemini-search

A simple search engine for Geminispace
git clone git://git.laack.co/gemini-search.git
Log | Files | Refs | README

convert.go (6815B)


      1 // Extracted from Go database/sql source code
      2 
      3 // Copyright 2011 The Go Authors. All rights reserved.
      4 // Use of this source code is governed by a BSD-style
      5 // license that can be found in the LICENSE file.
      6 
      7 // Type conversions for Scan.
      8 
      9 package sqlite3
     10 
     11 import (
     12 	"database/sql"
     13 	"database/sql/driver"
     14 	"errors"
     15 	"fmt"
     16 	"reflect"
     17 	"strconv"
     18 	"time"
     19 )
     20 
     21 var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
     22 
     23 // convertAssign copies to dest the value in src, converting it if possible.
     24 // An error is returned if the copy would result in loss of information.
     25 // dest should be a pointer type.
     26 func convertAssign(dest, src any) error {
     27 	// Common cases, without reflect.
     28 	switch s := src.(type) {
     29 	case string:
     30 		switch d := dest.(type) {
     31 		case *string:
     32 			if d == nil {
     33 				return errNilPtr
     34 			}
     35 			*d = s
     36 			return nil
     37 		case *[]byte:
     38 			if d == nil {
     39 				return errNilPtr
     40 			}
     41 			*d = []byte(s)
     42 			return nil
     43 		case *sql.RawBytes:
     44 			if d == nil {
     45 				return errNilPtr
     46 			}
     47 			*d = append((*d)[:0], s...)
     48 			return nil
     49 		}
     50 	case []byte:
     51 		switch d := dest.(type) {
     52 		case *string:
     53 			if d == nil {
     54 				return errNilPtr
     55 			}
     56 			*d = string(s)
     57 			return nil
     58 		case *any:
     59 			if d == nil {
     60 				return errNilPtr
     61 			}
     62 			*d = cloneBytes(s)
     63 			return nil
     64 		case *[]byte:
     65 			if d == nil {
     66 				return errNilPtr
     67 			}
     68 			*d = cloneBytes(s)
     69 			return nil
     70 		case *sql.RawBytes:
     71 			if d == nil {
     72 				return errNilPtr
     73 			}
     74 			*d = s
     75 			return nil
     76 		}
     77 	case time.Time:
     78 		switch d := dest.(type) {
     79 		case *time.Time:
     80 			*d = s
     81 			return nil
     82 		case *string:
     83 			*d = s.Format(time.RFC3339Nano)
     84 			return nil
     85 		case *[]byte:
     86 			if d == nil {
     87 				return errNilPtr
     88 			}
     89 			*d = []byte(s.Format(time.RFC3339Nano))
     90 			return nil
     91 		case *sql.RawBytes:
     92 			if d == nil {
     93 				return errNilPtr
     94 			}
     95 			*d = s.AppendFormat((*d)[:0], time.RFC3339Nano)
     96 			return nil
     97 		}
     98 	case nil:
     99 		switch d := dest.(type) {
    100 		case *any:
    101 			if d == nil {
    102 				return errNilPtr
    103 			}
    104 			*d = nil
    105 			return nil
    106 		case *[]byte:
    107 			if d == nil {
    108 				return errNilPtr
    109 			}
    110 			*d = nil
    111 			return nil
    112 		case *sql.RawBytes:
    113 			if d == nil {
    114 				return errNilPtr
    115 			}
    116 			*d = nil
    117 			return nil
    118 		}
    119 	}
    120 
    121 	var sv reflect.Value
    122 
    123 	switch d := dest.(type) {
    124 	case *string:
    125 		sv = reflect.ValueOf(src)
    126 		switch sv.Kind() {
    127 		case reflect.Bool,
    128 			reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
    129 			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
    130 			reflect.Float32, reflect.Float64:
    131 			*d = asString(src)
    132 			return nil
    133 		}
    134 	case *[]byte:
    135 		sv = reflect.ValueOf(src)
    136 		if b, ok := asBytes(nil, sv); ok {
    137 			*d = b
    138 			return nil
    139 		}
    140 	case *sql.RawBytes:
    141 		sv = reflect.ValueOf(src)
    142 		if b, ok := asBytes([]byte(*d)[:0], sv); ok {
    143 			*d = sql.RawBytes(b)
    144 			return nil
    145 		}
    146 	case *bool:
    147 		bv, err := driver.Bool.ConvertValue(src)
    148 		if err == nil {
    149 			*d = bv.(bool)
    150 		}
    151 		return err
    152 	case *any:
    153 		*d = src
    154 		return nil
    155 	}
    156 
    157 	if scanner, ok := dest.(sql.Scanner); ok {
    158 		return scanner.Scan(src)
    159 	}
    160 
    161 	dpv := reflect.ValueOf(dest)
    162 	if dpv.Kind() != reflect.Ptr {
    163 		return errors.New("destination not a pointer")
    164 	}
    165 	if dpv.IsNil() {
    166 		return errNilPtr
    167 	}
    168 
    169 	if !sv.IsValid() {
    170 		sv = reflect.ValueOf(src)
    171 	}
    172 
    173 	dv := reflect.Indirect(dpv)
    174 	if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
    175 		switch b := src.(type) {
    176 		case []byte:
    177 			dv.Set(reflect.ValueOf(cloneBytes(b)))
    178 		default:
    179 			dv.Set(sv)
    180 		}
    181 		return nil
    182 	}
    183 
    184 	if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) {
    185 		dv.Set(sv.Convert(dv.Type()))
    186 		return nil
    187 	}
    188 
    189 	// The following conversions use a string value as an intermediate representation
    190 	// to convert between various numeric types.
    191 	//
    192 	// This also allows scanning into user defined types such as "type Int int64".
    193 	// For symmetry, also check for string destination types.
    194 	switch dv.Kind() {
    195 	case reflect.Ptr:
    196 		if src == nil {
    197 			dv.Set(reflect.Zero(dv.Type()))
    198 			return nil
    199 		}
    200 		dv.Set(reflect.New(dv.Type().Elem()))
    201 		return convertAssign(dv.Interface(), src)
    202 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    203 		s := asString(src)
    204 		i64, err := strconv.ParseInt(s, 10, dv.Type().Bits())
    205 		if err != nil {
    206 			err = strconvErr(err)
    207 			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
    208 		}
    209 		dv.SetInt(i64)
    210 		return nil
    211 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
    212 		s := asString(src)
    213 		u64, err := strconv.ParseUint(s, 10, dv.Type().Bits())
    214 		if err != nil {
    215 			err = strconvErr(err)
    216 			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
    217 		}
    218 		dv.SetUint(u64)
    219 		return nil
    220 	case reflect.Float32, reflect.Float64:
    221 		s := asString(src)
    222 		f64, err := strconv.ParseFloat(s, dv.Type().Bits())
    223 		if err != nil {
    224 			err = strconvErr(err)
    225 			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err)
    226 		}
    227 		dv.SetFloat(f64)
    228 		return nil
    229 	case reflect.String:
    230 		switch v := src.(type) {
    231 		case string:
    232 			dv.SetString(v)
    233 			return nil
    234 		case []byte:
    235 			dv.SetString(string(v))
    236 			return nil
    237 		}
    238 	}
    239 
    240 	return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest)
    241 }
    242 
    243 func strconvErr(err error) error {
    244 	if ne, ok := err.(*strconv.NumError); ok {
    245 		return ne.Err
    246 	}
    247 	return err
    248 }
    249 
    250 func cloneBytes(b []byte) []byte {
    251 	if b == nil {
    252 		return nil
    253 	}
    254 	c := make([]byte, len(b))
    255 	copy(c, b)
    256 	return c
    257 }
    258 
    259 func asString(src any) string {
    260 	switch v := src.(type) {
    261 	case string:
    262 		return v
    263 	case []byte:
    264 		return string(v)
    265 	}
    266 	rv := reflect.ValueOf(src)
    267 	switch rv.Kind() {
    268 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    269 		return strconv.FormatInt(rv.Int(), 10)
    270 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
    271 		return strconv.FormatUint(rv.Uint(), 10)
    272 	case reflect.Float64:
    273 		return strconv.FormatFloat(rv.Float(), 'g', -1, 64)
    274 	case reflect.Float32:
    275 		return strconv.FormatFloat(rv.Float(), 'g', -1, 32)
    276 	case reflect.Bool:
    277 		return strconv.FormatBool(rv.Bool())
    278 	}
    279 	return fmt.Sprintf("%v", src)
    280 }
    281 
    282 func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
    283 	switch rv.Kind() {
    284 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    285 		return strconv.AppendInt(buf, rv.Int(), 10), true
    286 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
    287 		return strconv.AppendUint(buf, rv.Uint(), 10), true
    288 	case reflect.Float32:
    289 		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true
    290 	case reflect.Float64:
    291 		return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true
    292 	case reflect.Bool:
    293 		return strconv.AppendBool(buf, rv.Bool()), true
    294 	case reflect.String:
    295 		s := rv.String()
    296 		return append(buf, s...), true
    297 	}
    298 	return
    299 }