summaryrefslogtreecommitdiff
path: root/scalar.go
diff options
context:
space:
mode:
authorAlex Flint <[email protected]>2016-01-23 21:07:42 -0800
committerAlex Flint <[email protected]>2016-01-23 21:07:42 -0800
commit77dd0df006f564a0768ee7ddc194f08e328f864e (patch)
treed71dab9fd1abdac627ed1d17616e226897c50093 /scalar.go
parentc0809e537fc01b4a33ced1bf56212837108d7264 (diff)
parenta1c72f6aa9b1972a6d0e0c47052e805a0f1f3656 (diff)
Merge pull request #31 from alexflint/parse_ip_mac_and_email
Parse IP addresses, MAC addresses, and email addresses
Diffstat (limited to 'scalar.go')
-rw-r--r--scalar.go71
1 files changed, 69 insertions, 2 deletions
diff --git a/scalar.go b/scalar.go
index 67b4540..e79b002 100644
--- a/scalar.go
+++ b/scalar.go
@@ -3,11 +3,57 @@ package arg
import (
"encoding"
"fmt"
+ "net"
+ "net/mail"
"reflect"
"strconv"
"time"
)
+// The reflected form of some special types
+var (
+ textUnmarshalerType = reflect.TypeOf([]encoding.TextUnmarshaler{}).Elem()
+ durationType = reflect.TypeOf(time.Duration(0))
+ mailAddressType = reflect.TypeOf(mail.Address{})
+ ipType = reflect.TypeOf(net.IP{})
+ macType = reflect.TypeOf(net.HardwareAddr{})
+)
+
+// isScalar returns true if the type can be parsed from a single string
+func isScalar(t reflect.Type) (scalar, boolean bool) {
+ // If it implements encoding.TextUnmarshaler then use that
+ if t.Implements(textUnmarshalerType) {
+ // scalar=YES, boolean=NO
+ return true, false
+ }
+
+ // If we have a pointer then dereference it
+ if t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+
+ // Check for other special types
+ switch t {
+ case durationType, mailAddressType, ipType, macType:
+ // scalar=YES, boolean=NO
+ return true, false
+ }
+
+ // Fall back to checking the kind
+ switch t.Kind() {
+ case reflect.Bool:
+ // scalar=YES, boolean=YES
+ return true, 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.Float32, reflect.Float64:
+ // scalar=YES, boolean=NO
+ return true, false
+ }
+ // scalar=NO, boolean=NO
+ return false, false
+}
+
// set a value from a string
func setScalar(v reflect.Value, s string) error {
if !v.CanSet() {
@@ -35,11 +81,32 @@ func setScalar(v reflect.Value, s string) error {
// Switch on concrete type
switch scalar.(type) {
case time.Duration:
- x, err := time.ParseDuration(s)
+ 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.IP:
+ ip := net.ParseIP(s)
+ if ip == nil {
+ return fmt.Errorf(`invalid IP address: "%s"`, s)
+ }
+ v.Set(reflect.ValueOf(ip))
+ return nil
+ case net.HardwareAddr:
+ ip, err := net.ParseMAC(s)
if err != nil {
return err
}
- v.Set(reflect.ValueOf(x))
+ v.Set(reflect.ValueOf(ip))
return nil
}