packages feed

unboxing-vector 0.1.0.0 → 0.1.1.0

raw patch · 17 files changed

+527/−106 lines, 17 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Vector.Unboxing: Enum :: a -> Enum a
+ Data.Vector.Unboxing: EnumRep :: a -> EnumRep rep a
+ Data.Vector.Unboxing: newtype Enum a
+ Data.Vector.Unboxing: newtype EnumRep rep a
+ Data.Vector.Unboxing.Mutable: Enum :: a -> Enum a
+ Data.Vector.Unboxing.Mutable: EnumRep :: a -> EnumRep rep a
+ Data.Vector.Unboxing.Mutable: newtype Enum a
+ Data.Vector.Unboxing.Mutable: newtype EnumRep rep a

Files

ChangeLog.md view
@@ -1,5 +1,11 @@ # Changelog for unboxing-vector +## Version 0.1.1.0 (2019-07-01)++- Support older GHC versions.+- Add `Enum` and `EnumRep` wrappers.+- Add `Unboxable` instance for `Ordering`.+ ## Version 0.1.0.0 (2019-06-17)  Initial release with
README.md view
@@ -1,5 +1,7 @@-# unboxing-vector+# unboxing-vector: A newtype-friendly variant of unboxed vectors +[![Build Status](https://travis-ci.org/minoki/unboxing-vector.svg?branch=master)](https://travis-ci.org/minoki/unboxing-vector)+ This package provides newtype-friendly wrappers for `Data.Vector.Unboxed` in [`vector` package](http://hackage.haskell.org/package/vector).  ## Description@@ -7,48 +9,69 @@ Suppose you define a newtype for `Int` and want to store them in an unboxed vector.  ```haskell+import qualified Data.Vector.Unboxed as Unboxed+ newtype Foo = Foo Int -generate 10 (\i -> Foo i) :: Data.Vector.Unboxed.Vector Foo+vec :: Unboxed.Vector Foo+vec = Unboxed.generate 10 (\i -> Foo i) ``` -With plain `Data.Vector.Unboxed`, you either write two dozen of lines of code to get it work (the exact code is [here](https://github.com/minoki/unboxing-vector/blob/3a152014b9660ef1e2885d6b9c66423064223f63/test/Foo.hs#L36-L63)), or resort to Template Haskell ([`vector-th-unbox` package](http://hackage.haskell.org/package/vector-th-unbox)) to generate it.+With classic `Data.Vector.Unboxed`, you either write _two dozen of lines_ of code to get it work (the exact code is [here](https://github.com/minoki/unboxing-vector/blob/3a152014b9660ef1e2885d6b9c66423064223f63/test/Foo.hs#L36-L63)), or resort to Template Haskell ([`vector-th-unbox` package](http://hackage.haskell.org/package/vector-th-unbox)) to generate it. -But with `Data.Vector.Unboxing`, the code you write is just two lines:+Now you have the third option, namely `Data.Vector.Unboxing`.+With `Data.Vector.Unboxing`, the amount of code you write is just _two lines_:  ```haskell-instance Data.Vector.Unboxing.Unboxable Foo where+import qualified Data.Vector.Unboxing as Unboxing++instance Unboxing.Unboxable Foo where   type Rep Foo = Int -generate 10 (\i -> Foo i) :: Data.Vector.Unboxing.Vector Foo+vec :: Unboxing.Vector Foo+vec = Unboxing.generate 10 (\i -> Foo i) ```  ...and if you want to be even more concise, you can derive `Unboxable` instance with `GeneralizedNewtypeDeriving`.  Note that the vector type provided by this package (`Data.Vector.Unboxing.Vector`) is *different* from `Data.Vector.Unboxed.Vector`.+If you need to convert `Unboxing.Vector` to `Unboxed.Vector`, or vice versa, use `Unboxing.toUnboxedVector` or `Unboxing.fromUnboxedVector`. -The module defining the type `Foo` does not need to export its constructor to enable use of `Vector Foo`.+The module defining the type `Foo` does not need to export its constructor to enable use of `Unboxing.Vector Foo`.+In that case, the users of the abstract data type cannot convert between `Unboxing.Vector Int` and `Unboxing.Vector Foo` --- the abstraction is kept!  ## For non-newtypes -Suppose you define a datatype isomorphic to a tuple of primitive types, like:+Suppose you define a data type isomorphic to a tuple, like:  ```haskell data ComplexDouble = MkComplexDouble {-# UNPACK #-} !Double {-# UNPACK #-} !Double ``` -In this example, `ComplexDouble` is isomorphic to `(Double, Double)`, but has a different representation. Thus, you cannot derive `Data.Vector.Unboxing.Unboxable` from `(Double, Double)`.+In this example, `ComplexDouble` is isomorphic to `(Double, Double)`, but has a different representation. Thus, you cannot derive `Unboxing.Unboxable` from `(Double, Double)`.  For such cases, unboxing-vector provides a feature to derive `Unboxable` using `Generic`.+Use `Unboxing.Generics` newtype wrapper to derive it.  ```haskell {-# LANGUAGE DeriveGeneric, DerivingVia, UndecidableInstances #-} -data ComplexDouble = ..+data ComplexDouble = MkComplexDouble {-# UNPACK #-} !Double {-# UNPACK #-} !Double   deriving Generic   deriving Data.Vector.Unboxing.Unboxable via Data.Vector.Unboxing.Generics ComplexDouble ``` +Unboxing via `fromEnum`/`toEnum` is also available.+Use `Unboxing.Enum` or `Unboxing.EnumRep` to derive it.++```haskell+{-# LANGUAGE DerivingVia, UndecidableInstances #-}++data Direction = North | South | East | West+  deriving Enum+  deriving Unboxing.Unboxable via Unboxing.EnumRep Int8 Direction+```+ ## Conversion  ### Conversion from/to Unboxed vector@@ -78,3 +101,15 @@ and :: Unboxing.Vector Bool -> Bool and vec = getAll $ ofold (Unboxing.coerceVector vec :: Unboxing.Vector All) -- fails because the data constructor is not in scope ```++## Supported GHC versions++The library itself is tested with GHC 8.0.2 or later.++To use `GeneralizedNewtypeDeriving` on `Unboxable` class, you need GHC 8.2 or later,+because GND for associated type families became available on that version.++`DerivingVia` is avaliable since GHC 8.6.1.+This means that, defining an `Unboxable` instance for user-defined `data` types (like `ComplexDouble` or `Direction` in this document) requires a latest GHC.++If you want a way to make your `data` types on older GHCs, please [open an issue on GitHub](https://github.com/minoki/unboxing-vector/issues).
src/Data/Vector/Unboxing.hs view
@@ -3,6 +3,8 @@   (Vector   ,Unboxable(Rep)   ,Generics(..)+  ,Enum(..)+  ,EnumRep(..)   -- * Accessors   -- ** Length information   ,length,null@@ -83,7 +85,8 @@   ,freeze,thaw,copy,unsafeFreeze,unsafeThaw,unsafeCopy   ) where -import Prelude (Monad,Int,Bool,Maybe,Traversable,Eq,Num,Enum,Ord,Ordering)+import Prelude (Monad,Int,Bool,Maybe,Traversable,Eq,Num,Ord,Ordering)+import qualified Prelude import qualified Data.Vector.Generic as G import Data.Vector.Generic (convert) import Data.Vector.Unboxing.Internal@@ -266,11 +269,11 @@ enumFromStepN = G.enumFromStepN {-# INLINE enumFromStepN #-} -enumFromTo :: (Enum a, Unboxable a) => a -> a -> Vector a+enumFromTo :: (Prelude.Enum a, Unboxable a) => a -> a -> Vector a enumFromTo = G.enumFromTo {-# INLINE enumFromTo #-} -enumFromThenTo :: (Enum a, Unboxable a) => a -> a -> a -> Vector a+enumFromThenTo :: (Prelude.Enum a, Unboxable a) => a -> a -> a -> Vector a enumFromThenTo = G.enumFromThenTo {-# INLINE enumFromThenTo #-} 
src/Data/Vector/Unboxing/Internal.hs view
@@ -6,7 +6,6 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-}@@ -17,6 +16,8 @@   ,Vector(UnboxingVector)   ,MVector(UnboxingMVector)   ,Generics(..)+  ,Enum(..)+  ,EnumRep(..)   ,coerceVector   ,liftCoercion   ,vectorCoercion@@ -27,6 +28,8 @@   ,fromUnboxedMVector   ,coercionWithUnboxedMVector   ) where+import Prelude hiding (Enum)+import qualified Prelude import qualified Data.Vector.Generic as G import qualified Data.Vector.Generic.Mutable as GM import qualified Data.Vector.Unboxed as U@@ -135,9 +138,9 @@ coercionWithUnboxedMVector = Coercion {-# INLINE coercionWithUnboxedMVector #-} -------+-- -- Generics+--  -- | A newtype wrapper to be used with @DerivingVia@. --@@ -148,13 +151,13 @@ -- >   deriving Unboxable via Generics Bar newtype Generics a = Generics a -instance (GHC.Generics.Generic a, Unboxable (Rep' (GHC.Generics.Rep a)), Unboxable' (GHC.Generics.Rep a)) => Unboxable (Generics a) where-  type Rep (Generics a) = Rep (Rep' (GHC.Generics.Rep a))+instance (GHC.Generics.Generic a, U.Unbox (Rep' (GHC.Generics.Rep a)), Unboxable' (GHC.Generics.Rep a)) => Unboxable (Generics a) where+  type Rep (Generics a) = Rep' (GHC.Generics.Rep a)   type CoercibleRep (Generics a) = a   type IsTrivial (Generics a) = 'False-  unboxingFrom (Generics x) = unboxingFrom (from' (GHC.Generics.from x))+  unboxingFrom (Generics x) = from' (GHC.Generics.from x)   {-# INLINE unboxingFrom #-}-  unboxingTo y = Generics (GHC.Generics.to (to' (unboxingTo y)))+  unboxingTo y = Generics (GHC.Generics.to (to' y))   {-# INLINE unboxingTo #-}  class Unboxable' f where@@ -190,9 +193,48 @@   from' = undefined   to' = undefined ------+--+-- Enum+-- +-- | A newtype wrapper to be used with @DerivingVia@.+-- The value will be stored as 'Int', via `fromEnum`/`toEnum`.+--+-- Usage:+--+-- > data Direction = North | South | East | West+-- >   deriving Enum+-- >   deriving Data.Vector.Unboxing.Unboxable via Data.Vector.Unboxing.Enum Bar+newtype Enum a = Enum a+instance (Prelude.Enum a) => Unboxable (Enum a) where+  type Rep (Enum a) = Int+  type CoercibleRep (Enum a) = a+  type IsTrivial (Enum a) = 'False+  unboxingFrom (Enum x) = fromEnum x+  {-# INLINE unboxingFrom #-}+  unboxingTo y = Enum (toEnum y)+  {-# INLINE unboxingTo #-}++-- | A newtype wrapper to be used with @DerivingVia@.+--+-- Usage:+--+-- > data Direction = North | South | East | West+-- >   deriving Enum+-- >   deriving Data.Vector.Unboxing.Unboxable via Data.Vector.Unboxing.EnumRep Int8 Bar+newtype EnumRep rep a = EnumRep a+instance (Prelude.Enum a, Integral rep, U.Unbox rep) => Unboxable (EnumRep rep a) where+  type Rep (EnumRep rep a) = rep+  type CoercibleRep (EnumRep rep a) = a+  type IsTrivial (EnumRep rep a) = 'False+  unboxingFrom (EnumRep x) = fromIntegral (fromEnum x)+  {-# INLINE unboxingFrom #-}+  unboxingTo y = EnumRep (toEnum (fromIntegral y))+  {-# INLINE unboxingTo #-}++-- -- Instances+--  instance (Unboxable a) => IsList (Vector a) where   type Item (Vector a) = a@@ -223,15 +265,15 @@   {-# INLINE readPrec #-}   {-# INLINE readListPrec #-} -instance (Unboxable a) => Semigroup (Vector a) where+instance (Unboxable a) => Data.Semigroup.Semigroup (Vector a) where   (<>) = (G.++)   sconcat = G.concatNE   {-# INLINE (<>) #-}   {-# INLINE sconcat #-} -instance (Unboxable a) => Monoid (Vector a) where+instance (Unboxable a) => Data.Monoid.Monoid (Vector a) where   mempty = G.empty-  mappend = (<>)+  mappend = (Data.Semigroup.<>)   mconcat = G.concat   {-# INLINE mempty #-}   {-# INLINE mappend #-}@@ -283,9 +325,9 @@   {-# INLINE basicUnsafeCopy #-}   {-# INLINE elemseq #-} -------+-- -- Classes from mono-traversable+--  type instance Data.MonoTraversable.Element (Vector a) = a @@ -432,9 +474,9 @@   {-# INLINE indexEx #-}   {-# INLINE unsafeIndex #-} -------+-- -- Unboxable instances+--  instance Unboxable Bool where   type Rep Bool = Bool instance Unboxable Char where   type Rep Char = Char@@ -506,16 +548,111 @@   {-# INLINE unboxingFrom #-}   {-# INLINE unboxingTo #-} -deriving instance Unboxable a => Unboxable (Data.Functor.Identity.Identity a)-deriving instance Unboxable a => Unboxable (Data.Functor.Const.Const a b)-deriving instance Unboxable a => Unboxable (Data.Semigroup.Min a)-deriving instance Unboxable a => Unboxable (Data.Semigroup.Max a)-deriving instance Unboxable a => Unboxable (Data.Semigroup.First a)-deriving instance Unboxable a => Unboxable (Data.Semigroup.Last a)-deriving instance Unboxable a => Unboxable (Data.Semigroup.WrappedMonoid a)-deriving instance Unboxable a => Unboxable (Data.Monoid.Dual a)-deriving instance Unboxable Data.Monoid.All-deriving instance Unboxable Data.Monoid.Any-deriving instance Unboxable a => Unboxable (Data.Monoid.Sum a)-deriving instance Unboxable a => Unboxable (Data.Monoid.Product a)-deriving instance Unboxable a => Unboxable (Data.Ord.Down a)+{-+GND for type classes with associated type families is not available until GHC 8.2.+With GHC 8.2 or later, one can derive these instances like:++> deriving instance Unboxable a => Unboxable (Data.Functor.Identity.Identity a)+> deriving instance Unboxable a => Unboxable (Data.Functor.Const.Const a b)+> deriving instance Unboxable a => Unboxable (Data.Semigroup.Min a)+> deriving instance Unboxable a => Unboxable (Data.Semigroup.Max a)+> deriving instance Unboxable a => Unboxable (Data.Semigroup.First a)+> deriving instance Unboxable a => Unboxable (Data.Semigroup.Last a)+> deriving instance Unboxable a => Unboxable (Data.Semigroup.WrappedMonoid a)+> deriving instance Unboxable a => Unboxable (Data.Monoid.Dual a)+> deriving instance Unboxable Data.Monoid.All+> deriving instance Unboxable Data.Monoid.Any+> deriving instance Unboxable a => Unboxable (Data.Monoid.Sum a)+> deriving instance Unboxable a => Unboxable (Data.Monoid.Product a)+> deriving instance Unboxable a => Unboxable (Data.Ord.Down a)+-}++instance Unboxable a => Unboxable (Data.Functor.Identity.Identity a) where+  type Rep (Data.Functor.Identity.Identity a) = Rep a+  unboxingFrom = coerce (unboxingFrom @a)+  unboxingTo = coerce (unboxingTo @a)+  {-# INLINE unboxingFrom #-}+  {-# INLINE unboxingTo #-}++instance Unboxable a => Unboxable (Data.Functor.Const.Const a b) where+  type Rep (Data.Functor.Const.Const a b) = Rep a+  unboxingFrom = coerce (unboxingFrom @a)+  unboxingTo = coerce (unboxingTo @a)+  {-# INLINE unboxingFrom #-}+  {-# INLINE unboxingTo #-}++instance Unboxable a => Unboxable (Data.Semigroup.Min a) where+  type Rep (Data.Semigroup.Min a) = Rep a+  unboxingFrom = coerce (unboxingFrom @a)+  unboxingTo = coerce (unboxingTo @a)+  {-# INLINE unboxingFrom #-}+  {-# INLINE unboxingTo #-}++instance Unboxable a => Unboxable (Data.Semigroup.Max a) where+  type Rep (Data.Semigroup.Max a) = Rep a+  unboxingFrom = coerce (unboxingFrom @a)+  unboxingTo = coerce (unboxingTo @a)+  {-# INLINE unboxingFrom #-}+  {-# INLINE unboxingTo #-}++instance Unboxable a => Unboxable (Data.Semigroup.First a) where+  type Rep (Data.Semigroup.First a) = Rep a+  unboxingFrom = coerce (unboxingFrom @a)+  unboxingTo = coerce (unboxingTo @a)+  {-# INLINE unboxingFrom #-}+  {-# INLINE unboxingTo #-}++instance Unboxable a => Unboxable (Data.Semigroup.Last a) where+  type Rep (Data.Semigroup.Last a) = Rep a+  unboxingFrom = coerce (unboxingFrom @a)+  unboxingTo = coerce (unboxingTo @a)+  {-# INLINE unboxingFrom #-}+  {-# INLINE unboxingTo #-}++instance Unboxable a => Unboxable (Data.Semigroup.WrappedMonoid a) where+  type Rep (Data.Semigroup.WrappedMonoid a) = Rep a+  unboxingFrom = coerce (unboxingFrom @a)+  unboxingTo = coerce (unboxingTo @a)+  {-# INLINE unboxingFrom #-}+  {-# INLINE unboxingTo #-}++instance Unboxable a => Unboxable (Data.Monoid.Dual a) where+  type Rep (Data.Monoid.Dual a) = Rep a+  unboxingFrom = coerce (unboxingFrom @a)+  unboxingTo = coerce (unboxingTo @a)+  {-# INLINE unboxingFrom #-}+  {-# INLINE unboxingTo #-}++instance Unboxable Data.Monoid.All where+  type Rep Data.Monoid.All = Bool++instance Unboxable Data.Monoid.Any where+  type Rep Data.Monoid.Any = Bool++instance Unboxable a => Unboxable (Data.Monoid.Sum a) where+  type Rep (Data.Monoid.Sum a) = Rep a+  unboxingFrom = coerce (unboxingFrom @a)+  unboxingTo = coerce (unboxingTo @a)+  {-# INLINE unboxingFrom #-}+  {-# INLINE unboxingTo #-}++instance Unboxable a => Unboxable (Data.Monoid.Product a) where+  type Rep (Data.Monoid.Product a) = Rep a+  unboxingFrom = coerce (unboxingFrom @a)+  unboxingTo = coerce (unboxingTo @a)+  {-# INLINE unboxingFrom #-}+  {-# INLINE unboxingTo #-}++instance Unboxable a => Unboxable (Data.Ord.Down a) where+  type Rep (Data.Ord.Down a) = Rep a+  unboxingFrom = coerce (unboxingFrom @a)+  unboxingTo = coerce (unboxingTo @a)+  {-# INLINE unboxingFrom #-}+  {-# INLINE unboxingTo #-}++instance Unboxable Ordering where+  type Rep Ordering = Int8+  unboxingFrom x = fromIntegral (fromEnum x)+  unboxingTo y = toEnum (fromIntegral y)+  {-# INLINE unboxingFrom #-}+  {-# INLINE unboxingTo #-}
src/Data/Vector/Unboxing/Mutable.hs view
@@ -4,6 +4,8 @@   ,STVector   ,Unboxable(Rep)   ,Generics(..)+  ,Enum(..)+  ,EnumRep(..)   -- * Accessors   -- ** Length information   ,length,null
+ test-deriving-via/Enum.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE UndecidableInstances #-}+module Enum where+import qualified Data.Vector.Unboxing as V+import Data.Int++data OrderingEq = LT | LE | EQ | GE | GT+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+  deriving V.Unboxable via V.Enum OrderingEq++data Direction = North | South | East | West+  deriving (Eq, Ord, Enum, Bounded, Read, Show)+  deriving V.Unboxable via V.EnumRep Int8 Direction
+ test-deriving-via/Foo.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE MultiParamTypeClasses #-}+module Foo+  (Foo -- the constructor is not exported!+  ,mkFoo+  ) where+import Data.Vector.Unboxing (Unboxable(..))+import qualified Data.Vector.Unboxed as U+import qualified Data.Vector.Unboxed.Mutable as UM+import qualified Data.Vector.Generic as G+import qualified Data.Vector.Generic.Mutable as GM+import Control.DeepSeq (NFData)+import GHC.Generics+import Data.Coerce++newtype Foo = Foo Int deriving (Eq,Show,Generic)++instance NFData Foo++mkFoo :: Foo+mkFoo = Foo 42++-- Comparison of Data.Vector.Unboxing and Data.Vector.Unboxed:++-- The number of lines needed to enable 'Data.Vector.Unboxing.Vector Foo' is ...++instance Unboxable Foo where+  type Rep Foo = Int -- needs TypeFamilies here++-- ... only 2 lines!+-- Also, you can use GeneralizedNewtypeDeriving + UndecidableInstances if you want to write less.++-- On the other hand, the number of lines needed to enable 'Data.Vector.Unboxed.Vector Foo' is ...++newtype instance UM.MVector s Foo = MV_Foo (UM.MVector s Int)+newtype instance U.Vector Foo = V_Foo (U.Vector Int)++instance GM.MVector UM.MVector Foo where -- needs MultiParamTypeClasses here+  basicLength (MV_Foo mv) = GM.basicLength mv+  basicUnsafeSlice i l (MV_Foo mv) = MV_Foo (GM.basicUnsafeSlice i l mv)+  basicOverlaps (MV_Foo mv) (MV_Foo mv') = GM.basicOverlaps mv mv'+  basicUnsafeNew l = MV_Foo <$> GM.basicUnsafeNew l+  basicInitialize (MV_Foo mv) = GM.basicInitialize mv+  basicUnsafeReplicate i x = MV_Foo <$> GM.basicUnsafeReplicate i (coerce x)+  basicUnsafeRead (MV_Foo mv) i = coerce <$> GM.basicUnsafeRead mv i+  basicUnsafeWrite (MV_Foo mv) i x = GM.basicUnsafeWrite mv i (coerce x)+  basicClear (MV_Foo mv) = GM.basicClear mv+  basicSet (MV_Foo mv) x = GM.basicSet mv (coerce x)+  basicUnsafeCopy (MV_Foo mv) (MV_Foo mv') = GM.basicUnsafeCopy mv mv'+  basicUnsafeMove (MV_Foo mv) (MV_Foo mv') = GM.basicUnsafeMove mv mv'+  basicUnsafeGrow (MV_Foo mv) n = MV_Foo <$> GM.basicUnsafeGrow mv n++instance G.Vector U.Vector Foo where -- needs MultiParamTypeClasses here+  basicUnsafeFreeze (MV_Foo mv) = V_Foo <$> G.basicUnsafeFreeze mv+  basicUnsafeThaw (V_Foo v) = MV_Foo <$> G.basicUnsafeThaw v+  basicLength (V_Foo v) = G.basicLength v+  basicUnsafeSlice i l (V_Foo v) = V_Foo (G.basicUnsafeSlice i l v)+  basicUnsafeIndexM (V_Foo v) i = coerce <$> G.basicUnsafeIndexM v i+  basicUnsafeCopy (MV_Foo mv) (V_Foo v) = G.basicUnsafeCopy mv v+  elemseq (V_Foo v) x y = G.elemseq v (coerce x) y++instance U.Unbox Foo++-- ... enormous!+-- Unfortunately, you cannot use GeneralizedNewtypeDeriving to MVector/Vector classes.
+ test-deriving-via/Generic.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE UndecidableInstances #-}+module Generic where+import Test.HUnit+import qualified Data.Vector.Unboxing as V+import GHC.Generics+import Foo (Foo,mkFoo)+import Enum (Direction(North))++-- Deriving using Generic+data ComplexDouble = ComplexDouble { realPartD :: {-# UNPACK #-} !Double+                                   , imagPartD :: {-# UNPACK #-} !Double+                                   }+  deriving (Eq,Show,Generic)+  deriving V.Unboxable via V.Generics ComplexDouble++testComplexDouble = TestCase $ do+  let v :: V.Vector ComplexDouble+      v = V.singleton (ComplexDouble 1.0 2.0)+      x :: V.Vector Double+      x = V.map realPartD v+  assertEqual "construction" (ComplexDouble 1.0 2.0) (V.head v)+  assertEqual "map" (V.singleton 1.0) x++data Bar = Bar {-# UNPACK #-} !Foo {-# UNPACK #-} !Double !Direction+  deriving (Eq,Show,Generic)+  deriving V.Unboxable via V.Generics Bar++testBar = TestCase $ do+  let v :: V.Vector Bar+      v = V.singleton (Bar mkFoo 3.14 North)+  assertEqual "construction" (Bar mkFoo 3.14 North) (V.head v)+  assertEqual "map" (V.singleton mkFoo) (V.map (\(Bar foo _ _) -> foo) v)
+ test-deriving-via/Spec.hs view
@@ -0,0 +1,11 @@+import Prelude+import Test.HUnit+---+import Generic+import Enum++tests = TestList [TestLabel "Test with generic 1" testComplexDouble+                 ,TestLabel "Test with generic 2" testBar+                 ]++main = runTestTT tests
+ test-deriving-via/TestTypeErrors.hs view
@@ -0,0 +1,19 @@+-- {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -fdefer-type-errors -Wno-deferred-type-errors #-}+module TestTypeErrors where+import Test.HUnit+import Test.ShouldNotTypecheck+import qualified Data.Vector.Unboxing as V+import GHC.Generics++data Animal = Dog | Cat+  deriving (Eq,Show,Generic)+  deriving V.Unboxable via V.Generics Animal++testTypeErrors :: Test+testTypeErrors = TestList [TestLabel "Test generic deriving for a sum type" $ TestCase $ shouldNotTypecheck (V.singleton Dog)+                          ]+
+ test-gnd/Foo.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE UndecidableInstances #-}+module Foo+  (Foo -- the constructor is not exported!+  ,mkFoo+  ) where+import Data.Vector.Unboxing (Unboxable(..))+import Control.DeepSeq (NFData)+import GHC.Generics++newtype Foo = Foo Int deriving (Eq,Show,Generic,Unboxable)++instance NFData Foo++mkFoo :: Foo+mkFoo = Foo 42
+ test-gnd/Spec.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE UndecidableInstances #-}+import Prelude+import Test.HUnit+import qualified Data.Vector.Unboxing as V+import Data.Monoid (Sum(..))+import Data.MonoTraversable (ofold)+---+import Foo (Foo,mkFoo)++newtype IntMod17 = IntMod17 Int+  deriving (Eq,Show)+  deriving newtype V.Unboxable -- with DerivingStrategies++instance Num IntMod17 where+  IntMod17 x + IntMod17 y = IntMod17 ((x + y) `rem` 17)+  IntMod17 x - IntMod17 y = IntMod17 ((x - y) `mod` 17)+  IntMod17 x * IntMod17 y = IntMod17 ((x * y) `rem` 17)+  negate (IntMod17 x) = IntMod17 (negate x `mod` 17)+  fromInteger x = IntMod17 (fromIntegral (x `mod` 17))+  abs = undefined; signum = undefined++testIntMod17 = TestCase $ do+  let v = V.fromList [-3,-2,-1,0,1,2,3,4,5] :: V.Vector IntMod17+  assertEqual "construction" (V.fromList [14,15,16,0,1,2,3,4,5]) v+  assertEqual "sum" 9 (V.sum v) -- not 60+  assertEqual "coercion" (V.fromList [14,15,16,0,1,2,3,4,5] :: V.Vector Int) (V.coerceVector v) -- this is possible because the constructor of IntMod17 is visible here+  let vSum = V.coerceVector v :: V.Vector (Sum IntMod17)+  assertEqual "coercion and sum" (Sum 9) (ofold vSum)++newtype Baz = Baz Foo+  deriving (Eq,Show,V.Unboxable)++testBaz = TestCase $ do+  let foo :: V.Vector Foo+      foo = V.singleton mkFoo+      baz :: V.Vector Baz+      baz = V.singleton (Baz mkFoo)+  assertEqual "construction" (Baz mkFoo) (V.head baz)+  assertEqual "map 1" baz (V.map Baz foo)+  assertEqual "map 2" foo (V.map (\(Baz x) -> x) baz)+  assertEqual "coercion" baz (V.coerceVector foo)++-- We can make an unboxed vector of Foo, even though we don't have 'Coercible Int Foo' in scope.+testAbstractType = TestCase $ do+  let v = V.singleton mkFoo :: V.Vector Foo+  assertEqual "Foo" mkFoo (V.head v)+  assertEqual "coercion" mkFoo (getSum $ V.head (V.coerceVector v :: V.Vector (Sum Foo)))++tests = TestList [TestLabel "Basic features" testIntMod17+                 ,TestLabel "Test with abstract type" testAbstractType+                 ,TestLabel "Test with GND" testBaz+                 ]++main = runTestTT tests
− test/Generic.hs
@@ -1,33 +0,0 @@-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DerivingVia #-}-{-# LANGUAGE UndecidableInstances #-}-module Generic where-import Test.HUnit-import qualified Data.Vector.Unboxing as V-import GHC.Generics-import Foo (Foo,mkFoo)---- Deriving using Generic-data ComplexDouble = ComplexDouble { realPartD :: {-# UNPACK #-} !Double-                                   , imagPartD :: {-# UNPACK #-} !Double-                                   }-  deriving (Eq,Show,Generic)-  deriving V.Unboxable via V.Generics ComplexDouble--testComplexDouble = TestCase $ do-  let v :: V.Vector ComplexDouble-      v = V.singleton (ComplexDouble 1.0 2.0)-      x :: V.Vector Double-      x = V.map realPartD v-  assertEqual "construction" (ComplexDouble 1.0 2.0) (V.head v)-  assertEqual "map" (V.singleton 1.0) x--data Bar = Bar {-# UNPACK #-} !Foo {-# UNPACK #-} !Double-  deriving (Eq,Show,Generic)-  deriving V.Unboxable via V.Generics Bar--testBar = TestCase $ do-  let v :: V.Vector Bar-      v = V.singleton (Bar mkFoo 3.14)-  assertEqual "construction" (Bar mkFoo 3.14) (V.head v)-  assertEqual "map" (V.singleton mkFoo) (V.map (\(Bar foo _) -> foo) v)
+ test/Loop.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE DerivingStrategies #-}+-- {-# LANGUAGE DerivingVia #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE TypeFamilies #-}+module Loop where+import qualified Data.Vector.Unboxing as V+import GHC.Generics++-- Loop!+{-+newtype Bad = Bad Bad+  deriving newtype V.Unboxable+-}++{-+data Bad2 = Bad2 Bad2+  deriving Generic+  deriving V.Unboxable via V.Generics Bad2+-}++{-+class SomeClass a where+  type Foo a+--   foo :: a -> Foo a++newtype Bad = Bad Bad+  deriving newtype SomeClass++newtype BadT = BadT (Int, BadT)+  deriving newtype V.Unboxable+-}
test/Spec.hs view
@@ -11,7 +11,6 @@ --- import TestTypeErrors import Foo (Foo,mkFoo)-import Generic  testInt = TestCase $ do   let v = V.fromList [2,-5,42] :: V.Vector Int@@ -21,7 +20,6 @@  newtype IntMod17 = IntMod17 Int   deriving (Eq,Show)---  deriving newtype VF.Unboxable  instance V.Unboxable IntMod17 where   type Rep IntMod17 = Int@@ -42,19 +40,6 @@   let vSum = V.coerceVector v :: V.Vector (Sum IntMod17)   assertEqual "coercion and sum" (Sum 9) (ofold vSum) -newtype Baz = Baz Foo-  deriving (Eq,Show,V.Unboxable)--testBaz = TestCase $ do-  let foo :: V.Vector Foo-      foo = V.singleton mkFoo-      baz :: V.Vector Baz-      baz = V.singleton (Baz mkFoo)-  assertEqual "construction" (Baz mkFoo) (V.head baz)-  assertEqual "map 1" baz (V.map Baz foo)-  assertEqual "map 2" foo (V.map (\(Baz x) -> x) baz)-  assertEqual "coercion" baz (V.coerceVector foo)- -- We can make an unboxed vector of Foo, even though we don't have 'Coercible Int Foo' in scope. testAbstractType = TestCase $ do   let v = V.singleton mkFoo :: V.Vector Foo@@ -65,10 +50,6 @@                  ,TestLabel "Conversion with Data.Vector.Unboxed" testInt                  ,TestLabel "Test with abstract type" testAbstractType                  ,TestLabel "Check for type errors" testTypeErrors-                 ,TestLabel "Test with generic 1" testComplexDouble-                 ,TestLabel "Test with generic 2" testBar-                 ,TestLabel "Test with GND" testBaz                  ]  main = runTestTT tests-
test/TestTypeErrors.hs view
@@ -1,7 +1,4 @@ {-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DerivingVia #-}-{-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fdefer-type-errors -Wno-deferred-type-errors #-} module TestTypeErrors where import Test.HUnit@@ -9,7 +6,6 @@ import Data.Coerce import qualified Data.Vector.Unboxing as V import Foo (Foo)-import GHC.Generics  -- Since the module Foo does not export Foo's constructor, -- it should be impossible to create a value of Foo in this module.@@ -30,14 +26,9 @@ intToFoo3 :: (V.Unboxable a, a ~ Foo) => Int -> a intToFoo3 x = coerce x -data Animal = Dog | Cat-  deriving (Eq,Show,Generic)-  deriving V.Unboxable via V.Generics Animal- testTypeErrors :: Test testTypeErrors = TestList [TestLabel "Basic test for coerce" $ TestCase $ shouldNotTypecheck (intToFoo1 0xDEAD)                           ,TestLabel "Test for coerceVector" $ TestCase $ shouldNotTypecheck (intToFoo2 0xDEAD)                           ,TestLabel "Test for Unboxable" $ TestCase $ shouldNotTypecheck (intToFoo3 0xDEAD)-                          ,TestLabel "Test generic deriving for a sum type" $ TestCase $ shouldNotTypecheck (V.singleton Dog)                           ] 
unboxing-vector.cabal view
@@ -4,11 +4,11 @@ -- -- see: https://github.com/sol/hpack ----- hash: 6f43e3e12c9aa312cf1e18e1bc60132a5cb9878c463bd2b9863a20ea6c7125cf+-- hash: 8fec698d5a4391032074d2a71e767bc6f667b179e962ed429de29ca13c44b918  name:           unboxing-vector-version:        0.1.0.0-synopsis:       Newtype-friendly Unboxed Vectors+version:        0.1.1.0+synopsis:       A newtype-friendly variant of unboxed vectors description:    Please see the README on GitHub at <https://github.com/minoki/unboxing-vector#readme> category:       Data, Data Structures homepage:       https://github.com/minoki/unboxing-vector#readme@@ -49,7 +49,7 @@   main-is: Spec.hs   other-modules:       Foo-      Generic+      Loop       TestTypeErrors       Paths_unboxing_vector   hs-source-dirs:@@ -64,6 +64,56 @@     , should-not-typecheck     , unboxing-vector     , vector+  default-language: Haskell2010++test-suite unboxing-vector-test-deriving-via+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules:+      Enum+      Foo+      Generic+      TestTypeErrors+      Paths_unboxing_vector+  hs-source-dirs:+      test-deriving-via+  ghc-options: -Wall -Wno-missing-signatures+  build-depends:+      HUnit+    , base >=4.9 && <5+    , deepseq+    , mono-traversable+    , primitive+    , should-not-typecheck+    , unboxing-vector+    , vector+  if impl(ghc >= 8.6.1)+    buildable: True+  else+    buildable: False+  default-language: Haskell2010++test-suite unboxing-vector-test-gnd+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules:+      Foo+      Paths_unboxing_vector+  hs-source-dirs:+      test-gnd+  ghc-options: -Wall -Wno-missing-signatures+  build-depends:+      HUnit+    , base >=4.9 && <5+    , deepseq+    , mono-traversable+    , primitive+    , unboxing-vector+    , vector+  if impl(ghc >= 8.2.1)+    buildable: True+  else+    buildable: False   default-language: Haskell2010  benchmark unboxing-vector-benchmark