geomancy-0.4.0.0: test/Support/Swizzle.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Support.Swizzle
( Lanes(..)
, Mismatch
, swizzled
, swizzles
) where
import Data.Int (Int32, Int64)
import Data.Maybe (catMaybes, fromMaybe)
import Data.Proxy (Proxy(..))
import Data.Word (Word32, Word64)
import GHC.Float (castDoubleToWord64, castFloatToWord32)
import GHC.Records (HasField(..))
import GHC.TypeLits (KnownSymbol, symbolVal)
import Hedgehog
import Geomancy
import Support.Property (pattern PROP_TESTS)
class Lanes v where
lanes :: v -> [Word64]
instance Lanes Float where
lanes x = [fromIntegral (castFloatToWord32 x)]
instance Lanes Double where
lanes x = [castDoubleToWord64 x]
instance Lanes Int32 where
lanes x = [fromIntegral x]
instance Lanes Word32 where
lanes x = [fromIntegral x]
instance Lanes Int64 where
lanes x = [fromIntegral x]
instance Lanes Word64 where
lanes x = [x]
instance Lanes Vec2 where
lanes v = withVec2 v \x y -> concatMap lanes [x, y]
instance Lanes Vec3 where
lanes v = withVec3 v \x y z -> concatMap lanes [x, y, z]
instance Lanes Vec4 where
lanes v = withVec4 v \x y z w -> concatMap lanes [x, y, z, w]
instance Lanes DVec2 where
lanes v = withDVec2 v \x y -> concatMap lanes [x, y]
instance Lanes DVec3 where
lanes v = withDVec3 v \x y z -> concatMap lanes [x, y, z]
instance Lanes DVec4 where
lanes v = withDVec4 v \x y z w -> concatMap lanes [x, y, z, w]
instance Lanes IVec2 where
lanes v = withIVec2 v \x y -> concatMap lanes [x, y]
instance Lanes IVec3 where
lanes v = withIVec3 v \x y z -> concatMap lanes [x, y, z]
instance Lanes IVec4 where
lanes v = withIVec4 v \x y z w -> concatMap lanes [x, y, z, w]
instance Lanes UVec2 where
lanes v = withUVec2 v \x y -> concatMap lanes [x, y]
instance Lanes UVec3 where
lanes v = withUVec3 v \x y z -> concatMap lanes [x, y, z]
instance Lanes UVec4 where
lanes v = withUVec4 v \x y z w -> concatMap lanes [x, y, z, w]
instance Lanes I64Vec2 where
lanes v = withI64Vec2 v \x y -> concatMap lanes [x, y]
instance Lanes I64Vec3 where
lanes v = withI64Vec3 v \x y z -> concatMap lanes [x, y, z]
instance Lanes I64Vec4 where
lanes v = withI64Vec4 v \x y z w -> concatMap lanes [x, y, z, w]
instance Lanes U64Vec2 where
lanes v = withU64Vec2 v \x y -> concatMap lanes [x, y]
instance Lanes U64Vec3 where
lanes v = withU64Vec3 v \x y z -> concatMap lanes [x, y, z]
instance Lanes U64Vec4 where
lanes v = withU64Vec4 v \x y z w -> concatMap lanes [x, y, z, w]
data Mismatch = Mismatch String [Word64] [Word64]
deriving (Eq, Show)
swizzles :: Show v => Gen v -> (v -> [Maybe Mismatch]) -> Property
swizzles gen checks = withTests PROP_TESTS $ property do
v <- forAll gen
catMaybes (checks v) === []
swizzled
:: forall s v r
. (KnownSymbol s, HasField s v r, Lanes v, Lanes r, Num r)
=> v
-> Maybe Mismatch
swizzled v =
if expected == actual then
Nothing
else
Just (Mismatch name expected actual)
where
name = symbolVal (Proxy @s)
expected = concatMap lane name
actual = lanes (getField @s v)
lane c = fromMaybe (error $ "no lane " <> [c]) $ lookup c (zip "xyzw" (map pure (lanes v)) <> constants)
constants = [('0', splat 0), ('1', splat 1)]
splat x = take 1 (lanes (x :: r))