pinch-0.3.4.1: An alternative implementation of Thrift for Haskell.

Copyright(c) Abhinav Gupta 2015
LicenseBSD3
MaintainerAbhinav Gupta <mail@abhinavg.net>
Stabilityexperimental
Safe HaskellNone
LanguageHaskell2010

Pinch

Contents

Description

Pinch defines machinery to specify how types can be encoded into or decoded from Thrift payloads.

Synopsis

Serializing and deserializing

Types that can be serialized and deserialized into/from Thrift values implement the Pinchable typeclass. Instances may be derived automatically using generics, or written out by hand.

The Pinchable typeclass converts objects into and from Value objects, which act as a direct mapping to the Thrift wire representation. A Protocol is responsible for converting Value objects to and from bytestrings.

The encode and decode methods may be used on objects that implement the Pinchable typeclass to get the wire representation directly.

+------------+   Pinchable                    Protocol    +------------+
|            |               +------------+               |            |
|            +----pinch------>            +---serialize--->            |
| Your Type  |               |  Value a   |               | ByteString |
|            <---unpinch-----+            <--deserialize--+            |
|            |               +------------+               |            |
|            |                                            |            |
|            +-------------------encode------------------->            |
|            |                                            |            |
|            <-------------------decode-------------------+            |
+------------+                                            +------------+

encode :: Pinchable a => Protocol -> a -> ByteString Source #

Encode the given Pinchable value using the given Protocol.

>>> unpack $ encode binaryProtocol ["a" :: ByteString, "b"]
[11,0,0,0,2,0,0,0,1,97,0,0,0,1,98]

decode :: Pinchable a => Protocol -> ByteString -> Either String a Source #

Decode a Pinchable value from the using the given Protocol.

>>> let s = pack [11,0,0,0,2,0,0,0,1,97,0,0,0,1,98]
>>> decode binaryProtocol s :: Either String [ByteString]
Right ["a","b"]

RPC

Thrift requests implicitly form a struct and responses implicitly form a union. To send/receive the request/response, it must be wrapped inside a Message. The Message contains information like the method name, the message ID (to match out of order responses with requests), and whether it contains a request or a response.

Requests and responses may be wrapped into Message objects using the mkMessage function. The message body can be retrieved back using the getMessageBody function. The encodeMessage and decodeMessage functions may be used to encode and decode messages into/from bytestrings.

Consider the service method,

User getUser(1: string userName, 2: list<Attribute> attributes)
  throws (1: UserDoesNotExist doesNotExist,
          2: InternalError internalError)

The request and response for this method implictly take the form:

struct getUserRequest {
  1: string userName
  2: list<Attribute> attributes
}
union getUserResponse {
  0: User success
  1: UserDoesNotExist doesNotExist
  2: InternalError InternalError
}

(Note that the field ID 0 is reserved for the return value of the method.)

Given corresponding data types GetUserRequest and GetUserResponse, the client can do something similar to,

let req = GetUserRequest "jsmith" []
    msg = mkMessage "getUser" Call 0 req
response <- sendToServer (encodeMessage msg)
case decodeMessage response of
    Left err -> handleError err
    Right msg -> case getMessageBody msg of
        Left err -> handleError err
        Right (res :: GetUserResponse) -> handleResponse res

Similarly, on the server side,

case decodeMessage request of
    Left err -> handleError err
    Right msg -> case messageName msg of
        "getUser" -> case getMessageBody msg of
            Left err -> handleError err
            Right (req :: GetUserRequest) -> do
                let mid = messageId msg
                res <- handleGetUser req
                return (mkMessage "getUser" Reply mid res)
                -- Note that the response MUST contain the same
                -- message ID as its request.
        _ -> handleUnknownMethod

encodeMessage :: Protocol -> Message -> ByteString Source #

Encode the Message using the given Protocol.

let request = GetUserRequest (putField "jsmith") (putField [])
    message = mkMessage "getUser" Call 42 request
in encodeMessage binaryProtocol message

decodeMessage :: Protocol -> ByteString -> Either String Message Source #

Decode a Message using the given Protocol.

>>> decodeMessage binaryProtocol bs >>= getMessageBody :: Either String GetUserRequest
Right (GetUserRequest {userName = Field "jsmith", userAttributes = Field []})

Pinchable

class IsTType (Tag a) => Pinchable a where Source #

The Pinchable type class is implemented by types that can be sent or received over the wire as Thrift payloads.

Minimal complete definition

Nothing

Associated Types

type Tag a Source #

TType tag for this type.

