aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md6
-rw-r--r--README.md1
-rw-r--r--is/comparable.go18
-rw-r--r--is/doc.go28
-rw-r--r--is/is_test.go61
-rw-r--r--is/ordered.go34
-rw-r--r--is/time.go34
7 files changed, 182 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 88344e5..a876250 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,12 @@ SPDX-FileCopyrightText: 2025 Stefan Majewsky <majewsky@gmx.net>
SPDX-License-Identifier: Apache-2.0
-->
+# v1.5.0 (TBD)
+
+Changes:
+
+- Add package is.
+
# v1.4.0 (2025-11-18)
Changes:
diff --git a/README.md b/README.md
index aad5a55..90ae517 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,7 @@ My personal extension of the standard library, mostly containing foundational ge
- [assetembed](./assetembed/): HTTP handler for efficiently serving embedded assets using the cache-busting pattern
- [jsonmatch](./jsonmatch/): matching of encoded JSON payloads against fixed assertions
+- [is](./is/): binary operations that are expressed in a curried style, e.g. `is.LessThan(b)(a) == a < b`, for use with `Option.IsSomeAnd()` etc.
- [option](./option/): an Option type with strong isolation
- [options](./options/): additional functions for type Option
diff --git a/is/comparable.go b/is/comparable.go
new file mode 100644
index 0000000..7d639d8
--- /dev/null
+++ b/is/comparable.go
@@ -0,0 +1,18 @@
+// SPDX-FileCopyrightText: 2025 Stefan Majewsky <majewsky@gmx.net>
+// SPDX-License-Identifier: Apache-2.0
+
+package is
+
+// EqualTo(b)(a) is the same as a == b.
+func EqualTo[T comparable](rhs T) func(T) bool {
+ return func(lhs T) bool {
+ return lhs == rhs
+ }
+}
+
+// DifferentFrom(b)(a) is the same as a != b.
+func DifferentFrom[T comparable](rhs T) func(T) bool {
+ return func(lhs T) bool {
+ return lhs != rhs
+ }
+}
diff --git a/is/doc.go b/is/doc.go
new file mode 100644
index 0000000..42af01e
--- /dev/null
+++ b/is/doc.go
@@ -0,0 +1,28 @@
+// SPDX-FileCopyrightText: 2025 Stefan Majewsky <majewsky@gmx.net>
+// SPDX-License-Identifier: Apache-2.0
+
+// Package is contains functions to express binary operations in a curried style.
+// For example, "foo < bar" can be rewritten as "is.LessThan(bar)(foo)".
+//
+// This is not useful on its own, but may significantly improve readability
+// when replacing function literals. Consider the following example:
+//
+// import . "github.com/majewsky/gg/option"
+//
+// func checkNewVolumeSize(size, usage uint64, maxSize Option[uint64]) error {
+// switch {
+// case size < usage:
+// return errors.New("size cannot be smaller than usage")
+// case maxSize.IsSomeAnd(func(value uint64) bool { return maxSize < size }):
+// return errors.New("size cannot be larger than maximum")
+// }
+// }
+//
+// The IsSomeAnd() check is difficult to read because function literals in Go are clunky.
+// This can be rewritten in a clearer way using is.LessThan():
+//
+// // original
+// case maxSize.IsSomeAnd(func(value uint64) bool { return maxSize < size }):
+// // rewritten
+// case maxSize.IsSomeAnd(is.LessThan(size)):
+package is
diff --git a/is/is_test.go b/is/is_test.go
new file mode 100644
index 0000000..3c6c7db
--- /dev/null
+++ b/is/is_test.go
@@ -0,0 +1,61 @@
+// SPDX-FileCopyrightText: 2025 Stefan Majewsky <majewsky@gmx.net>
+// SPDX-License-Identifier: Apache-2.0
+
+package is_test
+
+import (
+ "testing"
+ "time"
+
+ . "github.com/majewsky/gg/internal/test"
+ "github.com/majewsky/gg/is"
+ . "github.com/majewsky/gg/option"
+)
+
+func TestComparable(t *testing.T) {
+ AssertEqual(t, Some("foo").IsSomeAnd(is.EqualTo("foo")), true)
+ AssertEqual(t, Some("bar").IsSomeAnd(is.EqualTo("foo")), false)
+
+ AssertEqual(t, Some("foo").IsSomeAnd(is.DifferentFrom("foo")), false)
+ AssertEqual(t, Some("bar").IsSomeAnd(is.DifferentFrom("foo")), true)
+}
+
+func TestOrdered(t *testing.T) {
+ AssertEqual(t, Some(3).IsSomeAnd(is.Above(4)), false)
+ AssertEqual(t, Some(4).IsSomeAnd(is.Above(4)), false)
+ AssertEqual(t, Some(5).IsSomeAnd(is.Above(4)), true)
+
+ AssertEqual(t, Some(3).IsSomeAnd(is.Below(4)), true)
+ AssertEqual(t, Some(4).IsSomeAnd(is.Below(4)), false)
+ AssertEqual(t, Some(5).IsSomeAnd(is.Below(4)), false)
+
+ AssertEqual(t, Some(3).IsSomeAnd(is.NotAbove(4)), true)
+ AssertEqual(t, Some(4).IsSomeAnd(is.NotAbove(4)), true)
+ AssertEqual(t, Some(5).IsSomeAnd(is.NotAbove(4)), false)
+
+ AssertEqual(t, Some(3).IsSomeAnd(is.NotBelow(4)), false)
+ AssertEqual(t, Some(4).IsSomeAnd(is.NotBelow(4)), true)
+ AssertEqual(t, Some(5).IsSomeAnd(is.NotBelow(4)), true)
+}
+
+func TestTime(t *testing.T) {
+ t1 := time.Now()
+ t2 := t1.Add(time.Second)
+ t3 := t2.Add(time.Second)
+
+ AssertEqual(t, Some(t1).IsSomeAnd(is.After(t2)), false)
+ AssertEqual(t, Some(t2).IsSomeAnd(is.After(t2)), false)
+ AssertEqual(t, Some(t3).IsSomeAnd(is.After(t2)), true)
+
+ AssertEqual(t, Some(t1).IsSomeAnd(is.Before(t2)), true)
+ AssertEqual(t, Some(t2).IsSomeAnd(is.Before(t2)), false)
+ AssertEqual(t, Some(t3).IsSomeAnd(is.Before(t2)), false)
+
+ AssertEqual(t, Some(t1).IsSomeAnd(is.NotAfter(t2)), true)
+ AssertEqual(t, Some(t2).IsSomeAnd(is.NotAfter(t2)), true)
+ AssertEqual(t, Some(t3).IsSomeAnd(is.NotAfter(t2)), false)
+
+ AssertEqual(t, Some(t1).IsSomeAnd(is.NotBefore(t2)), false)
+ AssertEqual(t, Some(t2).IsSomeAnd(is.NotBefore(t2)), true)
+ AssertEqual(t, Some(t3).IsSomeAnd(is.NotBefore(t2)), true)
+}
diff --git a/is/ordered.go b/is/ordered.go
new file mode 100644
index 0000000..79fada7
--- /dev/null
+++ b/is/ordered.go
@@ -0,0 +1,34 @@
+// SPDX-FileCopyrightText: 2025 Stefan Majewsky <majewsky@gmx.net>
+// SPDX-License-Identifier: Apache-2.0
+
+package is
+
+import "cmp"
+
+// Above(b)(a) is the same as a > b.
+func Above[T cmp.Ordered](rhs T) func(T) bool {
+ return func(lhs T) bool {
+ return lhs > rhs
+ }
+}
+
+// Below(b)(a) is the same as a < b.
+func Below[T cmp.Ordered](rhs T) func(T) bool {
+ return func(lhs T) bool {
+ return lhs < rhs
+ }
+}
+
+// NotAbove(b)(a) is the same as a <= b.
+func NotAbove[T cmp.Ordered](rhs T) func(T) bool {
+ return func(lhs T) bool {
+ return lhs <= rhs
+ }
+}
+
+// NotBelow(b)(a) is the same as a >= b.
+func NotBelow[T cmp.Ordered](rhs T) func(T) bool {
+ return func(lhs T) bool {
+ return lhs >= rhs
+ }
+}
diff --git a/is/time.go b/is/time.go
new file mode 100644
index 0000000..3aadaf1
--- /dev/null
+++ b/is/time.go
@@ -0,0 +1,34 @@
+// SPDX-FileCopyrightText: 2025 Stefan Majewsky <majewsky@gmx.net>
+// SPDX-License-Identifier: Apache-2.0
+
+package is
+
+import "time"
+
+// After(b)(a) is the same as a .After(b).
+func After(rhs time.Time) func(time.Time) bool {
+ return func(lhs time.Time) bool {
+ return lhs.After(rhs)
+ }
+}
+
+// Before(b)(a) is the same as a.Before(b).
+func Before(rhs time.Time) func(time.Time) bool {
+ return func(lhs time.Time) bool {
+ return lhs.Before(rhs)
+ }
+}
+
+// NotAfter(b)(a) is the same as !a.After(b).
+func NotAfter(rhs time.Time) func(time.Time) bool {
+ return func(lhs time.Time) bool {
+ return !lhs.After(rhs)
+ }
+}
+
+// NotBefore(b)(a) is the same as !a.Before(b).
+func NotBefore(rhs time.Time) func(time.Time) bool {
+ return func(lhs time.Time) bool {
+ return !lhs.Before(rhs)
+ }
+}