package scalar
import (
"encoding"
"errors"
"fmt"
"net"
"net/mail"
"net/url"
"reflect"
"strconv"
"time"
)
var (
textUnmarshalerType = reflect .TypeOf ([]encoding .TextUnmarshaler {}).Elem ()
durationType = reflect .TypeOf (time .Duration (0 ))
mailAddressType = reflect .TypeOf (mail .Address {})
macType = reflect .TypeOf (net .HardwareAddr {})
urlType = reflect .TypeOf (url .URL {})
)
var (
errNotSettable = errors .New ("value is not settable" )
errPtrNotSettable = errors .New ("value is a nil pointer and is not settable" )
)
func Parse (dest interface {}, s string ) error {
return ParseValue (reflect .ValueOf (dest ), s )
}
func ParseValue (v reflect .Value , s string ) error {
if v .Kind () == reflect .Ptr && v .IsNil () {
if !v .CanSet () {
return errPtrNotSettable
}
v .Set (reflect .New (v .Type ().Elem ()))
}
if scalar , ok := v .Interface ().(encoding .TextUnmarshaler ); ok {
return scalar .UnmarshalText ([]byte (s ))
}
if v .CanAddr () {
if scalar , ok := v .Addr ().Interface ().(encoding .TextUnmarshaler ); ok {
return scalar .UnmarshalText ([]byte (s ))
}
}
if v .Kind () == reflect .Ptr {
v = v .Elem ()
}
if !v .CanSet () {
return errNotSettable
}
switch scalar := v .Interface (); scalar .(type ) {
case time .Duration :
duration , err := time .ParseDuration (s )
if err != nil {
return err
}
v .Set (reflect .ValueOf (duration ))
return nil
case mail .Address :
addr , err := mail .ParseAddress (s )
if err != nil {
return err
}
v .Set (reflect .ValueOf (*addr ))
return nil
case net .HardwareAddr :
ip , err := net .ParseMAC (s )
if err != nil {
return err
}
v .Set (reflect .ValueOf (ip ))
return nil
case url .URL :
url , err := url .Parse (s )
if err != nil {
return err
}
v .Set (reflect .ValueOf (*url ))
return nil
}
switch v .Kind () {
case reflect .String :
v .SetString (s )
case reflect .Bool :
x , err := strconv .ParseBool (s )
if err != nil {
return err
}
v .SetBool (x )
case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
x , err := strconv .ParseInt (s , 0 , v .Type ().Bits ())
if err != nil {
return err
}
v .SetInt (x )
case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
x , err := strconv .ParseUint (s , 0 , v .Type ().Bits ())
if err != nil {
return err
}
v .SetUint (x )
case reflect .Float32 , reflect .Float64 :
x , err := strconv .ParseFloat (s , v .Type ().Bits ())
if err != nil {
return err
}
v .SetFloat (x )
default :
return fmt .Errorf ("cannot parse into %v" , v .Type ())
}
return nil
}
func CanParse (t reflect .Type ) bool {
if t .Implements (textUnmarshalerType ) || reflect .PtrTo (t ).Implements (textUnmarshalerType ) {
return true
}
if t .Kind () == reflect .Ptr {
t = t .Elem ()
}
switch t {
case durationType , mailAddressType , macType , urlType :
return true
}
switch t .Kind () {
case reflect .Bool :
return true
case reflect .String , reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 ,
reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr ,
reflect .Float32 , reflect .Float64 :
return true
}
return false
}
The pages are generated with Golds v0.8.2 . (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 @zigo_101 (reachable from the left QR code) to get the latest news of Golds .