-- -*-haskell-*-
--  class of flag types
--
--  Author : Duncan Coutts
--
--  Created: 21 January 2005
--
--  Copyright (C) 2001-2005 Duncan Coutts, Axel Simon
--
--  This library is free software; you can redistribute it and/or
--  modify it under the terms of the GNU Lesser General Public
--  License as published by the Free Software Foundation; either
--  version 2.1 of the License, or (at your option) any later version.
--
--  This library 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
--  Lesser General Public License for more details.
--
-- |
-- Maintainer  : gtk2hs-users@lists.sourceforge.net
-- Stability   : provisional
-- Portability : portable
--
-- This module defines a type class for flags that are marshaled as bitflags.
--
module System.Glib.Flags (
  Flags,
  fromFlags,
  toFlags
  ) where

import Data.Bits ((.|.), (.&.), testBit, shiftL, shiftR)
import Data.Maybe (catMaybes)

class  (Enum a, Bounded a) => Flags a

fromFlags :: Flags a => [a] -> Int
fromFlags :: forall a. Flags a => [a] -> Int
fromFlags [a]
is = forall {a}. Enum a => Int -> [a] -> Int
orNum Int
0 [a]
is
  where orNum :: Int -> [a] -> Int
orNum Int
n []     = Int
n
        orNum Int
n (a
i:[a]
is) = Int -> [a] -> Int
orNum (Int
n forall a. Bits a => a -> a -> a
.|. forall a. Enum a => a -> Int
fromEnum a
i) [a]
is

-- * Note that this function ignores bits set in the passed
--   'Int' that do not correspond to a flag.
toFlags :: Flags a => Int -> [a]
toFlags :: forall a. Flags a => Int -> [a]
toFlags Int
n = forall a. [Maybe a] -> [a]
catMaybes [ if Int
n forall a. Bits a => a -> a -> a
.&. forall a. Enum a => a -> Int
fromEnum a
flag forall a. Eq a => a -> a -> Bool
== forall a. Enum a => a -> Int
fromEnum a
flag
                           then forall a. a -> Maybe a
Just a
flag
                           else forall a. Maybe a
Nothing
                      | a
flag <- [forall a. Bounded a => a
minBound .. forall a. Bounded a => a
maxBound] ]

-------------------------
-- QuickCheck test code

{-
import Test.QuickCheck
import List (sort, nub)
-- to run these tests you must copy EventMask and its Enum instance here
-- and make it an instance of Ord, Eq and Show.

prop_ToFlagsFromFlags :: Int -> Property
prop_ToFlagsFromFlags n =
  (n >= 1 && n <= 21)
  ==>
  collect n $
  let flag :: [EventMask]
      flag = toFlags (2^n)
   in 2^n == fromFlags flag

prop_FromFlagsToFlags :: [EventMask] -> Bool
prop_FromFlagsToFlags flags =
  (nub . sort) flags == toFlags (fromFlags flags)

instance Arbitrary EventMask where
  arbitrary     = sized $ \_ -> do x <- choose (1,21 :: Int)
                                   return (toEnum $ 2^x)
-}