packages feed

derive-storable 0.1.0.6 → 0.1.1.0

raw patch · 9 files changed

+1324/−10 lines, 9 filesdep −derive-storabledep ~QuickCheckdep ~basedep ~hspecPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: derive-storable

Dependency ranges changed: QuickCheck, base, hspec

API changes (from Hackage documentation)

- Foreign.Storable.Generic: alignment :: Storable a => a -> Int
+ Foreign.Storable.Generic: alignment :: a -> Int
- Foreign.Storable.Generic: peek :: Storable a => Ptr a -> IO a
+ Foreign.Storable.Generic: peek :: Ptr a -> IO a
- Foreign.Storable.Generic: peekByteOff :: Storable a => Ptr b -> Int -> IO a
+ Foreign.Storable.Generic: peekByteOff :: Ptr b -> Int -> IO a
- Foreign.Storable.Generic: peekElemOff :: Storable a => Ptr a -> Int -> IO a
+ Foreign.Storable.Generic: peekElemOff :: Ptr a -> Int -> IO a
- Foreign.Storable.Generic: poke :: Storable a => Ptr a -> a -> IO ()
+ Foreign.Storable.Generic: poke :: Ptr a -> a -> IO ()
- Foreign.Storable.Generic: pokeByteOff :: Storable a => Ptr b -> Int -> a -> IO ()
+ Foreign.Storable.Generic: pokeByteOff :: Ptr b -> Int -> a -> IO ()
- Foreign.Storable.Generic: pokeElemOff :: Storable a => Ptr a -> Int -> a -> IO ()
+ Foreign.Storable.Generic: pokeElemOff :: Ptr a -> Int -> a -> IO ()
- Foreign.Storable.Generic: sizeOf :: Storable a => a -> Int
+ Foreign.Storable.Generic: sizeOf :: a -> Int

Files

