diff --git a/urlpath.go b/urlpath.go index 59552dc..d40fdd1 100644 --- a/urlpath.go +++ b/urlpath.go @@ -75,51 +75,45 @@ type Parser interface { Parse(string) error } -type stringParser struct { - destination *string +type StringType interface { + ~string } -// String creates a parser that will parse a path element into s. -func String(s *string) Parser { - return &stringParser{destination: s} +type stringParser[T StringType] struct { + destination *T } -func (p *stringParser) Parse(s string) error { - *p.destination = s +func (p *stringParser[T]) Parse(s string) error { + *p.destination = T(s) return nil } -type intParser struct { - destination *int +// String creates a parser that will parse a path element into s. +func String[T StringType](s *T) Parser { + return &stringParser[T]{destination: s} } -// Int creates a Parser that will parse a path element into i. -func Int(i *int) Parser { - return &intParser{destination: i} +// IntType represents any type compatible with the Go integer built-in types, +// to be used as a destination for writing the value of an url path element. +type IntType interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 } -func (p *intParser) Parse(s string) error { +type intParser[T IntType] struct { + destination *T +} + +func (p *intParser[T]) Parse(s string) error { i, err := strconv.Atoi(s) if err != nil { return err } - *p.destination = i + *p.destination = T(i) return nil } -type uint64Parser struct { - destination *uint64 -} - -func UInt64(i *uint64) Parser { - return &uint64Parser{destination: i} -} - -func (u uint64Parser) Parse(s string) error { - i, err := strconv.ParseUint(s, 10, 64) - if err != nil { - return err - } - *u.destination = i - return nil +// Int creates a Parser that will parse a path element into i. +func Int[T IntType](i *T) Parser { + return &intParser[T]{destination: i} } diff --git a/urlpath_test.go b/urlpath_test.go index 6b91817..6cf2ef0 100644 --- a/urlpath_test.go +++ b/urlpath_test.go @@ -48,24 +48,20 @@ func Test_ParseValues(t *testing.T) { var foo string var bar int - var id uint64 values := map[string]string{ "foo": "blah", "bar": "21", - "id": "42", } err := ParseValues(values, Schema{ "foo": String(&foo), "bar": Int(&bar), - "id": UInt64(&id), }) must.NoError(t, err) must.EqOp(t, "blah", foo) must.EqOp(t, 21, bar) - must.EqOp(t, 42, id) } func Test_ParseValues_incompatible(t *testing.T) { @@ -112,3 +108,39 @@ func Test_Parameter_String(t *testing.T) { s := p.String() must.EqOp(t, "{foo}", s) } + +func Test_ParseValues_StringType_Parse(t *testing.T) { + t.Parallel() + + values := map[string]string{ + "KEY": "value", + } + + type ident string + + var id ident + + err := ParseValues(values, Schema{ + "KEY": String(&id), + }) + must.NoError(t, err) + must.Eq(t, "value", id) +} + +func Test_ParseValues_IntType_Parse(t *testing.T) { + t.Parallel() + + type years int + var age years + + values := map[string]string{ + "age": "51", + } + + err := ParseValues(values, Schema{ + "age": Int(&age), + }) + + must.NoError(t, err) + must.Eq(t, 51, age) +}