defmodule Ch.Error do defexception [:code, :message] @type t :: %__MODULE__{code: pos_integer | nil, message: String.t()} def exception(code, message) do message = IO.iodata_to_binary(ensure_printable(message)) exception(code: code, message: message) end @dialyzer :no_improper_lists @doc false def ensure_printable(message) do printable(message, 0, 0, message, []) end defguardp is_printable(char) when char in 32..127 or char == ?\n defp printable(<>, from, len, original, acc) when is_printable(char) do printable(rest, from, len + 1, original, acc) end defp printable(<<_char, rest::bytes>>, from, len, original, acc) do acc = [acc | binary_part(original, from, len)] unprintable(rest, from + len, 1, original, acc) end defp printable(<<>>, from, len, original, acc) do [acc | binary_part(original, from, len)] end defp unprintable(<>, from, len, original, acc) when is_printable(char) do acc = [acc | inspect(binary_part(original, from, len))] printable(rest, from + len, 1, original, acc) end defp unprintable(<<_char, rest::bytes>>, from, len, original, acc) do unprintable(rest, from, len + 1, original, acc) end defp unprintable(<<>>, from, len, original, acc) do [acc | inspect(binary_part(original, from, len))] end end