Skip to content

Commit

Permalink
fix: Add custom marshal/unmarshal to immutable.Option
Browse files Browse the repository at this point in the history
Add custom marshal/unmarshal to immutable.Option
  • Loading branch information
islamaliev authored Apr 5, 2023
2 parents 2ef27bd + f39fcee commit 4277211
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 1 deletion.
27 changes: 26 additions & 1 deletion option.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package immutable

import "encoding/json"

// Option represents an item that may or may not have a value.
type Option[T any] struct {
// If HasValue is true, this Option contains a value, if
Expand All @@ -23,7 +25,7 @@ func None[T any]() Option[T] {
return Option[T]{}
}

// HasValue returns a boolean indicating whether or not this optino contains a value. If
// HasValue returns a boolean indicating whether or not this option contains a value. If
// it returns true, this Option contains a value, if it is false it contains no value.
func (o Option[T]) HasValue() bool {
return o.hasValue
Expand All @@ -34,3 +36,26 @@ func (o Option[T]) HasValue() bool {
func (o Option[T]) Value() T {
return o.value
}

// MarshalJSON implements the json.Marshaler interface.
func (o Option[T]) MarshalJSON() ([]byte, error) {
if o.HasValue() {
return json.Marshal(o.Value())
}
return []byte("null"), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface.
func (o *Option[T]) UnmarshalJSON(b []byte) error {
if string(b) == "null" {
*o = None[T]()
return nil
}
var value T
err := json.Unmarshal(b, &value)
if err != nil {
return err
}
*o = Some(value)
return nil
}
70 changes: 70 additions & 0 deletions option_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package immutable

import (
"encoding/json"
"testing"
)

func TestSome(t *testing.T) {
opt := Some(1)
if !opt.HasValue() {
t.Errorf("expected Some to return an Option with a value")
}
if opt.Value() != 1 {
t.Errorf("expected Some to return an Option with a value of 1")
}
}

func TestNone(t *testing.T) {
opt := None[int]()
if opt.HasValue() {
t.Errorf("expected None to return an Option with no value")
}
}

func TestOptionMarshal(t *testing.T) {
opt := Some(1)
b, err := json.Marshal(opt)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if string(b) != "1" {
t.Errorf("expected 1, got %s", b)
}
}

func TestOptionMarshalNone(t *testing.T) {
opt := None[int]()
b, err := json.Marshal(opt)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if string(b) != "null" {
t.Errorf("expected null, got %s", b)
}
}

func TestOptionUnmarshal(t *testing.T) {
var opt Option[int]
err := json.Unmarshal([]byte("1"), &opt)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if !opt.HasValue() {
t.Errorf("expected Some to return an Option with a value")
}
if opt.Value() != 1 {
t.Errorf("expected Some to return an Option with a value of 1")
}
}

func TestOptionUnmarshalNone(t *testing.T) {
var opt Option[int]
err := json.Unmarshal([]byte("null"), &opt)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if opt.HasValue() {
t.Errorf("expected None to return an Option with no value")
}
}

0 comments on commit 4277211

Please sign in to comment.