For most custom types, this will be TStruct, TUnion, or TException. For enums, it will be TEnum. If the instance automatically derived with use of Generic, this is not required because it is automatically determined by use of Field or Enumeration.

Methods

pinch :: a -> Value (Tag a) Source #

Convert an a into a Value.

For structs, struct, .=, and ?= may be used to construct Value objects tagged with TStruct.

unpinch :: Value (Tag a) -> Parser a Source #

Read a Value back into an a.

For structs, .: and .:? may be used to retrieve field values.

pinch :: (Generic a, Tag a ~ GTag (Rep a), GPinchable (Rep a)) => a -> Value (Tag a) Source #

Convert an a into a Value.

For structs, struct, .=, and ?= may be used to construct Value objects tagged with TStruct.

unpinch :: (Generic a, Tag a ~ GTag (Rep a), GPinchable (Rep a)) => Value (Tag a) -> Parser a Source #

Read a Value back into an a.

For structs, .: and .:? may be used to retrieve field values.

Instances
Pinchable Bool Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag Bool :: Type Source #

Pinchable Double Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag Double :: Type Source #

Pinchable Int8 Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag Int8 :: Type Source #

Pinchable Int16 Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag Int16 :: Type Source #

Pinchable Int32 Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag Int32 :: Type Source #

Pinchable Int64 Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag Int64 :: Type Source #

Pinchable ByteString Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag ByteString :: Type Source #

Pinchable ByteString Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag ByteString :: Type Source #

Pinchable Text Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag Text :: Type Source #

Pinchable Text Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag Text :: Type Source #

Pinchable a => Pinchable [a] Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag [a] :: Type Source #

Methods

pinch :: [a] -> Value (Tag [a]) Source #

unpinch :: Value (Tag [a]) -> Parser [a] Source #

(Ord a, Pinchable a) => Pinchable (Set a) Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag (Set a) :: Type Source #

Methods

pinch :: Set a -> Value (Tag (Set a)) Source #

unpinch :: Value (Tag (Set a)) -> Parser (Set a) Source #

(Eq a, Hashable a, Pinchable a) => Pinchable (HashSet a) Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag (HashSet a) :: Type Source #

Pinchable a => Pinchable (Vector a) Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag (Vector a) :: Type Source #

Methods

pinch :: Vector a -> Value (Tag (Vector a)) Source #

unpinch :: Value (Tag (Vector a)) -> Parser (Vector a) Source #

IsTType a => Pinchable (Value a) Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag (Value a) :: Type Source #

Methods

pinch :: Value a -> Value (Tag (Value a)) Source #

unpinch :: Value (Tag (Value a)) -> Parser (Value a) Source #

(Ord k, Pinchable k, Pinchable v) => Pinchable (Map k v) Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag (Map k v) :: Type Source #

Methods

pinch :: Map k v -> Value (Tag (Map k v)) Source #

unpinch :: Value (Tag (Map k v)) -> Parser (Map k v) Source #

(Eq k, Hashable k, Pinchable k, Pinchable v) => Pinchable (HashMap k v) Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag (HashMap k v) :: Type Source #

Methods

pinch :: HashMap k v -> Value (Tag (HashMap k v)) Source #

unpinch :: Value (Tag (HashMap k v)) -> Parser (HashMap k v) Source #

data Parser a Source #

A simple continuation-based parser.

This is just Either e a in continuation-passing style.

Instances
Monad Parser Source # 
Instance details

Defined in Pinch.Internal.Pinchable.Parser

Methods

(>>=) :: Parser a -> (a -> Parser b) -> Parser b #

(>>) :: Parser a -> Parser b -> Parser b #

return :: a -> Parser a #

fail :: String -> Parser a #

Functor Parser Source # 
Instance details

Defined in Pinch.Internal.Pinchable.Parser

Methods

fmap :: (a -> b) -> Parser a -> Parser b #

(<$) :: a -> Parser b -> Parser a #

Applicative Parser Source # 
Instance details

Defined in Pinch.Internal.Pinchable.Parser

Methods

pure :: a -> Parser a #

(<*>) :: Parser (a -> b) -> Parser a -> Parser b #

liftA2 :: (a -> b -> c) -> Parser a -> Parser b -> Parser c #

(*>) :: Parser a -> Parser b -> Parser b #

(<*) :: Parser a -> Parser b -> Parser a #

Alternative Parser Source # 
Instance details

Defined in Pinch.Internal.Pinchable.Parser

Methods

empty :: Parser a #

(<|>) :: Parser a -> Parser a -> Parser a #

some :: Parser a -> Parser [a] #

many :: Parser a -> Parser [a] #

MonadPlus Parser Source # 
Instance details