ChangeLog.md view
@@ -1,6 +1,10 @@ # Revision history for derive-storable -## 0.1.0.5  -- 2016-12-07+## 0.1.1.0  -- 2017-07-19++* Bumped to GHC 8.2.*++## 0.1.0.6  -- 2016-12-07  * Made the information about performance problems more visible in README.md 
derive-storable.cabal view
@@ -1,6 +1,6 @@ name:                derive-storable -version:             0.1.0.6+version:             0.1.1.0 synopsis:            Derive Storable instances with GHC.Generics.             description:         Derive Storable instances with GHC.Generics. The derived Storable instances have the same alignment as C structs.@@ -20,12 +20,12 @@ extra-source-files:  ChangeLog.md README.md  cabal-version:       >=1.10-+tested-with:         GHC==7.10.3, GHC==8.0.1, GHC==8.0.2, GHC==8.2.1  library   exposed-modules:     Foreign.Storable.Generic, Foreign.Storable.Generic.Tools                      , Foreign.Storable.Generic.Internal, Foreign.Storable.Generic.Instances       -  build-depends:       base >=4.8 && <4.10+  build-depends:       base >=4.8 && < 4.11   hs-source-dirs:      src   default-language:    Haskell2010  @@ -36,15 +36,31 @@   hs-source-dirs:      src, test/Basic, test/Basic/cbits   c-sources:           test/Basic/cbits/TestCases.c    main-is:             MemoryCSpec.hs-  build-depends:       base >= 4.8 && <4.10, hspec == 2.2.* ,QuickCheck == 2.8.*, derive-storable+  other-modules:       Foreign.Storable.Generic+                     , Foreign.Storable.Generic.Instances+                     , Foreign.Storable.Generic.Internal+                     , Foreign.Storable.Generic.Tools+                     , TestCases    +  build-depends:       base >= 4.8 && < 4.11, hspec == 2.4.*,QuickCheck >= 2.10+     default-language:    Haskell2010  test-suite spec-  type:                exitcode-stdio-1.0-  hs-source-dirs:      src/ test/Spec test/Basic test/GenericRep/-  Main-is:             Spec.hs-  build-depends:       base >= 4.8 && < 4.10, derive-storable, hspec == 2.2.*, QuickCheck == 2.8.*+  type:                  exitcode-stdio-1.0+  hs-source-dirs:        src/ test/Spec test/Basic test/GenericRep/+  Main-is:               Spec.hs+  other-modules:         Foreign.Storable.Generic+                       , Foreign.Storable.Generic.Instances+                       , Foreign.Storable.Generic.Internal+                       , Foreign.Storable.Generic.Internal.GStorable'Spec+                       , Foreign.Storable.Generic.Internal.GStorableSpec+                       , Foreign.Storable.Generic.InternalSpec+                       , Foreign.Storable.Generic.Tools+                       , Foreign.Storable.Generic.ToolsSpec+                       , GenericType++  build-depends:       base >= 4.8 && < 4.11, hspec == 2.4.*, QuickCheck >= 2.10    default-language:    Haskell2010 
test/Basic/MemoryCSpec.hs view
@@ -8,7 +8,7 @@  -- Test libraries import Test.Hspec-import Test.QuickCheck+import Test.QuickCheck hiding (getSize)  -- Helpers import Foreign.Marshal.Array
+ test/Basic/TestCases.hs view
@@ -0,0 +1,520 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}++module TestCases where++import GHC.Generics (Generic, Rep, from)+import Foreign.C.Types+import Foreign.Storable+import Foreign.Storable.Generic+import Foreign.Ptr (Ptr)+import Foreign.ForeignPtr (ForeignPtr, mallocForeignPtr)+import Foreign.Marshal.Alloc (malloc, free)+import Foreign.Marshal.Array (mallocArray, pokeArray)++import Foreign.Storable.Generic.Tools+import Foreign.Storable.Generic.Internal+import Foreign.Storable.Generic.Instances+import Data.Int+import Control.Monad (sequence, liftM)+import System.Exit++import Test.QuickCheck+-- The module tests the memory alignment of Storable data-types +-- derived with generic-storable package. ++-- Adding parametric polimorphism to reduce the boilerplate.+class (Storable a) => Checkable a where+  -- | Checks whether the fields are the same+  checkFields  :: Ptr a -> Ptr a -> IO Bool +  -- | Checks whether the offsets are the same+  checkOffsets :: a -> Ptr Int16 -> IO Bool +  -- | Checks whether the size is the same+  getSize    :: a -> IO Int              +  -- | Checks whether the alignment is the same+  getAlignment :: a-> IO Int              +  +  new          :: a -> IO (Ptr a)+++newStorable :: Storable a => a -> IO (Ptr a)+newStorable val = do+  ptr <- malloc+  poke ptr val+  return ptr++goffsets :: (GStorable' (Rep a), GStorable a, Generic a) => a -> [Int16]+goffsets v = map fromIntegral $ internalOffsets (from v)++data C1 = C1 Int32 Int32+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C1 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC1 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC1 offs+    getSize        a          = fromIntegral <$> getSizeC1+    getAlignment   a          = fromIntegral <$> getAlignmentC1+    new (C1 a b) = do+        ptr <- newC1 a b+        return ptr++instance Arbitrary C1 where +    arbitrary = C1 <$> arbitrary <*> arbitrary++foreign import ccall newC1 :: Int32 -> Int32 -> IO (Ptr C1)+foreign import ccall checkFieldsC1 :: Ptr C1 -> Ptr C1 -> IO Int8+foreign import ccall checkOffsetsC1 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC1 :: IO Int16+foreign import ccall getAlignmentC1 :: IO Int16++data C2 = C2 Int32 Int16 Int8+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C2 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC2 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC2 offs+    getSize        a          = fromIntegral <$> getSizeC2+    getAlignment   a          = fromIntegral <$> getAlignmentC2+    new (C2 a b c) = do+        ptr <- newC2 a b c+        return ptr++instance Arbitrary C2 where +    arbitrary = C2 <$> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC2 :: Int32 -> Int16 -> Int8 -> IO (Ptr C2)+foreign import ccall checkFieldsC2 :: Ptr C2 -> Ptr C2 -> IO Int8+foreign import ccall checkOffsetsC2 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC2 :: IO Int16+foreign import ccall getAlignmentC2 :: IO Int16++data C3 = C3 Int32 Int8 Int16+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C3 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC3 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC3 offs+    getSize        a          = fromIntegral <$> getSizeC3+    getAlignment   a          = fromIntegral <$> getAlignmentC3+    new (C3 a b c) = do+        ptr <- newC3 a b c+        return ptr++instance Arbitrary C3 where +    arbitrary = C3 <$> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC3 :: Int32 -> Int8 -> Int16 -> IO (Ptr C3)+foreign import ccall checkFieldsC3 :: Ptr C3 -> Ptr C3 -> IO Int8+foreign import ccall checkOffsetsC3 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC3 :: IO Int16+foreign import ccall getAlignmentC3 :: IO Int16++data C4 = C4 Int32 Int8 Int8+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C4 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC4 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC4 offs+    getSize        a          = fromIntegral <$> getSizeC4+    getAlignment   a          = fromIntegral <$> getAlignmentC4+    new (C4 a b c) = do+        ptr <- newC4 a b c+        return ptr++instance Arbitrary C4 where +    arbitrary = C4 <$> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC4 :: Int32 -> Int8 -> Int8 -> IO (Ptr C4)+foreign import ccall checkFieldsC4 :: Ptr C4 -> Ptr C4 -> IO Int8+foreign import ccall checkOffsetsC4 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC4 :: IO Int16+foreign import ccall getAlignmentC4 :: IO Int16++data C5 = C5 Int32 Int16 Int8 Int8 Int8+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C5 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC5 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC5 offs+    getSize        a          = fromIntegral <$> getSizeC5+    getAlignment   a          = fromIntegral <$> getAlignmentC5+    new (C5 a b c d e) = do+        ptr <- newC5 a b c d e+        return ptr++instance Arbitrary C5 where +    arbitrary = C5 <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC5 :: Int32 -> Int16 -> Int8 -> Int8 -> Int8 -> IO (Ptr C5)+foreign import ccall checkFieldsC5 :: Ptr C5 -> Ptr C5 -> IO Int8+foreign import ccall checkOffsetsC5 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC5 :: IO Int16+foreign import ccall getAlignmentC5 :: IO Int16++data C6 = C6 Int64 Int8 Int64+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C6 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC6 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC6 offs+    getSize        a          = fromIntegral <$> getSizeC6+    getAlignment   a          = fromIntegral <$> getAlignmentC6+    new (C6 a b c) = do+        ptr <- newC6 a b c+        return ptr++instance Arbitrary C6 where +    arbitrary = C6 <$> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC6 :: Int64 -> Int8 -> Int64 -> IO (Ptr C6)+foreign import ccall checkFieldsC6 :: Ptr C6 -> Ptr C6 -> IO Int8+foreign import ccall checkOffsetsC6 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC6 :: IO Int16+foreign import ccall getAlignmentC6 :: IO Int16++data C7 = C7 C1 Int32+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C7 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC7 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC7 offs+    getSize        a          = fromIntegral <$> getSizeC7+    getAlignment   a          = fromIntegral <$> getAlignmentC7+    new (C7 a b) = do+        ptr_a <- newStorable a+        ptr <- newC7 ptr_a b+        free ptr_a+        return ptr++instance Arbitrary C7 where +    arbitrary = C7 <$> arbitrary <*> arbitrary++foreign import ccall newC7 :: Ptr C1 -> Int32 -> IO (Ptr C7)+foreign import ccall checkFieldsC7 :: Ptr C7 -> Ptr C7 -> IO Int8+foreign import ccall checkOffsetsC7 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC7 :: IO Int16+foreign import ccall getAlignmentC7 :: IO Int16++data C8 = C8 C2 Int8 C4+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C8 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC8 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC8 offs+    getSize        a          = fromIntegral <$> getSizeC8+    getAlignment   a          = fromIntegral <$> getAlignmentC8+    new (C8 a b c) = do+        ptr_a <- newStorable a+        ptr_c <- newStorable c+        ptr <- newC8 ptr_a b ptr_c+        free ptr_a+        free ptr_c+        return ptr++instance Arbitrary C8 where +    arbitrary = C8 <$> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC8 :: Ptr C2 -> Int8 -> Ptr C4 -> IO (Ptr C8)+foreign import ccall checkFieldsC8 :: Ptr C8 -> Ptr C8 -> IO Int8+foreign import ccall checkOffsetsC8 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC8 :: IO Int16+foreign import ccall getAlignmentC8 :: IO Int16++data C9 = C9 C5 Int8 Int8 Int8+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C9 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC9 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC9 offs+    getSize        a          = fromIntegral <$> getSizeC9+    getAlignment   a          = fromIntegral <$> getAlignmentC9+    new (C9 a b c d) = do+        ptr_a <- newStorable a+        ptr <- newC9 ptr_a b c d+        free ptr_a+        return ptr++instance Arbitrary C9 where +    arbitrary = C9 <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC9 :: Ptr C5 -> Int8 -> Int8 -> Int8 -> IO (Ptr C9)+foreign import ccall checkFieldsC9 :: Ptr C9 -> Ptr C9 -> IO Int8+foreign import ccall checkOffsetsC9 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC9 :: IO Int16+foreign import ccall getAlignmentC9 :: IO Int16++data C10 = C10 C8 Int64 C1+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C10 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC10 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC10 offs+    getSize        a          = fromIntegral <$> getSizeC10+    getAlignment   a          = fromIntegral <$> getAlignmentC10+    new (C10 a b c) = do+        ptr_a <- newStorable a+        ptr_c <- newStorable c+        ptr <- newC10 ptr_a b ptr_c+        free ptr_a+        free ptr_c+        return ptr++instance Arbitrary C10 where +    arbitrary = C10 <$> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC10 :: Ptr C8 -> Int64 -> Ptr C1 -> IO (Ptr C10)+foreign import ccall checkFieldsC10 :: Ptr C10 -> Ptr C10 -> IO Int8+foreign import ccall checkOffsetsC10 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC10 :: IO Int16+foreign import ccall getAlignmentC10 :: IO Int16++data C11 = C11 C10 C10+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C11 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC11 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC11 offs+    getSize        a          = fromIntegral <$> getSizeC11+    getAlignment   a          = fromIntegral <$> getAlignmentC11+    new (C11 a b) = do+        ptr_a <- newStorable a+        ptr_b <- newStorable b+        ptr <- newC11 ptr_a ptr_b+        free ptr_a+        free ptr_b+        return ptr++instance Arbitrary C11 where +    arbitrary = C11 <$> arbitrary <*> arbitrary++foreign import ccall newC11 :: Ptr C10 -> Ptr C10 -> IO (Ptr C11)+foreign import ccall checkFieldsC11 :: Ptr C11 -> Ptr C11 -> IO Int8+foreign import ccall checkOffsetsC11 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC11 :: IO Int16+foreign import ccall getAlignmentC11 :: IO Int16++data C12 = C12 Int64 Int64 Int64 Int64+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C12 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC12 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC12 offs+    getSize        a          = fromIntegral <$> getSizeC12+    getAlignment   a          = fromIntegral <$> getAlignmentC12+    new (C12 a b c d) = do+        ptr <- newC12 a b c d+        return ptr++instance Arbitrary C12 where +    arbitrary = C12 <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC12 :: Int64 -> Int64 -> Int64 -> Int64 -> IO (Ptr C12)+foreign import ccall checkFieldsC12 :: Ptr C12 -> Ptr C12 -> IO Int8+foreign import ccall checkOffsetsC12 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC12 :: IO Int16+foreign import ccall getAlignmentC12 :: IO Int16++data C13 = C13 C12 C12 C12 C12+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C13 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC13 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC13 offs+    getSize        a          = fromIntegral <$> getSizeC13+    getAlignment   a          = fromIntegral <$> getAlignmentC13+    new (C13 a b c d) = do+        ptr_a <- newStorable a+        ptr_b <- newStorable b+        ptr_c <- newStorable c+        ptr_d <- newStorable d+        ptr <- newC13 ptr_a ptr_b ptr_c ptr_d+        free ptr_a+        free ptr_b+        free ptr_c+        free ptr_d+        return ptr++instance Arbitrary C13 where +    arbitrary = C13 <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC13 :: Ptr C12 -> Ptr C12 -> Ptr C12 -> Ptr C12 -> IO (Ptr C13)+foreign import ccall checkFieldsC13 :: Ptr C13 -> Ptr C13 -> IO Int8+foreign import ccall checkOffsetsC13 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC13 :: IO Int16+foreign import ccall getAlignmentC13 :: IO Int16++data C14 = C14 C13 C13 C13 C13 Int8+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C14 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC14 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC14 offs+    getSize        a          = fromIntegral <$> getSizeC14+    getAlignment   a          = fromIntegral <$> getAlignmentC14+    new (C14 a b c d e) = do+        ptr_a <- newStorable a+        ptr_b <- newStorable b+        ptr_c <- newStorable c+        ptr_d <- newStorable d+        ptr <- newC14 ptr_a ptr_b ptr_c ptr_d e+        free ptr_a+        free ptr_b+        free ptr_c+        free ptr_d+        return ptr++instance Arbitrary C14 where +    arbitrary = C14 <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC14 :: Ptr C13 -> Ptr C13 -> Ptr C13 -> Ptr C13 -> Int8 -> IO (Ptr C14)+foreign import ccall checkFieldsC14 :: Ptr C14 -> Ptr C14 -> IO Int8+foreign import ccall checkOffsetsC14 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC14 :: IO Int16+foreign import ccall getAlignmentC14 :: IO Int16++data C15 = C15 C12 C14+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C15 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC15 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC15 offs+    getSize        a          = fromIntegral <$> getSizeC15+    getAlignment   a          = fromIntegral <$> getAlignmentC15+    new (C15 a b) = do+        ptr_a <- newStorable a+        ptr_b <- newStorable b+        ptr <- newC15 ptr_a ptr_b+        free ptr_a+        free ptr_b+        return ptr++instance Arbitrary C15 where +    arbitrary = C15 <$> arbitrary <*> arbitrary++foreign import ccall newC15 :: Ptr C12 -> Ptr C14 -> IO (Ptr C15)+foreign import ccall checkFieldsC15 :: Ptr C15 -> Ptr C15 -> IO Int8+foreign import ccall checkOffsetsC15 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC15 :: IO Int16+foreign import ccall getAlignmentC15 :: IO Int16++data C16 = C16 C10 C15 C7+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C16 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC16 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC16 offs+    getSize        a          = fromIntegral <$> getSizeC16+    getAlignment   a          = fromIntegral <$> getAlignmentC16+    new (C16 a b c) = do+        ptr_a <- newStorable a+        ptr_b <- newStorable b+        ptr_c <- newStorable c+        ptr <- newC16 ptr_a ptr_b ptr_c+        free ptr_a+        free ptr_b+        free ptr_c+        return ptr++instance Arbitrary C16 where +    arbitrary = C16 <$> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC16 :: Ptr C10 -> Ptr C15 -> Ptr C7 -> IO (Ptr C16)+foreign import ccall checkFieldsC16 :: Ptr C16 -> Ptr C16 -> IO Int8+foreign import ccall checkOffsetsC16 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC16 :: IO Int16+foreign import ccall getAlignmentC16 :: IO Int16++data C17 = C17 Float Double Float+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C17 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC17 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC17 offs+    getSize        a          = fromIntegral <$> getSizeC17+    getAlignment   a          = fromIntegral <$> getAlignmentC17+    new (C17 a b c) = do+        ptr <- newC17 a b c+        return ptr++instance Arbitrary C17 where +    arbitrary = C17 <$> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC17 :: Float -> Double -> Float -> IO (Ptr C17)+foreign import ccall checkFieldsC17 :: Ptr C17 -> Ptr C17 -> IO Int8+foreign import ccall checkOffsetsC17 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC17 :: IO Int16+foreign import ccall getAlignmentC17 :: IO Int16++data C18 = C18 Float Float Double Float+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C18 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC18 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC18 offs+    getSize        a          = fromIntegral <$> getSizeC18+    getAlignment   a          = fromIntegral <$> getAlignmentC18+    new (C18 a b c d) = do+        ptr <- newC18 a b c d+        return ptr++instance Arbitrary C18 where +    arbitrary = C18 <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC18 :: Float -> Float -> Double -> Float -> IO (Ptr C18)+foreign import ccall checkFieldsC18 :: Ptr C18 -> Ptr C18 -> IO Int8+foreign import ccall checkOffsetsC18 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC18 :: IO Int16+foreign import ccall getAlignmentC18 :: IO Int16++data C19 = C19 C17 Float Double+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C19 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC19 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC19 offs+    getSize        a          = fromIntegral <$> getSizeC19+    getAlignment   a          = fromIntegral <$> getAlignmentC19+    new (C19 a b c) = do+        ptr_a <- newStorable a+        ptr <- newC19 ptr_a b c+        free ptr_a+        return ptr++instance Arbitrary C19 where +    arbitrary = C19 <$> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC19 :: Ptr C17 -> Float -> Double -> IO (Ptr C19)+foreign import ccall checkFieldsC19 :: Ptr C19 -> Ptr C19 -> IO Int8+foreign import ccall checkOffsetsC19 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC19 :: IO Int16+foreign import ccall getAlignmentC19 :: IO Int16++data C20 = C20 Double C18 Double C19+    deriving (Show, Eq, Generic, GStorable)++instance Checkable C20 where+    checkFields    ptr1 ptr2 = (==1) <$> checkFieldsC20 ptr1 ptr2+    checkOffsets   _    offs = (==1) <$> checkOffsetsC20 offs+    getSize        a          = fromIntegral <$> getSizeC20+    getAlignment   a          = fromIntegral <$> getAlignmentC20+    new (C20 a b c d) = do+        ptr_b <- newStorable b+        ptr_d <- newStorable d+        ptr <- newC20 a ptr_b c ptr_d+        free ptr_b+        free ptr_d+        return ptr++instance Arbitrary C20 where +    arbitrary = C20 <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary++foreign import ccall newC20 :: Double -> Ptr C18 -> Double -> Ptr C19 -> IO (Ptr C20)+foreign import ccall checkFieldsC20 :: Ptr C20 -> Ptr C20 -> IO Int8+foreign import ccall checkOffsetsC20 :: Ptr Int16 -> IO Int8+foreign import ccall getSizeC20 :: IO Int16+foreign import ccall getAlignmentC20 :: IO Int16+
+ test/GenericRep/GenericType.hs view
@@ -0,0 +1,239 @@+{-#LANGUAGE GADTs         #-}+{-#LANGUAGE TypeOperators #-}+{-#LANGUAGE KindSignatures #-}+{-#LANGUAGE FlexibleInstances #-}+{-#LANGUAGE FlexibleContexts #-}+{-#LANGUAGE ScopedTypeVariables #-} +{-#LANGUAGE InstanceSigs #-}+{-#LANGUAGE PartialTypeSignatures #-}++{-#LANGUAGE DataKinds #-}+module GenericType (+    BasicType(..),+    GenericType(..),+    NestedType(..),+    NestedToType(..),+    ok_vector+    ) where+-- Test modules+import Test.QuickCheck hiding ((.&.))+import Test.QuickCheck.Modifiers (NonEmptyList(..))+-- Tested modules+import Foreign.Storable.Generic.Internal++-- Test data+import Foreign.Storable.Generic.Tools+import Foreign.Storable.Generic.Instances+import Foreign.Ptr (Ptr, nullPtr, plusPtr)+import Foreign.C.Types+import Foreign.Storable+import GHC.Generics  +import Data.Int+import Data.Word+import Data.Bits+import Data.Proxy+import Debug.Trace+import GHC.TypeLits++import Unsafe.Coerce++-- | TestType - the basic building blocks from which+-- GStorable instances are built.+class (Arbitrary a,Eq a,GStorable a, Show a) => TestType a++-- Generating random pointers.+instance Arbitrary (Ptr a) where+    arbitrary = do+        plus <- choose (0, 10000)+        return $ plusPtr nullPtr plus++instance TestType Int+instance TestType Int8+instance TestType Int16+instance TestType Int32+instance TestType Int64++instance TestType Word+instance TestType Word8+instance TestType Word16+instance TestType Word32+instance TestType Word64++instance TestType Double+instance TestType Float+instance TestType (Ptr a)+instance TestType Char++instance TestType CFloat++instance TestType CDouble++-- | The wrappable type class. Wraps the type in generics+-- and then into GenericType data type.+class (Show a) => Wrappable a where+    wrapType :: a -> GenericType+++-------------------+-- | Contains the basic building blocks that generate GStorable type classes.+data BasicType where+   BasicType :: (TestType a) => a -> BasicType++instance Show BasicType where+    show (BasicType val) = show val++instance Arbitrary BasicType where+    arbitrary = do+        valInt     <- arbitrary  :: Gen Int +        valInt8    <- arbitrary  :: Gen Int8+        valInt16   <- arbitrary  :: Gen Int16 +        valInt32   <- arbitrary  :: Gen Int32 +        valInt64   <- arbitrary  :: Gen Int64+        valWord     <- arbitrary :: Gen Word +        valWord8    <- arbitrary :: Gen Word8+        valWord16   <- arbitrary :: Gen Word16 +        valWord32   <- arbitrary :: Gen Word32 +        valWord64   <- arbitrary :: Gen Word64+        valDouble  <- arbitrary  :: Gen Double+        valFloat   <- arbitrary  :: Gen Float+        valPtr     <- arbitrary  :: Gen (Ptr a)+        valChar    <- arbitrary  :: Gen Char++        valCDouble  <- arbitrary :: Gen CDouble+        valCFloat   <- arbitrary :: Gen CFloat++        elements [BasicType valInt,    BasicType valInt8, BasicType valInt16+                 ,BasicType valInt32 , BasicType valInt64, BasicType valCDouble+                 ,BasicType valCFloat, BasicType valPtr, BasicType valChar+                 ,BasicType valWord,   BasicType valWord8, BasicType valWord16+                 ,BasicType valWord32, BasicType valWord64]++-- | Wraps the basic type with 'M1' and 'K1' type constructors. +-- The result is usable by the testing algorithms.+instance Wrappable BasicType where+    wrapType (BasicType val) = GenericType $ M1 $ K1 val++-- Some tricks for generics:+instance Arbitrary c     => Arbitrary (K1 i c p) where+    arbitrary = K1 <$> arbitrary+instance Arbitrary (f p) => Arbitrary (M1 i c f p) where+    arbitrary = M1 <$> arbitrary+instance (Arbitrary (f p), Arbitrary (g p)) => Arbitrary ((:*:) f g p) where+    arbitrary = (:*:) <$> (arbitrary :: Gen (f p)) <*> (arbitrary :: Gen (g p))+++-- | Used withing GenericType to enforce that the types can be joined with :*:.+data MyPhantom++-- | Constains generic representations of arbitrary data-types.+-- The Show constraint is used so we can print out the badly working cases.+-- The Eq and Arbitrary one are for generating different values for the same types.+data GenericType where+   GenericType  :: (p ~ MyPhantom, Eq (f p), Arbitrary (f p), GStorable' f, Show (f p)) => f p -> GenericType++instance Arbitrary GenericType where+    arbitrary = do+        n <- choose (0,100) :: Gen Int+        genType n++-- | Generates a random generic representation.+-- Does not resemble the generic representation from real types.+genType :: Int  -- ^ Number of randomness. +        -> Gen GenericType+genType 0 = wrapType <$> (arbitrary :: Gen BasicType)+genType n = do+    -- Choose what kind of element this layer is.+    step <- arbitrary :: Gen GenTree+    case step of+        -- A product - a tree+        Producted -> do+            -- Generate two subtrees with the same function+            div <- choose  (0,n) +            gt1 <- genType  div+            gt2 <- genType (n-div)+            return $ (\(GenericType t1) (GenericType t2) -> GenericType $ t1 :*: t2) gt1 gt2 +        -- Wrap in meta-data anything that's generated later+        M1ed      -> (\(GenericType t) -> GenericType $ M1 t) <$> genType (n-1) +        -- Wrap in K1 anything that's generated later.+        K1ed      -> (\(GenericType t) -> GenericType $ K1 t) <$> genType (n-1) ++-- | Enums for generating the generic representations.+data GenTree = Producted | M1ed | K1ed++instance Arbitrary GenTree where+    arbitrary = elements [Producted, M1ed , K1ed]++-- | Show the generic metadata. Could use some pretty printing later. +instance Show GenericType where+    show (GenericType    val) = show val++-- | Wrap the generic representation as it were derived from a proper type.+instance Wrappable GenericType where+    wrapType    (GenericType  val) = GenericType $ M1 $ K1 $ val++-- | Wrapper for creating nested types.+data NestedType (n :: Nat) = NestedType GenericType++instance (KnownNat n) => Show (NestedType n) where+    show (NestedType (GenericType val)) = type_info ++ show val+        where type_info = "NestedType " ++ (show $ natVal (Proxy :: Proxy n)) ++ " "++instance (KnownNat n) => Arbitrary (NestedType n) where+    arbitrary = NestedType <$> nestedType (fromIntegral $ natVal (Proxy :: Proxy n))++-- | Wrapper for creating nested types up to a certain level.+data NestedToType (n :: Nat) = NestedToType GenericType++instance (KnownNat n) => Show (NestedToType n) where+    show (NestedToType (GenericType val)) = type_info ++ show val+        where type_info = "NestedToType " ++ (show $ natVal (Proxy :: Proxy n)) ++ " "++instance (KnownNat n) => Arbitrary (NestedToType n) where+    arbitrary = NestedToType <$> nestedToType (fromIntegral $ natVal (Proxy :: Proxy n))++-- | Generate a nested type.+nestedType :: Int             -- ^ Depth of the generated type. +           -> Gen GenericType -- ^ Resulting generator.+nestedType n  = nestedType' n gen+    where gen = wrapType <$> (arbitrary :: Gen BasicType) ++nestedType' :: Int             -- ^ Depth of the generated type.+            -> Gen GenericType -- ^ Accumulator+            -> Gen GenericType -- ^ Resulting generator+nestedType' n gen +    | n <  0 = error "GenericType.nestedType': n is less than 0"+    | n == 0 = gen+    | n > 0  = do +        fields <- choose (1, 4*n)+        nestedType' (n-1) (wrapType <$> toGenericType <$> vectorOf fields gen) ++-- | For generating nested types with components from levels below.+nestedToType :: Int -> Gen (GenericType)+nestedToType n =do+    sublist <- suchThat (sublistOf [0..n]) (\x -> length x > 0)+    wrapType <$> toGenericType <$> mapM nestedType sublist++-- | Uses the :*: operator to construct a representation of a product type.+typeProduct :: GenericType -> GenericType -> GenericType+typeProduct (GenericType val1) (GenericType val2) = GenericType $ val1 :*: val2++-- | Creates a tree for type product.+toGenericType :: [GenericType] -> GenericType+toGenericType []  = error "toGenericType requires at least one type"+toGenericType [v] = v+toGenericType types = foldl1 typeProduct types++-- | Simulates the K1 step for generic representations. +instance {-#OVERLAPS#-} (GStorable' f) => GStorable' (K1 i (f p)) where+    glistSizeOf'    _ = [internalSizeOf (undefined :: f p)]+    glistAlignment' _ = [internalAlignment (undefined :: f p)]+    gpeekByteOff' offs n ptr off   = K1 <$> internalPeekByteOff ptr (off + f_off)+        where f_off = offs !! n+    gpokeByteOff' offs n ptr off (K1 v) = internalPokeByteOff ptr (off + f_off) v+        where f_off = offs !! n+    gnumberOf'      _  = 1++-- | Helps with avoiding NaN problem. +ok_vector :: Int -> Gen [Word8]+ok_vector n = vectorOf n (suchThat arbitrary $ (\x-> (x .&. 127) /= 127) )+
+ test/Spec/Foreign/Storable/Generic/Internal/GStorable'Spec.hs view
@@ -0,0 +1,218 @@+{-#LANGUAGE ScopedTypeVariables #-}+{-#LANGUAGE DeriveGeneric       #-}+{-#LANGUAGE DataKinds           #-}+{-#LANGUAGE GADTs               #-}+module Foreign.Storable.Generic.Internal.GStorable'Spec where+++-- Test tools+import Test.Hspec+import Test.QuickCheck+import GenericType ++-- Tested modules+import Foreign.Storable.Generic.Internal ++-- Additional data+import Foreign.Storable.Generic.Instances+import GHC.Generics+import Foreign.Marshal.Alloc (malloc, mallocBytes, free)+import Foreign.Marshal.Array (peekArray, pokeArray)+import Data.Int+import Data.Word++++spec :: Spec+spec = do +    describe "glistSizeOf'" $ do+        it "instance M1    is equal to: glistSizeOf' a" $ do+            property (\(GenericType val) -> do+                glistSizeOf' (M1 $ val) `shouldBe` glistSizeOf' val +                )+        it "instance K1    is equal to: [internalSizeOf a]" $ do+            property (\(GenericType val) -> do+                glistSizeOf' (K1 $ val) `shouldBe` [internalSizeOf val] +                )+        it "instance (:*:) is equal to: glistSizeOf' a ++ glistSizeOf' b" $ do+            property (\(GenericType val1) (GenericType val2) -> do +                glistSizeOf' (val1 :*: val2 ) `shouldBe` (glistSizeOf' val1 ++ glistSizeOf' val2) +                )+    describe "glistAlignment'" $ do+        it "instance M1    is equal to: glistAlignment' a" $ do+            property (\(GenericType val) -> do+                glistAlignment' (M1 $ val) `shouldBe` glistAlignment' val +                )+        it "instance K1    is equal to: [internalAlignment a]" $ do+            property (\(GenericType val) -> do+                glistAlignment' (K1 $ val) `shouldBe` [internalAlignment val] +                )+        it "instance (:*:) is equal to: glistAlignment' a ++ glistAlignment' b" $ do+            property (\(GenericType val1) (GenericType val2) -> do +                glistAlignment' (val1 :*: val2 ) `shouldBe` (glistAlignment' val1 ++ glistAlignment' val2) +                )+    describe "gnumberOf' " $ do+        it "instance M1    is equal to: gnumberOf' a" $ do+            property (\(GenericType val) -> do+                gnumberOf' (M1 $ val) `shouldBe` gnumberOf' val +                )+        it "instance K1    is equal to: 1" $ do+            property (\(GenericType val) -> do+                gnumberOf' (K1 $ val) `shouldBe` 1+                )+        it "instance (:*:) is equal to: gnumberOf' a + gnumberOf' b" $ do+            property (\(GenericType val1) (GenericType val2) -> do +                gnumberOf' (val1 :*: val2 ) `shouldBe` (gnumberOf' val1 + gnumberOf' val2) +                )+    describe "gpeekByteOff' " $ do+        it "instance M1    is equal to: M1 <$> gpeekByteOff' offs ix ptr off" $ do+            property (\(GenericType (val :: f p)) -> do                +                let size      = internalSizeOf  val+                    offs      = internalOffsets val+                    no_fields = gnumberOf' (undefined :: f p)+                -- Random global offset+                off   <- generate $ suchThat arbitrary (\x -> x>=0 && x < 100)++                -- Reserve some memory and write some data to it.+                ptr    <- mallocBytes (off + size)+                values <- generate $ ok_vector (off + size) :: IO [Word8]+                pokeArray ptr values++                -- Check:+                -- With M1+                v1 <- gpeekByteOff' offs (no_fields - 1) ptr off     :: IO (M1 i c f p)+                -- Without M1+                v2 <- gpeekByteOff' offs (no_fields - 1) ptr off     :: IO (f p)+                free ptr++                v1 `shouldBe` M1 v2+                )+        it "instance K1    is equal to: K1 <$> internalPeekByteOff ptr (f_off + off) val" $ do+            property (\(GenericType (val :: f p)) -> do+                let size = internalSizeOf val+                -- Random global offsets and field offset+                f_off <- generate $ suchThat arbitrary (>=0) +                off   <- generate $ suchThat arbitrary (>=0)++                -- Reserve some memory and write some data to it.+                ptr    <- mallocBytes (f_off + off + size)+                values <- generate $ ok_vector (f_off + off + size) :: IO [Word8]+                pokeArray ptr values+               +                -- Check:+                -- With K1+                v1 <- gpeekByteOff' [f_off] 0 ptr off     :: IO (K1 i (f p) p)+                -- Without K1+                v2 <- internalPeekByteOff ptr (f_off + off) :: IO (f p)+                free ptr++                v1 `shouldBe` K1 v2++                )+        it "instance (:*:) is equal to: (:*:) <$> peeker (ix - n2) <*> peeker ix  \n\+            \                                where peeker n_ix   = gpeekByteOff' offsets n_ix ptr off \n" $ do+            property (\(GenericType (val1 :: f p)) (GenericType (val2 :: g p)) -> do                +                let offsets   = internalOffsets (undefined :: (:*:) f g p)+                    size      = internalSizeOf (undefined :: (:*:) f g p)+                    no_fields = gnumberOf' (undefined :: (:*:) f g p)+                    n2        = gnumberOf' (undefined :: g p)+++                -- Random global offset+                off   <- generate $ suchThat arbitrary (>=0)++                -- Reserve some memory and write some data to it.+                ptr    <- mallocBytes (off + size)+                values <- generate $ ok_vector (off + size) :: IO [Word8]+                pokeArray ptr values++                -- Check:+                -- Left side+                v1   <- gpeekByteOff' offsets (no_fields - 1)      ptr off :: IO ((:*:) f g p)+                -- Right side+                v2_a <- gpeekByteOff' offsets (no_fields - 1 - n2) ptr off :: IO (f p)+                v2_b <- gpeekByteOff' offsets (no_fields - 1)      ptr off :: IO (g p)+                free ptr++                v1 `shouldBe` (v2_a :*: v2_b)+                )+    describe "gpokeByteOff' " $ do+        it "instance M1    is equal to: gpokeByteOff' offs ix ptr off val" $ do+            property (\(GenericType (val :: f p)) -> do+                let size    = internalSizeOf val+                    offsets = internalOffsets val +                    no_fields= gnumberOf' (undefined :: f p)+                -- Get the offsets to test+                off   <- generate $ suchThat arbitrary (>=0)++                -- Reserve some memory to read from+                ptr    <- mallocBytes (off + size)+                +                -- First test+                -- With M1+                gpokeByteOff' offsets (no_fields - 1) ptr off (M1 val)+                bytes1 <- peekArray (off + size) ptr :: IO [Word8]+              +                -- Second test+                -- Without M1+                gpokeByteOff' offsets (no_fields - 1) ptr off val+                bytes2 <- peekArray (off + size) ptr :: IO [Word8]+         +                free ptr+                -- Check:+                bytes1 `shouldBe` bytes2+                )+        it "instance K1    is equal to: internalPokeByteOff ptr (f_off + off) val" $ do+            property (\(GenericType (val :: f p)) -> do+                let size = internalSizeOf val+                -- Get the offsets to test+                f_off <- generate $ suchThat arbitrary (>=0) +                off   <- generate $ suchThat arbitrary (>=0)++                -- Reserve some memory to read from+                ptr    <- mallocBytes (f_off + off + size)+                +                -- First test+                -- With K1+                gpokeByteOff' [f_off] 0 ptr off (K1 val)+                bytes1 <- peekArray (f_off + off + size) ptr :: IO [Word8]+              +                -- Second test+                -- Without K1+                internalPokeByteOff ptr (f_off + off) val+                bytes2 <- peekArray (f_off + off + size) ptr :: IO [Word8]+         +                free ptr+                -- Check:+                bytes1 `shouldBe` bytes2+                )+        it "instance (:*:) is equal to: (:*:) <$> poker (ix - n2) a <*> poker ix b \n\+            \                                where poker n_ix v  = gpokeByteOff' offsets n_ix ptr off v" $ do+            property (\(GenericType (val1 :: f p)) (GenericType (val2 :: g p)) -> do+                let offsets   = internalOffsets (undefined :: (:*:) f g p)+                    no_fields = gnumberOf'      (undefined :: (:*:) f g p)+                    n2        = gnumberOf'      (undefined :: g p        )+                    size      = internalSizeOf  (undefined :: (:*:) f g p)+                +                -- Get the offset to test+                off   <- generate $ suchThat arbitrary (>=0)++                -- Reserve some memory to read from+                ptr    <- mallocBytes (off + size)+                +                -- First poke+                -- Left part of the tree+                gpokeByteOff' offsets (no_fields - 1) ptr off (val1 :*: val2)+                bytes1 <- peekArray (off + size) ptr :: IO [Word8]+              +                -- Second pokes+                -- Right part of the tree+                gpokeByteOff' offsets (no_fields - 1 - n2) ptr off val1+                gpokeByteOff' offsets (no_fields -1)       ptr off val2+                +                bytes2 <- peekArray (off + size) ptr :: IO [Word8]+         +                free ptr+                -- Check:+                bytes1 `shouldBe` bytes2+                )
+ test/Spec/Foreign/Storable/Generic/Internal/GStorableSpec.hs view
@@ -0,0 +1,130 @@+{-#LANGUAGE ScopedTypeVariables #-}+{-#LANGUAGe DataKinds           #-}+{-#LANGUAGE DeriveGeneric       #-}+{-#LANGUAGE DeriveAnyClass      #-}+{-#LANGUAGE FlexibleContexts    #-}+module Foreign.Storable.Generic.Internal.GStorableSpec where++-- Test tools+import Test.Hspec+import Test.QuickCheck++import GenericType ++-- Tested modules+import Foreign.Storable.Generic.Internal ++-- Additional data+import Foreign.Storable.Generic -- overlapping Storable+import Foreign.Storable.Generic.Instances+import Data.Int+import Data.Word+import GHC.Generics+import Foreign.Ptr (Ptr, plusPtr)+import Foreign.Marshal.Alloc (malloc, mallocBytes, free)+import Foreign.Marshal.Array (peekArray,pokeArray)++data TestData  = TestData Int Int64 Int8 Int8+    deriving (Show, Generic, GStorable, Eq)+instance Arbitrary TestData where+    arbitrary = TestData <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary+++data TestData2 = TestData2 Int8 TestData Int32 Int64+    deriving (Show, Generic, GStorable, Eq)+instance Arbitrary TestData2 where+    arbitrary = TestData2 <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary++data TestData3 = TestData3 Int64 TestData2 Int16 TestData Int8+    deriving (Show, Generic, GStorable, Eq)+instance Arbitrary TestData3 where+    arbitrary = TestData3 <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary+++sizeEquality a = do+    gsizeOf a `shouldBe` internalSizeOf (from a)++alignmentEquality a = do+    gsizeOf a `shouldBe` internalSizeOf (from a)++pokeEquality a = do+    let size = gsizeOf a+    off <- generate $ suchThat arbitrary (>=0)++    ptr <- mallocBytes (off + size)+    -- First poke+    gpokeByteOff ptr off a+    bytes1 <- peekArray (off+size) ptr :: IO [Word8]++    internalPokeByteOff ptr off (from a)+    bytes2 <- peekArray (off+size) ptr :: IO [Word8]++    free ptr+    bytes1 `shouldBe` bytes2            ++peekEquality (a :: t) = do+    let size = gsizeOf a+    off   <- generate $ suchThat arbitrary (>=0)+    ptr   <- mallocBytes (off + size)+    bytes <- generate $ ok_vector (off+size) :: IO [Word8]+   +    -- Save random stuff to memory+    pokeArray ptr bytes+   +    -- Take a peek+    v1 <- gpeekByteOff        ptr off :: IO t+    v2 <- internalPeekByteOff ptr off :: IO (Rep t p)++    free ptr+    +    v1 `shouldBe` to v2           +++peekAndPoke (a :: t)= do+    ptr   <- malloc :: IO (Ptr t)+    gpokeByteOff ptr 0 a+    (gpeekByteOff ptr 0) `shouldReturn` a+++spec :: Spec+spec = do+    describe "gsizeOf" $ do+        it "is equal to: internalSizeOf (from a)" $ property $ do +            test1 <- generate $ arbitrary :: IO TestData+            test2 <- generate $ arbitrary :: IO TestData2+            test3 <- generate $ arbitrary :: IO TestData3+            sizeEquality test1+            sizeEquality test2+            sizeEquality test3+    describe "galignment" $ do+        it "is equal to: internalAlignment (from a)" $ property $ do +            test1 <- generate $ arbitrary :: IO TestData+            test2 <- generate $ arbitrary :: IO TestData2+            test3 <- generate $ arbitrary :: IO TestData3+            alignmentEquality test1+            alignmentEquality test2+            alignmentEquality test3+    describe "gpokeByteOff" $ do+        it "is equal to: internalPokeByteOff ptr off (from a)" $ property $ do +            test1 <- generate $ arbitrary :: IO TestData+            test2 <- generate $ arbitrary :: IO TestData2+            test3 <- generate $ arbitrary :: IO TestData3+            pokeEquality test1+            pokeEquality test2+            pokeEquality test3+    describe "gpeekByteOff" $ do+        it "is equal to: to <$> internalPeekByteOff ptr off" $ property $ do +            test1 <- generate $ arbitrary :: IO TestData+            test2 <- generate $ arbitrary :: IO TestData2+            test3 <- generate $ arbitrary :: IO TestData3+            peekEquality test1+            peekEquality test2+            peekEquality test3+    describe "Other tests:" $ do+        it "gpokeByteOff ptr 0 val >> gpeekByteOff ptr 0 == val" $ property $ do        +            test1 <- generate $ arbitrary :: IO TestData+            test2 <- generate $ arbitrary :: IO TestData2+            test3 <- generate $ arbitrary :: IO TestData3+            peekAndPoke test1+            peekAndPoke test2+            peekAndPoke test3 
+ test/Spec/Foreign/Storable/Generic/InternalSpec.hs view
@@ -0,0 +1,158 @@+{-#LANGUAGE ScopedTypeVariables #-}+{-#LANGUAGE DeriveGeneric       #-}+{-#LANGUAGE DataKinds           #-}+{-#LANGUAGE GADTs               #-}+module Foreign.Storable.Generic.InternalSpec where+++-- Test tools+import Test.Hspec+import Test.QuickCheck+import GenericType ++-- Tested modules+import Foreign.Storable.Generic.Internal ++-- Additional data+import Foreign.Storable.Generic.Tools+import Foreign.Storable.Generic.Instances+import GHC.Generics+import Foreign.Marshal.Alloc (malloc, mallocBytes, free)+import Foreign.Marshal.Array (peekArray, pokeArray)+import Foreign.Ptr (Ptr, plusPtr)+import Data.Word++++spec :: Spec+spec = do +    describe "internalSizeOf" $ do+        it "is equal to: calcSize $ zip (glistSizeOf' a) (glistAlignment' a)" $ do+            property (\((NestedToType (GenericType val)) :: NestedToType 4) -> +                internalSizeOf val `shouldBe` (calcSize $ zip (glistSizeOf' val) (glistAlignment' val) ) )+    describe "internalAlignment" $ do+        it "is equal to: maximum (glistAlignment' a)" $ do+            property (\((NestedToType (GenericType val)) :: NestedToType 4) -> +                internalAlignment val `shouldBe` (maximum $ glistAlignment' val) )+    describe "internalOffsets" $ do+        it "is equal to: calcOffsets $ zip (glistSizeOf' a) (glistAlignment' a)" $ do+            property (\((NestedToType (GenericType val)) :: NestedToType 4) -> +                internalOffsets val `shouldBe` (calcOffsets $ zip (glistSizeOf' val) (glistAlignment' val) ) )+    describe "internalPeekByteOff" $ do+        it "is equal to: gpeekByteOff' (internalOffsets a) ptr off" $ do+            property (\((NestedToType (GenericType (val :: f p))) :: NestedToType 4) -> do+                let size      = internalSizeOf val+                    no_fields = gnumberOf' (undefined :: f p)+                off <- generate $ suchThat arbitrary (\x -> x>=0 && x < 100)+                +                -- Area in memory to peek+                bytes <- generate $ ok_vector (off + size)+                ptr <- mallocBytes (off + size)+                pokeArray ptr bytes+                +                -- first peek+                v1 <- internalPeekByteOff ptr off :: IO (f p)+                v2 <- gpeekByteOff' (internalOffsets val) (no_fields - 1) ptr off :: IO (f p)+                +                free ptr+                v1 `shouldBe` v2+                )+        it "it reads only specified area of the memory" $ do+            property $ (\((NestedToType (GenericType (test_type1 :: f p))) :: NestedToType 4) -> do    +                let size      = internalSizeOf test_type1 +                    pokeBytes = pokeArray :: (Ptr Word8 -> [Word8] -> IO ())+                -- The memory area+                ptr <- mallocBytes (size+16)+                +                -- Beginning state.+                bytes1_beginning <- generate $ ok_vector 8+                bytes1_middle    <- generate $ ok_vector size+                bytes1_end       <- generate $ ok_vector 8+                +                pokeBytes  ptr                   bytes1_beginning+                pokeBytes (plusPtr ptr 8)        bytes1_middle+                pokeBytes (plusPtr ptr (size+8)) bytes1_end+            +                v1 <- internalPeekByteOff ptr 8 :: IO (f p)+                +                -- Changed state +                bytes2_beginning <- generate $ suchThat (ok_vector 8) (/=bytes1_beginning)+                bytes2_end       <- generate $ suchThat (ok_vector 8) (/=bytes1_end)+                +                pokeBytes  ptr               bytes2_beginning+                pokeBytes (plusPtr ptr (size + 8)) bytes2_end+                +                v2 <- internalPeekByteOff ptr 8 :: IO (f p) + +                v1 `shouldBe` v2+                )+    describe "internalPokeByteOff" $ do+        it "is equal to: gpokeByteOff' (internalOffsets a) ptr off v" $ do+            property (\((NestedToType (GenericType (val :: f p))) :: NestedToType 4)  -> do+                let size = internalSizeOf val+                    no_fields = gnumberOf' (undefined :: f p)+                off <- generate $ suchThat arbitrary (\x -> x>=0 && x < 100)+                +                -- Area in memory to poke+                ptr <- mallocBytes (off + size)+                +                -- first poke+                internalPokeByteOff ptr off val+                bytes1 <- peekArray (off + size) ptr :: IO [Word8]+                +                -- second poke+                gpokeByteOff' (internalOffsets val) (no_fields - 1) ptr off val+                bytes2 <- peekArray (off + size) ptr :: IO [Word8]+ +                free ptr+                +                bytes1 `shouldBe` bytes2+                )+        it "it modifies only specified area of the memory" $ do+            property $ (\((NestedToType (GenericType test_type1)) ::NestedToType 4)-> do    +                test_type2 <- generate $ suchThat arbitrary (/=test_type1)+                -- if test_type1 is different from test_type2, then +                -- the memory state has to change when poking both of them+                let size = internalSizeOf test_type1 +                    peekBytes = peekArray :: (Int -> Ptr Word8 -> IO [Word8])+                -- The memory area+                ptr <- mallocBytes (size+16)+               +                -- Beginning state.+                mem_state1_beginning <- peekBytes 8     ptr                   +                mem_state1_middle    <- peekBytes size (plusPtr ptr 8)              +                mem_state1_end       <- peekBytes 8    (plusPtr ptr (size+8))+            +                internalPokeByteOff ptr 8 test_type1+                -- Poked first variable+                mem_state2_beginning <- peekBytes 8     ptr+                mem_state2_middle    <- peekBytes size (plusPtr ptr 8)+                mem_state2_end       <- peekBytes 8    (plusPtr ptr (size+8))+            +                internalPokeByteOff ptr 8 test_type2+                -- Poked second state+                mem_state3_beginning <- peekBytes 8     ptr+                mem_state3_middle    <- peekBytes size (plusPtr ptr 8)+                mem_state3_end       <- peekBytes 8    (plusPtr ptr (size+8))+                +  +                -- Beginnings and ends should stay the same. The middle one should be different from+                -- the one at the beginning.+                sequence_ [mem_state1_beginning `shouldBe` mem_state2_beginning+                          ,mem_state2_beginning `shouldBe` mem_state3_beginning+                          ,mem_state1_end       `shouldBe` mem_state2_end                  +                          ,mem_state2_end       `shouldBe` mem_state3_end+                          ,(mem_state1_middle /= mem_state2_middle) || (mem_state1_middle /= mem_state3_middle) `shouldBe` True]+                )+    describe "other" $ do+        it "poke, then peek: receive the poked value" $ do+            property $ (\((NestedToType (GenericType (val :: f p) )) :: NestedToType 4) -> do+                let size = internalSizeOf val+                off <- generate $ suchThat arbitrary (\x -> x>=0 && x < 100)+                +                ptr <- mallocBytes (size + off)++                internalPokeByteOff ptr off val+                p_val <- internalPeekByteOff ptr off :: IO (f p) +                val `shouldBe` p_val+                ) 
+ test/Spec/Foreign/Storable/Generic/ToolsSpec.hs view
@@ -0,0 +1,29 @@+module Foreign.Storable.Generic.ToolsSpec where++--Tested modules+import Foreign.Storable.Generic.Tools++import Test.Hspec+import Test.QuickCheck++spec :: Spec +spec = do +    describe "getFilling" $ do+        it "getFilling [(2,2),(4,4),(1,1),(2,2)] == [Size 2, Padding 2, Size 4, Size 1, Padding 1, Size 2]" $ do+            getFilling [(2,2),(4,4),(1,1),(2,2)] `shouldBe` [Size 2, Padding 2, Size 4, Size 1, Padding 1, Size 2]+        it "getFilling [] = []" $ do+            getFilling [] `shouldBe` []+    describe "calcSize" $ do+        it "calcSize [] = 0" $ do+            calcSize [] `shouldBe` 0+        it "is equal to sum of padding" $ do+            let summer (Padding a) = a+                summer (Size    a) = a+            property $ do+                ls <- generate $ listOf $ suchThat arbitrary (\(a,b) -> a > 0 && b > 0)+                calcSize ls `shouldBe` (sum $ map summer $ getFilling ls)+    describe "calcOffsets" $ do+        it "calcOffsets [(2,2),(4,4),(1,1),(2,2)] == [0,4,8,10]" $ do+            calcOffsets [(2,2),(4,4),(1,1),(2,2)] `shouldBe` [0,4,8,10]+        it "calcOffsets [] = []" $ do+            calcOffsets [] `shouldBe` []