packages feed

Workflow-0.5.8: Data/Persistent/Queue/Queue.inc.hs


data Queue a= Queue {name :: String, imp :: [a], out ::  [a]}  deriving (Typeable)

class  (Monad writerm
       ,Monad readerm)
       => SerialiserString  writerm readerm
       | writerm -> readerm
       , readerm -> writerm
     where
    serialString :: String -> writerm ()
    deserialString :: readerm String

class ( Serializer w r [a]
      , SerialiserString w r
      , RunSerializer w r)
      => QueueConstraints w r a

instance ( Serializer w r [a]
      , SerialiserString w r
      , RunSerializer w r)
      => QueueConstraints w r a

instance (Serializer w r [a]
         , SerialiserString w r)
         => Serializer w r (Queue a) where
  serial (Queue n i o)= serialString n >> serial i >> serial o
  deserial= do
       n <-   deserialString
       i <-   deserial
       o <-   deserial
       return $ Queue n i o




queuePrefix= "Queue#"
lenQPrefix= Prelude.length queuePrefix



instance  QueueConstraints w r a => Serializable (Queue a ) where
  serialize = runSerial . serial
  deserialize = runDeserial  deserial

-- | a queue reference
type RefQueue a= DBRef (Queue a)

unreadSTM :: (Typeable a, QueueConstraints w r a) => RefQueue a -> a -> STM ()
unreadSTM queue x= do
    r <- readQRef queue
    writeDBRef queue $ doit r
    where
    doit (Queue  n  imp out) =   Queue n  imp ( x : out)


-- | check if the queue is empty
isEmpty ::  (Typeable a, QueueConstraints w r a) => RefQueue a -> IO Bool
isEmpty = atomically . isEmptySTM

isEmptySTM :: (Typeable a, QueueConstraints w r a) => RefQueue a -> STM Bool
isEmptySTM queue= do
   r <- readDBRef queue
   return $ case r of
        Nothing  ->  True
        Just (Queue _ [] []) -> True
        _    ->  False



-- | get the reference to new or existing queue trough its name
getQRef ::  (Typeable a, QueueConstraints w r a)  => String -> RefQueue a
getQRef n = getDBRef . key $ Queue n undefined undefined


-- | empty the queue (factually, it is deleted)
flush ::   (Typeable a, QueueConstraints w r a)  => RefQueue a -> IO ()
flush = atomically . flushSTM

-- | version in the STM monad
flushSTM ::  (Typeable a, QueueConstraints w r a)  => RefQueue a -> STM ()
flushSTM tv= delDBRef tv

-- | read  the first element in the queue and delete it (pop)
pop
      ::  (Typeable a, QueueConstraints w r a)  => RefQueue a       -- ^ Queue name
      -> IO a              -- ^ the returned elems
pop tv = atomically $ popSTM tv


readQRef :: (Typeable a, QueueConstraints w r a)  => RefQueue a -> STM(Queue a)
readQRef tv= do
    mdx <- readDBRef tv
    case mdx of
     Nothing -> do
            let q= Queue ( Prelude.drop lenQPrefix $ keyObjDBRef tv) [] []
            writeDBRef tv q
            return q
     Just dx ->
            return dx

-- | version in the STM monad
popSTM :: (Typeable a, QueueConstraints w r a) =>  RefQueue a
              -> STM  a
popSTM tv=do
    dx <- readQRef tv
    doit  dx

    where
    --doit :: (Typeable a, Serializer m n [a]) => Queue a -> STM a
    doit (Queue n [x] [])= do
                 writeDBRef tv $  (Queue n  [] [])
                 return   x
    doit (Queue _ [] []) =  retry
    doit (Queue  n imp [])  =  doit  (Queue  n [] $ Prelude.reverse imp)
    doit (Queue n imp  list ) = do
                 writeDBRef tv  (Queue  n imp (Prelude.tail list ))
                 return  $ Prelude.head list

