string: Implement TextMarshaler, TextUnmarshaler (#70)
Since String holds textual information, instead of implementing
json.Marshaler and json.Unmarshaler, we should implement
encoding.TextMarshaler and encoding.TextUnmarshaler on String.
This makes it encodable and decodable using a variety of formats
including JSON, XML, YAML, and TOML.
diff --git a/string.go b/string.go
index 5bc08ef..fc95659 100644
--- a/string.go
+++ b/string.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2016 Uber Technologies, Inc.
+// Copyright (c) 2016-2020 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -20,10 +20,6 @@
package atomic
-import (
- "encoding/json"
-)
-
// String is an atomic type-safe wrapper around Value for strings.
type String struct{ v Value }
@@ -45,18 +41,18 @@
return v.(string)
}
-// MarshalJSON encodes the wrapped string into JSON.
-func (s *String) MarshalJSON() ([]byte, error) {
- return json.Marshal(s.Load())
+// MarshalText encodes the wrapped string into a textual form.
+//
+// This makes it encodable as JSON, YAML, XML, and more.
+func (s *String) MarshalText() ([]byte, error) {
+ return []byte(s.Load()), nil
}
-// UnmarshalJSON decodes JSON into the wrapped string.
-func (s *String) UnmarshalJSON(b []byte) error {
- var v string
- if err := json.Unmarshal(b, &v); err != nil {
- return err
- }
- s.Store(v)
+// UnmarshalText decodes text and replaces the wrapped string with it.
+//
+// This makes it decodable from JSON, YAML, XML, and more.
+func (s *String) UnmarshalText(b []byte) error {
+ s.Store(string(b))
return nil
}
diff --git a/string_test.go b/string_test.go
index 2360c2b..c875ed1 100644
--- a/string_test.go
+++ b/string_test.go
@@ -22,6 +22,7 @@
import (
"encoding/json"
+ "encoding/xml"
"testing"
"github.com/stretchr/testify/require"
@@ -60,4 +61,18 @@
assertErrorJSONUnmarshalType(t, err,
"json.Unmarshal failed with unexpected error %v, want UnmarshalTypeError.", err)
})
+
+ atom = NewString("foo")
+
+ t.Run("XML/Marshal", func(t *testing.T) {
+ bytes, err := xml.Marshal(atom)
+ require.NoError(t, err, "xml.Marshal errored unexpectedly.")
+ require.Equal(t, []byte("<String>foo</String>"), bytes, "xml.Marshal encoded the wrong bytes.")
+ })
+
+ t.Run("XML/Unmarshal", func(t *testing.T) {
+ err := xml.Unmarshal([]byte("<String>bar</String>"), &atom)
+ require.NoError(t, err, "xml.Unmarshal errored unexpectedly.")
+ require.Equal(t, "bar", atom.Load(), "xml.Unmarshal didn't set the correct value.")
+ })
}