{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} -- | This module gives ways to force the alignment of types. module Raaz.Core.Types.Aligned ( -- * Types to force alignment. Aligned, unAligned, aligned16Bytes, aligned32Bytes, aligned64Bytes ) where #if MIN_VERSION_base(4,7,0) import Data.Proxy #endif import GHC.TypeLits import Foreign.Ptr ( castPtr ) import Foreign.Storable ( Storable(..) ) import Prelude hiding ( length ) -- | A type @w@ forced to be aligned to the alignment boundary @alg@ newtype Aligned (align :: Nat) w = Aligned { unAligned :: w -- ^ The underlying unAligned value. } -- | Align the value to 16-byte boundary aligned16Bytes :: w -> Aligned 16 w {-# INLINE aligned16Bytes #-} -- | Align the value to 32-byte boundary aligned32Bytes :: w -> Aligned 32 w {-# INLINE aligned32Bytes #-} -- | Align the value to 64-byte boundary aligned64Bytes :: w -> Aligned 64 w {-# INLINE aligned64Bytes #-} aligned16Bytes = Aligned aligned32Bytes = Aligned aligned64Bytes = Aligned #if MIN_VERSION_base(4,7,0) -- | The constraint on the alignment o(since base 4.7.0). type AlignBoundary (alg :: Nat) = KnownNat alg alignmentBoundary :: AlignBoundary alg => Aligned alg a -> Int alignmentBoundary = aB Proxy where aB :: AlignBoundary algn => Proxy algn -> Aligned algn a -> Int aB algn _ = fromEnum $ natVal algn #else -- | The constraint on the alignment (pre base 4.7.0). type AlignBoundary (alg :: Nat) = SingI alg alignmentBoundary :: AlignBoundary algn => Aligned algn a -> Int alignmentBoundary = withSing aB where aB :: AlignBoundary algn => Sing algn -> Aligned algn a -> Int aB algn _ = fromEnum $ fromSing algn #endif instance (Storable a, AlignBoundary alg) => Storable (Aligned alg a) where sizeOf = sizeOf . unAligned alignment alg = lcm valueAlignment forceAlignment where valueAlignment = alignment $ unAligned alg forceAlignment = alignmentBoundary alg peek = fmap Aligned . peek . castPtr poke ptr = poke (castPtr ptr) . unAligned