summaryrefslogtreecommitdiffstats
path: root/app/Data/Iban.hs
diff options
context:
space:
mode:
authorRutger Broekhoff2025-08-25 19:48:19 +0200
committerRutger Broekhoff2025-08-25 19:48:19 +0200
commit95d50b25c990e8c945ce2507b16ff3c8b039d286 (patch)
treec1ff4c7f9601c6980eed1a7235ba336c5c6f6106 /app/Data/Iban.hs
parent29b26dcbc1404925bbf12cddd66f7fcd3c57cfe7 (diff)
downloadrdcapsis-95d50b25c990e8c945ce2507b16ff3c8b039d286.tar.gz
rdcapsis-95d50b25c990e8c945ce2507b16ff3c8b039d286.zip
OCaml
Diffstat (limited to 'app/Data/Iban.hs')
-rw-r--r--app/Data/Iban.hs48
1 files changed, 0 insertions, 48 deletions
diff --git a/app/Data/Iban.hs b/app/Data/Iban.hs
deleted file mode 100644
index d9566b9..0000000
--- a/app/Data/Iban.hs
+++ /dev/null
@@ -1,48 +0,0 @@
1module Data.Iban (Iban, mkIban, toText) where
2
3import Control.Applicative ((<|>))
4import Data.Attoparsec.Text as AP
5import Data.Char
6 ( digitToInt,
7 isAscii,
8 isDigit,
9 ord,
10 toUpper,
11 )
12import Data.Text qualified as T
13
14newtype Iban = Iban T.Text deriving (Show, Eq)
15
16mkIban :: T.Text -> Either String Iban
17mkIban t = validateIban t >> return (Iban t)
18
19validateIban :: T.Text -> Either String ()
20validateIban = AP.parseOnly $ do
21 countryCode <- AP.count 2 AP.letter
22 checkDigits <- AP.count 2 AP.digit
23 chars <- AP.many1 (AP.letter <|> AP.digit)
24 endOfInput
25 if length chars < 30
26 then
27 if valid countryCode checkDigits chars
28 then return ()
29 else fail $ "IBAN checksum does not match (" ++ countryCode ++ checkDigits ++ chars ++ ")"
30 else fail "IBAN has more than 34 characters"
31 where
32 letterToInt c = ord (toUpper c) - ord 'A' + 10
33 charsToInteger =
34 foldl'
35 ( \acc -> \case
36 d
37 | isDigit d -> acc * 10 + toInteger (digitToInt d)
38 | isAscii d -> acc * 100 + toInteger (letterToInt d)
39 | otherwise -> error "unreachable"
40 )
41 0
42 ibanToInteger countryCode checkDigits chars =
43 charsToInteger chars * 1000000 + charsToInteger countryCode * 100 + charsToInteger checkDigits
44 valid countryCode checkDigits chars =
45 ibanToInteger countryCode checkDigits chars `mod` 97 == 1
46
47toText :: Iban -> T.Text
48toText (Iban t) = t