Defined in Pinch.Internal.Pinchable.Parser

Methods

mzero :: Parser a #

mplus :: Parser a -> Parser a -> Parser a #

runParser :: Parser a -> Either String a Source #

Run a Parser and return the result inside an Either.

Automatically deriving instances

Pinch supports deriving instances of Pinchable automatically for types that implement the Generic typeclass provided that they follow the outlined patterns in their constructors.

Structs and exceptions

Given the struct,

struct User {
  1: required string name
  2: optional string emailAddress
}

A Pinchable instance for it can be automatically derived by wrapping fields of the data type with the Field type and specifying the field identifier as a type-level numeral. Fields which hold a Maybe value are considered optional.

data User = User
    { userName         :: Field 1 Text
    , userEmailAddress :: Field 2 (Maybe Text)
    }
  deriving (Generic)

instance Pinchable User

The DeriveGeneric extension is required to automatically derive instances of the Generic typeclass and the DataKinds extension is required to use type-level numerals.

Unions

As with structs and exceptions, fields of the data type representing a union must be tagged with Field, but to satisfy the property of a union that only one value is set at a time, they must be on separate constructors.

For example, given the union,

union Item {
  1: binary bin
  2: string str
  3: i32    int
}

A Pinchable instance can be derived like so,

data Item
    = ItemBin (Field 1 ByteString)
    | ItemStr (Field 2 Text)
    | ItemInt (Field 3 Int32)
  deriving (Generic)

instance Pinchable Item

The DeriveGeneric extension is required to automatically derive instances of the Generic typeclass and the DataKinds extension is required to use type-level numerals.

If the union represents the response of a service method which returns a void result, the type Void may be used.

data GetFooResponse
  = GetFooDoesNotExist  (Field 1 FooDoesNotExist)
  | GetFooInternalError (Field 2 InternalError)
  | GetFooSuccess Void

newtype Field (n :: Nat) a Source #

Fields of data types that represent structs, unions, and exceptions should be wrapped inside Field and tagged with the field identifier.

data Foo = Foo (Field 1 Text) (Field 2 (Maybe Int32)) deriving Generic
instance Pinchable Foo
data A = A (Field 1 Int32) | B (Field 2 Text) deriving Generic
instance Pinchable Foo

Fields which hold Maybe values are treated as optional. All fields values must be Pinchable to automatically derive a Pinchable instance for the new data type.

Constructors

Field a 
Instances
Functor (Field n) Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

fmap :: (a -> b) -> Field n a -> Field n b #

(<$) :: a -> Field n b -> Field n a #

Foldable (Field n) Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

fold :: Monoid m => Field n m -> m #

foldMap :: Monoid m => (a -> m) -> Field n a -> m #

foldr :: (a -> b -> b) -> b -> Field n a -> b #

foldr' :: (a -> b -> b) -> b -> Field n a -> b #

foldl :: (b -> a -> b) -> b -> Field n a -> b #

foldl' :: (b -> a -> b) -> b -> Field n a -> b #

foldr1 :: (a -> a -> a) -> Field n a -> a #

foldl1 :: (a -> a -> a) -> Field n a -> a #

toList :: Field n a -> [a] #

null :: Field n a -> Bool #

length :: Field n a -> Int #

elem :: Eq a => a -> Field n a -> Bool #

maximum :: Ord a => Field n a -> a #

minimum :: Ord a => Field n a -> a #

sum :: Num a => Field n a -> a #

product :: Num a => Field n a -> a #

Traversable (Field n) Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

traverse :: Applicative f => (a -> f b) -> Field n a -> f (Field n b) #

sequenceA :: Applicative f => Field n (f a) -> f (Field n a) #

mapM :: Monad m => (a -> m b) -> Field n a -> m (Field n b) #

sequence :: Monad m => Field n (m a) -> m (Field n a) #

Bounded a => Bounded (Field n a) Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

minBound :: Field n a #

maxBound :: Field n a #

Enum a => Enum (Field n a) Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

succ :: Field n a -> Field n a #

pred :: Field n a -> Field n a #

toEnum :: Int -> Field n a #

fromEnum :: Field n a -> Int #

enumFrom :: Field n a -> [Field n a] #

enumFromThen :: Field n a -> Field n a -> [Field n a] #

enumFromTo :: Field n a -> Field n a -> [Field n a] #

enumFromThenTo :: Field n a -> Field n a -> Field n a -> [Field n a] #

Eq a => Eq (Field n a) Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

(==) :: Field n a -> Field n a -> Bool #

(/=) :: Field n a -> Field n a -> Bool #

Ord a => Ord (Field n a) Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

compare :: Field n a -> Field n a -> Ordering #

