Merge pull request #5 from LucasRouckhout/master

Implement the Unmarshaler and Marshaler interfaces.
This commit is contained in:
Tevin 2021-05-23 00:38:58 +08:00 committed by GitHub
commit 9f5df6da9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 1 deletions

View File

@ -62,3 +62,5 @@ BenchmarkAtomicBoolToggle-4 169871972 7.02 ns/op # <--- This packag
- [@barryz](https://github.com/barryz) - [@barryz](https://github.com/barryz)
- Added the `Toggle` method - Added the `Toggle` method
- [@LucasRouckhout](https://github.com/LucasRouckhout)
- Implemented JSON Unmarshal and Marshal interface

23
bool.go
View File

@ -2,7 +2,10 @@
// better performance. // better performance.
package abool package abool
import "sync/atomic" import (
"encoding/json"
"sync/atomic"
)
// New creates an AtomicBool with default set to false. // New creates an AtomicBool with default set to false.
func New() *AtomicBool { func New() *AtomicBool {
@ -69,3 +72,21 @@ func (ab *AtomicBool) SetToIf(old, new bool) (set bool) {
} }
return atomic.CompareAndSwapInt32((*int32)(ab), o, n) return atomic.CompareAndSwapInt32((*int32)(ab), o, n)
} }
// MarshalJSON behaves the same as if the AtomicBool is a builtin.bool.
// NOTE: There's no lock during the process, usually it shouldn't be called with other methods in parallel.
func (ab *AtomicBool) MarshalJSON() ([]byte, error) {
return json.Marshal(ab.IsSet())
}
// UnmarshalJSON behaves the same as if the AtomicBool is a builtin.bool.
// NOTE: There's no lock during the process, usually it shouldn't be called with other methods in parallel.
func (ab *AtomicBool) UnmarshalJSON(b []byte) error {
var v bool
err := json.Unmarshal(b, &v)
if err == nil {
ab.SetTo(v)
}
return err
}

View File

@ -1,6 +1,7 @@
package abool package abool
import ( import (
"encoding/json"
"math" "math"
"sync" "sync"
"sync/atomic" "sync/atomic"
@ -181,6 +182,69 @@ func TestRace(t *testing.T) {
wg.Wait() wg.Wait()
} }
func TestJSONCompatibleWithBuiltinBool(t *testing.T) {
for _, value := range []bool{true, false} {
// Test bool -> bytes -> AtomicBool
// act 1. bool -> bytes
buf, err := json.Marshal(value)
if err != nil {
t.Fatalf("json.Marshal(%t) failed: %s", value, err)
}
// act 2. bytes -> AtomicBool
//
// Try to unmarshall the JSON byte slice
// of a normal boolean into an AtomicBool
//
// Create an AtomicBool with the oppsite default to ensure the unmarshal process did the work
ab := NewBool(!value)
err = json.Unmarshal(buf, ab)
if err != nil {
t.Fatalf(`json.Unmarshal("%s", %T) failed: %s`, buf, ab, err)
}
// assert
if ab.IsSet() != value {
t.Fatalf("Expected AtomicBool to represent %t but actual value was %t", value, ab.IsSet())
}
// Test AtomicBool -> bytes -> bool
// act 3. AtomicBool -> bytes
buf, err = json.Marshal(ab)
if err != nil {
t.Fatalf("json.Marshal(%T) failed: %s", ab, err)
}
// using the opposite value for the same reason as the former case
b := ab.IsNotSet()
// act 4. bytes -> bool
err = json.Unmarshal(buf, &b)
if err != nil {
t.Fatalf(`json.Unmarshal("%s", %T) failed: %s`, buf, &b, err)
}
// assert
if b != ab.IsSet() {
t.Fatalf(`json.Unmarshal("%s", %T) didn't work, expected %t, got %t`, buf, ab, ab.IsSet(), b)
}
}
}
func TestUnmarshalJSONErrorNoWrite(t *testing.T) {
for _, val := range []bool{true, false} {
ab := NewBool(val)
oldVal := ab.IsSet()
buf := []byte("invalid-json")
err := json.Unmarshal(buf, ab)
if err == nil {
t.Fatalf(`Error expected from json.Unmarshal("%s", %T)`, buf, ab)
}
if oldVal != ab.IsSet() {
t.Fatal("Failed json.Unmarshal modified the value of AtomicBool which is not expected")
}
}
}
func ExampleAtomicBool() { func ExampleAtomicBool() {
cond := New() // default to false cond := New() // default to false
any := true any := true