Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop dependency on reflect #31

Merged
merged 3 commits into from
Dec 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 13 additions & 17 deletions period.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package synchro

import (
"fmt"
"reflect"
"time"
"unsafe"

"github.com/Code-Hex/synchro/internal/constraints"
"github.com/Code-Hex/synchro/iso8601"
Expand All @@ -13,8 +13,6 @@ type timeish[T TimeZone] interface {
Time[T] | time.Time | constraints.Bytes
}

var stringType = reflect.TypeOf("")

// Period allows iteration over a set of dates and times,
// recurring at regular intervals, over a given period.
type Period[T TimeZone] struct {
Expand All @@ -39,11 +37,11 @@ func (p Period[T]) To() Time[T] { return p.to }
// When a string or []byte is passed, ParseISO function is called internally. Therefore, these
// parameters should be in a format compatible with ParseISO.
func NewPeriod[T TimeZone, T1 timeish[T], T2 timeish[T]](from T1, to T2) (Period[T], error) {
start, err := convertTime[T](any(from))
start, err := convertTime[T, T1](unsafe.Pointer(&from))
if err != nil {
return Period[T]{}, fmt.Errorf("failed to parse from: %w", err)
}
end, err := convertTime[T](any(to))
end, err := convertTime[T, T2](unsafe.Pointer(&to))
if err != nil {
return Period[T]{}, fmt.Errorf("failed to parse to: %w", err)
}
Expand Down Expand Up @@ -183,21 +181,19 @@ func (p Period[T]) PeriodicISODuration(duration string) (periodical[T], error) {
}), nil
}

func convertTime[T TimeZone](arg any) (Time[T], error) {
switch v := arg.(type) {
func convertTime[T TimeZone, argType timeish[T]](argPtr unsafe.Pointer) (Time[T], error) {
var dummy argType
switch any(dummy).(type) {
case Time[T]:
return v, nil
return *(*Time[T])(argPtr), nil
case time.Time:
return In[T](v), nil
case string:
return ParseISO[T](v)
return In[T](*(*time.Time)(argPtr)), nil
case []byte:
return ParseISO[T](string(v))
bytes := *(*[]byte)(argPtr)
str := unsafe.String(unsafe.SliceData(bytes), len(bytes))
return ParseISO[T](str)
default:
rv := reflect.ValueOf(v)
if rv.CanConvert(stringType) {
return ParseISO[T](rv.Convert(stringType).String())
}
panic("unreachable")
// argType is ~string, argPtr can be safely converted to *string
return ParseISO[T](*(*string)(argPtr))
}
}
10 changes: 0 additions & 10 deletions period_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,16 +284,6 @@ func TestPeriod_PeriodicISO(t *testing.T) {
})
}

// Unfortunate test to cover 100%
func TestConvertTime_Panic(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("The code did not panic")
}
}()
convertTime[tz.UTC](true)
}

func TestPeriod_Contains(t *testing.T) {
cases := []struct {
name string
Expand Down