(<) :: Field n a -> Field n a -> Bool #

(<=) :: Field n a -> Field n a -> Bool #

(>) :: Field n a -> Field n a -> Bool #

(>=) :: Field n a -> Field n a -> Bool #

max :: Field n a -> Field n a -> Field n a #

min :: Field n a -> Field n a -> Field n a #

Show a => Show (Field n a) Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

showsPrec :: Int -> Field n a -> ShowS #

show :: Field n a -> String #

showList :: [Field n a] -> ShowS #

Generic (Field n a) Source # 
Instance details

Defined in Pinch.Internal.Generic

Associated Types

type Rep (Field n a) :: Type -> Type #

Methods

from :: Field n a -> Rep (Field n a) x #

to :: Rep (Field n a) x -> Field n a #

Semigroup a => Semigroup (Field n a) Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

(<>) :: Field n a -> Field n a -> Field n a #

sconcat :: NonEmpty (Field n a) -> Field n a #

stimes :: Integral b => b -> Field n a -> Field n a #

Monoid a => Monoid (Field n a) Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

mempty :: Field n a #

mappend :: Field n a -> Field n a -> Field n a #

mconcat :: [Field n a] -> Field n a #

NFData a => NFData (Field n a) Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

rnf :: Field n a -> () #

(Pinchable a, KnownNat n) => GPinchable (K1 i (Field n (Maybe a)) :: Type -> Type) Source # 
Instance details

Defined in Pinch.Internal.Generic

Associated Types

type GTag (K1 i (Field n (Maybe a))) :: Type Source #

Methods

gPinch :: K1 i (Field n (Maybe a)) a0 -> Value (GTag (K1 i (Field n (Maybe a)))) Source #

gUnpinch :: Value (GTag (K1 i (Field n (Maybe a)))) -> Parser (K1 i (Field n (Maybe a)) a0) Source #

(Pinchable a, KnownNat n) => GPinchable (K1 i (Field n a) :: Type -> Type) Source # 
Instance details

Defined in Pinch.Internal.Generic

Associated Types

type GTag (K1 i (Field n a)) :: Type Source #

Methods

gPinch :: K1 i (Field n a) a0 -> Value (GTag (K1 i (Field n a))) Source #

gUnpinch :: Value (GTag (K1 i (Field n a))) -> Parser (K1 i (Field n a) a0) Source #

type Rep (Field n a) Source # 
Instance details

Defined in Pinch.Internal.Generic

type Rep (Field n a) = D1 (MetaData "Field" "Pinch.Internal.Generic" "pinch-0.3.4.1-6i8lWHA1d5m12B6E7SIAjq" True) (C1 (MetaCons "Field" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 a)))
type GTag (K1 i (Field n (Maybe a)) :: Type -> Type) Source # 
Instance details

Defined in Pinch.Internal.Generic

type GTag (K1 i (Field n (Maybe a)) :: Type -> Type) = TStruct
type GTag (K1 i (Field n a) :: Type -> Type) Source # 
Instance details

Defined in Pinch.Internal.Generic

type GTag (K1 i (Field n a) :: Type -> Type) = TStruct

getField :: Field n a -> a Source #

Gets the current value of a field.

let Foo a' _ = {- ... -}
    a = getField a'

putField :: a -> Field n a Source #

Puts a value inside a field.

Foo (putField "Hello") (putField (Just 42))

field :: Functor f => (a -> f b) -> Field n a -> f (Field n b) Source #

A lens on Field wrappers for use with the lens library.

person & name . field .~ "new value"

data Void Source #

Represents a void result for methods.

This should be used as an element in a response union along with Field tags.

For a method,

void setValue(..) throws
  (1: ValueAlreadyExists alreadyExists,
   2: InternalError internalError)

Something similar to the following can be used.

data SetValueResponse
  = SetValueAlreadyExists (Field 1 ValueAlreadyExists)
  | SetValueInternalError (Field 2 InternalError)
  | SetValueSuccess Void
  deriving (Generic)

instance Pinchable SetValueResponse

Constructors

Void 
Instances
Eq Void Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

(==) :: Void -> Void -> Bool #

(/=) :: Void -> Void -> Bool #

Ord Void Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

compare :: Void -> Void -> Ordering #

(<) :: Void -> Void -> Bool #

(<=) :: Void -> Void -> Bool #

(>) :: Void -> Void -> Bool #

(>=) :: Void -> Void -> Bool #

max :: Void -> Void -> Void #

min :: Void -> Void -> Void #

Show Void Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

showsPrec :: Int -> Void -> ShowS #

show :: Void -> String #

