module Codec.Crockford (encode, decode, prop_crockfordRoundTrip) where import Control.Monad import Data.Char import Data.Digits (digits, unDigits) import Data.Maybe import Test.QuickCheck {- 0 0 O o 0 1 1 I i L l 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 7 7 7 8 8 8 9 9 9 10 A a A 11 B b B 12 C c C 13 D d D 14 E e E 15 F f F 16 G g G 17 H h H 18 J j J 19 K k K 20 M m M 21 N n N 22 P p P 23 Q q Q 24 R r R 25 S s S 26 T t T 27 V v V 28 W w W 29 X x X 30 Y y Y 31 Z z Z -} decode :: Integral i => String -> Maybe i decode s = mapM decodeChar s >>= return . unDigits 32 encode :: Integral i => i -> String encode = fromJust . mapM encodeChar . digits 32 decodeChar :: Integral i => Char -> Maybe i decodeChar c = case toUpper c of '0' -> Just 0 'O' -> Just 0 '1' -> Just 1 'I' -> Just 1 'L' -> Just 1 '2' -> Just 2 '3' -> Just 3 '4' -> Just 4 '5' -> Just 5 '6' -> Just 6 '7' -> Just 7 '8' -> Just 8 '9' -> Just 9 'A' -> Just 10 'B' -> Just 11 'C' -> Just 12 'D' -> Just 13 'E' -> Just 14 'F' -> Just 15 'G' -> Just 16 'H' -> Just 17 'J' -> Just 18 'K' -> Just 19 'M' -> Just 20 'N' -> Just 21 'P' -> Just 22 'Q' -> Just 23 'R' -> Just 24 'S' -> Just 25 'T' -> Just 26 'V' -> Just 27 'W' -> Just 28 'X' -> Just 29 'Y' -> Just 30 'Z' -> Just 31 _ -> Nothing encodeChar :: Integral i => i -> Maybe Char encodeChar i = case i of 0 -> Just '0' 1 -> Just '1' 2 -> Just '2' 3 -> Just '3' 4 -> Just '4' 5 -> Just '5' 6 -> Just '6' 7 -> Just '7' 8 -> Just '8' 9 -> Just '9' 10 -> Just 'A' 11 -> Just 'B' 12 -> Just 'C' 13 -> Just 'D' 14 -> Just 'E' 15 -> Just 'F' 16 -> Just 'G' 17 -> Just 'H' 18 -> Just 'J' 19 -> Just 'K' 20 -> Just 'M' 21 -> Just 'N' 22 -> Just 'P' 23 -> Just 'Q' 24 -> Just 'R' 25 -> Just 'S' 26 -> Just 'T' 27 -> Just 'V' 28 -> Just 'W' 29 -> Just 'X' 30 -> Just 'Y' 31 -> Just 'Z' _ -> Nothing prop_crockfordRoundTrip :: Integer -- ^ The integer to test. -> Property prop_crockfordRoundTrip i = i > 0 ==> Just i == (decode . encode) i