 
 defimpl String.Chars, for: Gullintanni.Listener.Socket do
   def to_string(socket) do
-    case tuple_size(socket.address) do
-      4 -> "#{:inet.ntoa(socket.address)}:#{socket.port}"
-      8 -> "[#{:inet.ntoa(socket.address)}]:#{socket.port}"
+    case tuple_size(socket.ip) do
+      4 -> "#{:inet.ntoa(socket.ip)}:#{socket.port}"
+      8 -> "[#{:inet.ntoa(socket.ip)}]:#{socket.port}"
     end
   end
 end

      #Socket<[FE80::204:ACFF:FE17:BF38]:80>

      iex> Gullintanni.Listener.Socket.new("100.200.300.400", 80)
      {:error, :invalid_address}

      iex> Gullintanni.Listener.Socket.new("0.0.0.0", 99999)
      {:error, :invalid_port}
  """
  @spec new(address, port_number) :: {:ok, t} | {:error, :invalid_address} | {:error, :invalid_port}
  def new(address, port) do
    address = parse(address)

    cond do
      address == nil ->
        {:error, :invalid_address}
      Enum.member?(@valid_ports, port) == false ->
        {:error, :invalid_port}
      true ->
        {:ok, %Socket{address: address, port: port}}
    end
  end

  # Parses a string into an IP address tuple.
  @spec parse(address) :: :inet.ip_address | nil
  defp parse(address) when address |> is_binary do
    address
    |> String.to_char_list
    |> parse
  end
  defp parse(address) when address |> is_list do
    case :inet.parse_address(address) do
      {:ok, ip_address} -> ip_address
      {:error, :einval} -> nil
    end
  end
  defp parse(address) do
    address
  end
end



defmodule Gullintanni.Listener.Socket do
  @moduledoc """
  Utility module for handling Internet socket address parsing and validation.

  A *socket address* is the combination of an IP address and a port number.
  This can be used along with a transport protocol in order to define an
  endpoint of a connection across a network.
  """

  alias __MODULE__, as: Socket

  @typedoc "The IP address of a socket"
  @type ip_address :: String.t | char_list | :inet.ip_address

  @typedoc "The port number of a socket"
  @type port_number :: 0..65535

  @typedoc "The socket address type"
  @type t :: %Socket{ip: :inet.ip_address, port: port_number}

  @enforce_keys [:ip, :port]
  defstruct [:ip, :port]

  @valid_ports 0..65535

  @doc """
  Creates a new socket address with the given `ip` and `port`.

  Returns `{:ok, socket}` if the IP address and port number are valid, returns
  `{:error, reason}` otherwise. A valid IP address is anything that can be
  parsed by `:inet.parse_address/1`, and a valid port must be an integer in the
  range of `#{inspect @valid_ports}`.

  ## Examples