showList :: [Void] -> ShowS #

Generic Void Source # 
Instance details

Defined in Pinch.Internal.Generic

Associated Types

type Rep Void :: Type -> Type #

Methods

from :: Void -> Rep Void x #

to :: Rep Void x -> Void #

GPinchable (K1 i Void :: Type -> Type) Source # 
Instance details

Defined in Pinch.Internal.Generic

Associated Types

type GTag (K1 i Void) :: Type Source #

Methods

gPinch :: K1 i Void a -> Value (GTag (K1 i Void)) Source #

gUnpinch :: Value (GTag (K1 i Void)) -> Parser (K1 i Void a) Source #

type Rep Void Source # 
Instance details

Defined in Pinch.Internal.Generic

type Rep Void = D1 (MetaData "Void" "Pinch.Internal.Generic" "pinch-0.3.4.1-6i8lWHA1d5m12B6E7SIAjq" False) (C1 (MetaCons "Void" PrefixI False) (U1 :: Type -> Type))
type GTag (K1 i Void :: Type -> Type) Source # 
Instance details

Defined in Pinch.Internal.Generic

type GTag (K1 i Void :: Type -> Type) = TStruct

Enums

Given the enum,

enum Op {
  Add, Sub, Mul, Div
}

A Pinchable instance can be derived for it by creating one constructor for each of the enum values and providing it a single Enumeration argument tagged with the enum value.

data Op
    = OpAdd (Enumeration 0)
    | OpSub (Enumeration 1)
    | OpMul (Enumeration 2)
    | OpDiv (Enumeration 3)
  deriving (Generic)

instance Pinchable Op

Note that you need to know the values assigned to the enums. If not specified, Thrift automatically assigns incrementing values to the items in the order they appear starting at 0.

The DeriveGeneric extension is required to automatically derive instances of the Generic typeclass and the DataKinds extension is required to use type-level numerals.

data Enumeration (n :: Nat) Source #

Data types that represent Thrift enums must have one constructor for each enum item accepting an Enumeration object tagged with the corresponding enum value.

data Role = RoleUser (Enumeration 1) | RoleAdmin (Enumeration 2)
  deriving Generic
instance Pinchable Role

Constructors

Enumeration 
Instances
Eq (Enumeration n) Source # 
Instance details

Defined in Pinch.Internal.Generic

Ord (Enumeration n) Source # 
Instance details

Defined in Pinch.Internal.Generic

Show (Enumeration n) Source # 
Instance details

Defined in Pinch.Internal.Generic

Generic (Enumeration n) Source # 
Instance details

Defined in Pinch.Internal.Generic

Associated Types

type Rep (Enumeration n) :: Type -> Type #

Methods

from :: Enumeration n -> Rep (Enumeration n) x #

to :: Rep (Enumeration n) x -> Enumeration n #

NFData (Enumeration n) Source # 
Instance details

Defined in Pinch.Internal.Generic

Methods

rnf :: Enumeration n -> () #

KnownNat n => GPinchable (K1 i (Enumeration n) :: Type -> Type) Source # 
Instance details

Defined in Pinch.Internal.Generic

Associated Types

type GTag (K1 i (Enumeration n)) :: Type Source #

Methods

gPinch :: K1 i (Enumeration n) a -> Value (GTag (K1 i (Enumeration n))) Source #

gUnpinch :: Value (GTag (K1 i (Enumeration n))) -> Parser (K1 i (Enumeration n) a) Source #

type Rep (Enumeration n) Source # 
Instance details

Defined in Pinch.Internal.Generic

type Rep (Enumeration n) = D1 (MetaData "Enumeration" "Pinch.Internal.Generic" "pinch-0.3.4.1-6i8lWHA1d5m12B6E7SIAjq" False) (C1 (MetaCons "Enumeration" PrefixI False) (U1 :: Type -> Type))
type GTag (K1 i (Enumeration n) :: Type -> Type) Source # 
Instance details

Defined in Pinch.Internal.Generic

type GTag (K1 i (Enumeration n) :: Type -> Type) = TEnum

enum :: Enumeration n Source #

Convenience function to construct Enumeration objects.

let role = RoleUser enum

Manually writing instances

Instances of Pinchable can be constructed by composing together existing instances and using the .=, .:, etc. helpers.

Structs and exceptions

Given a Thrift struct,

struct Post {
  1: optional string subject
  2: required string body
}

The Pinchable instance for it will be,

data Post = Post
    { postSubject :: Maybe Text
    , postBody    :: Text
    }

