{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE UnboxedTuples #-} module Asn ( Asn(..) , encode , decode ) where import Data.Text (Text) import Data.Primitive.Types (Prim) import Data.Word (Word32) import Data.Hashable (Hashable) import Foreign.Storable (Storable) import qualified Data.Aeson as AE import qualified Data.Scientific as SCI import qualified Data.Text as T import qualified Data.Text.Read as TR newtype Asn = Asn { getAsn :: Word32 } deriving (Show,Read,Eq,Ord,Prim,Hashable,Storable) instance AE.ToJSON Asn where toJSON = AE.String . encode instance AE.FromJSON Asn where parseJSON v = case v of AE.Object _ -> fail "expected ASN (String or Number), encountered Object" AE.Array _ -> fail "expected ASN (String or Number), encountered Array" AE.String t -> case decode t of Nothing -> fail "ASN string was invalid" Just w -> return w AE.Number n -> case SCI.toBoundedInteger n of Nothing -> fail "numeric ASN was invalid" Just w -> return (Asn w) AE.Bool _ -> fail "expected ASN (String or Number), encountered Bool" AE.Null -> fail "expected ASN (String or Number), encountered Null" encode :: Asn -> Text encode (Asn w) = T.pack (show w) decode :: Text -> Maybe Asn decode t | T.take 2 t == "AS" = decodeAsnDigits (T.drop 2 t) | otherwise = decodeAsnDigits t decodeAsnDigits :: Text -> Maybe Asn decodeAsnDigits t = case TR.decimal t of Left _ -> Nothing Right (w,extra) -> if T.null extra then Just (Asn w) else Nothing