text: package sockaddr
  
  import (
  	"fmt"
  	"net"
  )
  
  // IfAddr is a union of a SockAddr and a net.Interface.
  type IfAddr struct {
  	SockAddr
  	net.Interface
  }
  
  // Attr returns the named attribute as a string
  func (ifAddr IfAddr) Attr(attrName AttrName) (string, error) {
  	val := IfAddrAttr(ifAddr, attrName)
  	if val != "" {
  		return val, nil
  	}
  
  	return Attr(ifAddr.SockAddr, attrName)
  }
  
  // Attr returns the named attribute as a string
  func Attr(sa SockAddr, attrName AttrName) (string, error) {
  	switch sockType := sa.Type(); {
  	case sockType&TypeIP != 0:
  		ip := *ToIPAddr(sa)
  		attrVal := IPAddrAttr(ip, attrName)
  		if attrVal != "" {
  			return attrVal, nil
  		}
  
  		if sockType == TypeIPv4 {
  			ipv4 := *ToIPv4Addr(sa)
  			attrVal := IPv4AddrAttr(ipv4, attrName)
  			if attrVal != "" {
  				return attrVal, nil
  			}
  		} else if sockType == TypeIPv6 {
  			ipv6 := *ToIPv6Addr(sa)
  			attrVal := IPv6AddrAttr(ipv6, attrName)
  			if attrVal != "" {
  				return attrVal, nil
  			}
  		}
  
  	case sockType == TypeUnix:
  		us := *ToUnixSock(sa)
  		attrVal := UnixSockAttr(us, attrName)
  		if attrVal != "" {
  			return attrVal, nil
  		}
  	}
  
  	// Non type-specific attributes
  	switch attrName {
  	case "string":
  		return sa.String(), nil
  	case "type":
  		return sa.Type().String(), nil
  	}
  
  	return "", fmt.Errorf("unsupported attribute name %q", attrName)
  }
  