Use netip package for representing inet and cidr types

pull/1281/head
Jack Christensen 2022-07-10 14:29:44 -05:00
parent 7974a102fc
commit e7eb8a3250
8 changed files with 231 additions and 124 deletions

View File

@ -102,6 +102,7 @@ This matches the convention set by `database/sql`. In addition, for comparable t
* `Hstore` is now defined as `map[string]*string`.
* `JSON` and `JSONB` types removed. Use `[]byte` or `string` directly.
* `QChar` type removed. Use `rune` or `byte` directly.
* `Inet` and `Cidr` types removed. Use `netip.Addr` and `netip.Prefix` directly. These types are more memory efficient than the previous `net.IPNet`.
* `Macaddr` type removed. Use `net.HardwareAddr` directly.
* Renamed `pgtype.ConnInfo` to `pgtype.Map`.
* Renamed `pgtype.DataType` to `pgtype.Type`.

View File

@ -80,7 +80,7 @@ pgx supports many features beyond what is available through `database/sql`:
* Conversion of PostgreSQL arrays to Go slice mappings for integers, floats, and strings
* Hstore support
* JSON and JSONB support
* Maps `inet` and `cidr` PostgreSQL types to `net.IPNet` and `net.IP`
* Maps `inet` and `cidr` PostgreSQL types to `netip.Addr` and `netip.Prefix`
* Large object support
* NULL mapping to Null* struct or pointer to pointer
* Supports `database/sql.Scanner` and `database/sql/driver.Valuer` interfaces for custom types

3
doc.go
View File

@ -152,8 +152,7 @@ pgx includes built-in support to marshal and unmarshal between Go types and the
Inet and CIDR Mapping
pgx encodes from net.IPNet to and from inet and cidr PostgreSQL types. In addition, as a convenience pgx will encode
from a net.IP; it will assume a /32 netmask for IPv4 and a /128 for IPv6.
pgx converts netip.Prefix and netip.Addr to and from inet and cidr PostgreSQL types.
Custom Type Support

View File