--  | read the first element in the queue but it does not delete it
pick
      ::  (Typeable a, QueueConstraints w r a)  => RefQueue a       -- ^ Queue name
      -> IO a              -- ^ the returned elems
pick tv = atomically $ do
    dx <- readQRef tv
    doit dx
    where
    doit (Queue _ [x] [])= return   x
    doit (Queue _ [] []) =  retry
    doit (Queue  n imp [])  =  doit  (Queue  n [] $ Prelude.reverse imp)
    doit (Queue n imp  list ) = return  $ Prelude.head list

-- | push an element in the queue
push  ::   (Typeable a, QueueConstraints w r a)  => RefQueue a -> a -> IO ()
push tv v = atomically $ pushSTM tv v

-- | version in the STM monad
pushSTM ::  (Typeable a, QueueConstraints w r a)  => RefQueue a -> a -> STM ()
pushSTM  tv   v=
      readQRef tv  >>= \ ((Queue n  imp out))  -> writeDBRef tv  $ Queue n  (v : imp) out

-- | return the list of all elements in the queue. The queue remains unchanged
pickAll ::  (Typeable a, QueueConstraints w r a)  => RefQueue a -> IO [a]
pickAll= atomically  . pickAllSTM

-- | version in the STM monad
pickAllSTM :: (Typeable a, QueueConstraints w r a)  => RefQueue a -> STM [a]
pickAllSTM tv= do
     (Queue name imp out) <- readQRef tv
     return $ out ++ Prelude.reverse imp

-- | return the first element in the queue that has the given key
pickElem ::(Indexable a,Typeable a, QueueConstraints w r a) => RefQueue a -> String -> IO(Maybe a)
pickElem tv key= atomically $ pickElemSTM tv key

-- | version in the STM monad
pickElemSTM :: (Indexable a,Typeable a, QueueConstraints w r a)
                     => RefQueue a -> String -> STM(Maybe a)
pickElemSTM tv key1=  do
     Queue name imp out <- readQRef tv
     let xs= out ++ Prelude.reverse imp
     when (not $ Prelude.null imp) $ writeDBRef tv $ Queue name [] xs
     case  Prelude.filter (\x-> key x == key1) xs of
          []    -> return $ Nothing
          (x:_) -> return $ Just  x

-- | update the first element of the queue with a new element with the same key
updateElem :: (Indexable a,Typeable a, QueueConstraints w r a)
                    => RefQueue a  -> a -> IO()
updateElem tv x = atomically $ updateElemSTM tv  x

-- | version in the STM monad
updateElemSTM :: (Indexable a,Typeable a, QueueConstraints w r a)
                       => RefQueue a  -> a -> STM()
updateElemSTM tv v= do
     Queue name imp out <- readQRef tv
     let xs= out ++ Prelude.reverse imp
     let xs'= Prelude.map (\x -> if key x == n then v else x) xs
     writeDBRef tv  $ Queue name [] xs'
     where
     n= key v

-- | return the list of all elements in the queue and empty it
readAll ::  (Typeable a, QueueConstraints w r a) => RefQueue a -> IO [a]
readAll= atomically  . readAllSTM

-- | a version in the STM monad
readAllSTM ::  (Typeable a, QueueConstraints w r a)  => RefQueue a -> STM [a]
readAllSTM tv= do
     Queue name imp out <- readQRef tv
     writeDBRef tv  $ Queue name [] []
     return $ out ++ Prelude.reverse imp

-- | delete all the elements of the queue that has the key of the parameter passed
deleteElem :: (Indexable a,Typeable a, QueueConstraints w r a) => RefQueue a-> a -> IO ()
deleteElem tv x= atomically $ deleteElemSTM tv x

-- | verison in the STM monad
deleteElemSTM :: (Typeable a,Indexable a,QueueConstraints w r a) => RefQueue a-> a -> STM ()
deleteElemSTM tv x= do
     Queue name imp out <- readQRef tv
     let xs= out ++ Prelude.reverse imp
     writeDBRef tv $ Queue name [] $ Prelude.filter (\x-> key x /= k) xs
     where
     k=key x