proto3-suite-0.9.4: src/Proto3/Suite/Types.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE ExplicitNamespaces #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Proto3.Suite.Types
(
-- * Integral Types
Fixed(..)
, Signed(..)
-- * Enumerable Types
, Enumerated(..)
, codeFromEnumerated
, codeToEnumerated
-- * String and Bytes Types
, String(..)
, Bytes(..)
, ForceEmit(..)
, Nested(..)
, UnpackedVec(..)
, PackedVec(..)
, NestedVec(..)
, Commented(..)
, type (//)()
) where
import Control.Applicative
import Control.DeepSeq (NFData)
import GHC.Exts (IsList(..))
import GHC.Generics (Generic)
import Data.Function (on)
import Data.Int (Int32)
import qualified Data.Vector as V
import GHC.TypeLits (Symbol)
import Prelude hiding (String)
import Proto3.Wire.Class (ProtoEnum(..))
import Test.QuickCheck (Arbitrary(..))
-- | 'Fixed' provides a way to encode integers in the fixed-width wire formats.
newtype Fixed a = Fixed { fixed :: a }
deriving (Show, Eq, Ord, Num, Generic, NFData, Arbitrary, Enum, Bounded
, Functor, Foldable, Traversable)
-- | 'Signed' provides a way to encode integers in the signed wire formats.
newtype Signed a = Signed { signed :: a }
deriving (Show, Eq, Ord, Num, Generic, NFData, Arbitrary, Bounded
, Functor, Foldable, Traversable)
-- | 'Enumerated' lifts any type with an 'IsEnum' instance so that it can be encoded
-- with 'HasEncoding'.
newtype Enumerated a = Enumerated { enumerated :: Either Int32 a }
deriving (Show, Generic, NFData, Functor, Foldable, Traversable)
-- | We consider two enumerated values to be equal if they serialize to the same code.
instance ProtoEnum a => Eq (Enumerated a) where
(==) = (==) `on` either id fromProtoEnum . enumerated
{-# INLINABLE (==) #-}
-- | We compare two enumerated values by comparing the code to which they serialize.
instance ProtoEnum a => Ord (Enumerated a) where
compare = compare `on` either id fromProtoEnum . enumerated
{-# INLINABLE compare #-}
instance ProtoEnum a => Arbitrary (Enumerated a) where
arbitrary = do
i <- arbitrary
return . Enumerated $ maybe (Left i) Right (toProtoEnumMay i)
-- | Pass through those values that are outside the enum range;
-- this is for forward compatibility as enumerations are extended.
codeFromEnumerated :: ProtoEnum e => Enumerated e -> Int32
codeFromEnumerated = either id fromProtoEnum . enumerated
{-# INLINE codeFromEnumerated #-}
-- | Values inside the enum range are in Right, the rest in Left;
-- this is for forward compatibility as enumerations are extended.
codeToEnumerated :: ProtoEnum e => Int32 -> Enumerated e
codeToEnumerated code = Enumerated (maybe (Left code) Right (toProtoEnumMay code))
{-# INLINE codeToEnumerated #-}
-- | 'String' provides a way to indicate that the given type expresses
-- a Protobuf string scalar. @'String' a@ may have type class instances
-- that are more specific to Protobuf uses than those of @a@.
newtype String a = String { string :: a }
deriving (Show, Eq, Ord, Generic, Monoid, NFData, Arbitrary,
Functor, Foldable, Semigroup, Traversable)
-- | 'Bytes' provides a way to indicate that the given type expresses
-- a Protobuf bytes scalar. @'Bytes' a@ may have type class instances
-- that are more specific to Protobuf uses than those of @a@.
newtype Bytes a = Bytes { bytes :: a }
deriving (Show, Eq, Ord, Generic, Monoid, NFData, Arbitrary,
Functor, Foldable, Semigroup, Traversable)
-- | 'PackedVec' provides a way to encode packed lists of basic protobuf types into
-- the wire format.
newtype PackedVec a = PackedVec { packedvec :: V.Vector a }
deriving (Show, Eq, Functor, Foldable, Traversable, Ord, NFData, Applicative,
Alternative, Monoid, Semigroup)
instance IsList (PackedVec a) where
type Item (PackedVec a) = a
fromList = PackedVec . V.fromList
toList = V.toList . packedvec
instance Arbitrary a => Arbitrary (PackedVec a) where
arbitrary = fmap (PackedVec . V.fromList) arbitrary
newtype UnpackedVec a = UnpackedVec {unpackedvec :: V.Vector a }
deriving (Show, Eq, Functor, Foldable, Traversable, Ord, NFData, Applicative,
Alternative, Monoid, Semigroup)
instance IsList (UnpackedVec a) where
type Item (UnpackedVec a) = a
fromList = UnpackedVec . V.fromList
toList = V.toList . unpackedvec
instance Arbitrary a => Arbitrary (UnpackedVec a) where
arbitrary = fmap (UnpackedVec . V.fromList) arbitrary
newtype NestedVec a =
NestedVec { nestedvec :: V.Vector a }
deriving (Show, Eq, Functor, Foldable, Traversable, Ord, NFData, Applicative,
Alternative, Monoid, Semigroup)
instance IsList (NestedVec a) where
type Item (NestedVec a) = a
fromList = NestedVec . V.fromList
toList = V.toList . nestedvec
instance Arbitrary a => Arbitrary (NestedVec a) where
arbitrary = fmap (NestedVec . V.fromList) arbitrary
-- | 'Nested' provides a way to nest protobuf messages within protobuf messages.
newtype Nested a = Nested { nested :: Maybe a }
deriving (Show, Eq, Ord, Generic, NFData, Monoid, Arbitrary, Functor, Foldable,
Traversable, Applicative, Alternative, Monad, Semigroup)
-- | 'ForceEmit' provides a way to force emission of field values,
-- even when they have the default value. Used for @optional@ fields
-- and fields that are part of a @oneof@.
newtype ForceEmit a = ForceEmit{ forceEmit :: a }
deriving (Show, Eq, Ord, Generic, NFData, Monoid, Arbitrary, Functor, Foldable,
Traversable, Semigroup)
-- | 'Commented' provides a way to add comments to generated @.proto@ files.
newtype Commented (comment :: Symbol) a = Commented { unCommented :: a }
deriving (Show, Eq, Ord, Generic, NFData, Monoid, Arbitrary, Functor, Foldable, Traversable, Semigroup)
-- | A type operator synonym for 'Commented', so that we can write C-style
-- comments on fields.
type a // (comment :: Symbol) = Commented comment a