blob: ed779a27d5fa4cccba123fcd93dc9182ac08bafa [file] [log] [blame]
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -07001{-# LANGUAGE CPP #-}
Bryan Duxburye59a80f2010-09-20 15:21:37 +00002{-# LANGUAGE DeriveDataTypeable #-}
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -07003{-# LANGUAGE OverloadedStrings #-}
Bryan Duxbury0781f2b2009-04-07 23:29:42 +00004--
5-- Licensed to the Apache Software Foundation (ASF) under one
6-- or more contributor license agreements. See the NOTICE file
7-- distributed with this work for additional information
8-- regarding copyright ownership. The ASF licenses this file
9-- to you under the Apache License, Version 2.0 (the
10-- "License"); you may not use this file except in compliance
11-- with the License. You may obtain a copy of the License at
12--
13-- http://www.apache.org/licenses/LICENSE-2.0
14--
15-- Unless required by applicable law or agreed to in writing,
16-- software distributed under the License is distributed on an
17-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18-- KIND, either express or implied. See the License for the
19-- specific language governing permissions and limitations
20-- under the License.
21--
22
23module Thrift.Protocol
24 ( Protocol(..)
Bryan Duxbury0781f2b2009-04-07 23:29:42 +000025 , ProtocolExn(..)
26 , ProtocolExnType(..)
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070027 , getTypeOf
28 , runParser
29 , versionMask
30 , version1
31 , bsToDouble
Nobuaki Sukegawa7c7d6792015-12-09 03:22:35 +090032 , bsToDoubleLE
Bryan Duxbury0781f2b2009-04-07 23:29:42 +000033 ) where
34
Bryan Duxbury0781f2b2009-04-07 23:29:42 +000035import Control.Exception
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070036import Data.Attoparsec.ByteString
37import Data.Bits
38import Data.ByteString.Lazy (ByteString, toStrict)
39import Data.ByteString.Unsafe
40import Data.Functor ((<$>))
Roger Meier6849f202012-05-18 07:35:19 +000041import Data.Int
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070042import Data.Monoid (mempty)
43import Data.Text.Lazy (Text)
44import Data.Typeable (Typeable)
45import Data.Word
46import Foreign.Ptr (castPtr)
47import Foreign.Storable (Storable, peek, poke)
48import System.IO.Unsafe
49import qualified Data.ByteString as BS
50import qualified Data.HashMap.Strict as Map
Bryan Duxbury0781f2b2009-04-07 23:29:42 +000051
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070052import Thrift.Types
Bryan Duxbury0781f2b2009-04-07 23:29:42 +000053import Thrift.Transport
54
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070055versionMask :: Int32
56versionMask = fromIntegral (0xffff0000 :: Word32)
Bryan Duxbury0781f2b2009-04-07 23:29:42 +000057
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070058version1 :: Int32
59version1 = fromIntegral (0x80010000 :: Word32)
Bryan Duxbury0781f2b2009-04-07 23:29:42 +000060
61class Protocol a where
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070062 getTransport :: Transport t => a t -> t
Bryan Duxbury0781f2b2009-04-07 23:29:42 +000063
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070064 writeMessageBegin :: Transport t => a t -> (Text, MessageType, Int32) -> IO ()
65 writeMessageEnd :: Transport t => a t -> IO ()
66 writeMessageEnd _ = return ()
67
68 readMessageBegin :: Transport t => a t -> IO (Text, MessageType, Int32)
69 readMessageEnd :: Transport t => a t -> IO ()
70 readMessageEnd _ = return ()
Bryan Duxbury0781f2b2009-04-07 23:29:42 +000071
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070072 serializeVal :: Transport t => a t -> ThriftVal -> ByteString
73 deserializeVal :: Transport t => a t -> ThriftType -> ByteString -> ThriftVal
Bryan Duxbury0781f2b2009-04-07 23:29:42 +000074
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070075 writeVal :: Transport t => a t -> ThriftVal -> IO ()
76 writeVal p = tWrite (getTransport p) . serializeVal p
77 readVal :: Transport t => a t -> ThriftType -> IO ThriftVal
Bryan Duxbury0781f2b2009-04-07 23:29:42 +000078
79data ProtocolExnType
80 = PE_UNKNOWN
81 | PE_INVALID_DATA
82 | PE_NEGATIVE_SIZE
83 | PE_SIZE_LIMIT
84 | PE_BAD_VERSION
Jens Geyer6d1a83a2014-05-03 00:49:05 +020085 | PE_NOT_IMPLEMENTED
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070086 | PE_MISSING_REQUIRED_FIELD
Bryan Duxbury0781f2b2009-04-07 23:29:42 +000087 deriving ( Eq, Show, Typeable )
88
89data ProtocolExn = ProtocolExn ProtocolExnType String
90 deriving ( Show, Typeable )
91instance Exception ProtocolExn
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -070092
93getTypeOf :: ThriftVal -> ThriftType
94getTypeOf v = case v of
95 TStruct{} -> T_STRUCT Map.empty
96 TMap{} -> T_MAP T_VOID T_VOID
97 TList{} -> T_LIST T_VOID
98 TSet{} -> T_SET T_VOID
99 TBool{} -> T_BOOL
100 TByte{} -> T_BYTE
101 TI16{} -> T_I16
102 TI32{} -> T_I32
103 TI64{} -> T_I64
104 TString{} -> T_STRING
Nobuaki Sukegawae68ccc22015-12-13 21:45:39 +0900105 TBinary{} -> T_BINARY
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700106 TDouble{} -> T_DOUBLE
107
108runParser :: (Protocol p, Transport t, Show a) => p t -> Parser a -> IO a
109runParser prot p = refill >>= getResult . parse p
110 where
Nobuaki Sukegawaef2b5282015-12-11 02:24:17 +0900111 refill = handle handleEOF $ toStrict <$> tReadAll (getTransport prot) 1
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700112 getResult (Done _ a) = return a
113 getResult (Partial k) = refill >>= getResult . k
114 getResult f = throw $ ProtocolExn PE_INVALID_DATA (show f)
115
116handleEOF :: SomeException -> IO BS.ByteString
117handleEOF = const $ return mempty
118
119-- | Converts a ByteString to a Floating point number
120-- The ByteString is assumed to be encoded in network order (Big Endian)
121-- therefore the behavior of this function varies based on whether the local
122-- machine is big endian or little endian.
123bsToDouble :: BS.ByteString -> Double
Nobuaki Sukegawa7c7d6792015-12-09 03:22:35 +0900124bsToDoubleLE :: BS.ByteString -> Double
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700125#if __BYTE_ORDER == __LITTLE_ENDIAN
Nobuaki Sukegawa7c7d6792015-12-09 03:22:35 +0900126bsToDouble bs = unsafeDupablePerformIO $ unsafeUseAsCString bs castBsSwapped
127bsToDoubleLE bs = unsafeDupablePerformIO $ unsafeUseAsCString bs castBs
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700128#else
Nobuaki Sukegawa7c7d6792015-12-09 03:22:35 +0900129bsToDouble bs = unsafeDupablePerformIO $ unsafeUseAsCString bs castBs
130bsToDoubleLE bs = unsafeDupablePerformIO $ unsafeUseAsCString bs castBsSwapped
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700131#endif
132
Nobuaki Sukegawa7c7d6792015-12-09 03:22:35 +0900133
134castBsSwapped chrPtr = do
135 w <- peek (castPtr chrPtr)
136 poke (castPtr chrPtr) (byteSwap w)
137 peek (castPtr chrPtr)
138castBs = peek . castPtr
139
Noam Zilbersteinaf5d64a2014-07-31 15:44:13 -0700140-- | Swap endianness of a 64-bit word
141byteSwap :: Word64 -> Word64
142byteSwap w = (w `shiftL` 56 .&. 0xFF00000000000000) .|.
143 (w `shiftL` 40 .&. 0x00FF000000000000) .|.
144 (w `shiftL` 24 .&. 0x0000FF0000000000) .|.
145 (w `shiftL` 8 .&. 0x000000FF00000000) .|.
146 (w `shiftR` 8 .&. 0x00000000FF000000) .|.
147 (w `shiftR` 24 .&. 0x0000000000FF0000) .|.
148 (w `shiftR` 40 .&. 0x000000000000FF00) .|.
149 (w `shiftR` 56 .&. 0x00000000000000FF)