instance Pinchable Post where
    type Tag Post = TStruct

    pinch (Post subject body) =
        struct [ 1 ?= subject
               , 2 .= body
               ]

    unpinch value =
        Post <$> value .:? 1
             <*> value .:  2

Unions

Given a Thrift union,

union PostBody {
  1: string markdown
  2: binary rtf
}

The Pinchable instance for it will be,

data PostBody
    = PostBodyMarkdown Text
    | PostBodyRtf ByteString

instance Pinchable PostBody where
    type Tag PostBody = TUnion

    pinch (PostBodyMarkdown markdownBody) =
        union 1 markdownBody
    pinch (PostBodyRtf rtfBody) =
        union 2 rtfBody

    unpinch v = PostBodyMarkdown <$> v .: 1
            <|> PostBodyRtf      <$> v .: 2

Enums

Given an enum,

enum Role {
  DISABLED = 0,
  USER,
  ADMIN,
}

The Pinchable instance for it will be,

data Role = RoleDisabled | RoleUser | RoleAdmin

instance Pinchable Role where
    type Tag Role = TEnum

    pinch RoleDisabled = pinch (0 :: Int32)
    pinch RoleUser     = pinch (1 :: Int32)
    pinch RoleAdmin    = pinch (2 :: Int32)

    unpinch v = do
       value <- unpinch v
       case (value :: Int32) of
           0 -> Right RoleDisabled
           1 -> Right RoleUser
           2 -> Right RoleAdmin
           _ -> Left $ "Unknown role: " ++ show value

Helpers

pinch

(.=) :: Pinchable a => Int16 -> a -> FieldPair Source #

Construct a FieldPair from a field identifier and a Pinchable value.

(?=) :: Pinchable a => Int16 -> Maybe a -> FieldPair Source #

Construct a FieldPair from a field identifier and an optional Pinchable value.

struct :: [FieldPair] -> Value TStruct Source #

Construct a Value tagged with a TStruct from the given key-value pairs. Optional fields whose values were omitted will be ignored.

struct [1 .= ("Hello" :: Text), 2 .= (42 :: Int16)]

union :: Pinchable a => Int16 -> a -> Value TUnion Source #

Constructs a Value tagged with TUnion.

union 1 ("foo" :: ByteString)

type FieldPair = (Int16, Maybe SomeValue) Source #

A pair of field identifier and maybe a value stored in the field. If the value is absent, the field will be ignored.

unpinch

(.:) :: forall a. Pinchable a => Value TStruct -> Int16 -> Parser a Source #

Given a field ID and a Value TStruct, get the value stored in the struct under that field ID. The lookup fails if the field is absent or if it's not the same type as expected by this call's context.

(.:?) :: forall a. Pinchable a => Value TStruct -> Int16 -> Parser (Maybe a) Source #

Given a field ID and a Value TStruct, get the optional value stored in the struct under the given field ID. The value returned is Nothing if it was absent or the wrong type. The lookup fails only if the value retrieved fails to unpinch.

Value

Value is an intermediate representation of Thrift payloads tagged with TType tags. Types that want to be serialized into/deserialized from Thrift payloads need only define a way to convert themselves to and from Value objects via Pinchable.

data Value a Source #

Value maps directly to serialized representation of Thrift types. It contains about as much information as what gets sent over the wire. Value objects are tagged with different TType values to indicate the type of the value.

Typical usage will not involve accessing the constructors for this type. Pinchable must be used to construct Value objects or convert them back to original types.

Instances
Eq (Value a) Source # 
Instance details

Defined in Pinch.Internal.Value

Methods

(==) :: Value a -> Value a -> Bool #

(/=) :: Value a -> Value a -> Bool #

Show (Value a) Source # 
Instance details

Defined in Pinch.Internal.Value

Methods

showsPrec :: Int -> Value a -> ShowS #

show :: Value a -> String #

showList :: [Value a] -> ShowS #

NFData (Value a) Source # 
Instance details

Defined in Pinch.Internal.Value

Methods

rnf :: Value a -> () #

Hashable (Value a) Source # 
Instance details

Defined in Pinch.Internal.Value

Methods

hashWithSalt :: Int -> Value a -> Int #

hash :: Value a -> Int #

IsTType a => Pinchable (Value a) Source # 
Instance details

Defined in Pinch.Internal.Pinchable

Associated Types

type Tag (Value a) :: Type Source #

Methods

pinch :: Value a -> Value (Tag (Value a)) Source #

unpinch :: Value (Tag (Value a)) -> Parser (Value a) Source #

type Tag (Value a) Source # 
Instance details

Defined in Pinch.Internal.Pinchable

type Tag (Value a) = a

data SomeValue where Source #

