locators 0.3.0.3 → 0.3.0.5
raw patch · 7 files changed
+325/−372 lines, 7 filesdep +cryptondep −cryptonite
Dependencies added: crypton
Dependencies removed: cryptonite
Files
- lib/Data/Locator.hs +0/−13
- lib/Data/Locator/Common.hs +43/−61
- lib/Data/Locator/English16.hs +129/−125
- lib/Data/Locator/Hashes.hs +24/−41
- lib/Data/Locator/Latin25.hs +111/−97
- locators.cabal +6/−7
- tests/TestSuite.hs +12/−28
lib/Data/Locator.hs view
@@ -1,16 +1,3 @@------ Human exchangable identifiers and locators------ Copyright © 2011-2018 Operational Dynamics Consulting, Pty Ltd------ The code in this file, and the program it is a part of, is--- made available to you by its authors as open source software:--- you can redistribute it and/or modify it under the terms of--- the BSD licence.------ This code originally licenced GPLv2. Relicenced BSD3 on 2 Jan 2014.---- {-# LANGUAGE OverloadedStrings #-} --
lib/Data/Locator/Common.hs view
@@ -1,30 +1,18 @@------ Human exchangable identifiers and locators------ Copyright © 2011-2018 Operational Dynamics Consulting, Pty Ltd------ The code in this file, and the program it is a part of, is--- made available to you by its authors as open source software:--- you can redistribute it and/or modify it under the terms of--- the BSD licence.------ This code originally licenced GPLv2. Relicenced BSD3 on 2 Jan 2014.---+{-# LANGUAGE InstanceSigs #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE InstanceSigs #-} {-# LANGUAGE TypeApplications #-} -module Data.Locator.Common- ( Locator(..)- , represent- , value- , toLocatorUnique- , multiply- , fromLocator- , concatToInteger- , digest- ) where+module Data.Locator.Common (+ Locator (..),+ represent,+ value,+ toLocatorUnique,+ multiply,+ fromLocator,+ concatToInteger,+ digest,+) where import Prelude hiding (toInteger) @@ -40,7 +28,6 @@ locatorToDigit :: α -> Char digitToLocator :: Char -> α - represent :: Locator α => α -> Int -> Char represent (_ :: α) n = locatorToDigit $ (toEnum n :: α)@@ -56,41 +43,39 @@ fromEnum $ (digitToLocator c :: α) ----- | Represent a number in Locator16a format. This uses the Locator16 symbol--- set, and additionally specifies that no symbol can be repeated. The /a/ in--- Locator16a represents that this transformation is done on the cheap; when--- converting if we end up with \'9\' \'9\' we simply pick the subsequent digit--- in the enum, in this case getting you \'9\' \'K\'.------ Note that the transformation is /not/ reversible. A number like @4369@--- (which is @0x1111@, incidentally) encodes as @12C4@. So do @4370@, @4371@,--- and @4372@. The point is not uniqueness, but readibility in adverse--- conditions. So while you can count locators, they don't map continuously to--- base10 integers.------ The first argument is the number of digits you'd like in the locator; if the--- number passed in is less than 16^limit, then the result will be padded.------ >>> toLocator16a 6 4369--- 12C40F---++{- |+Represent a number in Locator16a format. This uses the Locator16 symbol+set, and additionally specifies that no symbol can be repeated. The /a/ in+Locator16a represents that this transformation is done on the cheap; when+converting if we end up with \'9\' \'9\' we simply pick the subsequent digit+in the enum, in this case getting you \'9\' \'K\'.++Note that the transformation is /not/ reversible. A number like @4369@+(which is @0x1111@, incidentally) encodes as @12C4@. So do @4370@, @4371@,+and @4372@. The point is not uniqueness, but readibility in adverse+conditions. So while you can count locators, they don't map continuously to+base10 integers.++The first argument is the number of digits you'd like in the locator; if the+number passed in is less than 16^limit, then the result will be padded.++>>> toLocator16a 6 4369+12C40F+-} toLocatorUnique :: Locator α => Int -> Int -> α -> String toLocatorUnique limit n (_ :: α) =- let- n' = abs n- ls = convert n' (replicate limit (minBound @α))- (_,us) = mapAccumL uniq Set.empty ls- in- map locatorToDigit (take limit us)+ let n' = abs n+ ls = convert n' (replicate limit (minBound @α))+ (_, us) = mapAccumL uniq Set.empty ls+ in map locatorToDigit (take limit us) where convert :: Locator α => Int -> [α] -> [α] convert 0 xs = xs convert i xs =- let- (d,r) = divMod i 16- x = toEnum r- in- convert d (x:xs)+ let (d, r) = divMod i 16+ x = toEnum r+ in convert d (x : xs) uniq :: Locator α => Set α -> α -> (Set α, α) uniq s x =@@ -106,14 +91,12 @@ multiply :: Locator α => α -> Int -> Char -> Int multiply (locator :: a) acc c =- let- base = fromEnum (maxBound @a) + 1- in- (acc * base) + (value locator c)+ let base = fromEnum (maxBound @a) + 1+ in (acc * base) + (value locator c) --+ -- | Given a number encoded as a Locator, convert it back to an integer.--- fromLocator :: Locator α => α -> String -> Int fromLocator locator ss = foldl (multiply locator) 0 ss@@ -131,8 +114,7 @@ digest ws = i where- i = concatToInteger h- h = B.unpack h'+ i = concatToInteger h+ h = B.unpack h' h' = Crypto.hash x' :: Crypto.Digest Crypto.SHA1 x' = S.pack ws-
lib/Data/Locator/English16.hs view
@@ -1,34 +1,21 @@------ Human exchangable identifiers and locators------ Copyright © 2011-2018 Operational Dynamics Consulting, Pty Ltd------ The code in this file, and the program it is a part of, is--- made available to you by its authors as open source software:--- you can redistribute it and/or modify it under the terms of--- the BSD licence.------ This code originally licenced GPLv2. Relicenced BSD3 on 2 Jan 2014.---+{-# LANGUAGE InstanceSigs #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE InstanceSigs #-} {-# LANGUAGE TypeApplications #-} -module Data.Locator.English16- ( Locator(..)- , English16(..)- , fromEnglish16- , toEnglish16- , toEnglish16a- , hashStringToEnglish16a-+module Data.Locator.English16 (+ Locator (..),+ English16 (..),+ fromEnglish16,+ toEnglish16,+ toEnglish16a,+ hashStringToEnglish16a, -- Deprecated- , fromLocator16- , toLocator16- , toLocator16a- , hashStringToLocator16a- ) where+ fromLocator16,+ toLocator16,+ toLocator16a,+ hashStringToLocator16a,+) where import Prelude hiding (toInteger) @@ -42,20 +29,23 @@ import Data.Locator.Common ----- | A symbol set with sixteen uniquely pronounceable digits.------ The fact there are sixteen symbols is more an indication of a certain degree--- of bullheaded-ness on the part of the author, and less of any kind of actual--- requirement. We might have a slighly better readback score if we dropped to--- 15 or 14 unique characters. It does mean you can match up with hexidecimal,--- which is not entirely without merit.------ The grouping of letters and numbers was the hard part; having come up with--- the set and deconflicted the choices, the ordering is then entirely--- arbitrary. Since there are some numbers, might as well have them at the same--- place they correspond to in base 10; the letters were then allocated in--- alpha order in the remaining slots.---++{- |+A symbol set with sixteen uniquely pronounceable digits.++The fact there are sixteen symbols is more an indication of a certain degree+of bullheaded-ness on the part of the author, and less of any kind of actual+requirement. We might have a slighly better readback score if we dropped to+15 or 14 unique characters. It does mean you can match up with hexidecimal,+which is not entirely without merit.++The grouping of letters and numbers was the hard part; having come up with+the set and deconflicted the choices, the ordering is then entirely+arbitrary. Since there are some numbers, might as well have them at the same+place they correspond to in base 10; the letters were then allocated in alpha+order in the remaining slots.+-}+ {- -- 0 Conflicts with @\'O\'@ obviously, and @\'Q\'@ often enough --@@ -90,44 +80,60 @@ -- usual reason of being similar to @\'1\'@. -} data English16- = Zero -- ^ @\'0\'@ /0th/- | One -- ^ @\'1\'@ /1st/- | Two -- ^ @\'2\'@ /2nd/- | Charlie -- ^ @\'C\'@ /3rd/- | Four -- ^ @\'4\'@ /4th/- | Foxtrot -- ^ @\'F\'@ /5th/- | Hotel -- ^ @\'H\'@ /6th/- | Seven -- ^ @\'7\'@ /7th/- | Eight -- ^ @\'8\'@ /8th/- | Nine -- ^ @\'9\'@ /9th/- | Kilo -- ^ @\'K\'@ /10th/- | Lima -- ^ @\'L\'@ /11th/- | Mike -- ^ @\'M\'@ /12th/- | Romeo -- ^ @\'R\'@ /13th/- | XRay -- ^ @\'X\'@ /14th/- | Yankee -- ^ @\'Y\'@ /15th/+ = -- | @\'0\'@ /0th/+ Zero+ | -- | @\'1\'@ /1st/+ One+ | -- | @\'2\'@ /2nd/+ Two+ | -- | @\'C\'@ /3rd/+ Charlie+ | -- | @\'4\'@ /4th/+ Four+ | -- | @\'F\'@ /5th/+ Foxtrot+ | -- | @\'H\'@ /6th/+ Hotel+ | -- | @\'7\'@ /7th/+ Seven+ | -- | @\'8\'@ /8th/+ Eight+ | -- | @\'9\'@ /9th/+ Nine+ | -- | @\'K\'@ /10th/+ Kilo+ | -- | @\'L\'@ /11th/+ Lima+ | -- | @\'M\'@ /12th/+ Mike+ | -- | @\'R\'@ /13th/+ Romeo+ | -- | @\'X\'@ /14th/+ XRay+ | -- | @\'Y\'@ /15th/+ Yankee deriving (Eq, Ord, Enum, Bounded) instance Locator English16 where locatorToDigit :: English16 -> Char locatorToDigit x = case x of- Zero -> '0'- One -> '1'- Two -> '2'+ Zero -> '0'+ One -> '1'+ Two -> '2' Charlie -> 'C'- Four -> '4'+ Four -> '4' Foxtrot -> 'F'- Hotel -> 'H'- Seven -> '7'- Eight -> '8'- Nine -> '9'- Kilo -> 'K'- Lima -> 'L'- Mike -> 'M'- Romeo -> 'R'- XRay -> 'X'- Yankee -> 'Y'+ Hotel -> 'H'+ Seven -> '7'+ Eight -> '8'+ Nine -> '9'+ Kilo -> 'K'+ Lima -> 'L'+ Mike -> 'M'+ Romeo -> 'R'+ XRay -> 'X'+ Yankee -> 'Y' digitToLocator :: Char -> English16 digitToLocator c =@@ -148,7 +154,7 @@ 'R' -> Romeo 'X' -> XRay 'Y' -> Yankee- _ -> error "Illegal digit"+ _ -> error "Illegal digit" instance Show English16 where show x = [c]@@ -156,54 +162,54 @@ c = locatorToDigit x ----- | Given a number, convert it to a string in the English16 base 16 symbol--- alphabet. You can use this as a replacement for the standard \'0\'-\'9\'--- \'A\'-\'F\' symbols traditionally used to express hexidemimal, though really--- the fact that we came up with 16 total unique symbols was a nice--- co-incidence, not a requirement.---++{- |+Given a number, convert it to a string in the English16 base 16 symbol+alphabet. You can use this as a replacement for the standard \'0\'-\'9\'+\'A\'-\'F\' symbols traditionally used to express hexidemimal, though really+the fact that we came up with 16 total unique symbols was a nice+co-incidence, not a requirement.+-} toEnglish16 :: Int -> String toEnglish16 x = showIntAtBase 16 (represent Yankee) x "" ----- | Represent a number in English16a format. This uses the Locator16 symbol--- set, and additionally specifies that no symbol can be repeated. The /a/ in--- Locator16a represents that this transformation is done on the cheap; when--- converting if we end up with \'9\' \'9\' we simply pick the subsequent digit--- in the enum, in this case getting you \'9\' \'K\'.------ Note that the transformation is /not/ reversible. A number like @4369@--- (which is @0x1111@, incidentally) encodes as @12C4@. So do @4370@, @4371@,--- and @4372@. The point is not uniqueness, but readibility in adverse--- conditions. So while you can count locators, they don't map continuously to--- base10 integers.------ The first argument is the number of digits you'd like in the locator; if the--- number passed in is less than 16^limit, then the result will be padded.------ >>> toEnglish16a 6 4369--- 12C40F---++{- |+Represent a number in English16a format. This uses the Locator16 symbol+set, and additionally specifies that no symbol can be repeated. The /a/ in+Locator16a represents that this transformation is done on the cheap; when+converting if we end up with \'9\' \'9\' we simply pick the subsequent digit+in the enum, in this case getting you \'9\' \'K\'.++Note that the transformation is /not/ reversible. A number like @4369@+(which is @0x1111@, incidentally) encodes as @12C4@. So do @4370@, @4371@,+and @4372@. The point is not uniqueness, but readibility in adverse+conditions. So while you can count locators, they don't map continuously to+base10 integers.++The first argument is the number of digits you'd like in the locator; if the+number passed in is less than 16^limit, then the result will be padded.++>>> toEnglish16a 6 4369+12C40F+-} toEnglish16a :: Int -> Int -> String toEnglish16a limit n- | limit > 16 = error "Can only request a maximum of 16 English16a characters, not " ++ (show limit)- | otherwise =- let- n' = abs n- ls = convert n' (replicate limit minBound) :: [English16]- (_,us) = mapAccumL uniq Set.empty ls- in- map locatorToDigit (take limit us)+ | limit > 16 = error "Can only request a maximum of 16 English16a characters, not " ++ (show limit)+ | otherwise =+ let n' = abs n+ ls = convert n' (replicate limit minBound) :: [English16]+ (_, us) = mapAccumL uniq Set.empty ls+ in map locatorToDigit (take limit us) where convert :: Locator α => Int -> [α] -> [α] convert 0 xs = xs convert i xs =- let- (d,r) = divMod i 16- x = toEnum r- in- convert d (x:xs)+ let (d, r) = divMod i 16+ x = toEnum r+ in convert d (x : xs) uniq :: Locator α => Set α -> α -> (Set α, α) uniq s x =@@ -218,33 +224,32 @@ else succ x --+ -- | Given a number encoded in Locator16, convert it back to an integer.--- fromEnglish16 :: [Char] -> Int fromEnglish16 ss = foldl (multiply Yankee) 0 ss ----- | Take an arbitrary sequence of bytes, hash it with SHA1, then format as a--- short @digits@-long Locator16 string.------ >>> hashStringToLocator16a 6 "Hello World"--- M48HR0---++{- |+Take an arbitrary sequence of bytes, hash it with SHA1, then format as a+short @digits@-long Locator16 string.++>>> hashStringToLocator16a 6 "Hello World"+M48HR0+-} hashStringToEnglish16a :: Int -> ByteString -> ByteString hashStringToEnglish16a limit s' =- let- s = S.unpack s'- n = digest s -- SHA1 hash- r = mod n upperBound -- trim to specified number of base 16 chars- x = toLocator16a limit r -- express in locator16- b' = S.pack x- in- b'+ let s = S.unpack s'+ n = digest s -- SHA1 hash+ r = mod n upperBound -- trim to specified number of base 16 chars+ x = toLocator16a limit r -- express in locator16+ b' = S.pack x+ in b' where upperBound = 16 ^ limit - toLocator16 :: Int -> String toLocator16 = toEnglish16 {-# DEPRECATED toLocator16 "Use toEnglish16 instead" #-}@@ -256,7 +261,6 @@ fromLocator16 :: [Char] -> Int fromLocator16 = fromEnglish16 {-# DEPRECATED fromLocator16 "Use fromEnglish16 instead" #-}- hashStringToLocator16a :: Int -> ByteString -> ByteString hashStringToLocator16a = hashStringToEnglish16a
lib/Data/Locator/Hashes.hs view
@@ -1,26 +1,12 @@------ Human exchangable identifiers and locators------ Copyright © 2011-2017 Operational Dynamics Consulting, Pty Ltd------ The code in this file, and the program it is a part of, is--- made available to you by its authors as open source software:--- you can redistribute it and/or modify it under the terms of--- the BSD licence.------ This code originally licenced GPLv2. Relicenced BSD3 on 2 Jan 2014.---- {-# LANGUAGE OverloadedStrings #-} module Data.Locator.Hashes ( toBase62, fromBase62, padWithZeros,- hashStringToBase62+ hashStringToBase62, ) where - import Prelude hiding (toInteger) import Crypto.Hash as Crypto@@ -47,13 +33,14 @@ showIntAtBase 62 represent x "" ----- | Utility function to prepend \'0\' characters to a string representing a--- number. This allows you to ensure a fixed width for numbers that are less--- than the desired width in size. This comes up frequently when representing--- numbers in other bases greater than 10 as they are inevitably presented as--- text, and not having them evenly justified can (at best) be ugly and (at--- worst) actually lead to parsing and conversion bugs.---++{- | Utility function to prepend \'0\' characters to a string representing a+ number. This allows you to ensure a fixed width for numbers that are less+ than the desired width in size. This comes up frequently when representing+ numbers in other bases greater than 10 as they are inevitably presented as+ text, and not having them evenly justified can (at best) be ugly and (at+ worst) actually lead to parsing and conversion bugs.+-} padWithZeros :: Int -> String -> String padWithZeros digits str = pad ++ str@@ -61,7 +48,6 @@ pad = take len (replicate digits '0') len = digits - length str - value :: Char -> Int value c | isDigit c = ord c - 48@@ -77,43 +63,40 @@ fromBase62 ss = foldl multiply 0 ss - concatToInteger :: [Word8] -> Integer concatToInteger bytes = foldl fn 0 bytes where fn acc b = (acc * 256) + (fromIntegral b) - digest :: String -> Integer digest ws = i where- i = concatToInteger h- h = B.unpack h'+ i = concatToInteger h+ h = B.unpack h' h' = Crypto.hash x' :: Crypto.Digest Crypto.SHA1 x' = S.pack ws - ----- | Take an arbitrary string, hash it, then pad it with zeros up to be a--- @digits@-long string in base 62.------ You may be interested to know that the 160-bit SHA1 hash used here can be--- expressed without loss as 27 digits of base 62, for example:------ >>> hashStringToBase62 27 "Hello World"--- 1T8Sj4C5jVU6iQXCwCwJEPSWX6u---++{- | Take an arbitrary string, hash it, then pad it with zeros up to be a+ @digits@-long string in base 62.++ You may be interested to know that the 160-bit SHA1 hash used here can be+ expressed without loss as 27 digits of base 62, for example:++ >>> hashStringToBase62 27 "Hello World"+ 1T8Sj4C5jVU6iQXCwCwJEPSWX6u+-} hashStringToBase62 :: Int -> ByteString -> ByteString hashStringToBase62 digits s' = r' where s = S.unpack s'- n = digest s -- SHA1 hash+ n = digest s -- SHA1 hash limit = 62 ^ digits- x = mod n limit -- trim to specified number base62 chars+ x = mod n limit -- trim to specified number base62 chars str = toBase62 x- r = padWithZeros digits str -- convert to String+ r = padWithZeros digits str -- convert to String r' = S.pack r-
lib/Data/Locator/Latin25.hs view
@@ -1,26 +1,13 @@------ Human exchangable identifiers and locators------ Copyright © 2011-2018 Operational Dynamics Consulting, Pty Ltd------ The code in this file, and the program it is a part of, is--- made available to you by its authors as open source software:--- you can redistribute it and/or modify it under the terms of--- the BSD licence.------ This code originally licenced GPLv2. Relicenced BSD3 on 2 Jan 2014.-----{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-} -module Data.Locator.Latin25- ( Latin25(..)- , toLatin25- , fromLatin25- , hashStringToLatin25- ) where+module Data.Locator.Latin25 (+ Latin25 (..),+ toLatin25,+ fromLatin25,+ hashStringToLatin25,+) where import Prelude hiding (toInteger) @@ -31,12 +18,13 @@ import Data.Locator.Common import Data.Locator.Hashes (padWithZeros) ------ | A symbol set with twenty-five visually distinct characters.------ These are not protected against similar pronounciations; if you need to--- read your identifiers /aloud/ use 'English16' instead.---+{- |+A symbol set with twenty-five visually distinct characters.++These are not protected against similar pronounciations; if you need to+read your identifiers /aloud/ use 'English16' instead.+-}+ {- -- | Two -- Obvious conflict with Z@@ -44,7 +32,7 @@ -- | Six -- Too close to G -- | Bravo -- Too close to 8 -- | Delta -- Shape of D too close to O- -- | Foxtrot -- A bit close to E, and since we've included S, skip+ -- | Foxtrot -- Excluded because too close to E -- | India -- Too close to 1 and J -- | Oscar -- Obvious conflict with 0 -- | Quebec -- The tail on Q is too easy to miss, thereby colliding with O/0@@ -53,61 +41,86 @@ -} data Latin25- = Zero' -- ^ @\'0\'@ /0th/- | One' -- ^ @\'1\'@ /1st/- | Three' -- ^ @\'3\'@ /2nd/- | Four' -- ^ @\'4\'@ /3rd/- | Seven' -- ^ @\'7\'@ /4th/- | Eight' -- ^ @\'8\'@ /5th/- | Nine' -- ^ @\'9\'@ /6th/- | Alpha' -- ^ @\'A\'@ /7th/- | Charlie' -- ^ @\'C\'@ /8th/- | Echo' -- ^ @\'E\'@ /9th/- | Golf' -- ^ @\'G\'@ /10th/- | Hotel' -- ^ @\'H\'@ /11th/- | Juliet' -- ^ @\'J\'@ /12th/- | Kilo' -- ^ @\'K\'@ /13th/- | Lima' -- ^ @\'L\'@ /14th/- | Mike' -- ^ @\'M\'@ /15th/- | November' -- ^ @\'N\'@ /16th/- | Papa' -- ^ @\'P\'@ /17th/- | Sierra' -- ^ @\'S\'@ /18th/- | Tango' -- ^ @\'T\'@ /19th/- | Victor' -- ^ @\'V\'@ /20th/- | Whiskey' -- ^ @\'W\'@ /21st/- | XRay' -- ^ @\'X\'@ /22nd/- | Yankee' -- ^ @\'Y\'@ /23rd/- | Zulu' -- ^ @\'Z\'@ /24th/+ = -- | @\'0\'@ /0th/+ Zero'+ | -- | @\'1\'@ /1st/+ One'+ | -- | @\'3\'@ /2nd/+ Three'+ | -- | @\'4\'@ /3rd/+ Four'+ | -- | @\'7\'@ /4th/+ Seven'+ | -- | @\'8\'@ /5th/+ Eight'+ | -- | @\'9\'@ /6th/+ Nine'+ | -- | @\'A\'@ /7th/+ Alpha'+ | -- | @\'C\'@ /8th/+ Charlie'+ | -- | @\'E\'@ /9th/+ Echo'+ | -- | @\'G\'@ /10th/+ Golf'+ | -- | @\'H\'@ /11th/+ Hotel'+ | -- | @\'J\'@ /12th/+ Juliet'+ | -- | @\'K\'@ /13th/+ Kilo'+ | -- | @\'L\'@ /14th/+ Lima'+ | -- | @\'M\'@ /15th/+ Mike'+ | -- | @\'N\'@ /16th/+ November'+ | -- | @\'P\'@ /17th/+ Papa'+ | -- | @\'S\'@ /18th/+ Sierra'+ | -- | @\'T\'@ /19th/+ Tango'+ | -- | @\'V\'@ /20th/+ Victor'+ | -- | @\'W\'@ /21st/+ Whiskey'+ | -- | @\'X\'@ /22nd/+ XRay'+ | -- | @\'Y\'@ /23rd/+ Yankee'+ | -- | @\'Z\'@ /24th/+ Zulu' deriving (Eq, Ord, Enum, Bounded) instance Locator Latin25 where locatorToDigit x = case x of- Zero' -> '0'- One' -> '1'- Three' -> '3'- Four' -> '4'- Seven' -> '7'- Eight' -> '8'- Nine' -> '9'- Alpha' -> 'A'+ Zero' -> '0'+ One' -> '1'+ Three' -> '3'+ Four' -> '4'+ Seven' -> '7'+ Eight' -> '8'+ Nine' -> '9'+ Alpha' -> 'A' Charlie' -> 'C'- Echo' -> 'E'- Golf' -> 'G'- Hotel' -> 'H'+ Echo' -> 'E'+ Golf' -> 'G'+ Hotel' -> 'H' Juliet' -> 'J'- Kilo' -> 'K'- Lima' -> 'L'- Mike' -> 'M'+ Kilo' -> 'K'+ Lima' -> 'L'+ Mike' -> 'M' November' -> 'N'- Papa' -> 'P'+ Papa' -> 'P' Sierra' -> 'S'- Tango' -> 'T'+ Tango' -> 'T' Victor' -> 'V'- Whiskey'-> 'W'- XRay' -> 'X'+ Whiskey' -> 'W'+ XRay' -> 'X' Yankee' -> 'Y'- Zulu' -> 'Z'+ Zulu' -> 'Z' digitToLocator :: Char -> Latin25 digitToLocator c =@@ -137,8 +150,7 @@ 'X' -> XRay' 'Y' -> Yankee' 'Z' -> Zulu'- _ -> error "Illegal digit"-+ _ -> error "Illegal digit" instance Show Latin25 where show x = [c]@@ -146,41 +158,43 @@ c = locatorToDigit x ----- | Given a number, convert it to a string in the Latin25 base 25 symbol--- alphabet. This is useful for primary keys and object identifiers that you--- need to scan for in log output, for example.---++{- |+Given a number, convert it to a string in the Latin25 base 25 symbol+alphabet. This is useful for primary keys and object identifiers that you+need to scan for in log output, for example.+-} toLatin25 :: Int -> String toLatin25 x = showIntAtBase 25 (represent Zulu') x "" --+ -- | Given a number encoded in Locator16, convert it back to an integer.--- fromLatin25 :: String -> Int fromLatin25 ss = foldl (multiply Zulu') 0 ss ----- | Take an arbitrary sequence of bytes, hash it with SHA1, then format as a--- short @limit@-long Latin25 string.------ >>> hashStringToLatin25 5 "You'll get used to it. Or, you'll have a psychotic episode"--- XSAV1------ 17 characters is the widest hash you can request.---++{- |+Take an arbitrary sequence of bytes, hash it with SHA1, then format as a+short @limit@-long Latin25 string.++>>> hashStringToLatin25 5 "You'll get used to it. Or, you'll have a psychotic episode"+SG8XP++17 characters is the widest hash you can request.+-} hashStringToLatin25 :: Int -> ByteString -> ByteString hashStringToLatin25 limit s'- | limit > 17 = error "Can only request a maximum width of 17, sorry"- | otherwise =- let- s = S.unpack s'- n = digest s -- SHA1 hash- r = mod n upperBound -- trim to specified number of base 25 chars- x = toLatin25 r -- express in Latin25- b' = S.pack (padWithZeros limit x)- in- b'+ | limit > 17 = error "Can only request a maximum width of 17, sorry"+ | otherwise =+ let s = S.unpack s'+ n = digest s -- SHA1 hash+ r = mod n upperBound -- trim to specified number of base 25 chars+ x = toLatin25 r -- express in Latin25+ b' = S.pack (padWithZeros limit x)+ in b' where upperBound = 25 ^ limit
locators.cabal view
@@ -1,6 +1,6 @@ cabal-version: 1.24 name: locators-version: 0.3.0.3+version: 0.3.0.5 synopsis: Human exchangable identifiers and locators license: MIT license-file: LICENSE@@ -13,9 +13,9 @@ author: Andrew Cowie <istathar@gmail.com> maintainer: Andrew Cowie <istathar@gmail.com>-copyright: © 2013-2020 Athae Eredh Siniath and Others+copyright: © 2013-2024 Athae Eredh Siniath and Others category: Other-tested-with: GHC == 8.8.3+tested-with: GHC == 9.6.5 stability: experimental build-type: Simple@@ -27,7 +27,7 @@ memory, bytestring, containers,- cryptonite+ crypton hs-source-dirs: lib include-dirs: .@@ -38,7 +38,6 @@ Data.Locator.English16 Data.Locator.Latin25 - ghc-options: -Wall -Wwarn -fwarn-tabs@@ -60,7 +59,7 @@ QuickCheck, bytestring, containers,- cryptonite,+ crypton, locators hs-source-dirs: tests@@ -80,7 +79,7 @@ source-repository head type: git- location: git@github.com:aesiniath/locators.git+ location: git@github.com:aesiniath/locators-haskell.git -- vim: set tabstop=21 expandtab:
tests/TestSuite.hs view
@@ -1,15 +1,5 @@------ Human exchangable identifiers and locators------ Copyright © 2013-2018 Operational Dynamics Consulting, Pty Ltd------ The code in this file, and the program it is a part of, is--- made available to you by its authors as open source software:--- you can redistribute it and/or modify it under the terms of--- the BSD licence.---- {-# LANGUAGE OverloadedStrings #-}+ {-# OPTIONS -fno-warn-unused-imports #-} {-# OPTIONS -fno-warn-orphans #-} {-# OPTIONS -fno-warn-type-defaults #-}@@ -18,9 +8,9 @@ module TestSuite where import Control.Exception (evaluate)+import Test.HUnit import Test.Hspec import Test.Hspec.QuickCheck-import Test.HUnit import Test.QuickCheck (elements, property) import Test.QuickCheck.Arbitrary (Arbitrary, arbitrary) @@ -58,18 +48,14 @@ describe "Hashes" $ do testPaddingRefactored - testRoundTripEnglish16 = prop "safe conversion to/from English16" prop_English16 prop_English16 :: Int -> Bool prop_English16 i =- let- n = abs i- decoded = fromEnglish16 (toEnglish16 n)- in- n == decoded-+ let n = abs i+ decoded = fromEnglish16 (toEnglish16 n)+ in n == decoded -- -- Have to do these manually, since Locator16a is not round-trip safe.@@ -90,15 +76,15 @@ it "correctly pads strings" $ do padWithZeros 5 "1" `shouldBe` "00001" padWithZeros 5 "123456" `shouldBe` "123456"- (padWithZeros 11 . toBase62 $ 2^64) `shouldBe` "LygHa16AHYG"- (hashStringToBase62 11 . S.pack . show $ 2^64) `shouldBe` "k8SQgkJtxLo"+ (padWithZeros 11 . toBase62 $ 2 ^ 64) `shouldBe` "LygHa16AHYG"+ (hashStringToBase62 11 . S.pack . show $ 2 ^ 64) `shouldBe` "k8SQgkJtxLo" testNegativeNumbers = it "doesn't explode if fed a negative number" $ do toEnglish16a 1 (-1) `shouldBe` "1" testKnownLatin25 =- it "base 25 is correct" $ do+ it "base 26 is correct" $ do toLatin25 0 `shouldBe` "0" toLatin25 1 `shouldBe` "1" toLatin25 24 `shouldBe` "Z"@@ -109,12 +95,10 @@ prop_Latin25 :: Int -> Bool prop_Latin25 i =- let- n = abs i- encoded = toLatin25 n- decoded = fromLatin25 encoded- in- n == decoded+ let n = abs i+ encoded = toLatin25 n+ decoded = fromLatin25 encoded+ in n == decoded testHashLatin25 = it "hashToLatin25 generates an appropriate hash" $ do