-
-
Notifications
You must be signed in to change notification settings - Fork 475
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Wrapper container with easy to understand helper methods
- Loading branch information
Showing
3 changed files
with
213 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package optional | ||
|
||
import ( | ||
"sync" | ||
) | ||
|
||
// Optional is a type that may or may not contain a non-nil value. | ||
type Optional[T any] struct { | ||
value *T | ||
mu sync.RWMutex // Ensures thread-safety similar to the Java implementation's value-based behavior | ||
} | ||
|
||
// Empty returns an empty Optional instance. | ||
func Empty[T any]() Optional[T] { | ||
return Optional[T]{} | ||
} | ||
|
||
// Of returns an Optional with a non-nil value. | ||
func Of[T any](value T) Optional[T] { | ||
return Optional[T]{value: &value} | ||
} | ||
|
||
// OfNullable returns an Optional for a given value, which may be nil. | ||
func OfNullable[T any](value *T) Optional[T] { | ||
if value == nil { | ||
return Empty[T]() | ||
} | ||
return Optional[T]{value: value} | ||
} | ||
|
||
// IsPresent checks if there is a value present. | ||
func (o Optional[T]) IsPresent() bool { | ||
o.mu.RLock() | ||
defer o.mu.RUnlock() | ||
|
||
return o.value != nil | ||
} | ||
|
||
// IsEmpty checks if the Optional is empty. | ||
func (o Optional[T]) IsEmpty() bool { | ||
return !o.IsPresent() | ||
} | ||
|
||
// IfPresent performs the given action with the value if a value is present. | ||
func (o Optional[T]) IfPresent(action func(value T)) { | ||
o.mu.RLock() | ||
defer o.mu.RUnlock() | ||
|
||
if o.value != nil { | ||
action(*o.value) | ||
} | ||
} | ||
|
||
// IfPresentOrElse performs the action with the value if present, otherwise performs the empty-based action. | ||
func (o Optional[T]) IfPresentOrElse(action func(value T), emptyAction func()) { | ||
o.mu.RLock() | ||
defer o.mu.RUnlock() | ||
|
||
if o.value != nil { | ||
action(*o.value) | ||
} else { | ||
emptyAction() | ||
} | ||
} | ||
|
||
// Get returns the value if present, otherwise panics. | ||
func (o Optional[T]) Get() T { | ||
o.mu.RLock() | ||
defer o.mu.RUnlock() | ||
|
||
if o.value == nil { | ||
panic("Optional.Get: no value present") | ||
} | ||
return *o.value | ||
} | ||
|
||
// OrElse returns the value if present, otherwise returns other. | ||
func (o Optional[T]) OrElse(other T) T { | ||
o.mu.RLock() | ||
defer o.mu.RUnlock() | ||
|
||
if o.value != nil { | ||
return *o.value | ||
} | ||
return other | ||
} | ||
|
||
// OrElseGet returns the value if present, otherwise invokes supplier and returns the result. | ||
func (o Optional[T]) OrElseGet(supplier func() T) T { | ||
o.mu.RLock() | ||
defer o.mu.RUnlock() | ||
|
||
if o.value != nil { | ||
return *o.value | ||
} | ||
return supplier() | ||
} | ||
|
||
// OrElseThrow returns the value if present, otherwise returns an error. | ||
func (o Optional[T]) OrElseThrow(errorSupplier func() error) (T, error) { | ||
o.mu.RLock() | ||
defer o.mu.RUnlock() | ||
|
||
if o.value == nil { | ||
return *new(T), errorSupplier() | ||
} | ||
return *o.value, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package optional | ||
|
||
import ( | ||
"errors" | ||
"testing" | ||
|
||
"github.com/duke-git/lancet/v2/internal" | ||
) | ||
|
||
func TestEmpty(t *testing.T) { | ||
assert := internal.NewAssert(t, "TestEmpty") | ||
opt := Empty[int]() | ||
|
||
assert.ShouldBeFalse(opt.IsPresent()) | ||
} | ||
|
||
func TestOf(t *testing.T) { | ||
assert := internal.NewAssert(t, "TestOf") | ||
value := 42 | ||
opt := Of(value) | ||
|
||
assert.ShouldBeTrue(opt.IsPresent()) | ||
assert.Equal(opt.Get(), value) | ||
} | ||
|
||
func TestOfNullable(t *testing.T) { | ||
assert := internal.NewAssert(t, "TestOfNullable") | ||
var value *int = nil | ||
opt := OfNullable(value) | ||
|
||
assert.ShouldBeFalse(opt.IsPresent()) | ||
|
||
value = new(int) | ||
*value = 42 | ||
opt = OfNullable(value) | ||
|
||
assert.ShouldBeTrue(opt.IsPresent()) | ||
} | ||
|
||
func TestOrElse(t *testing.T) { | ||
assert := internal.NewAssert(t, "TestOrElse") | ||
optEmpty := Empty[int]() | ||
defaultValue := 100 | ||
|
||
val := optEmpty.OrElse(defaultValue) | ||
assert.Equal(val, defaultValue) | ||
|
||
optWithValue := Of(42) | ||
val = optWithValue.OrElse(defaultValue) | ||
assert.Equal(val, 42) | ||
} | ||
|
||
func TestOrElseGet(t *testing.T) { | ||
assert := internal.NewAssert(t, "TestOrElseGet") | ||
optEmpty := Empty[int]() | ||
supplier := func() int { return 100 } | ||
|
||
val := optEmpty.OrElseGet(supplier) | ||
assert.Equal(val, supplier()) | ||
} | ||
|
||
func TestOrElseThrow(t *testing.T) { | ||
assert := internal.NewAssert(t, "TestOrElseThrow") | ||
optEmpty := Empty[int]() | ||
_, err := optEmpty.OrElseThrow(func() error { return errors.New("no value") }) | ||
|
||
assert.Equal(err.Error(), "no value") | ||
|
||
optWithValue := Of(42) | ||
val, err := optWithValue.OrElseThrow(func() error { return errors.New("no value") }) | ||
|
||
assert.IsNil(err) | ||
assert.Equal(val, 42) | ||
} | ||
|
||
func TestIfPresent(t *testing.T) { | ||
assert := internal.NewAssert(t, "TestIfPresent") | ||
called := false | ||
action := func(value int) { called = true } | ||
|
||
optEmpty := Empty[int]() | ||
optEmpty.IfPresent(action) | ||
|
||
assert.ShouldBeFalse(called) | ||
|
||
called = false // Reset for next test | ||
optWithValue := Of(42) | ||
optWithValue.IfPresent(action) | ||
|
||
assert.ShouldBeTrue(called) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters