net: use readable JSON marshaling for IPNet, IPMask, HardwareAddr
Adds a GODEBUG netreadablejson to control this.
The default is the current encoding, with a plan to change that in Go 1.27.
The unmarshaler recognizes both the current and the new encoding.
Fixes #29678
diff --git a/api/next/29678.txt b/api/next/29678.txt
new file mode 100644
index 0000000..39cedfc
--- /dev/null
+++ b/api/next/29678.txt
@@ -0,0 +1,4 @@
+pkg net, method (*HardwareAddr) UnmarshalText([]uint8) error #29678
+pkg net, method (HardwareAddr) MarshalText() ([]uint8, error) #29678
+pkg net, method (*IPMask) UnmarshalText([]uint8) error #29678
+pkg net, method (IPMask) MarshalText() ([]uint8, error) #29678
diff --git a/doc/godebug.md b/doc/godebug.md
index f3ad820..e2a7102 100644
--- a/doc/godebug.md
+++ b/doc/godebug.md
@@ -169,6 +169,20 @@
The default value `embedfollowsymlinks=0` does not allow following
symlinks. `embedfollowsymlinks=1` will allow following symlinks.
+Go 1.25 added a new `netreadablejson` setting that controls whether
+the text marshaling of the types `net.IPMask`, `net.IPNet`, and
+`net.HardwareAddr` is readable. Text marshaling will be used for,
+among other things, JSON encoding, hence the name of the setting. The
+value `netreadablejson=0` will JSON encode those types using an
+unreadable base64 encoding. The value `netreadablejson=1` will use a
+readable version such as the IP address. For Go 1.25 and 1.26 the
+default value remains `netreadablejson=0`. This ensures that JSON
+generated by those versions will be readable by older versions of
+Go. The expectation is that Go 1.27 will change the default to be
+netreadablejson=1. Go 1.25 and all future releases will support both
+the old and new encodings when reading data. This setting may be
+removed in a future Go release, Go 1.31 at the earliest.
+
### Go 1.24
Go 1.24 added a new `fips140` setting that controls whether the Go
diff --git a/doc/next/6-stdlib/99-minor/net/29678.md b/doc/next/6-stdlib/99-minor/net/29678.md
new file mode 100644
index 0000000..51632a9
--- /dev/null
+++ b/doc/next/6-stdlib/99-minor/net/29678.md
@@ -0,0 +1,8 @@
+The [IPMask], [IPNet], and [HardwareAddr] types each now implement
+a [encoding.TextUnmarshaler] method. This method will recognize
+the current marshaling of those types, as well as a planned future
+marshaling format. The future marshaling format will be readable
+in JSON format, unlike the current format which is a base64 encoding.
+The future marshaling format will become the default in a later Go release.
+This is being done as a two-step process so that JSON generated
+by this release of Go can still be read by earlier releases of Go.
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index c355cb4..60d6878 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -406,6 +406,7 @@
golang.org/x/net/dns/dnsmessage,
golang.org/x/net/lif,
internal/godebug,
+ internal/goversion,
internal/nettrace,
internal/poll,
internal/routebsd,
diff --git a/src/internal/godebugs/table.go b/src/internal/godebugs/table.go
index 26d079c..61b51eb 100644
--- a/src/internal/godebugs/table.go
+++ b/src/internal/godebugs/table.go
@@ -50,6 +50,7 @@
{Name: "multipathtcp", Package: "net", Changed: 24, Old: "0"},
{Name: "netdns", Package: "net", Opaque: true},
{Name: "netedns0", Package: "net", Changed: 19, Old: "0"},
+ {Name: "netreadablejson", Package: "net", Changed: 27, Old: "0"},
{Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"},
{Name: "randautoseed", Package: "math/rand"},
{Name: "randseednop", Package: "math/rand", Changed: 24, Old: "0"},
diff --git a/src/net/ip.go b/src/net/ip.go
index e3ee6ca..56a1e30 100644
--- a/src/net/ip.go
+++ b/src/net/ip.go
@@ -14,6 +14,8 @@
import (
"internal/bytealg"
+ "internal/godebug"
+ "internal/goversion"
"internal/itoa"
"internal/stringslite"
"net/netip"
@@ -453,6 +455,63 @@
return hexString(m)
}
+var netreadablejson = godebug.New("netreadablejson")
+
+// MarshalText implements the [encoding.TextMarshaler] interface.
+// We marshal an IPMask as though it were an IP address.
+func (m IPMask) MarshalText() ([]byte, error) {
+ // For backward compatibility, GODEBUG=netreadablejson=0
+ // marshals as plain []byte.
+ if netreadablejson.Value() == "0" {
+ // We currently expect that the default for Go <= 1.26 is 0,
+ // and the default for Go >= 1.27 is 1.
+ if goversion.Version >= 27 {
+ netreadablejson.IncNonDefault()
+ }
+
+ return base64Encode(m), nil
+ }
+
+ // We currently expect that the default for Go <= 1.26 is 0,
+ // and the default for Go >= 1.27 is 1.
+ if goversion.Version <= 26 {
+ netreadablejson.IncNonDefault()
+ }
+
+ // We don't use IP.MarshalText directly because
+ // we want to preserve the length.
+ addr, _ := netip.AddrFromSlice(m)
+ return addr.AppendTo(nil), nil
+}
+
+// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
+// In older Go versions the JSON encoding of IPMask was
+// that of a []byte. In order to support new Go programs reading JSON
+// encodings produced by old Go programs, we support the []byte encoding.
+func (m *IPMask) UnmarshalText(text []byte) error {
+ var ip IP
+ err := ip.UnmarshalText(text)
+ if err == nil {
+ if bytealg.IndexByte(text, ':') < 0 {
+ ip = ip.To4()
+ }
+ *m = IPMask(ip)
+ return nil
+ }
+
+ // IP.Unmarshal failed; try base64.
+
+ dst := make([]byte, len(text)/4*3)
+ n, ok := base64Decode(dst, text)
+ if ok {
+ *m = IPMask(dst[:n])
+ return nil
+ }
+
+ // The base64 decode failed: return the IP.Unmarshal error.
+ return err
+}
+
func networkNumberAndMask(n *IPNet) (ip IP, m IPMask) {
if ip = n.IP.To4(); ip == nil {
ip = n.IP
@@ -572,3 +631,119 @@
copy(y, x)
return y
}
+
+// base64Coding is the standard base64 coding characters.
+const base64Coding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+
+// base64Encode returned src encoded as base64,
+// assuming the standard encoding.
+// This stores (len(src) + 2) / 3 * 4 bytes into dst.
+// This is here so that the net package doesn't depend on encoding/base64.
+func base64Encode(src []byte) []byte {
+ dst := make([]byte, (len(src)+2)/3*4)
+
+ di, si := 0, 0
+ n := len(src) / 3 * 3
+ for si < n {
+ val := uint(src[si+0])<<16 | uint(src[si+1])<<8 | uint(src[si+2])
+
+ dst[di+0] = base64Coding[(val>>18)&0x3F]
+ dst[di+1] = base64Coding[(val>>12)&0x3F]
+ dst[di+2] = base64Coding[(val>>6)&0x3F]
+ dst[di+3] = base64Coding[val&0x3F]
+
+ si += 3
+ di += 4
+ }
+
+ remain := len(src) - si
+ if remain == 0 {
+ return dst
+ }
+
+ val := uint(src[si+0]) << 16
+ if remain == 2 {
+ val |= uint(src[si+1]) << 8
+ }
+
+ dst[di+0] = base64Coding[(val>>18)&0x3F]
+ dst[di+1] = base64Coding[(val>>12)&0x3F]
+
+ switch remain {
+ case 2:
+ dst[di+2] = base64Coding[(val>>6)&0x3F]
+ dst[di+3] = '='
+ case 1:
+ dst[di+2] = '='
+ dst[di+3] = '='
+ }
+
+ return dst
+}
+
+// base64Decode decodes base64 data from text into dst,
+// assuming the standard encoding.
+// It returns the number of bytes placed in dst,
+// and whether the decode was successful.
+// This is here so that the net package doesn't depend on encoding/base64.
+func base64Decode(dst, text []byte) (int, bool) {
+ n := 0
+ for len(text) > 0 {
+ var dbuf [4]byte
+ dlen := 4
+ for j := range dbuf {
+ if len(text) == 0 {
+ return 0, false
+ }
+ in := text[0]
+ text = text[1:]
+
+ // Check for padding at end of input.
+ if in == '=' {
+ switch j {
+ case 0, 1:
+ return 0, false
+ case 2:
+ // We expect one more padding character.
+ if len(text) != 1 || text[0] != '=' {
+ return 0, false
+ }
+ text = text[1:]
+ case 3:
+ if len(text) != 0 {
+ return 0, false
+ }
+ }
+
+ dlen = j
+ break
+ }
+
+ out := bytealg.IndexByteString(base64Coding, in)
+ if out < 0 {
+ return 0, false
+ }
+
+ dbuf[j] = byte(out)
+ }
+
+ // Convert 4 6-bit sources into 3 bytes.
+ val := uint32(dbuf[0])<<18 | uint32(dbuf[1])<<12 | uint32(dbuf[2])<<6 | uint32(dbuf[3])
+ dbuf[2], dbuf[1], dbuf[0] = byte(val>>0), byte(val>>8), byte(val>>16)
+ switch dlen {
+ case 4:
+ dst[2] = dbuf[2]
+ fallthrough
+ case 3:
+ dst[1] = dbuf[1]
+ fallthrough
+ case 2:
+ dst[0] = dbuf[0]
+ }
+
+ dst = dst[3:]
+ n += dlen - 1
+ }
+
+ return n, true
+}
diff --git a/src/net/ip_test.go b/src/net/ip_test.go
index 55c66fd..9e7e1c7 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -6,9 +6,11 @@
import (
"bytes"
+ "encoding/json"
"math/rand"
"reflect"
"runtime"
+ "slices"
"testing"
)
@@ -389,6 +391,90 @@
}
}
+var ipMaskJSONTests = []struct {
+ in IPMask
+ out0 string // expected marshaling with GODEBUG=netreadablejson=0
+ out1 string // expected marshaling with GODEBUG=netreadablejson=1
+}{
+ {
+ nil,
+ `""`,
+ `""`,
+ },
+ {
+ IPv4Mask(255, 255, 255, 0),
+ `"////AA=="`,
+ `"255.255.255.0"`,
+ },
+ {
+ IPMask(ParseIP("ffff:ff80::")),
+ `"////gAAAAAAAAAAAAAAAAA=="`,
+ `"ffff:ff80::"`,
+ },
+}
+
+func TestIPMaskJSON(t *testing.T) {
+ // testReadable tests that we can marshal m and unmarshal the result.
+ // We will call this with different GODEBUG settings to make
+ // sure that the unmarshaler, which doesn't check GODEBUG,
+ // works in all scenarios.
+ testReadable := func(m IPMask) {
+ b, err := json.Marshal(m)
+ if err != nil {
+ t.Errorf("json.Marshal(%s) failed: %v", m, err)
+ return
+ }
+
+ var m2 IPMask
+ if err = json.Unmarshal(b, &m2); err != nil {
+ t.Errorf("json.Unmarshal of %q (from %s) failed: %v", b, m, err)
+ return
+ }
+
+ if !slices.Equal(m, m2) {
+ t.Errorf("%s marshaled to %q, unmarshaled to different value %s", m, b, m2)
+ }
+ }
+
+ for _, d := range []string{"unset", "0", "1"} {
+ t.Run("GODEBUG="+d, func(t *testing.T) {
+ if d != "unset" {
+ t.Setenv("GODEBUG", "netreadablejson="+d)
+
+ for _, tt := range ipMaskJSONTests {
+ b, err := json.Marshal(tt.in)
+ if err != nil {
+ t.Errorf("json.Marshal(%s) failed: %v", tt.in, err)
+ continue
+ }
+ var want string
+ if d == "0" {
+ want = tt.out0
+ } else {
+ want = tt.out1
+ }
+ if string(b) != want {
+ t.Errorf("json.Marshal(%s) = %q, want %q", tt.in, b, want)
+ }
+ }
+ }
+
+ testReadable(nil)
+ testReadable(classAMask)
+ testReadable(classBMask)
+ testReadable(classCMask)
+
+ for _, tt := range ipMaskTests {
+ testReadable(tt.mask)
+ }
+
+ for _, tt := range ipMaskStringTests {
+ testReadable(tt.in)
+ }
+ })
+ }
+}
+
func BenchmarkIPMaskString(b *testing.B) {
testHookUninstaller.Do(uninstallTestHooks)
@@ -559,6 +645,93 @@
}
}
+var ipNetJSONTests = []struct {
+ in IPNet
+ out0 string // expected marshaling with GODEBUG=netreadablejson=0
+ out1 string // expected marshaling with GODEBUG=netreadablejson=1
+}{
+ {
+ IPNet{IP: IPv4(0, 0, 0, 0), Mask: IPv4Mask(255, 255, 255, 0)},
+ `{"IP":"0.0.0.0","Mask":"////AA=="}`,
+ `{"IP":"0.0.0.0","Mask":"255.255.255.0"}`,
+ },
+ {
+ IPNet{IP: IPv4(172, 16, 0, 0), Mask: CIDRMask(12, 32)},
+ `{"IP":"172.16.0.0","Mask":"//AAAA=="}`,
+ `{"IP":"172.16.0.0","Mask":"255.240.0.0"}`,
+ },
+ {
+ IPNet{IP: ParseIP("2001:db8:1::"), Mask: CIDRMask(47, 128)},
+ `{"IP":"2001:db8:1::","Mask":"///////+AAAAAAAAAAAAAA=="}`,
+ `{"IP":"2001:db8:1::","Mask":"ffff:ffff:fffe::"}`,
+ },
+}
+
+func TestIPNetJSON(t *testing.T) {
+ // testReadable tests that we can marshal n and unmarshal the result.
+ // We will call this with different GODEBUG settings to make
+ // sure that the unmarshaler, which doesn't check GODEBUG,
+ // works in all scenarios.
+ testReadable := func(n *IPNet) {
+ b, err := json.Marshal(n)
+ if err != nil {
+ t.Errorf("json.Marshal(%s) failed: %v", n, err)
+ return
+ }
+
+ var n2 IPNet
+ if err = json.Unmarshal(b, &n2); err != nil {
+ t.Errorf("json.Unmarshal of %q (from %s) failed: %v", b, n, err)
+ return
+ }
+
+ var equal bool
+ if n == nil {
+ equal = len(n2.IP) == 0 && len(n2.Mask) == 0
+ } else {
+ equal = n.IP.Equal(n2.IP) && slices.Equal(n.Mask, n2.Mask)
+ }
+ if !equal {
+ t.Errorf("%s marshaled to %q, unmarshaled to different value %s", n, b, n2)
+ }
+ }
+
+ for _, d := range []string{"unset", "0", "1"} {
+ t.Run("GODEBUG="+d, func(t *testing.T) {
+ if d != "unset" {
+ t.Setenv("GODEBUG", "netreadablejson="+d)
+
+ for _, tt := range ipNetJSONTests {
+ b, err := json.Marshal(tt.in)
+ if err != nil {
+ t.Errorf("json.Marshal(%s) failed: %v", tt.in, err)
+ continue
+ }
+ var want string
+ if d == "0" {
+ want = tt.out0
+ } else {
+ want = tt.out1
+ }
+ if string(b) != want {
+ t.Errorf("json.Marshal(%s) = %q, want %q", tt.in, b, want)
+ }
+ }
+ }
+
+ for _, tt := range parseCIDRTests {
+ testReadable(tt.net)
+ }
+ for _, tt := range ipNetContainsTests {
+ testReadable(tt.net)
+ }
+ for _, tt := range ipNetStringTests {
+ testReadable(tt.in)
+ }
+ })
+ }
+}
+
func TestSplitHostPort(t *testing.T) {
for _, tt := range []struct {
hostPort string
diff --git a/src/net/mac.go b/src/net/mac.go
index 53d5b2d..5e9ff42 100644
--- a/src/net/mac.go
+++ b/src/net/mac.go
@@ -4,6 +4,10 @@
package net
+import (
+ "internal/goversion"
+)
+
const hexDigit = "0123456789abcdef"
// A HardwareAddr represents a physical hardware address.
@@ -84,3 +88,52 @@
error:
return nil, &AddrError{Err: "invalid MAC address", Addr: s}
}
+
+// MarshalText implements the [encoding.TextMarshaler] interface.
+// The encoding is the same as the one returned by [HardwareAddr.String].
+// This will be enabled in a future Go release; see issue #29678.
+func (a HardwareAddr) MarshalText() ([]byte, error) {
+ // For backward compatibility, GODEBUG=netreadablejson=0
+ // marshals as plain []byte.
+ if netreadablejson.Value() == "0" {
+ // We currently expect that the default for Go <= 1.26 is 0,
+ // and the default for Go >= 1.27 is 1.
+ if goversion.Version >= 27 {
+ netreadablejson.IncNonDefault()
+ }
+
+ return base64Encode(a), nil
+ }
+
+ // We currently expect that the default for Go <= 1.26 is 0,
+ // and the default for Go >= 1.27 is 1.
+ if goversion.Version <= 26 {
+ netreadablejson.IncNonDefault()
+ }
+
+ return []byte(a.String()), nil
+}
+
+// UnmarshalText implements the [encoding.TextUnmarshaler] interface.
+// In older Go versions the JSON encoding of HardwareAddr was
+// that of a []byte. In order to support new Go programs reading JSON
+// encodings produced by old Go programs, we support the []byte encoding.
+func (a *HardwareAddr) UnmarshalText(text []byte) error {
+ hw, err := ParseMAC(string(text))
+ if err == nil {
+ *a = hw
+ return nil
+ }
+
+ // ParseMAC failed: try base64.
+
+ dst := make([]byte, len(text)/4*3)
+ n, ok := base64Decode(dst, text)
+ if ok {
+ *a = HardwareAddr(dst[:n])
+ return nil
+ }
+
+ // The base64 decode failed: return the ParseMAC error.
+ return err
+}
diff --git a/src/net/mac_test.go b/src/net/mac_test.go
index cad884f..5530e71 100644
--- a/src/net/mac_test.go
+++ b/src/net/mac_test.go
@@ -5,7 +5,9 @@
package net
import (
+ "encoding/json"
"reflect"
+ "slices"
"strings"
"testing"
)
@@ -107,3 +109,78 @@
}
}
}
+
+var hardwareAddrJSONTests = []struct {
+ in HardwareAddr
+ out0 string // expected marshaling with GODEBUG=netreadablejson=0
+ out1 string // expected marshaling with GODEBUG=netreadablejson=1
+}{
+ {
+ nil,
+ `""`,
+ `""`,
+ },
+ {
+ HardwareAddr{0x00, 0x00, 0x5e, 0x00, 0x53, 0x01},
+ `"AABeAFMB"`,
+ `"00:00:5e:00:53:01"`,
+ },
+}
+
+// TestMACJSON tests JSON marshaling for HardwareAddr.
+func TestMACJSON(t *testing.T) {
+ // testReadable tests that we can marshal hw and unmarshal the result.
+ // We will call this with different GODEBUG settings to make
+ // sure that the unmarshaler, which doesn't check GODEBUG,
+ // works in all scenarios.
+ testReadable := func(hw HardwareAddr) {
+ b, err := json.Marshal(hw)
+ if err != nil {
+ t.Errorf("json.Marshal(%s) failed: %v", hw, err)
+ return
+ }
+
+ var hw2 HardwareAddr
+ if err = json.Unmarshal(b, &hw2); err != nil {
+ t.Errorf("json.Unmarshal of %q (from %s) failed: %v", b, hw, err)
+ return
+ }
+
+ if !slices.Equal(hw, hw2) {
+ t.Errorf("%s marshaled to %q, unmarshaled to different value %s", hw, b, hw2)
+ }
+ }
+
+ for _, d := range []string{"unset", "0", "1"} {
+ t.Run("GODEBUG="+d, func(t *testing.T) {
+ if d != "unset" {
+ t.Setenv("GODEBUG", "netreadablejson="+d)
+
+ for _, tt := range hardwareAddrJSONTests {
+ b, err := json.Marshal(tt.in)
+ if err != nil {
+ t.Errorf("json.Marshal(%s) failed: %v", tt.in, err)
+ continue
+ }
+ var want string
+ if d == "0" {
+ want = tt.out0
+ } else {
+ want = tt.out1
+ }
+ if string(b) != want {
+ t.Errorf("json.Marshal(%s) = %q, want %q", tt.in, b, want)
+ }
+ }
+ }
+
+ testReadable(nil)
+
+ for _, tt := range parseMACTests {
+ if tt.out != nil {
+ testReadable(tt.out)
+ }
+ }
+ })
+ }
+}
diff --git a/src/runtime/metrics/doc.go b/src/runtime/metrics/doc.go
index 0d35314e..79dd684 100644
--- a/src/runtime/metrics/doc.go
+++ b/src/runtime/metrics/doc.go
@@ -308,6 +308,10 @@
The number of non-default behaviors executed by the net package
due to a non-default GODEBUG=netedns0=... setting.
+ /godebug/non-default-behavior/netreadablejson:events
+ The number of non-default behaviors executed by the net package
+ due to a non-default GODEBUG=netreadablejson=... setting.
+
/godebug/non-default-behavior/panicnil:events
The number of non-default behaviors executed by the runtime
package due to a non-default GODEBUG=panicnil=... setting.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +2 |
// base64Encode returned src encoded as base64,typo: returns
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
// base64Encode returned src encoded as base64,Ian Lance Taylortypo: returns
Done
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
The proposal was accepted, I think this just needs to rename the godebug to `netmarshal`, and do the same for IPNet.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
The proposal was accepted, I think this just needs to rename the godebug to `netmarshal`, and do the same for IPNet.
Unresolving this for visibility and removing Hold.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Removed Hold+1 by Ian Lance Taylor <ia...@golang.org>
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
The accepted proposal lists changes to IPNet as well. It looks like those are missing from this CL.
For Go 1.28 and 1.29 thedefault value remains `netmarshal=0`.s/the/& /
{Name: "netmarshal", Package: "net", Changed: 29, Old: "0"},s/29/30/
// For backward compatibility, GODEBUG=netmarshal=0The godebug API usage doesn't look right to me. Unless there is an explicit setting, Value() returns "". If you want to make that key off the version automatically instead of having to return to this code, the way to do that would be:
```
form := netmarshal.Value()
switch form {
case "":
if goversion.Version < 30 {
form = "0"
} else {
form = "1"
}
case "0":
if goversion.Version >= 30 {
netmarshal.IncNonDefault()
}
default:
if goversion.Version < 30 {
netmarshal.IncNonDefault()
}
}
if form == "0" { ... base 64 ... }
... text ...
```
The form logic might be worth pulling into its own function since it will be used elsewhere too.
// For backward compatibility, GODEBUG=netmarshal=0Same comments about netmarshal.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
// This stores (len(src) + 2) / 3 * 4 bytes into dst.Stale. Delete line.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
The accepted proposal lists changes to IPNet as well. It looks like those are missing from this CL.
IPNet includes a field of type IP. The changes to IP marshaling affect IPNet marshaling. This is tested by TestIPNetJSON.
For Go 1.28 and 1.29 thedefault value remains `netmarshal=0`.Ian Lance Taylors/the/& /
Done
{Name: "netmarshal", Package: "net", Changed: 29, Old: "0"},Ian Lance Taylors/29/30/
Done
The godebug API usage doesn't look right to me. Unless there is an explicit setting, Value() returns "". If you want to make that key off the version automatically instead of having to return to this code, the way to do that would be:
```
form := netmarshal.Value()
switch form {
case "":
if goversion.Version < 30 {
form = "0"
} else {
form = "1"
}
case "0":
if goversion.Version >= 30 {
netmarshal.IncNonDefault()
}
default:
if goversion.Version < 30 {
netmarshal.IncNonDefault()
}
}if form == "0" { ... base 64 ... }
... text ...
```The form logic might be worth pulling into its own function since it will be used elsewhere too.
Thanks, done.
// This stores (len(src) + 2) / 3 * 4 bytes into dst.Ian Lance TaylorStale. Delete line.
Done
// For backward compatibility, GODEBUG=netmarshal=0Ian Lance TaylorSame comments about netmarshal.
Done
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Dmitri ShuralyovThe proposal was accepted, I think this just needs to rename the godebug to `netmarshal`, and do the same for IPNet.
Unresolving this for visibility and removing Hold.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +2 |
The default is the current encoding, with a plan to change that in Go 1.29.1.30?
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
The default is the current encoding, with a plan to change that in Go 1.29.Ian Lance Taylor1.30?
Done
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +1 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Code-Review | +1 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
net: use readable JSON marshaling for IPNet, IPMask, HardwareAddr
Adds a GODEBUG netmarshal to control this.
The default is the current encoding, with a plan to change that in Go 1.30.
The unmarshaler recognizes both the current and the new encoding.
Fixes #29678
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |