Skip to content

Commit b43b2dd

Browse files
andrewthadRyanGlScott
authored andcommitted
Add PrimStorable for deriving getting a Storable instance from a Prim instance (#136)
* Add PrimStorable for deriving getting a Storable instance from a Prim instance * fix name of example type in docs for PrimStorable * add tests to be run once GHC 8.6 comes out
1 parent 81b0e26 commit b43b2dd

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

Data/Primitive/Types.hs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{-# LANGUAGE CPP, UnboxedTuples, MagicHash, DeriveDataTypeable #-}
22
{-# LANGUAGE GeneralizedNewtypeDeriving, StandaloneDeriving #-}
3+
{-# LANGUAGE ScopedTypeVariables #-}
34
#if __GLASGOW_HASKELL__ >= 800
45
{-# LANGUAGE TypeInType #-}
56
#endif
@@ -22,6 +23,7 @@ module Data.Primitive.Types (
2223
sizeOf, alignment,
2324

2425
Addr(..),
26+
PrimStorable(..)
2527
) where
2628

2729
import Control.Monad.Primitive
@@ -55,8 +57,11 @@ import GHC.Prim
5557
import Data.Typeable ( Typeable )
5658
import Data.Data ( Data(..) )
5759
import Data.Primitive.Internal.Compat ( isTrue#, mkNoRepType )
60+
import Foreign.Storable (Storable)
5861
import Numeric
5962

63+
import qualified Foreign.Storable as FS
64+
6065
-- | A machine address
6166
data Addr = Addr Addr# deriving ( Typeable )
6267

@@ -130,6 +135,28 @@ sizeOf x = I# (sizeOf# x)
130135
alignment :: Prim a => a -> Int
131136
alignment x = I# (alignment# x)
132137

138+
-- | Newtype that uses a 'Prim' instance to give rise to a 'Storable' instance.
139+
-- This type is intended to be used with the @DerivingVia@ extension available
140+
-- in GHC 8.6 and up. For example, consider a user-defined 'Prim' instance for
141+
-- a multi-word data type.
142+
--
143+
-- > data Uuid = Uuid Word64 Word64
144+
-- > deriving Storable via (PrimStorable Uuid)
145+
-- > instance Prim Uuid where ...
146+
--
147+
-- Writing the 'Prim' instance is tedious and unavoidable, but the 'Storable'
148+
-- instance comes for free once the 'Prim' instance is written.
149+
newtype PrimStorable a = PrimStorable { getPrimStorable :: a }
150+
151+
instance Prim a => Storable (PrimStorable a) where
152+
sizeOf _ = sizeOf (undefined :: a)
153+
alignment _ = alignment (undefined :: a)
154+
peekElemOff (Ptr addr#) (I# i#) =
155+
primitive $ \s0# -> case readOffAddr# addr# i# s0# of
156+
(# s1, x #) -> (# s1, PrimStorable x #)
157+
pokeElemOff (Ptr addr#) (I# i#) (PrimStorable a) = primitive_ $ \s# ->
158+
writeOffAddr# addr# i# a s#
159+
133160
#define derivePrim(ty, ctr, sz, align, idx_arr, rd_arr, wr_arr, set_arr, idx_addr, rd_addr, wr_addr, set_addr) \
134161
instance Prim (ty) where { \
135162
sizeOf# _ = unI# sz \

test/main.hs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ main = do
119119
, TQC.testProperty "mapMaybePrimArrayP" (QCCL.mapMaybeMProp int16 int32 mapMaybePrimArrayP)
120120
#endif
121121
]
122+
-- , testGroup "PrimStorable"
123+
-- [ lawsToTest (QCC.storableLaws (Proxy :: Proxy Derived))
124+
-- ]
122125
]
123126

124127
int16 :: Proxy Int16
@@ -276,3 +279,12 @@ iforM_ xs0 f = go 0 xs0 where
276279
go !_ [] = return ()
277280
go !ix (x : xs) = f ix x >> go (ix + 1) xs
278281

282+
-- TODO: Uncomment this out when GHC 8.6 is release. Also, uncomment
283+
-- the corresponding PrimStorable test group above.
284+
--
285+
-- newtype Derived = Derived Int16
286+
-- deriving newtype (Prim)
287+
-- deriving Storable via (PrimStorable Derived)
288+
289+
290+

0 commit comments

Comments
 (0)