Skip to content

Commit

Permalink
Add TextMarshaler
Browse files Browse the repository at this point in the history
  • Loading branch information
cristaloleg committed May 21, 2022
1 parent 625f487 commit b751118
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 0 deletions.
17 changes: 17 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package flagx_test

import (
"fmt"
"net"
"os"
"time"

Expand All @@ -22,3 +23,19 @@ func ExampleFlagSet() {
panic(fmt.Sprintf("got %v want %v", d, 20*time.Second))
}
}

func ExampleTextVar() {
fs := flagx.NewFlagSet("ExampleTextVar", os.Stdout)

var ip net.IP
fs.Text(&ip, "ip", "", net.IPv4(192, 168, 0, 100), "`IP address` to parse")

err := fs.Parse([]string{"-ip", "127.0.0.1"})
if err != nil {
panic(err)
}
fmt.Printf("{ip: %v}\n\n", ip)

// Output:
// {ip: 127.0.0.1}
}
15 changes: 15 additions & 0 deletions flagx.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package flagx

import (
"encoding"
"flag"
"io"
"time"
Expand Down Expand Up @@ -80,6 +81,20 @@ func (f *FlagSet) Func(name, alias, usage string, fn func(string) error) {
}
}

// Text defines a flag with the specified name and usage string.
// The argument p must be a pointer to a variable that will hold the value
// of the flag, and p must implement encoding.TextUnmarshaler.
// If the flag is used, the flag value will be passed to p's UnmarshalText method.
// The type of the default value must be the same as the type of p.
// Empty string for alias means no alias will be created.
func (f *FlagSet) Text(p encoding.TextUnmarshaler, name, alias string, value encoding.TextMarshaler, usage string) {
// TODO(cristaloleg): for Go 1.19 this can be f.fs.TextVar(...)
f.fs.Var(newTextValue(value, p), name, usage)
if alias != "" {
f.fs.Var(newTextValue(value, p), alias, usage)
}
}

// Bool defines a bool flag with specified name, alias, default value, and usage string.
// The argument p points to a bool variable in which to store the value of the flag.
// Empty string for alias means no alias will be created.
Expand Down
44 changes: 44 additions & 0 deletions utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package flagx

import (
"encoding"
"fmt"
"reflect"
)

type textValue struct {
val encoding.TextUnmarshaler
}

func newTextValue(val encoding.TextMarshaler, p encoding.TextUnmarshaler) textValue {
ptrVal := reflect.ValueOf(p)
if ptrVal.Kind() != reflect.Ptr {
panic("flagx: variable value type must be a pointer")
}
defVal := reflect.ValueOf(val)
if defVal.Kind() == reflect.Ptr {
defVal = defVal.Elem()
}
if defVal.Type() != ptrVal.Type().Elem() {
panic(fmt.Sprintf("flagx: default type does not match variable type: %v != %v", defVal.Type(), ptrVal.Type().Elem()))
}
ptrVal.Elem().Set(defVal)
return textValue{p}
}

func (v textValue) Set(s string) error {
return v.val.UnmarshalText([]byte(s))
}

func (v textValue) Get() interface{} {
return v.val
}

func (v textValue) String() string {
if m, ok := v.val.(encoding.TextMarshaler); ok {
if b, err := m.MarshalText(); err == nil {
return string(b)
}
}
return ""
}

0 comments on commit b751118

Please sign in to comment.