module Periodic.IOList
  ( IOList
  , newIOList
  , insert
  , append
  , elem
  , elemSTM
  , delete
  , deleteSTM
  , toList
  , toListSTM
  , clearSTM
  , fromList
  ) where

import qualified Data.List as L
import           Prelude   hiding (elem)
import           UnliftIO  (MonadIO, STM, TVar, atomically, modifyTVar',
                            newTVarIO, readTVar, readTVarIO, writeTVar)


newtype IOList a = IOList (TVar [a])

newIOList :: MonadIO m => m (IOList a)
newIOList :: m (IOList a)
newIOList = TVar [a] -> IOList a
forall a. TVar [a] -> IOList a
IOList (TVar [a] -> IOList a) -> m (TVar [a]) -> m (IOList a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [a] -> m (TVar [a])
forall (m :: * -> *) a. MonadIO m => a -> m (TVar a)
newTVarIO []

fromList :: MonadIO m => [a] -> m (IOList a)
fromList :: [a] -> m (IOList a)
fromList l :: [a]
l = TVar [a] -> IOList a
forall a. TVar [a] -> IOList a
IOList (TVar [a] -> IOList a) -> m (TVar [a]) -> m (IOList a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [a] -> m (TVar [a])
forall (m :: * -> *) a. MonadIO m => a -> m (TVar a)
newTVarIO [a]
l

insert :: MonadIO m => IOList a -> a -> m ()
insert :: IOList a -> a -> m ()
insert (IOList h :: TVar [a]
h) a :: a
a = STM () -> m ()
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM () -> m ())
-> (([a] -> [a]) -> STM ()) -> ([a] -> [a]) -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TVar [a] -> ([a] -> [a]) -> STM ()
forall a. TVar a -> (a -> a) -> STM ()
modifyTVar' TVar [a]
h (([a] -> [a]) -> m ()) -> ([a] -> [a]) -> m ()
forall a b. (a -> b) -> a -> b
$ \v :: [a]
v -> a
aa -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
v

append :: MonadIO m => IOList a -> a -> m ()
append :: IOList a -> a -> m ()
append (IOList h :: TVar [a]
h) a :: a
a = STM () -> m ()
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM () -> m ())
-> (([a] -> [a]) -> STM ()) -> ([a] -> [a]) -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TVar [a] -> ([a] -> [a]) -> STM ()
forall a. TVar a -> (a -> a) -> STM ()
modifyTVar' TVar [a]
h (([a] -> [a]) -> m ()) -> ([a] -> [a]) -> m ()
forall a b. (a -> b) -> a -> b
$ \v :: [a]
v -> [a]
v [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a
a]

elem :: (Eq a, MonadIO m) => IOList a -> a -> m Bool
elem :: IOList a -> a -> m Bool
elem (IOList h :: TVar [a]
h) a :: a
a = a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
L.elem a
a ([a] -> Bool) -> m [a] -> m Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TVar [a] -> m [a]
forall (m :: * -> *) a. MonadIO m => TVar a -> m a
readTVarIO TVar [a]
h

elemSTM :: (Eq a) => IOList a -> a -> STM Bool
elemSTM :: IOList a -> a -> STM Bool
elemSTM (IOList h :: TVar [a]
h) a :: a
a = a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
L.elem a
a ([a] -> Bool) -> STM [a] -> STM Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TVar [a] -> STM [a]
forall a. TVar a -> STM a
readTVar TVar [a]
h

delete :: (Eq a, MonadIO m) => IOList a -> a -> m ()
delete :: IOList a -> a -> m ()
delete (IOList h :: TVar [a]
h) a :: a
a = STM () -> m ()
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM () -> m ())
-> (([a] -> [a]) -> STM ()) -> ([a] -> [a]) -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TVar [a] -> ([a] -> [a]) -> STM ()
forall a. TVar a -> (a -> a) -> STM ()
modifyTVar' TVar [a]
h (([a] -> [a]) -> m ()) -> ([a] -> [a]) -> m ()
forall a b. (a -> b) -> a -> b
$ a -> [a] -> [a]
forall a. Eq a => a -> [a] -> [a]
L.delete a
a

deleteSTM :: (Eq a) => IOList a -> a -> STM ()
deleteSTM :: IOList a -> a -> STM ()
deleteSTM (IOList h :: TVar [a]
h) a :: a
a = TVar [a] -> ([a] -> [a]) -> STM ()
forall a. TVar a -> (a -> a) -> STM ()
modifyTVar' TVar [a]
h (([a] -> [a]) -> STM ()) -> ([a] -> [a]) -> STM ()
forall a b. (a -> b) -> a -> b
$ a -> [a] -> [a]
forall a. Eq a => a -> [a] -> [a]
L.delete a
a

toList :: MonadIO m => IOList a -> m [a]
toList :: IOList a -> m [a]
toList (IOList h :: TVar [a]
h) = TVar [a] -> m [a]
forall (m :: * -> *) a. MonadIO m => TVar a -> m a
readTVarIO TVar [a]
h

toListSTM :: IOList a -> STM [a]
toListSTM :: IOList a -> STM [a]
toListSTM (IOList h :: TVar [a]
h) = TVar [a] -> STM [a]
forall a. TVar a -> STM a
readTVar TVar [a]
h

clearSTM :: IOList a -> STM ()
clearSTM :: IOList a -> STM ()
clearSTM (IOList h :: TVar [a]
h) = TVar [a] -> [a] -> STM ()
forall a. TVar a -> a -> STM ()
writeTVar TVar [a]
h []