    const std = @import("../../std.zig");

    const fmt = std.fmt;

    const IPv4 = std.x.os.IPv4;
    const IPv6 = std.x.os.IPv6;
    const Socket = std.x.os.Socket;

    /// A generic IP abstraction.
    const ip = @This();

    /// A union of all eligible types of IP addresses.
    pub const Address = union(enum) {
        ipv4: IPv4.Address,
        ipv6: IPv6.Address,

        /// Instantiate a new address with a IPv4 host and port.
        pub fn initIPv4(host: IPv4, port: u16) Address {
            return .{ .ipv4 = .{ .host = host, .port = port } };
        }

        /// Instantiate a new address with a IPv6 host and port.
        pub fn initIPv6(host: IPv6, port: u16) Address {
            return .{ .ipv6 = .{ .host = host, .port = port } };
        }

        /// Re-interpret a generic socket address into an IP address.
        pub fn from(address: Socket.Address) ip.Address {
            return switch (address) {
                .ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
                .ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
            };
        }

        /// Re-interpret an IP address into a generic socket address.
        pub fn into(self: ip.Address) Socket.Address {
            return switch (self) {
                .ipv4 => |ipv4_address| .{ .ipv4 = ipv4_address },
                .ipv6 => |ipv6_address| .{ .ipv6 = ipv6_address },
            };
        }

        /// Implements the `std.fmt.format` API.
        pub fn format(
            self: ip.Address,
            comptime layout: []const u8,
            opts: fmt.FormatOptions,
            writer: anytype,
        ) !void {
            _ = opts;
            _ = layout;
            switch (self) {
                .ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
                .ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
            }
        }
    };