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
2729import Control.Monad.Primitive
@@ -55,8 +57,11 @@ import GHC.Prim
5557import Data.Typeable ( Typeable )
5658import Data.Data ( Data (.. ) )
5759import Data.Primitive.Internal.Compat ( isTrue #, mkNoRepType )
60+ import Foreign.Storable (Storable )
5861import Numeric
5962
63+ import qualified Foreign.Storable as FS
64+
6065-- | A machine address
6166data Addr = Addr Addr # deriving ( Typeable )
6267
@@ -130,6 +135,28 @@ sizeOf x = I# (sizeOf# x)
130135alignment :: Prim a => a -> Int
131136alignment 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) \
134161instance Prim (ty ) where { \
135162 sizeOf# _ = unI# sz \
0 commit comments