@ -1,9 +1,11 @@
package pgtype
import (
"errors"
"fmt"
"math"
"net"
"net/netip"
"reflect"
"time"
)
@ -460,44 +462,95 @@ func (w durationWrapper) IntervalValue() (Interval, error) {
type netIPNetWrapper net.IPNet
func (w *netIPNetWrapper) ScanInet(v Inet) error {
if !v.Valid {
func (w *netIPNetWrapper) ScanNetipPrefix(v netip.Prefix) error {
if !v.IsValid() {
return fmt.Errorf("cannot scan NULL into *net.IPNet")
}
*w = (netIPNetWrapper)(*v.IPNet)
*w = netIPNetWrapper{
IP: v.Addr().AsSlice(),
Mask: net.CIDRMask(v.Bits(), v.Addr().BitLen()),
}
return nil
}
func (w netIPNetWrapper) NetipPrefixValue() (netip.Prefix, error) {
ip, ok := netip.AddrFromSlice(w.IP)
if !ok {
return netip.Prefix{}, errors.New("invalid net.IPNet")
}
func (w netIPNetWrapper) InetValue() (Inet, error) {
return Inet{IPNet: (*net.IPNet)(&w), Valid: true}, nil
ones, _ := w.Mask.Size()
return netip.PrefixFrom(ip, ones), nil
}
type netIPWrapper net.IP
func (w netIPWrapper) SkipUnderlyingTypePlan() {}
func (w *netIPWrapper) ScanInet(v Inet) error {
if !v.Valid {
func (w *netIPWrapper) ScanNetipPrefix(v netip.Prefix) error {
if !v.IsValid() {
*w = nil
return nil
}
if oneCount, bitCount := v.IPNet.Mask.Size(); oneCount != bitCount {
if v.Addr().BitLen() != v.Bits() {
return fmt.Errorf("cannot scan %v to *net.IP", v)
}
*w = netIPWrapper(v.IPNet.IP)
*w = netIPWrapper(v.Addr().AsSlice())
return nil
}
func (w netIPWrapper) InetValue() (Inet, error) {
func (w netIPWrapper) NetipPrefixValue() (netip.Prefix, error) {
if w == nil {
return Inet{}, nil
return netip.Prefix{}, nil
}
bitCount := len(w) * 8
mask := net.CIDRMask(bitCount, bitCount)
return Inet{IPNet: &net.IPNet{Mask: mask, IP: net.IP(w)}, Valid: true}, nil
addr, ok := netip.AddrFromSlice([]byte(w))
if !ok {
return netip.Prefix{}, errors.New("invalid net.IP")
}
return netip.PrefixFrom(addr, addr.BitLen()), nil
}
type netipPrefixWrapper netip.Prefix
func (w *netipPrefixWrapper) ScanNetipPrefix(v netip.Prefix) error {
*w = netipPrefixWrapper(v)
return nil
}
func (w netipPrefixWrapper) NetipPrefixValue() (netip.Prefix, error) {
return netip.Prefix(w), nil
}
type netipAddrWrapper netip.Addr
func (w *netipAddrWrapper) ScanNetipPrefix(v netip.Prefix) error {
if !v.IsValid() {
*w = netipAddrWrapper(netip.Addr{})
return nil
}
if v.Addr().BitLen() != v.Bits() {
return fmt.Errorf("cannot scan %v to netip.Addr", v)
}
*w = netipAddrWrapper(v.Addr())
return nil
}
func (w netipAddrWrapper) NetipPrefixValue() (netip.Prefix, error) {
addr := (netip.Addr)(w)
if !addr.IsValid() {
return netip.Prefix{}, nil
}
return netip.PrefixFrom(addr, addr.BitLen()), nil
}
type mapStringToPointerStringWrapper map[string]*string

View File

@ -1,9 +1,11 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"errors"
"fmt"
"net"
"net/netip"
)
// Network address family is dependent on server socket.h value for AF_INET.
@ -14,57 +16,16 @@ const (
defaultAFInet6 = 3
)
type InetScanner interface {
ScanInet(v Inet) error
type NetipPrefixScanner interface {
ScanNetipPrefix(v netip.Prefix) error
}
type InetValuer interface {
InetValue() (Inet, error)
}
// Inet represents both inet and cidr PostgreSQL types.
type Inet struct {
IPNet *net.IPNet
Valid bool
}
func (inet *Inet) ScanInet(v Inet) error {
*inet = v
return nil
}
func (inet Inet) InetValue() (Inet, error) {
return inet, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Inet) Scan(src any) error {
if src == nil {
*dst = Inet{}
return nil
}
switch src := src.(type) {
case string:
return scanPlanTextAnyToInetScanner{}.Scan([]byte(src), dst)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Inet) Value() (driver.Value, error) {
if !src.Valid {
return nil, nil
}
buf, err := InetCodec{}.PlanEncode(nil, 0, TextFormatCode, src).Encode(src, nil)
if err != nil {
return nil, err
}
return string(buf), err
type NetipPrefixValuer interface {
NetipPrefixValue() (netip.Prefix, error)
}
// InetCodec handles both inet and cidr PostgreSQL types. The preferred Go types are netip.Prefix and netip.Addr. If
// IsValid() is false then they are treated as SQL NULL.
type InetCodec struct{}
func (InetCodec) FormatSupported(format int16) bool {
@ -76,7 +37,7 @@ func (InetCodec) PreferredFormat() int16 {
}
func (InetCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
if _, ok := value.(InetValuer); !ok {
if _, ok := value.(NetipPrefixValuer); !ok {
return nil
}
@ -93,51 +54,56 @@ func (InetCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodeP
type encodePlanInetCodecBinary struct{}
func (encodePlanInetCodecBinary) Encode(value any, buf []byte) (newBuf []byte, err error) {
inet, err := value.(InetValuer).InetValue()
prefix, err := value.(NetipPrefixValuer).NetipPrefixValue()
if err != nil {
return nil, err
}
if !inet.Valid {
if !prefix.IsValid() {
return nil, nil
}
var family byte
switch len(inet.IPNet.IP) {
case net.IPv4len:
if prefix.Addr().Is4() {
family = defaultAFInet
case net.IPv6len:
} else {
family = defaultAFInet6
default:
return nil, fmt.Errorf("Unexpected IP length: %v", len(inet.IPNet.IP))
}
buf = append(buf, family)
ones, _ := inet.IPNet.Mask.Size()
ones := prefix.Bits()
buf = append(buf, byte(ones))
// is_cidr is ignored on server
buf = append(buf, 0)
buf = append(buf, byte(len(inet.IPNet.IP)))
if family == defaultAFInet {
buf = append(buf, byte(4))
b := prefix.Addr().As4()
buf = append(buf, b[:]...)
} else {
buf = append(buf, byte(16))
b := prefix.Addr().As16()
buf = append(buf, b[:]...)
}
return append(buf, inet.IPNet.IP...), nil
return buf, nil
}
type encodePlanInetCodecText struct{}
func (encodePlanInetCodecText) Encode(value any, buf []byte) (newBuf []byte, err error) {
inet, err := value.(InetValuer).InetValue()
prefix, err := value.(NetipPrefixValuer).NetipPrefixValue()
if err != nil {
return nil, err
}
if !inet.Valid {
if !prefix.IsValid() {
return nil, nil
}
return append(buf, inet.IPNet.String()...), nil
return append(buf, prefix.String()...), nil
}
func (InetCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
@ -145,13 +111,13 @@ func (InetCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan
switch format {
case BinaryFormatCode:
switch target.(type) {
case InetScanner:
return scanPlanBinaryInetToInetScanner{}
case NetipPrefixScanner:
return scanPlanBinaryInetToNetipPrefixScanner{}
}
case TextFormatCode:
switch target.(type) {
case InetScanner:
return scanPlanTextAnyToInetScanner{}
case NetipPrefixScanner:
return scanPlanTextAnyToNetipPrefixScanner{}
}
}
@ -167,26 +133,26 @@ func (c InetCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (an
return nil, nil
}
var inet Inet
err := codecScan(c, m, oid, format, src, &inet)
var prefix netip.Prefix
err := codecScan(c, m, oid, format, src, &prefix)
if err != nil {
return nil, err
}
if !inet.Valid {
if !prefix.IsValid() {
return nil, nil
}
return inet.IPNet, nil
return prefix, nil
}
type scanPlanBinaryInetToInetScanner struct{}
type scanPlanBinaryInetToNetipPrefixScanner struct{}
func (scanPlanBinaryInetToInetScanner) Scan(src []byte, dst any) error {
scanner := (dst).(InetScanner)
func (scanPlanBinaryInetToNetipPrefixScanner) Scan(src []byte, dst any) error {
scanner := (dst).(NetipPrefixScanner)
if src == nil {
return scanner.ScanInet(Inet{})
return scanner.ScanNetipPrefix(netip.Prefix{})
}
if len(src) != 8 && len(src) != 20 {
@ -196,49 +162,39 @@ func (scanPlanBinaryInetToInetScanner) Scan(src []byte, dst any) error {
// ignore family
bits := src[1]
// ignore is_cidr
addressLength := src[3]
// ignore addressLength - implicit in length of message
var ipnet net.IPNet
ipnet.IP = make(net.IP, int(addressLength))
copy(ipnet.IP, src[4:])
if ipv4 := ipnet.IP.To4(); ipv4 != nil {
ipnet.IP = ipv4
addr, ok := netip.AddrFromSlice(src[4:])
if !ok {
return errors.New("netip.AddrFromSlice failed")
}
ipnet.Mask = net.CIDRMask(int(bits), len(ipnet.IP)*8)
return scanner.ScanInet(Inet{IPNet: &ipnet, Valid: true})
return scanner.ScanNetipPrefix(netip.PrefixFrom(addr, int(bits)))
}
type scanPlanTextAnyToInetScanner struct{}
type scanPlanTextAnyToNetipPrefixScanner struct{}
func (scanPlanTextAnyToInetScanner) Scan(src []byte, dst any) error {
scanner := (dst).(InetScanner)
func (scanPlanTextAnyToNetipPrefixScanner) Scan(src []byte, dst any) error {
scanner := (dst).(NetipPrefixScanner)
if src == nil {
return scanner.ScanInet(Inet{})
return scanner.ScanNetipPrefix(netip.Prefix{})
}
var ipnet *net.IPNet
var err error
if ip := net.ParseIP(string(src)); ip != nil {
if ipv4 := ip.To4(); ipv4 != nil {
ip = ipv4
}
bitCount := len(ip) * 8
mask := net.CIDRMask(bitCount, bitCount)
ipnet = &net.IPNet{Mask: mask, IP: ip}
} else {
ip, ipnet, err = net.ParseCIDR(string(src))
var prefix netip.Prefix
if bytes.IndexByte(src, '/') == -1 {
addr, err := netip.ParseAddr(string(src))
if err != nil {
return err
}
if ipv4 := ip.To4(); ipv4 != nil {
ip = ipv4
prefix = netip.PrefixFrom(addr, addr.BitLen())
} else {
var err error
prefix, err = netip.ParsePrefix(string(src))
if err != nil {
return err
}
ones, _ := ipnet.Mask.Size()
*ipnet = net.IPNet{IP: ip, Mask: net.CIDRMask(ones, len(ip)*8)}
}
return scanner.ScanInet(Inet{IPNet: ipnet, Valid: true})
return scanner.ScanNetipPrefix(prefix)
}

View File

@ -3,9 +3,9 @@ package pgtype_test
import (
"context"
"net"
"net/netip"
"testing"
"github.com/jackc/pgx/v5/pgtype"
"github.com/jackc/pgx/v5/pgxtest"
)
@ -31,7 +31,42 @@ func TestInetTranscode(t *testing.T) {
{mustParseInet(t, "::/0"), new(net.IPNet), isExpectedEqIPNet(mustParseInet(t, "::/0"))},
{mustParseInet(t, "::1/128"), new(net.IPNet), isExpectedEqIPNet(mustParseInet(t, "::1/128"))},
{mustParseInet(t, "2607:f8b0:4009:80b::200e/64"), new(net.IPNet), isExpectedEqIPNet(mustParseInet(t, "2607:f8b0:4009:80b::200e/64"))},
{nil, new(pgtype.Inet), isExpectedEq(pgtype.Inet{})},
{mustParseInet(t, "0.0.0.0/32"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("0.0.0.0/32"))},
{mustParseInet(t, "127.0.0.1/8"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("127.0.0.1/8"))},
{mustParseInet(t, "12.34.56.65/32"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("12.34.56.65/32"))},
{mustParseInet(t, "192.168.1.16/24"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("192.168.1.16/24"))},
{mustParseInet(t, "255.0.0.0/8"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("255.0.0.0/8"))},
{mustParseInet(t, "255.255.255.255/32"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("255.255.255.255/32"))},
{mustParseInet(t, "2607:f8b0:4009:80b::200e"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("2607:f8b0:4009:80b::200e/128"))},
{mustParseInet(t, "::1/64"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("::1/64"))},
{mustParseInet(t, "::/0"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("::/0"))},
{mustParseInet(t, "::1/128"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("::1/128"))},
{mustParseInet(t, "2607:f8b0:4009:80b::200e/64"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("2607:f8b0:4009:80b::200e/64"))},
{netip.MustParsePrefix("0.0.0.0/32"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("0.0.0.0/32"))},
{netip.MustParsePrefix("127.0.0.1/8"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("127.0.0.1/8"))},
{netip.MustParsePrefix("12.34.56.65/32"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("12.34.56.65/32"))},
{netip.MustParsePrefix("192.168.1.16/24"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("192.168.1.16/24"))},
{netip.MustParsePrefix("255.0.0.0/8"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("255.0.0.0/8"))},
{netip.MustParsePrefix("255.255.255.255/32"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("255.255.255.255/32"))},
{netip.MustParsePrefix("::1/64"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("::1/64"))},
{netip.MustParsePrefix("::/0"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("::/0"))},
{netip.MustParsePrefix("::1/128"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("::1/128"))},
{netip.MustParsePrefix("2607:f8b0:4009:80b::200e/64"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("2607:f8b0:4009:80b::200e/64"))},
{netip.MustParseAddr("0.0.0.0"), new(netip.Addr), isExpectedEq(netip.MustParseAddr("0.0.0.0"))},
{netip.MustParseAddr("127.0.0.1"), new(netip.Addr), isExpectedEq(netip.MustParseAddr("127.0.0.1"))},
{netip.MustParseAddr("12.34.56.65"), new(netip.Addr), isExpectedEq(netip.MustParseAddr("12.34.56.65"))},
{netip.MustParseAddr("192.168.1.16"), new(netip.Addr), isExpectedEq(netip.MustParseAddr("192.168.1.16"))},
{netip.MustParseAddr("255.0.0.0"), new(netip.Addr), isExpectedEq(netip.MustParseAddr("255.0.0.0"))},
{netip.MustParseAddr("255.255.255.255"), new(netip.Addr), isExpectedEq(netip.MustParseAddr("255.255.255.255"))},
{netip.MustParseAddr("2607:f8b0:4009:80b::200e"), new(netip.Addr), isExpectedEq(netip.MustParseAddr("2607:f8b0:4009:80b::200e"))},
{netip.MustParseAddr("::1"), new(netip.Addr), isExpectedEq(netip.MustParseAddr("::1"))},
{netip.MustParseAddr("::"), new(netip.Addr), isExpectedEq(netip.MustParseAddr("::"))},
{netip.MustParseAddr("2607:f8b0:4009:80b::200e"), new(netip.Addr), isExpectedEq(netip.MustParseAddr("2607:f8b0:4009:80b::200e"))},
{nil, new(netip.Prefix), isExpectedEq(netip.Prefix{})},
})
}
@ -48,6 +83,17 @@ func TestCidrTranscode(t *testing.T) {
{mustParseInet(t, "::/0"), new(net.IPNet), isExpectedEqIPNet(mustParseInet(t, "::/0"))},
{mustParseInet(t, "::1/128"), new(net.IPNet), isExpectedEqIPNet(mustParseInet(t, "::1/128"))},
{mustParseInet(t, "2607:f8b0:4009:80b::200e/128"), new(net.IPNet), isExpectedEqIPNet(mustParseInet(t, "2607:f8b0:4009:80b::200e/128"))},
{nil, new(pgtype.Inet), isExpectedEq(pgtype.Inet{})},
{netip.MustParsePrefix("0.0.0.0/32"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("0.0.0.0/32"))},
{netip.MustParsePrefix("127.0.0.1/32"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("127.0.0.1/32"))},
{netip.MustParsePrefix("12.34.56.0/32"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("12.34.56.0/32"))},
{netip.MustParsePrefix("192.168.1.0/24"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("192.168.1.0/24"))},
{netip.MustParsePrefix("255.0.0.0/8"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("255.0.0.0/8"))},
{netip.MustParsePrefix("::/128"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("::/128"))},
{netip.MustParsePrefix("::/0"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("::/0"))},
{netip.MustParsePrefix("::1/128"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("::1/128"))},
{netip.MustParsePrefix("2607:f8b0:4009:80b::200e/128"), new(netip.Prefix), isExpectedEq(netip.MustParsePrefix("2607:f8b0:4009:80b::200e/128"))},
{nil, new(netip.Prefix), isExpectedEq(netip.Prefix{})},
})
}

View File

@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"net"
"net/netip"
"reflect"
"time"
)
@ -364,6 +365,8 @@ func NewMap() *Map {
registerDefaultPgTypeVariants[net.IP](m, "inet")
registerDefaultPgTypeVariants[net.IPNet](m, "cidr")
registerDefaultPgTypeVariants[netip.Addr](m, "inet")
registerDefaultPgTypeVariants[netip.Prefix](m, "cidr")
// pgtype provided structs
registerDefaultPgTypeVariants[Bits](m, "varbit")
@ -377,7 +380,6 @@ func NewMap() *Map {
registerDefaultPgTypeVariants[Float8](m, "float8")
registerDefaultPgTypeVariants[Range[Float8]](m, "numrange") // There is no PostgreSQL builtin float8range so map it to numrange.
registerDefaultPgTypeVariants[Multirange[Range[Float8]]](m, "nummultirange") // There is no PostgreSQL builtin float8multirange so map it to nummultirange.
registerDefaultPgTypeVariants[Inet](m, "inet")
registerDefaultPgTypeVariants[Int2](m, "int2")
registerDefaultPgTypeVariants[Int4](m, "int4")
registerDefaultPgTypeVariants[Range[Int4]](m, "int4range")
@ -751,6 +753,10 @@ func TryWrapBuiltinTypeScanPlan(target any) (plan WrappedScanPlanNextSetter, nex
return &wrapNetIPNetScanPlan{}, (*netIPNetWrapper)(target), true
case *net.IP:
return &wrapNetIPScanPlan{}, (*netIPWrapper)(target), true
case *netip.Prefix:
return &wrapNetipPrefixScanPlan{}, (*netipPrefixWrapper)(target), true
case *netip.Addr:
return &wrapNetipAddrScanPlan{}, (*netipAddrWrapper)(target), true
case *map[string]*string:
return &wrapMapStringToPointerStringScanPlan{}, (*mapStringToPointerStringWrapper)(target), true
case *map[string]string:
@ -934,6 +940,26 @@ func (plan *wrapNetIPScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*netIPWrapper)(dst.(*net.IP)))
}
type wrapNetipPrefixScanPlan struct {
next ScanPlan
}
func (plan *wrapNetipPrefixScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapNetipPrefixScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*netipPrefixWrapper)(dst.(*netip.Prefix)))
}
type wrapNetipAddrScanPlan struct {
next ScanPlan
}
func (plan *wrapNetipAddrScanPlan) SetNext(next ScanPlan) { plan.next = next }
func (plan *wrapNetipAddrScanPlan) Scan(src []byte, dst any) error {
return plan.next.Scan(src, (*netipAddrWrapper)(dst.(*netip.Addr)))
}
type wrapMapStringToPointerStringScanPlan struct {
next ScanPlan
}
@ -1454,6 +1480,10 @@ func TryWrapBuiltinTypeEncodePlan(value any) (plan WrappedEncodePlanNextSetter,
return &wrapNetIPNetEncodePlan{}, netIPNetWrapper(value), true
case net.IP:
return &wrapNetIPEncodePlan{}, netIPWrapper(value), true
case netip.Prefix:
return &wrapNetipPrefixEncodePlan{}, netipPrefixWrapper(value), true
case netip.Addr:
return &wrapNetipAddrEncodePlan{}, netipAddrWrapper(value), true
case map[string]*string:
return &wrapMapStringToPointerStringEncodePlan{}, mapStringToPointerStringWrapper(value), true
case map[string]string:
@ -1639,6 +1669,26 @@ func (plan *wrapNetIPEncodePlan) Encode(value any, buf []byte) (newBuf []byte, e
return plan.next.Encode(netIPWrapper(value.(net.IP)), buf)
}
type wrapNetipPrefixEncodePlan struct {
next EncodePlan
}
func (plan *wrapNetipPrefixEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapNetipPrefixEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(netipPrefixWrapper(value.(netip.Prefix)), buf)
}
type wrapNetipAddrEncodePlan struct {
next EncodePlan
}
func (plan *wrapNetipAddrEncodePlan) SetNext(next EncodePlan) { plan.next = next }
func (plan *wrapNetipAddrEncodePlan) Encode(value any, buf []byte) (newBuf []byte, err error) {
return plan.next.Encode(netipAddrWrapper(value.(netip.Addr)), buf)
}
type wrapMapStringToPointerStringEncodePlan struct {
next EncodePlan
}

View File

@ -55,6 +55,8 @@ func mustParseInet(t testing.TB, s string) *net.IPNet {
if err == nil {
if ipv4 := ip.To4(); ipv4 != nil {
ipnet.IP = ipv4
} else {
ipnet.IP = ip
}
return ipnet
}