From 45664ca27e47913ea922f409f87363df71738fe5 Mon Sep 17 00:00:00 2001 From: Kimmo Lehto Date: Thu, 13 Jun 2024 10:09:28 +0300 Subject: [PATCH] Use sync.OnceValue only on go1.21+ sync.OnceValue was introduced in go1.21. Currently validator's go.mod states minimum go version to be go1.18. This commit moves the lazy regex initialization into its own file lazy.go and provides backwards compatibility using buildtags and the file lazy_compat.go which contains a backported (non-generic) version of sync.OnceValue. Signed-off-by: Kimmo Lehto --- lazy.go | 14 ++++++++++++++ lazy_compat.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ regexes.go | 11 ----------- 3 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 lazy.go create mode 100644 lazy_compat.go 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)