module Ros.Internal.RosBinary where
import Control.Applicative ((<$>), (<*>))
import Control.Monad (replicateM)
import Data.Binary.Get
import Data.Binary.Put
import Data.Int
import qualified Data.Vector.Storable as V
import Data.Word
import Unsafe.Coerce (unsafeCoerce)
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BC8
import Foreign.Storable (sizeOf, Storable)
import Ros.Internal.RosTypes
import Ros.Internal.Util.BytesToVector
class RosBinary a where
put :: a -> Put
get :: Get a
putMsg :: Word32 -> a -> Put
putMsg _ = put
instance RosBinary Bool where
put True = putWord8 1
put False = putWord8 0
get = (> 0) <$> getWord8
instance RosBinary Int8 where
put = putWord8 . fromIntegral
get = fromIntegral <$> getWord8
instance RosBinary Word8 where
put = putWord8
get = getWord8
instance RosBinary Int16 where
put = putWord16host . fromIntegral
get = fromIntegral <$> getWord16host
instance RosBinary Word16 where
put = putWord16host
get = getWord16host
instance RosBinary Int where
put = putWord32host . fromIntegral
get = fromIntegral <$> getWord32host
instance RosBinary Word32 where
put = putWord32host
get = getWord32host
instance RosBinary Int64 where
put = putWord64host . fromIntegral
get = fromIntegral <$> getWord64host
instance RosBinary Word64 where
put = putWord64host
get = getWord64host
instance RosBinary Float where
put = putWord32le . unsafeCoerce
get = unsafeCoerce <$> getWord32le
instance RosBinary Double where
put = putWord64le . unsafeCoerce
get = unsafeCoerce <$> getWord64le
getAscii :: Get Char
getAscii = toEnum . fromEnum <$> getWord8
putAscii :: Char -> Put
putAscii = putWord8 . toEnum . fromEnum
putUnit :: Put
putUnit = putWord8 0
getUnit :: Get ()
getUnit = getWord8 >> return ()
instance RosBinary String where
put s = let s' = BC8.pack s
in putInt32 (BC8.length s') >> putByteString s'
get = getInt32 >>= (BC8.unpack <$>) . getByteString
instance RosBinary B.ByteString where
put b = putInt32 (B.length b) >> putByteString b
get = getInt32 >>= getByteString
instance RosBinary ROSTime where
put (s,n) = putWord32host s >> putWord32host n
get = (,) <$> getWord32host <*> getWord32host
putList :: RosBinary a => [a] -> Put
putList xs = putInt32 (length xs) >> mapM_ put xs
getList :: RosBinary a => Get [a]
getList = getInt32 >>= flip replicateM get
putFixedList :: RosBinary a => [a] -> Put
putFixedList = mapM_ put
getFixedList :: RosBinary a => Int -> Get [a]
getFixedList = flip replicateM get
getInt32 :: Get Int
getInt32 = fromIntegral <$> getWord32le
putInt32 :: Int -> Put
putInt32 = putWord32le . fromIntegral
instance (RosBinary a, Storable a) => RosBinary (V.Vector a) where
put v = putInt32 (V.length v) >> putByteString (vectorToBytes v)
get = getInt32 >>= getFixed
getFixed :: forall a. Storable a => Int -> Get (V.Vector a)
getFixed n = bytesToVector n <$> getByteString (n*(sizeOf (undefined::a)))
putFixed :: (Storable a, RosBinary a) => V.Vector a -> Put
putFixed = putByteString . vectorToBytes