{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE RecordWildCards      #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans      #-}
{-|
 This module provides a generalized conversion function between a
 'Flake' and all members of the typeclass 'Integral'.  It is specialized
 for the 'Integer', 'Word32', and 'Word64' types. It is marked as
 incoherent due to the constraint being no smaller than the instance type,
 so it is undecidable.
-}

module Data.Snowchecked.Encoding.Integral
	( module Data.Snowchecked.Encoding.Class
	) where

import           Data.Snowchecked.Encoding.Class
import           Data.Snowchecked.Internal.Import

instance {-# INCOHERENT #-} (Integral a) => IsFlake a where
	fromFlake :: Flake -> a
fromFlake Flake{Word256
SnowcheckedConfig
flakeConfig :: Flake -> SnowcheckedConfig
flakeNodeId :: Flake -> Word256
flakeCount :: Flake -> Word256
flakeTime :: Flake -> Word256
flakeConfig :: SnowcheckedConfig
flakeNodeId :: Word256
flakeCount :: Word256
flakeTime :: Word256
..} = forall a. Num a => Integer -> a
fromInteger
			forall a b. (a -> b) -> a -> b
$   forall a bitCount.
(Num a, Bits a, Integral bitCount) =>
a -> bitCount -> a
cutBits Integer
checkInteger Integer
checkBitsInteger
			forall a. Bits a => a -> a -> a
.|. forall a cutBitCount shiftBitCount.
(Num a, Bits a, Integral cutBitCount, Integral shiftBitCount) =>
a -> cutBitCount -> shiftBitCount -> a
cutShiftBits Integer
nodeIdInteger Integer
nodeBitsInteger Integer
checkBitsInteger
			forall a. Bits a => a -> a -> a
.|. forall a cutBitCount shiftBitCount.
(Num a, Bits a, Integral cutBitCount, Integral shiftBitCount) =>
a -> cutBitCount -> shiftBitCount -> a
cutShiftBits Integer
countInteger Integer
countBitsInteger (Integer
checkBitsInteger forall a. Num a => a -> a -> a
+ Integer
nodeBitsInteger)
			forall a. Bits a => a -> a -> a
.|. forall a cutBitCount shiftBitCount.
(Num a, Bits a, Integral cutBitCount, Integral shiftBitCount) =>
a -> cutBitCount -> shiftBitCount -> a
cutShiftBits Integer
timeInteger Integer
timeBitsInteger (Integer
checkBitsInteger forall a. Num a => a -> a -> a
+ Integer
nodeBitsInteger forall a. Num a => a -> a -> a
+ Integer
countBitsInteger)
		where
			SnowcheckedConfig{Word8
confCheckBits :: SnowcheckedConfig -> Word8
confNodeBits :: SnowcheckedConfig -> Word8
confCountBits :: SnowcheckedConfig -> Word8
confTimeBits :: SnowcheckedConfig -> Word8
confCheckBits :: Word8
confNodeBits :: Word8
confCountBits :: Word8
confTimeBits :: Word8
..} = SnowcheckedConfig
flakeConfig
			checkBitsInteger :: Integer
checkBitsInteger = forall a. Integral a => a -> Integer
toInteger Word8
confCheckBits
			nodeBitsInteger :: Integer
nodeBitsInteger = forall a. Integral a => a -> Integer
toInteger Word8
confNodeBits
			timeBitsInteger :: Integer
timeBitsInteger = forall a. Integral a => a -> Integer
toInteger Word8
confTimeBits
			countBitsInteger :: Integer
countBitsInteger = forall a. Integral a => a -> Integer
toInteger Word8
confCountBits
			nodeIdInteger :: Integer
nodeIdInteger = forall a. Integral a => a -> Integer
toInteger Word256
flakeNodeId
			timeInteger :: Integer
timeInteger = forall a. Integral a => a -> Integer
toInteger Word256
flakeTime
			countInteger :: Integer
countInteger = forall a. Integral a => a -> Integer
toInteger Word256
flakeCount
			checkInteger :: Integer
checkInteger = Integer
nodeIdInteger forall a. Num a => a -> a -> a
+ Integer
timeInteger forall a. Num a => a -> a -> a
+ Integer
countInteger
	{-# INLINEABLE fromFlake #-}

	parseFish :: forall (m :: * -> *).
MonadFail m =>
SnowcheckedConfig -> a -> m Flakeish
parseFish SnowcheckedConfig{Word8
confCheckBits :: Word8
confNodeBits :: Word8
confCountBits :: Word8
confTimeBits :: Word8
confCheckBits :: SnowcheckedConfig -> Word8
confNodeBits :: SnowcheckedConfig -> Word8
confCountBits :: SnowcheckedConfig -> Word8
confTimeBits :: SnowcheckedConfig -> Word8
..} a
i = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Flakeish
			{ fishCheck :: Word256
fishCheck = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a bitCount.
(Num a, Bits a, Integral bitCount) =>
a -> bitCount -> a
cutBits Integer
n Integer
checkBitsInteger
			, fishNodeId :: Word256
fishNodeId = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a cutBitCount shiftBitCount.
(Num a, Bits a, Integral cutBitCount, Integral shiftBitCount) =>
a -> shiftBitCount -> cutBitCount -> a
shiftCutBits Integer
n Integer
checkBitsInteger Integer
nodeBitsInteger
			, fishCount :: Word256
fishCount = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a cutBitCount shiftBitCount.
(Num a, Bits a, Integral cutBitCount, Integral shiftBitCount) =>
a -> shiftBitCount -> cutBitCount -> a
shiftCutBits Integer
n (Integer
checkBitsInteger forall a. Num a => a -> a -> a
+ Integer
nodeBitsInteger) Integer
countBitsInteger
			, fishTime :: Word256
fishTime = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall a cutBitCount shiftBitCount.
(Num a, Bits a, Integral cutBitCount, Integral shiftBitCount) =>
a -> shiftBitCount -> cutBitCount -> a
shiftCutBits Integer
n (Integer
checkBitsInteger forall a. Num a => a -> a -> a
+ Integer
nodeBitsInteger forall a. Num a => a -> a -> a
+ Integer
countBitsInteger) Integer
timeBitsInteger
			}
		where
			n :: Integer
n = forall a. Integral a => a -> Integer
toInteger a
i
			checkBitsInteger :: Integer
checkBitsInteger = forall a. Integral a => a -> Integer
toInteger Word8
confCheckBits
			nodeBitsInteger :: Integer
nodeBitsInteger = forall a. Integral a => a -> Integer
toInteger Word8
confNodeBits
			timeBitsInteger :: Integer
timeBitsInteger = forall a. Integral a => a -> Integer
toInteger Word8
confTimeBits
			countBitsInteger :: Integer
countBitsInteger = forall a. Integral a => a -> Integer
toInteger Word8
confCountBits
	{-# INLINE parseFish #-}