SomeValue holds any value, regardless of type. This may be used when the type of the value is not necessarily known at compile time. Typically, this will be pattern matched on and code that depends on the value's TType will go inside the scope of the match.

Constructors

SomeValue :: IsTType a => !(Value a) -> SomeValue 
Instances
Eq SomeValue Source # 
Instance details

Defined in Pinch.Internal.Value

Show SomeValue Source # 
Instance details

Defined in Pinch.Internal.Value

NFData SomeValue Source # 
Instance details

Defined in Pinch.Internal.Value

Methods

rnf :: SomeValue -> () #

Hashable SomeValue Source # 
Instance details

Defined in Pinch.Internal.Value

Messages

data Message Source #

Message envelope for Thrift payloads.

Instances
Eq Message Source # 
Instance details

Defined in Pinch.Internal.Message

Methods

(==) :: Message -> Message -> Bool #

(/=) :: Message -> Message -> Bool #

Show Message Source # 
Instance details

Defined in Pinch.Internal.Message

Generic Message Source # 
Instance details

Defined in Pinch.Internal.Message

Associated Types

type Rep Message :: Type -> Type #

Methods

from :: Message -> Rep Message x #

to :: Rep Message x -> Message #

NFData Message Source # 
Instance details

Defined in Pinch.Internal.Message

Methods

rnf :: Message -> () #

type Rep Message Source # 
Instance details

Defined in Pinch.Internal.Message

type Rep Message = D1 (MetaData "Message" "Pinch.Internal.Message" "pinch-0.3.4.1-6i8lWHA1d5m12B6E7SIAjq" False) (C1 (MetaCons "Message" PrefixI True) ((S1 (MetaSel (Just "messageName") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 Text) :*: S1 (MetaSel (Just "messageType") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 MessageType)) :*: (S1 (MetaSel (Just "messageId") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 Int32) :*: S1 (MetaSel (Just "messagePayload") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 (Value TStruct)))))

mkMessage Source #

Arguments

:: (Pinchable a, Tag a ~ TStruct) 
=> Text

Name of the target method.

-> MessageType

Type of the message.

-> Int32

Message ID.

-> a

Message payload. This must be an object which serializes into a struct.

-> Message 

Build a Message.

messageName :: Message -> Text Source #

Name of the method to which this message is targeted.

messageType :: Message -> MessageType Source #

Type of the message.

messageId :: Message -> Int32 Source #

Sequence ID of the message.

If the clients expect to receive out-of-order responses, they may use the message ID to map responses back to their corresponding requests. If the client does not expect out-of-order responses, they are free to use the same message ID for all messages.

The server's contract regarding message IDs is that all responses must have the same message ID as their corresponding requests.

getMessageBody :: (Pinchable a, Tag a ~ TStruct) => Message -> Either String a Source #

Read the message contents.

This returns a Left result if the message contents do not match the requested type.

data MessageType Source #

Type of message being sent.

Constructors

Call

A call to a specific method.

The message body is the request arguments struct.

Reply

Response to a call.

The message body is the response union.

Exception

Failure to make a call.

Note: This message type is not used for exceptions that are defined under the throws clause of a method. Those exceptions are part of the response union of the method and are received in a Reply. This message type is used for Thrift-level failures.

Oneway

One-way call that expects no response.

Instances
Eq MessageType Source # 
Instance details

Defined in Pinch.Internal.Message

Data MessageType Source # 
Instance details

Defined in Pinch.Internal.Message

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> MessageType -> c MessageType #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c MessageType #

toConstr :: MessageType -> Constr #

dataTypeOf :: MessageType -> DataType #

dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c MessageType) #

dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c MessageType) #

gmapT :: (forall b. Data b => b -> b) -> MessageType -> MessageType #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> MessageType -> r #

gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> MessageType -> r #

gmapQ :: (forall d. Data d => d -> u) -> MessageType -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> MessageType -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> MessageType -> m MessageType #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> MessageType -> m MessageType #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> MessageType -> m MessageType #

Show MessageType Source # 
Instance details

Defined in Pinch.Internal.Message

Generic MessageType Source # 
Instance details

Defined in Pinch.Internal.Message

Associated Types

type Rep MessageType :: Type -> Type #

NFData MessageType Source # 
Instance details

Defined in Pinch.Internal.Message

Methods

rnf :: MessageType -> () #

type Rep MessageType Source # 
Instance details

Defined in Pinch.Internal.Message

