func (ipv6 IPv6Addr) FirstUsable() IPAddr {
	return IPv6Addr{
		Address: IPv6Address(ipv6.NetworkAddress()),
		Mask:    ipv6HostMask,
	}
}
FirstUsable returns an IPv6Addr set to the first address following the
network prefix.  The first usable address in a network is normally the
gateway and should not be used except by devices forwarding packets
between two administratively distinct networks (i.e. a router).  This
function does not discriminate against first usable vs "first address that
should be used."  For example, FirstUsable() on "2001:0db8::0003/64" would
return "2001:0db8::00011".
package sockaddr
import (
	"bytes"
	"encoding/binary"
	"fmt"
	"math/big"
	"net"
)
type (
	IPv6Address *big.Int
	IPv6Network *big.Int
	IPv6Mask *big.Int
)
const IPv6HostPrefix = IPPrefixLen(128)
var ipv6HostMask IPv6Mask
var ipv6AddrAttrMap map[AttrName]func(IPv6Addr) string
var ipv6AddrAttrs []AttrName
func init() {
	biMask := new(big.Int)
	biMask.SetBytes([]byte{
		0xff, 0xff,
		0xff, 0xff,
		0xff, 0xff,
		0xff, 0xff,
		0xff, 0xff,
		0xff, 0xff,
		0xff, 0xff,
		0xff, 0xff,
	},
	)
	ipv6HostMask = IPv6Mask(biMask)
	ipv6AddrInit()
}
type IPv6Addr struct {
	IPAddr
	Address IPv6Address
	Mask    IPv6Mask
	Port    IPPort
}
func NewIPv6Addr(ipv6Str string) (IPv6Addr, error) {
	v6Addr := false
LOOP:
	for i := 0; i < len(ipv6Str); i++ {
		switch ipv6Str[i] {
		case '.':
			break LOOP
		case ':':
			v6Addr = true
			break LOOP
		}
	}
	if !v6Addr {
		return IPv6Addr{}, fmt.Errorf("Unable to resolve %+q as an IPv6 address, appears to be an IPv4 address", ipv6Str)
	}
	tcpAddr, err := net.ResolveTCPAddr("tcp6", ipv6Str)
	if err == nil {
		ipv6 := tcpAddr.IP.To16()
		if ipv6 == nil {
			return IPv6Addr{}, fmt.Errorf("Unable to resolve %+q as a 16byte IPv6 address", ipv6Str)
		}
		ipv6BigIntAddr := new(big.Int)
		ipv6BigIntAddr.SetBytes(ipv6)
		ipv6BigIntMask := new(big.Int)
		ipv6BigIntMask.Set(ipv6HostMask)
		ipv6Addr := IPv6Addr{
			Address: IPv6Address(ipv6BigIntAddr),
			Mask:    IPv6Mask(ipv6BigIntMask),
			Port:    IPPort(tcpAddr.Port),
		}
		return ipv6Addr, nil
	}
	if len(ipv6Str) > 2 && ipv6Str[0] == '[' && ipv6Str[len(ipv6Str)-1] == ']' {
		ipv6Str = ipv6Str[1 : len(ipv6Str)-1]
	}
	ip := net.ParseIP(ipv6Str)
	if ip != nil {
		ipv6 := ip.To16()
		if ipv6 == nil {
			return IPv6Addr{}, fmt.Errorf("Unable to string convert %+q to a 16byte IPv6 address", ipv6Str)
		}
		ipv6BigIntAddr := new(big.Int)
		ipv6BigIntAddr.SetBytes(ipv6)
		ipv6BigIntMask := new(big.Int)
		ipv6BigIntMask.Set(ipv6HostMask)
		return IPv6Addr{
			Address: IPv6Address(ipv6BigIntAddr),
			Mask:    IPv6Mask(ipv6BigIntMask),
		}, nil
	}
	ipAddr, network, err := net.ParseCIDR(ipv6Str)
	if err == nil {
		ipv6 := ipAddr.To16()
		if ipv6 == nil {
			return IPv6Addr{}, fmt.Errorf("Unable to convert %+q to a 16byte IPv6 address", ipv6Str)
		}
		ipv6BigIntAddr := new(big.Int)
		ipv6BigIntAddr.SetBytes(ipv6)
		ipv6BigIntMask := new(big.Int)
		ipv6BigIntMask.SetBytes(network.Mask)
		ipv6Addr := IPv6Addr{
			Address: IPv6Address(ipv6BigIntAddr),
			Mask:    IPv6Mask(ipv6BigIntMask),
		}
		return ipv6Addr, nil
	}
	return IPv6Addr{}, fmt.Errorf("Unable to parse %+q to an IPv6 address: %v", ipv6Str, err)
}
func (ipv6 IPv6Addr) AddressBinString() string {
	bi := big.Int(*ipv6.Address)
	return fmt.Sprintf("%0128s", bi.Text(2))
}
func (ipv6 IPv6Addr) AddressHexString() string {
	bi := big.Int(*ipv6.Address)
	return fmt.Sprintf("%032s", bi.Text(16))
}
func (ipv6 IPv6Addr) CmpAddress(sa SockAddr) int {
	ipv6b, ok := sa.(IPv6Addr)
	if !ok {
		return sortDeferDecision
	}
	ipv6aBigInt := new(big.Int)
	ipv6aBigInt.Set(ipv6.Address)
	ipv6bBigInt := new(big.Int)
	ipv6bBigInt.Set(ipv6b.Address)
	return ipv6aBigInt.Cmp(ipv6bBigInt)
}
func (ipv6 IPv6Addr) CmpPort(sa SockAddr) int {
	var saPort IPPort
	switch v := sa.(type) {
	case IPv4Addr:
		saPort = v.Port
	case IPv6Addr:
		saPort = v.Port
	default:
		return sortDeferDecision
	}
	switch {
	case ipv6.Port == saPort:
		return sortDeferDecision
	case ipv6.Port < saPort:
		return sortReceiverBeforeArg
	default:
		return sortArgBeforeReceiver
	}
}
func (ipv6 IPv6Addr) CmpRFC(rfcNum uint, sa SockAddr) int {
	recvInRFC := IsRFC(rfcNum, ipv6)
	ipv6b, ok := sa.(IPv6Addr)
	if !ok {
		if recvInRFC {
			return sortReceiverBeforeArg
		} else {
			return sortDeferDecision
		}
	}
	argInRFC := IsRFC(rfcNum, ipv6b)
	switch {
	case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC):
		return sortDeferDecision
	case recvInRFC && !argInRFC:
		return sortReceiverBeforeArg
	default:
		return sortArgBeforeReceiver
	}
}
func (ipv6 IPv6Addr) Contains(sa SockAddr) bool {
	ipv6b, ok := sa.(IPv6Addr)
	if !ok {
		return false
	}
	return ipv6.ContainsNetwork(ipv6b)
}
func (ipv6 IPv6Addr) ContainsAddress(x IPv6Address) bool {
	xAddr := IPv6Addr{
		Address: x,
		Mask:    ipv6HostMask,
	}
	{
		xIPv6 := xAddr.FirstUsable().(IPv6Addr)
		yIPv6 := ipv6.FirstUsable().(IPv6Addr)
		if xIPv6.CmpAddress(yIPv6) >= 1 {
			return false
		}
	}
	{
		xIPv6 := xAddr.LastUsable().(IPv6Addr)
		yIPv6 := ipv6.LastUsable().(IPv6Addr)
		if xIPv6.CmpAddress(yIPv6) <= -1 {
			return false
		}
	}
	return true
}
func (x IPv6Addr) ContainsNetwork(y IPv6Addr) bool {
	{
		xIPv6 := x.FirstUsable().(IPv6Addr)
		yIPv6 := y.FirstUsable().(IPv6Addr)
		if ret := xIPv6.CmpAddress(yIPv6); ret >= 1 {
			return false
		}
	}
	{
		xIPv6 := x.LastUsable().(IPv6Addr)
		yIPv6 := y.LastUsable().(IPv6Addr)
		if ret := xIPv6.CmpAddress(yIPv6); ret <= -1 {
			return false
		}
	}
	return true
}
func (ipv6 IPv6Addr) DialPacketArgs() (network, dialArgs string) {
	ipv6Mask := big.Int(*ipv6.Mask)
	if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 {
		return "udp6", ""
	}
	return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
}
func (ipv6 IPv6Addr) DialStreamArgs() (network, dialArgs string) {
	ipv6Mask := big.Int(*ipv6.Mask)
	if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 {
		return "tcp6", ""
	}
	return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port)
}
func (ipv6a IPv6Addr) Equal(sa SockAddr) bool {
	ipv6b, ok := sa.(IPv6Addr)
	if !ok {
		return false
	}
	if ipv6a.NetIP().String() != ipv6b.NetIP().String() {
		return false
	}
	if ipv6a.NetIPNet().String() != ipv6b.NetIPNet().String() {
		return false
	}
	if ipv6a.Port != ipv6b.Port {
		return false
	}
	return true
}