-- Copyright (c) 2019  Herbert Valerio Riedel <hvr@gnu.org>
--
--  This file is free software: you may copy, redistribute and/or modify it
--  under the terms of the GNU General Public License as published by the
--  Free Software Foundation, either version 2 of the License, or (at your
--  option) any later version.
--
--  This file is distributed in the hope that it will be useful, but
--  WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
--  General Public License for more details.
--
--  You should have received a copy of the GNU General Public License
--  along with this program (see `LICENSE`).  If not, see
--  <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>.

{-# LANGUAGE DataKinds                  #-}
{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses      #-}

module LDAPv3.Message.Types where

import           Common
import           Data.ASN1         (ASN1)
import           Data.Int.Subtypes

{- | LDAPv3 protocol ASN.1 constant as per <https://tools.ietf.org/html/rfc4511#section-4.1.1 RFC4511 Section 4.1.1>

> maxInt INTEGER ::= 2147483647 -- (2^^31 - 1)

-}
type MaxInt = 2147483647

{- | Message ID (<https://tools.ietf.org/html/rfc4511#section-4.1.1.1 RFC4511 Section 4.1.1.1>)

> MessageID ::= INTEGER (0 ..  maxInt)

-}
newtype MessageID = MessageID (UInt 0 MaxInt Int32)
                  deriving ((forall x. MessageID -> Rep MessageID x)
-> (forall x. Rep MessageID x -> MessageID) -> Generic MessageID
forall x. Rep MessageID x -> MessageID
forall x. MessageID -> Rep MessageID x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep MessageID x -> MessageID
$cfrom :: forall x. MessageID -> Rep MessageID x
Generic,MessageID -> ()
(MessageID -> ()) -> NFData MessageID
forall a. (a -> ()) -> NFData a
rnf :: MessageID -> ()
$crnf :: MessageID -> ()
NFData,Eq MessageID
Eq MessageID =>
(MessageID -> MessageID -> Ordering)
-> (MessageID -> MessageID -> Bool)
-> (MessageID -> MessageID -> Bool)
-> (MessageID -> MessageID -> Bool)
-> (MessageID -> MessageID -> Bool)
-> (MessageID -> MessageID -> MessageID)
-> (MessageID -> MessageID -> MessageID)
-> Ord MessageID
MessageID -> MessageID -> Bool
MessageID -> MessageID -> Ordering
MessageID -> MessageID -> MessageID
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: MessageID -> MessageID -> MessageID
$cmin :: MessageID -> MessageID -> MessageID
max :: MessageID -> MessageID -> MessageID
$cmax :: MessageID -> MessageID -> MessageID
>= :: MessageID -> MessageID -> Bool
$c>= :: MessageID -> MessageID -> Bool
> :: MessageID -> MessageID -> Bool
$c> :: MessageID -> MessageID -> Bool
<= :: MessageID -> MessageID -> Bool
$c<= :: MessageID -> MessageID -> Bool
< :: MessageID -> MessageID -> Bool
$c< :: MessageID -> MessageID -> Bool
compare :: MessageID -> MessageID -> Ordering
$ccompare :: MessageID -> MessageID -> Ordering
$cp1Ord :: Eq MessageID
Ord,MessageID
MessageID -> MessageID -> Bounded MessageID
forall a. a -> a -> Bounded a
maxBound :: MessageID
$cmaxBound :: MessageID
minBound :: MessageID
$cminBound :: MessageID
Bounded,Int -> MessageID -> ShowS
[MessageID] -> ShowS
MessageID -> String
(Int -> MessageID -> ShowS)
-> (MessageID -> String)
-> ([MessageID] -> ShowS)
-> Show MessageID
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [MessageID] -> ShowS
$cshowList :: [MessageID] -> ShowS
show :: MessageID -> String
$cshow :: MessageID -> String
showsPrec :: Int -> MessageID -> ShowS
$cshowsPrec :: Int -> MessageID -> ShowS
Show,MessageID -> MessageID -> Bool
(MessageID -> MessageID -> Bool)
-> (MessageID -> MessageID -> Bool) -> Eq MessageID
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: MessageID -> MessageID -> Bool
$c/= :: MessageID -> MessageID -> Bool
== :: MessageID -> MessageID -> Bool
$c== :: MessageID -> MessageID -> Bool
Eq,ASN1Decode MessageID
Proxy MessageID -> Tag
MessageID -> ASN1Encode Word64
(Proxy MessageID -> Tag)
-> ASN1Decode MessageID
-> (MessageID -> ASN1Encode Word64)
-> ASN1 MessageID
forall t.
(Proxy t -> Tag)
-> ASN1Decode t -> (t -> ASN1Encode Word64) -> ASN1 t
asn1encode :: MessageID -> ASN1Encode Word64
$casn1encode :: MessageID -> ASN1Encode Word64
asn1decode :: ASN1Decode MessageID
$casn1decode :: ASN1Decode MessageID
asn1defTag :: Proxy MessageID -> Tag
$casn1defTag :: Proxy MessageID -> Tag
ASN1)

instance Newtype MessageID (UInt 0 MaxInt Int32)

-- | @since 0.1.0
instance Enum MessageID where
  succ :: MessageID -> MessageID
succ (MessageID i :: UInt 0 MaxInt Int32
i) = UInt 0 MaxInt Int32 -> MessageID
MessageID (UInt 0 MaxInt Int32
iUInt 0 MaxInt Int32 -> UInt 0 MaxInt Int32 -> UInt 0 MaxInt Int32
forall a. Num a => a -> a -> a
+1)
  pred :: MessageID -> MessageID
pred (MessageID i :: UInt 0 MaxInt Int32
i) = UInt 0 MaxInt Int32 -> MessageID
MessageID (UInt 0 MaxInt Int32
iUInt 0 MaxInt Int32 -> UInt 0 MaxInt Int32 -> UInt 0 MaxInt Int32
forall a. Num a => a -> a -> a
-1)

  fromEnum :: MessageID -> Int
fromEnum (MessageID i :: UInt 0 MaxInt Int32
i) = Int32 -> Int
forall a b.
(Integral a, Integral b, IsIntSubType a b ~ 'True) =>
a -> b
intCast (UInt 0 MaxInt Int32 -> Int32
forall (lb :: Nat) (ub :: Nat) t. UInt lb ub t -> t
fromUInt UInt 0 MaxInt Int32
i)

  toEnum :: Int -> MessageID
toEnum i :: Int
i
    | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< 0          = ArithException -> MessageID
forall a e. Exception e => e -> a
throw ArithException
Underflow
    | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 0x7fffffff = ArithException -> MessageID
forall a e. Exception e => e -> a
throw ArithException
Overflow
    | Bool
otherwise      = UInt 0 MaxInt Int32 -> MessageID
MessageID (Int32 -> UInt 0 MaxInt Int32
forall (lb :: Nat) (ub :: Nat) t.
(UIntBounds lb ub t, Num t, Ord t) =>
t -> UInt lb ub t
toUInt' (Int -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i))

  enumFrom :: MessageID -> [MessageID]
enumFrom     x :: MessageID
x   = MessageID -> MessageID -> [MessageID]
forall a. Enum a => a -> a -> [a]
enumFromTo     MessageID
x MessageID
forall a. Bounded a => a
maxBound
  enumFromThen :: MessageID -> MessageID -> [MessageID]
enumFromThen x :: MessageID
x y :: MessageID
y = MessageID -> MessageID -> MessageID -> [MessageID]
forall a. Enum a => a -> a -> a -> [a]
enumFromThenTo MessageID
x MessageID
y MessageID
bound
    where
      bound :: MessageID
bound | MessageID
y MessageID -> MessageID -> Bool
forall a. Ord a => a -> a -> Bool
>= MessageID
x     = MessageID
forall a. Bounded a => a
maxBound
            | Bool
otherwise  = MessageID
forall a. Bounded a => a
minBound