aboutsummaryrefslogtreecommitdiff
path: root/flag.go
blob: ce394b87a66a77007b8de7f3b5d893200f491b9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// SPDX-FileCopyrightText: © 2022 Grégoire Duchêne <gduchene@awhk.org>
// SPDX-License-Identifier: ISC

package core

import (
	"flag"
	"fmt"
	"time"
)

func FlagVar[T any](fs *flag.FlagSet, name, usage string, parse ParseFunc[T]) *T {
	v := &flagValue[T]{Parse: parse, Value: new(T)}
	fs.Var(v, name, usage)
	return v.Value
}

func FlagVarDef[T any](fs *flag.FlagSet, name, usage string, parse ParseFunc[T], def T) *T {
	val := def
	FlagVarPtr(fs, name, usage, parse, &val)
	return &val
}

func FlagVarPtr[T any](fs *flag.FlagSet, name, usage string, parse ParseFunc[T], val *T) {
	fs.Var(&flagValue[T]{Parse: parse, Value: val}, name, usage)
}

func FlagVarSlice[T any](fs *flag.FlagSet, name, usage string, parse ParseFunc[T]) *[]T {
	v := &flagValueSlice[T]{Parse: parse, Values: new([]T)}
	fs.Var(v, name, usage)
	return v.Values
}

func FlagVarSliceDef[T any](fs *flag.FlagSet, name, usage string, parse ParseFunc[T], def []T) *[]T {
	vals := make([]T, len(def))
	copy(vals, def)
	FlagVarSlicePtr(fs, name, usage, parse, &vals)
	return &vals
}

func FlagVarSlicePtr[T any](fs *flag.FlagSet, name, usage string, parse ParseFunc[T], vals *[]T) {
	fs.Var(&flagValueSlice[T]{Parse: parse, Values: vals}, name, usage)
}

// ParseString returns the string passed with no error set.
func ParseString(s string) (string, error) {
	return s, nil
}

// ParseTime parses a string according to the time.RFC3339 format.
func ParseTime(s string) (time.Time, error) {
	return time.Parse(time.RFC3339, s)
}

// ParseFunc describes functions that will parse a string and return a
// value or an error.
type ParseFunc[T any] func(string) (T, error)

type flagValue[T any] struct {
	Parse ParseFunc[T]
	Value *T
}

var _ flag.Value = &flagValue[any]{}

func (f *flagValue[T]) Set(s string) error {
	val, err := f.Parse(s)
	if err != nil {
		return err
	}
	*f.Value = val
	return nil
}

func (f *flagValue[T]) String() string {
	return fmt.Sprintf("%v", f.Value)
}

type flagValueSlice[T any] struct {
	Parse  ParseFunc[T]
	Values *[]T

	shouldAppend bool
}

var _ flag.Value = &flagValueSlice[any]{}

func (f *flagValueSlice[T]) Set(s string) error {
	val, err := f.Parse(s)
	if err != nil {
		return err
	}
	if f.shouldAppend {
		*f.Values = append(*f.Values, val)
	} else {
		*f.Values = []T{val}
		f.shouldAppend = true
	}
	return nil
}

func (f *flagValueSlice[T]) String() string {
	return fmt.Sprintf("%v", f.Values)
}