packages feed

NineP 0.0.0 → 0.0.1

raw patch · 2 files changed

+79/−5 lines, 2 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Data.NineP: getBytes32 :: Get ByteString
- Data.NineP: getList16 :: (Bin a) => Get [a]
- Data.NineP: getListAll :: (Bin a) => Get [a]
- Data.NineP: getNest :: (Integral n) => n -> Get a -> Get a
- Data.NineP: getNestList16 :: (Bin a) => Get [a]
- Data.NineP: getTag :: VarMsg -> Tag
- Data.NineP: getVarMsg :: Tag -> Get VarMsg
- Data.NineP: maxSize :: Word32
- Data.NineP: putBytes32 :: ByteString -> Put
- Data.NineP: putList16 :: (Bin a) => [a] -> Put
- Data.NineP: putListAll :: (Bin a) => [a] -> Put
- Data.NineP: putNestList16 :: (Bin a) => [a] -> Put
- Data.NineP: putVarMsg :: VarMsg -> Put

Files

NineP.cabal view
@@ -1,5 +1,5 @@ name:		NineP-version:	0.0.0+version:	0.0.1 license:	BSD3 license-file:	LICENSE author:		Tim Newsham <newsham@lava.net>, Dave Leimbach <leimy2k@gmail.com>
src/Data/NineP.hs view
@@ -1,5 +1,55 @@ {-# LANGUAGE TypeSynonymInstances #-}-module Data.NineP where+-----------------------------------------------------------------------------+-- |+-- Module      : Data.NineP+-- Copyright   : Tim Newsham+-- License     : BSD3-style (see LICENSE)+-- +-- Maintainer  : David Leimbach <leimy2k@gmail.com>+-- Stability   : experimental+-- Portability : Only tested on GHC 6.12.1, uses TypeSynonnymInstances+--+-- Binary serialization of 9P messages to and from lazy ByteStrings.+-- This library does not currently provide any networking support or +-- wrappers for easy to write clients or servers, though that may come +-- with time as we decide the best way to implement these.+-- +-- Perhaps interesting about 9P is that the messages are send in little endian+-- as opposed to the somewhat misnamed "network byte order" that most people+-- refer to for "big endian".+--+-- It's fairly easy to use runPut or runGet to generate or parse 9P messages+-- example: +--+--   send sock $ runPut (put (Msg TTVersion (-1) & Tversion 1024 "9P2000"))+-- +-- This sends a lazy ByteString over a socket to begin a handshake of a 9P +-- connection with a server, negotiating the use of the "9P2000" protocol, +-- with a maximum message size of 1KB, using a tag of (-1) (known as NOTAG in +-- 9P space.+--+-- This 9P implementation has been lightly tested against an Inferno operating+-- system share with no authentication successfully.+-----------------------------------------------------------------------------++module Data.NineP ( +                  -- * Bin is the little endian encode/decode class for 9P2000+                   Bin(..)+                  -- * The Qid class (http://9p.cat-v.org for details)+                  , Qid(..)++                  -- * like stat for unix filesystems, but for 9P2000+                  , Stat(..)++                  -- * The Msg type is an enveleope for 9P2000 messages+                  , Msg(..)+                       +                  -- ** Tag is the (possibly misnamed) message payload type+                  , Tag(..)++                  -- ** VarMsg is an algebraic type allowing for the various types of messages 9P2000 can have to be grouped under one type+                  , VarMsg(..)+                  ) where import Control.Applicative import Control.Monad import Data.Binary.Get@@ -21,31 +71,39 @@ instance Bin Word8 where     get = getWord8     put = putWord8+ instance Bin Word16 where     get = getWord16le     put = putWord16le+ instance Bin Word32 where     get = getWord32le     put = putWord32le+ instance Bin Word64 where     get = getWord64le     put = putWord64le+ instance Bin Char where     get = chr . fromIntegral <$> getWord8     put = putWord8 . fromIntegral . ord+ instance Bin String where     get = getWord16le >>= \n -> replicateM (fromIntegral n) get     put xs = putWord16le (fromIntegral $ length xs) >> mapM_ put xs +-- | A Plan 9 Qid type.  See http://9p.cat-v.org for more information data Qid = Qid {     qid_typ :: Word8,     qid_vers :: Word32,     qid_path :: Word64 } deriving (Show, Eq) +-- Instnace of Bin for Qid. instance Bin Qid where     get = Qid <$> get <*> get <*> get     put (Qid t v p) = put t >> put v >> put p +-- | Takes a fixed size lazy ByteString @sz@, running @g@ on it, and returning the result if all the input is consumed, uses @Prelude.error@ otherwise. (Throws an exception) getNest :: Integral n => n -> Get a -> Get a getNest sz g = do     b <- getLazyByteString (fromIntegral sz)@@ -58,7 +116,7 @@               n <- remaining               error $ show n ++ " extra bytes in nested structure" -+-- | Provides information on a path entry at a 9P2000 server data Stat = Stat {     st_typ :: Word16,     st_dev :: Word32,@@ -83,7 +141,7 @@         putLazyByteString buf       where p  = put a >> put b >> put c >> put d >> put e >> put f >> put g >> put h >> put i >> put j >> put k -+-- | A variable message type that encapsulates the valid kinds of messages in a 9P2000 payload data VarMsg =      Tversion {         tv_msize :: Word32,@@ -147,6 +205,7 @@     deriving (Show, Eq)  +-- | A type that enumerates all the valid (and one invalid) message types in 9P2000 data Tag = TTversion | TRversion | TTauth | TRauth | TTattach | TRattach     | XXX_TTerror | TRerror | TTflush | TRflush      | TTwalk | TRwalk | TTopen | TRopen @@ -163,32 +222,44 @@                     else error $ "invalid tag: " ++ (show n)     put = putWord8 . toEnum . (+ 100) . fromEnum +-- | A monadic action in Get that returns all parseable entries as a list, returning [] if none exist getListAll :: (Bin a) => Get [a] getListAll = do     e <- isEmpty      if e        then return []        else (:) <$> get <*> getListAll++-- | A monadic action in Put that maps all encodable items into the Put monad for serialization putListAll :: (Bin a) => [a] -> Put putListAll = mapM_ put +-- | Like 'getNest' but is preceded by a little endian 16bit word.  Useful for retrieving 16bit payload lengths from 9P2000 messages that support it. getNestList16 :: (Bin a) => Get [a] getNestList16 = do     n <- getWord16le     getNest n getListAll++-- | Runs 'putListAll' over @xs@ followed by computing the 16bit (little endian) length of the list, and prepending it to the final payload.  Useful for automatically computing lengths for 9P2000 messages that require it putNestList16 :: Bin a => [a] -> Put putNestList16 xs = do     let buf = runPut (putListAll xs)     putWord16le $ fromIntegral $ L.length buf     putLazyByteString buf +-- | Gets a 16bit value from the stream, then executes @Data.Binary.Get.get@ that many times to produce a list of parsed values. getList16 :: Bin a => Get [a] getList16 = getWord16le >>= \n -> replicateM (fromIntegral n) get++-- | Puts @xs@ into the Put stream prepended by its length. putList16 :: Bin a => [a] -> Put putList16 xs = putWord16le (fromIntegral $ length xs) >> mapM_ put xs +-- | Gets a 32bit little endian legnth from the stream, then gets a lazy ByteString of that size from the stream, returning only the ByteString getBytes32 :: Get L.ByteString getBytes32 = getWord32le >>= getLazyByteString . fromIntegral++-- | Takes length of @xs@ and then prepends that to the lazy ByteString it places in the Stream putBytes32 :: L.ByteString -> Put putBytes32 xs = putWord32le (fromIntegral $ L.length xs) >> putLazyByteString xs @@ -221,6 +292,7 @@ getTag (Twstat _ _) = TTwstat getTag (Rwstat) = TRwstat +-- | For every messages type, runs a Get parser to decode that type of payload from the 9P2000 stream getVarMsg :: Tag -> Get VarMsg getVarMsg TTversion = Tversion <$> get <*> get getVarMsg TRversion = Rversion <$> get <*> get@@ -251,6 +323,7 @@ getVarMsg TTwstat = Twstat <$> get <*> getNestList16 getVarMsg TRwstat = return Rwstat +-- | For every lower level VarMsg type, encodes a full wrapper around that type for use with 9P2000 streams putVarMsg :: VarMsg -> Put putVarMsg (Tversion a b) = put a >> put b putVarMsg (Rversion a b) = put a >> put b@@ -280,12 +353,13 @@ putVarMsg (Twstat a b) = put a >> putNestList16 b putVarMsg (Rwstat) = return () -+-- | The message envelope type for all 9P2000 messages data Msg = Msg {     msg_typ :: Tag,     msg_tag :: Word16,     msg_body :: VarMsg } deriving(Show, Eq) +-- | An arbitrarily chosen maxiumum size for any Msg maxSize :: Word32 maxSize = 1024 * 1024 -- XXX arbitrary, configured?