diff --git a/lazy.go b/lazy.go new file mode 100644 index 00000000..af6cc219 --- /dev/null +++ b/lazy.go @@ -0,0 +1,14 @@ +//go:build go1.21 + +package validator + +import ( + "regexp" + "sync" +) + +func lazyRegexCompile(str string) func() *regexp.Regexp { + return sync.OnceValue(func() *regexp.Regexp { + return regexp.MustCompile(str) + }) +} diff --git a/lazy_compat.go b/lazy_compat.go new file mode 100644 index 00000000..5270f021 --- /dev/null +++ b/lazy_compat.go @@ -0,0 +1,46 @@ +//go:build !go1.21 + +package validator + +import ( + "regexp" + "sync" +) + +// Copied and adapted from go1.21 stdlib's sync.OnceValue for backwards compatibility: +// OnceValue returns a function that invokes f only once and returns the value +// returned by f. The returned function may be called concurrently. +// +// If f panics, the returned function will panic with the same value on every call. +func onceValue(f func() *regexp.Regexp) func() *regexp.Regexp { + var ( + once sync.Once + valid bool + p any + result *regexp.Regexp + ) + g := func() { + defer func() { + p = recover() + if !valid { + panic(p) + } + }() + result = f() + f = nil + valid = true + } + return func() *regexp.Regexp { + once.Do(g) + if !valid { + panic(p) + } + return result + } +} + +func lazyRegexCompile(str string) func() *regexp.Regexp { + return onceValue(func() *regexp.Regexp { + return regexp.MustCompile(str) + }) +} diff --git a/regexes.go b/regexes.go index f0dc2581..df0cfde7 100644 --- a/regexes.go +++ b/regexes.go @@ -1,10 +1,5 @@ package validator -import ( - "regexp" - "sync" -) - const ( alphaRegexString = "^[a-zA-Z]+$" alphaNumericRegexString = "^[a-zA-Z0-9]+$" @@ -79,12 +74,6 @@ const ( spicedbTypeRegexString = "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$" ) -func lazyRegexCompile(str string) func() *regexp.Regexp { - return sync.OnceValue(func() *regexp.Regexp { - return regexp.MustCompile(str) - }) -} - var ( alphaRegex = lazyRegexCompile(alphaRegexString) alphaNumericRegex = lazyRegexCompile(alphaNumericRegexString)