# MIT License # # Copyright (c) 2018 Knoxen # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. defmodule Puid.CharSet do @moduledoc """ Pre-defined `Puid.CharSet`s Pre-defined `Puid.CharSet`s are specified via an atom `charset` option during `Puid` module definition. ## Example defmodule(AlphanumId, do: use(Puid, charset: :alphanum)) ## CharSets ### :alpha Upper/lower case alphabet ```none ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ``` ### :alpha_lower Lower case alphabet ```none abcdefghijklmnopqrstuvwxyz ``` ### :alpha_upper Upper case alphabet ```none ABCDEFGHIJKLMNOPQRSTUVWXYZ ``` ### :alphanum Upper/lower case alphabet and numbers ```none ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ``` ### :alphanum_lower Lower case alphabet and numbers ```none abcdefghijklmnopqrstuvwxyz0123456789 ``` ### :alphanum_upper Upper case alphabet and numbers ```none ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ``` ### :base32 [RFC 4648](https://tools.ietf.org/html/rfc4648#section-6) base32 character set ```none ABCDEFGHIJKLMNOPQRSTUVWXYZ234567 ``` ### :base32_hex [RFC 4648](https://tools.ietf.org/html/rfc4648#section-7) base32 extended hex character set with lowercase letters ```none 0123456789abcdefghijklmnopqrstuv ``` ### :base32_hex_upper [RFC 4648](https://tools.ietf.org/html/rfc4648#section-7) base32 extended hex character set ```none 0123456789ABCDEFGHIJKLMNOPQRSTUV ``` ### :decimal Decimal digits ```none 0123456789 ``` ### :hex Lowercase hexidecimal ```none 0123456789abcdef ``` ### :hex_upper Uppercase hexidecimal ```none 0123456789ABCDEF ``` ### :safe32 Strings that don't look like English words and are easy to parse visually ```none 2346789bdfghjmnpqrtBDFGHJLMNPQRT ``` - remove all upper and lower case vowels (including y) - remove all numbers that look like letters - remove all letters that look like numbers - remove all letters that have poor distinction between upper and lower case values ### :safe64 [RFC 4648](https://tools.ietf.org/html/rfc4648#section-5) file system and URL safe character set ```none ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_ ``` ### :printable_ascii Printable ASCII characters from `?!` to `?~` ```none `!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\`abcdefghijklmnopqrstuvwxyz{|}~` ``` """ @doc false def unique?(chars) when is_binary(chars), do: unique?(chars, true) defp unique?("", unique), do: unique defp unique?(_, false), do: false defp unique?(chars, true) do {char, rest} = chars |> String.next_grapheme() unique?(rest, rest |> String.contains?(char) |> Kernel.!()) end ## ----------------------------------------------------------------------------------------------- ## Characters for charset ## ----------------------------------------------------------------------------------------------- @doc """ Return pre-defined `Puid.CharSet` characters or `:undefined` """ @spec chars(atom()) :: String.t() | :undefined def chars(charset) def chars(:alpha), do: chars(:alpha_upper) <> chars(:alpha_lower) def chars(:alpha_lower), do: "abcdefghijklmnopqrstuvwxyz" def chars(:alpha_upper), do: "ABCDEFGHIJKLMNOPQRSTUVWXYZ" def chars(:alphanum), do: chars(:alpha) <> chars(:decimal) def chars(:alphanum_lower), do: chars(:alpha_lower) <> chars(:decimal) def chars(:alphanum_upper), do: chars(:alpha_upper) <> chars(:decimal) def chars(:base32), do: chars(:alpha_upper) <> "234567" def chars(:base32_hex), do: chars(:decimal) <> "abcdefghijklmnopqrstuv" def chars(:base32_hex_upper), do: chars(:decimal) <> "ABCDEFGHIJKLMNOPQRSTUV" def chars(:decimal), do: "0123456789" def chars(:hex), do: chars(:decimal) <> "abcdef" def chars(:hex_upper), do: chars(:decimal) <> "ABCDEF" def chars(:printable_ascii), do: ?!..?~ |> Enum.to_list() |> to_string() def chars(:safe32), do: "2346789bdfghjmnpqrtBDFGHJLMNPQRT" def chars(:safe64), do: chars(:alpha_upper) <> chars(:alpha_lower) <> chars(:decimal) <> "-_" def chars(_), do: :undefined end