type Rep MessageType = D1 (MetaData "MessageType" "Pinch.Internal.Message" "pinch-0.3.4.1-6i8lWHA1d5m12B6E7SIAjq" False) ((C1 (MetaCons "Call" PrefixI False) (U1 :: Type -> Type) :+: C1 (MetaCons "Reply" PrefixI False) (U1 :: Type -> Type)) :+: (C1 (MetaCons "Exception" PrefixI False) (U1 :: Type -> Type) :+: C1 (MetaCons "Oneway" PrefixI False) (U1 :: Type -> Type)))

Protocols

data Protocol Source #

Protocols define a specific way to convert values into binary and back.

binaryProtocol :: Protocol Source #

Provides an implementation of the Thrift Binary Protocol.

compactProtocol :: Protocol Source #

Provides an implementation of the Thrift Compact Protocol.

TType

TType is used to refer to the Thrift protocol-level type of a value.

data TType a Source #

Represents the type of a Thrift value.

Objects of this type are tagged with one of the TType tags, so this type also acts as a singleton on the TTypes. It allows writing code that can enforce properties about the TType of values at compile time.

Instances
Eq (TType a) Source # 
Instance details

Defined in Pinch.Internal.TType

Methods

(==) :: TType a -> TType a -> Bool #

(/=) :: TType a -> TType a -> Bool #

Show (TType a) Source # 
Instance details

Defined in Pinch.Internal.TType

Methods

showsPrec :: Int -> TType a -> ShowS #

show :: TType a -> String #

showList :: [TType a] -> ShowS #

Hashable (TType a) Source # 
Instance details

Defined in Pinch.Internal.TType

Methods

hashWithSalt :: Int -> TType a -> Int #

hash :: TType a -> Int #

class Typeable a => IsTType a where Source #

Typeclass used to map type-leve TTypes into TType objects. All TType tags are instances of this class.

Methods

ttype :: TType a Source #

Based on the context in which this is used, it will automatically return the corresponding TType object.

Instances
IsTType TList Source # 
Instance details

Defined in Pinch.Internal.TType

IsTType TSet Source # 
Instance details

Defined in Pinch.Internal.TType

Methods

ttype :: TType TSet Source #

IsTType TMap Source # 
Instance details

Defined in Pinch.Internal.TType

Methods

ttype :: TType TMap Source #

IsTType TStruct Source # 
Instance details

Defined in Pinch.Internal.TType

IsTType TBinary Source # 
Instance details

Defined in Pinch.Internal.TType

IsTType TInt64 Source # 
Instance details

Defined in Pinch.Internal.TType

IsTType TInt32 Source # 
Instance details

Defined in Pinch.Internal.TType

IsTType TInt16 Source # 
Instance details

Defined in Pinch.Internal.TType

IsTType TDouble Source # 
Instance details

Defined in Pinch.Internal.TType

IsTType TByte Source # 
Instance details

Defined in Pinch.Internal.TType

IsTType TBool Source # 
Instance details

Defined in Pinch.Internal.TType

Tags

TType tags allow writing code that depends on knowing the TType of values, or asserting conditions on it, at compile time.

For example, values in a map, list, or set must all have the same TType. This is enforced at the type level by parameterizing Value over these tags.

data TBool Source #

bool
Instances
IsTType TBool Source # 
Instance details

Defined in Pinch.Internal.TType

data TByte Source #

byte
Instances
IsTType TByte Source # 
Instance details

Defined in Pinch.Internal.TType

data TDouble Source #

double
Instances
IsTType TDouble Source # 
Instance details

Defined in Pinch.Internal.TType

type TEnum = TInt32 Source #

enum

data TInt16 Source #

i16
Instances
IsTType TInt16 Source # 
Instance details

Defined in Pinch.Internal.TType

data TInt32 Source #

i32
Instances
IsTType TInt32 Source # 
Instance details

Defined in Pinch.Internal.TType

data TInt64 Source #

i64
Instances
IsTType TInt64 Source # 
Instance details

Defined in Pinch.Internal.TType

data TBinary Source #

binary
Instances
IsTType TBinary Source # 
Instance details

Defined in Pinch.Internal.TType

data TStruct Source #

struct
Instances
IsTType TStruct Source # 
Instance details

Defined in Pinch.Internal.TType

type TUnion = TStruct Source #

union

type TException = TStruct Source #

exception

data TMap Source #

map<k, v>
Instances
IsTType TMap Source # 
Instance details

Defined in Pinch.Internal.TType

Methods

ttype :: TType TMap Source #

data TSet Source #

set<x>
Instances
IsTType TSet Source # 
Instance details

Defined in Pinch.Internal.TType

Methods

ttype :: TType TSet Source #

data TList Source #

list<x>
Instances
IsTType TList Source # 
Instance details

Defined in Pinch.Internal.TType