{-# LANGUAGE RankNTypes #-}

module RON.UUID.Experimental (variety, value, variant, version, origin) where

import           RON.Prelude

import           Data.Bits (shiftL, shiftR, (.&.), (.|.))

import           RON.UUID (UUID (..))
import           RON.Util.Word (Word2, Word4, Word60, leastSignificant2,
                                leastSignificant4, leastSignificant60, safeCast)

-- data UuidFields = UuidFields
--     { uuidVariety :: !Word4
--     , uuidValue   :: !Word60
--     , uuidVariant :: !Word2
--     , uuidVersion :: !Word2
--     , uuidOrigin  :: !Word60
--     }

variety :: Lens' UUID Word4
variety :: (Word4 -> f Word4) -> UUID -> f UUID
variety =
  (UUID -> Word4)
-> (UUID -> Word4 -> UUID) -> Lens UUID UUID Word4 Word4
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens
    (\(UUID Word64
x Word64
_) -> Word64 -> Word4
forall integral. Integral integral => integral -> Word4
leastSignificant4 (Word64 -> Word4) -> Word64 -> Word4
forall a b. (a -> b) -> a -> b
$ Word64
x Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
60)
    (\(UUID Word64
x Word64
y) Word4
v ->
      Word64 -> Word64 -> UUID
UUID (Word64
x Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0x0FFFFFFFFFFFFFFF Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word4 -> Word64
forall v w. SafeCast v w => v -> w
safeCast Word4
v Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
60)) Word64
y)

value :: Lens' UUID Word60
value :: (Word60 -> f Word60) -> UUID -> f UUID
value =
  (UUID -> Word60)
-> (UUID -> Word60 -> UUID) -> Lens UUID UUID Word60 Word60
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens
    (\(UUID Word64
x Word64
_) -> Word64 -> Word60
forall integral. Integral integral => integral -> Word60
leastSignificant60 Word64
x)
    (\(UUID Word64
x Word64
y) Word60
v -> Word64 -> Word64 -> UUID
UUID (Word64
x Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xF000000000000000 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word60 -> Word64
forall v w. SafeCast v w => v -> w
safeCast Word60
v) Word64
y)

variant :: Lens' UUID Word2
variant :: (Word2 -> f Word2) -> UUID -> f UUID
variant =
  (UUID -> Word2)
-> (UUID -> Word2 -> UUID) -> Lens UUID UUID Word2 Word2
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens
    (\(UUID Word64
_ Word64
y) -> Word64 -> Word2
forall integral. Integral integral => integral -> Word2
leastSignificant2 (Word64 -> Word2) -> Word64 -> Word2
forall a b. (a -> b) -> a -> b
$ Word64
y Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
62)
    (\(UUID Word64
x Word64
y) Word2
v ->
      Word64 -> Word64 -> UUID
UUID Word64
x (Word64
y Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0x3FFFFFFFFFFFFFFF Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word2 -> Word64
forall v w. SafeCast v w => v -> w
safeCast Word2
v Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
62)))

version :: Lens' UUID Word2
version :: (Word2 -> f Word2) -> UUID -> f UUID
version =
  (UUID -> Word2)
-> (UUID -> Word2 -> UUID) -> Lens UUID UUID Word2 Word2
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens
    (\(UUID Word64
_ Word64
y) -> Word64 -> Word2
forall integral. Integral integral => integral -> Word2
leastSignificant2 (Word64 -> Word2) -> Word64 -> Word2
forall a b. (a -> b) -> a -> b
$ Word64
y Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
60)
    (\(UUID Word64
x Word64
y) Word2
v ->
      Word64 -> Word64 -> UUID
UUID Word64
x (Word64
y Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xCFFFFFFFFFFFFFFF Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. (Word2 -> Word64
forall v w. SafeCast v w => v -> w
safeCast Word2
v Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftL` Int
60)))

origin :: Lens' UUID Word60
origin :: (Word60 -> f Word60) -> UUID -> f UUID
origin =
  (UUID -> Word60)
-> (UUID -> Word60 -> UUID) -> Lens UUID UUID Word60 Word60
forall s a b t. (s -> a) -> (s -> b -> t) -> Lens s t a b
lens
    (\(UUID Word64
_ Word64
y) -> Word64 -> Word60
forall integral. Integral integral => integral -> Word60
leastSignificant60 Word64
y)
    (\(UUID Word64
x Word64
y) Word60
v -> Word64 -> Word64 -> UUID
UUID Word64
x (Word64
y Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xF000000000000000 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.|. Word60 -> Word64
forall v w. SafeCast v w => v -> w
safeCast Word60
v))

type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t

type Lens' s a = Lens s s a a

lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
lens s -> a
sa s -> b -> t
sbt a -> f b
afb s
s = s -> b -> t
sbt s
s (b -> t) -> f b -> f t
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> f b
afb (s -> a
sa s
s)
{-# INLINE lens #-}