defmodule Codex.Base64 do import Codex @capitals 65..90 |> Enum.map(&:binary.encode_unsigned/1) @lowers 97..122 |> Enum.map(&:binary.encode_unsigned/1) @numbers 48..57 |> Enum.map(&:binary.encode_unsigned/1) @char_list (@capitals ++ @lowers ++ @numbers ++ ["+", "/"]) |> Enum.with_index() @char_to_num @char_list |> Enum.into(%{}) @num_to_char @char_list |> Enum.map(fn {char, num} -> {num, char} end) |> Enum.into(%{}) @spec codec() :: Codex.codec(String.t()) def codec() do padding = value("=") char_6 = bits(6) |> index_to_char() char_2 = bits(2) |> done() |> pad(4) |> index_to_char() char_4 = bits(4) |> done() |> pad(2) |> index_to_char() list( choice([ list_of(4, char_6) |> join(), [char_6, char_2, padding, padding] |> sequence() |> join(), [char_6, char_6, char_4, padding] |> sequence() |> join() ]) ) |> join(4) end defp index_to_char(index), do: convert(index, &Map.fetch!(@num_to_char, &1), &Map.fetch!(@char_to_num, &1)) end