File: Main.hs

package info (click to toggle)
haskell-bytestring-to-vector 0.3.0.1-6
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 76 kB
  • sloc: haskell: 89; makefile: 6
file content (93 lines) | stat: -rw-r--r-- 2,692 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
{-# LANGUAGE
    ScopedTypeVariables #-}

module Main
    ( main
    )
where

import qualified Data.ByteString               as B
import qualified Data.Vector.Storable          as V

import           Data.Word
import           System.ByteOrder   -- package 'byteorder'
import           Test.QuickCheck
import           Foreign.Storable

import           Data.Vector.Storable.ByteString


arbList :: (Bounded a, Integral a) => Gen [a]
arbList = choose (0, 16384) >>= flip vectorOf arbitraryBoundedIntegral

instance Arbitrary B.ByteString where
    arbitrary = fmap B.pack arbList

instance (Bounded a, Integral a, Storable a) => Arbitrary (V.Vector a) where
    arbitrary = fmap V.fromList arbList


-- Reference implementations

fromBE, fromHost :: (Integral a) => [Word8] -> a
fromBE = foldl (\n x -> n * 256 + fromIntegral x) 0
fromHost = case byteOrder of
    LittleEndian -> fromBE . reverse
    BigEndian    -> fromBE

toLE, toHost :: (Integral a) => Int -> a -> [Word8]
toLE sz = take sz . map (fromIntegral . (`mod` 256)) . iterate (`div` 256)
toHost = case byteOrder of
    LittleEndian -> toLE
    BigEndian    -> \sz -> reverse . toLE sz

data Rep a = Rep Int ([Word8] -> a) (a -> [Word8])

rep8 :: Rep Word8
rep8 = Rep 1 (\[x] -> x) return

repN :: forall a . (Storable a, Integral a) => Rep a
repN = let n = sizeOf (undefined :: a) in Rep n fromHost (toHost n)

ref_byteStringToVector :: (Storable a) => Rep a -> B.ByteString -> V.Vector a
ref_byteStringToVector (Rep n f _) = V.fromList . go  where
    go bs = case B.splitAt n bs of
        (x, xs) | B.length x == n -> f (B.unpack x) : go xs
        _                         -> []

ref_vectorToByteString :: (Storable a) => Rep a -> V.Vector a -> B.ByteString
ref_vectorToByteString (Rep _ _ f) = B.pack . concatMap f . V.toList


-- Properties

mkProp_inv _ x = byteStringToVector (vectorToByteString x) == x
mkProp_inv_ref r x = ref_byteStringToVector r (ref_vectorToByteString r x) == x

mkProp_inv_ref1 r x = ref_byteStringToVector r (vectorToByteString x) == x
mkProp_inv_ref2 r x = byteStringToVector (ref_vectorToByteString r x) == x

mkProp_eq_BV r x = ref_byteStringToVector r x == byteStringToVector x
mkProp_eq_VB r x = ref_vectorToByteString r x == vectorToByteString x


-- Test runner

runFor :: (Integral a, Bounded a, Storable a, Show a) => Rep a -> IO ()
runFor r = do
    mapM_
        (quickCheck . ($ r))
        [ mkProp_inv
        , mkProp_inv_ref
        , mkProp_inv_ref1
        , mkProp_inv_ref2
        , mkProp_eq_VB
        ]
    quickCheck (mkProp_eq_BV r)

main :: IO ()
main = do
    runFor rep8
    runFor (repN :: Rep Word16)
    runFor (repN :: Rep Word32)
    runFor (repN :: Rep Word64)