ip 0.8 → 0.8.1
raw patch · 7 files changed
+148/−121 lines, 7 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Net.Mac: Mac :: {-# UNPACK #-} !Word16 -> {-# UNPACK #-} !Word32 -> Mac
- Net.Mac: [macA] :: Mac -> {-# UNPACK #-} !Word16
- Net.Mac: [macB] :: Mac -> {-# UNPACK #-} !Word32
- Net.Mac: bytestringParser :: Parser Mac
- Net.Mac: data Mac
- Net.Mac: fromOctets' :: Word16 -> Word16 -> Word32 -> Word32 -> Word32 -> Word32 -> Mac
- Net.Mac: fromText :: Text -> Maybe Mac
- Net.Mac: fromText' :: Text -> Either String Mac
- Net.Mac: instance Data.Aeson.Types.Class.FromJSON Net.Mac.Mac
- Net.Mac: instance Data.Aeson.Types.Class.ToJSON Net.Mac.Mac
- Net.Mac: instance Data.Hashable.Class.Hashable Net.Mac.Mac
- Net.Mac: instance GHC.Classes.Eq Net.Mac.Mac
- Net.Mac: instance GHC.Classes.Ord Net.Mac.Mac
- Net.Mac: instance GHC.Generics.Generic Net.Mac.Mac
- Net.Mac: instance GHC.Read.Read Net.Mac.Mac
- Net.Mac: instance GHC.Show.Show Net.Mac.Mac
- Net.Mac: textParser :: Parser Mac
- Net.Mac: toText :: Mac -> Text
- Net.Mac: toTextBuilder :: Mac -> Builder
+ Net.Internal: macFromText :: (Word16 -> Word16 -> Word32 -> Word32 -> Word32 -> Word32 -> a) -> Text -> Maybe a
+ Net.Internal: macFromText' :: (Word16 -> Word16 -> Word32 -> Word32 -> Word32 -> Word32 -> a) -> Text -> Either String a
+ Net.Internal: macTextParser :: (Word16 -> Word16 -> Word32 -> Word32 -> Word32 -> Word32 -> a) -> Parser a
+ Net.Internal: macToText :: Word16 -> Word32 -> Text
+ Net.Internal: macToTextBuilder :: Word16 -> Word32 -> Builder
+ Net.Mac: fromOctetsNoCast :: Word16 -> Word16 -> Word32 -> Word32 -> Word32 -> Word32 -> Mac
+ Net.Types: Mac :: {-# UNPACK #-} !Word16 -> {-# UNPACK #-} !Word32 -> Mac
+ Net.Types: [macA] :: Mac -> {-# UNPACK #-} !Word16
+ Net.Types: [macB] :: Mac -> {-# UNPACK #-} !Word32
+ Net.Types: data Mac
+ Net.Types: instance Data.Aeson.Types.Class.FromJSON Net.Types.Mac
+ Net.Types: instance Data.Aeson.Types.Class.ToJSON Net.Types.Mac
+ Net.Types: instance Data.Hashable.Class.Hashable Net.Types.Mac
+ Net.Types: instance Data.Primitive.Types.Prim Net.Types.IPv4
+ Net.Types: instance Data.Vector.Generic.Base.Vector Data.Vector.Unboxed.Base.Vector Net.Types.IPv4
+ Net.Types: instance Data.Vector.Generic.Mutable.Base.MVector Data.Vector.Unboxed.Base.MVector Net.Types.IPv4
+ Net.Types: instance Data.Vector.Unboxed.Base.Unbox Net.Types.IPv4
+ Net.Types: instance GHC.Classes.Eq Net.Types.Mac
+ Net.Types: instance GHC.Classes.Ord Net.Types.Mac
+ Net.Types: instance GHC.Generics.Generic Net.Types.Mac
+ Net.Types: instance GHC.Read.Read Net.Types.Mac
+ Net.Types: instance GHC.Show.Show Net.Types.Mac
Files
- ip.cabal +1/−1
- src/Net/IPv4.hs +0/−6
- src/Net/Internal.hs +45/−0
- src/Net/Mac.hs +9/−81
- src/Net/Mac/ByteString/Char8.hs +3/−2
- src/Net/Mac/Text.hs +8/−7
- src/Net/Types.hs +82/−24
ip.cabal view
@@ -1,5 +1,5 @@ name: ip-version: 0.8+version: 0.8.1 synopsis: Library for IP and MAC addresses description: Please see README.md homepage: https://github.com/andrewthad/haskell-ip#readme
src/Net/IPv4.hs view
@@ -1,8 +1,3 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE InstanceSigs #-}-{-# LANGUAGE ScopedTypeVariables #-}- {-| An IPv4 data type This module provides the IPv4 data type and functions for working@@ -49,7 +44,6 @@ import qualified Net.Internal as Internal import qualified Data.Text.Lazy as LText import qualified Data.Text.IO as Text-import qualified Data.Vector.Unboxed as UVector import qualified Data.ByteString as ByteString import qualified Data.ByteString.Unsafe as ByteString
src/Net/Internal.hs view
@@ -15,6 +15,7 @@ import qualified Data.ByteString as ByteString import qualified Data.ByteString.Unsafe as ByteString import qualified Data.Text.Lazy.Builder as TBuilder+import qualified Data.Text.Lazy.Builder.Int as TBuilder attoparsecParseJSON :: AT.Parser a -> Aeson.Value -> Aeson.Parser a attoparsecParseJSON p v =@@ -207,4 +208,48 @@ -- r1,r2,r3,r4,r5,r6 :: Word32 -- r1 = fromOctets' 0 0 0 0 +macTextParser :: (Word16 -> Word16 -> Word32 -> Word32 -> Word32 -> Word32 -> a) -> AT.Parser a+macTextParser f = f+ <$> (AT.hexadecimal >>= limitSize)+ <* AT.char ':'+ <*> (AT.hexadecimal >>= limitSize)+ <* AT.char ':'+ <*> (AT.hexadecimal >>= limitSize)+ <* AT.char ':'+ <*> (AT.hexadecimal >>= limitSize)+ <* AT.char ':'+ <*> (AT.hexadecimal >>= limitSize)+ <* AT.char ':'+ <*> (AT.hexadecimal >>= limitSize)+ where+ limitSize i =+ if i > 255+ then fail "All octets in a mac address must be between 00 and FF"+ else return i++macToText :: Word16 -> Word32 -> Text+macToText a b = LText.toStrict (TBuilder.toLazyText (macToTextBuilder a b))++macToTextBuilder :: Word16 -> Word32 -> TBuilder.Builder+macToTextBuilder a b =+ TBuilder.hexadecimal (255 .&. shiftR a 8 )+ <> colon+ <> TBuilder.hexadecimal (255 .&. a )+ <> colon+ <> TBuilder.hexadecimal (255 .&. shiftR b 24 )+ <> colon+ <> TBuilder.hexadecimal (255 .&. shiftR b 16 )+ <> colon+ <> TBuilder.hexadecimal (255 .&. shiftR b 8 )+ <> colon+ <> TBuilder.hexadecimal (255 .&. b)+ where colon = TBuilder.singleton ':'++macFromText :: (Word16 -> Word16 -> Word32 -> Word32 -> Word32 -> Word32 -> a) -> Text -> Maybe a+macFromText f = rightToMaybe . macFromText' f+{-# INLINE macFromText #-}++macFromText' :: (Word16 -> Word16 -> Word32 -> Word32 -> Word32 -> Word32 -> a) -> Text -> Either String a+macFromText' f = AT.parseOnly (macTextParser f <* AT.endOfInput)+{-# INLINE macFromText' #-}
src/Net/Mac.hs view
@@ -1,8 +1,12 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} -module Net.Mac where+module Net.Mac+ ( fromOctets+ , fromOctetsNoCast+ ) where +import Net.Types (Mac(..)) import Data.Text (Text) import Data.Hashable (Hashable) import GHC.Generics (Generic)@@ -18,91 +22,15 @@ import qualified Data.Aeson as Aeson import qualified Data.Text.Lazy as LText -data Mac = Mac- { macA :: {-# UNPACK #-} !Word16- , macB :: {-# UNPACK #-} !Word32- }- deriving (Eq,Ord,Show,Read,Generic)--instance Hashable Mac--instance ToJSON Mac where- toJSON = Aeson.String . toText--instance FromJSON Mac where- parseJSON = attoparsecParseJSON (textParser <* AT.endOfInput)--toText :: Mac -> Text-toText = LText.toStrict . TBuilder.toLazyText . toTextBuilder--fromText :: Text -> Maybe Mac-fromText = rightToMaybe . fromText'--fromText' :: Text -> Either String Mac-fromText' t = AT.parseOnly (textParser <* AT.endOfInput) t--toTextBuilder :: Mac -> TBuilder.Builder-toTextBuilder (Mac a b) =- hexadecimal (255 .&. shiftR a 8 )- <> colon- <> hexadecimal (255 .&. a )- <> colon- <> hexadecimal (255 .&. shiftR b 24 )- <> colon- <> hexadecimal (255 .&. shiftR b 16 )- <> colon- <> hexadecimal (255 .&. shiftR b 8 )- <> colon- <> hexadecimal (255 .&. b)- where colon = TBuilder.singleton ':'---- | This does not do an endOfInput check-textParser :: AT.Parser Mac-textParser = fromOctets'- <$> (AT.hexadecimal >>= limitSize)- <* AT.char ':'- <*> (AT.hexadecimal >>= limitSize)- <* AT.char ':'- <*> (AT.hexadecimal >>= limitSize)- <* AT.char ':'- <*> (AT.hexadecimal >>= limitSize)- <* AT.char ':'- <*> (AT.hexadecimal >>= limitSize)- <* AT.char ':'- <*> (AT.hexadecimal >>= limitSize)- where- limitSize i =- if i > 255- then fail "All octets in a mac address must be between 00 and FF"- else return i--bytestringParser :: AB.Parser Mac-bytestringParser = fromOctets'- <$> (AB.hexadecimal >>= limitSize)- <* AB.char ':'- <*> (AB.hexadecimal >>= limitSize)- <* AB.char ':'- <*> (AB.hexadecimal >>= limitSize)- <* AB.char ':'- <*> (AB.hexadecimal >>= limitSize)- <* AB.char ':'- <*> (AB.hexadecimal >>= limitSize)- <* AB.char ':'- <*> (AB.hexadecimal >>= limitSize)- where- limitSize i =- if i > 255- then fail "All octets in a mac address must be between 00 and FF"- else return i- fromOctets :: Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Mac-fromOctets a b c d e f = fromOctets'+fromOctets a b c d e f = fromOctetsNoCast (fromIntegral a) (fromIntegral b) (fromIntegral c) (fromIntegral d) (fromIntegral e) (fromIntegral f) -fromOctets' :: Word16 -> Word16 -> Word32 -> Word32 -> Word32 -> Word32 -> Mac-fromOctets' a b c d e f = Mac+fromOctetsNoCast :: Word16 -> Word16 -> Word32 -> Word32 -> Word32 -> Word32 -> Mac+fromOctetsNoCast a b c d e f = Mac ( shiftL a 8 .|. b ) ( shiftL c 24 .|. shiftL d 16 .|. shiftL e 8 .|. f )+{-# INLINE fromOctetsNoCast #-}
src/Net/Mac/ByteString/Char8.hs view
@@ -5,7 +5,8 @@ , parser ) where -import Net.Mac+import Net.Types (Mac(..))+import Net.Mac (fromOctetsNoCast) import Data.ByteString (ByteString) import Data.Attoparsec.ByteString.Char8 (Parser) import Data.ByteString.Lazy.Builder (Builder)@@ -28,7 +29,7 @@ builder = Builder.byteString . encode parser :: Parser Mac-parser = fromOctets'+parser = fromOctetsNoCast <$> (AB.hexadecimal >>= limitSize) <* AB.char ':' <*> (AB.hexadecimal >>= limitSize)
src/Net/Mac/Text.hs view
@@ -6,24 +6,25 @@ , parser ) where -import Net.Mac+import Net.Types (Mac(..))+import Net.Mac (fromOctetsNoCast) import Data.Text (Text)-import Net.Internal (rightToMaybe)+import qualified Net.Internal as Internal import qualified Data.Attoparsec.Text as AT import qualified Data.Text.Lazy.Builder as TBuilder encode :: Mac -> Text-encode = toText+encode (Mac a b) = Internal.macToText a b decodeEither :: Text -> Either String Mac-decodeEither = fromText'+decodeEither = Internal.macFromText' fromOctetsNoCast decode :: Text -> Maybe Mac-decode = rightToMaybe . decodeEither+decode = Internal.rightToMaybe . decodeEither builder :: Mac -> TBuilder.Builder-builder = toTextBuilder+builder (Mac a b) = Internal.macToTextBuilder a b parser :: AT.Parser Mac-parser = textParser+parser = Internal.macTextParser fromOctetsNoCast
src/Net/Types.hs view
@@ -1,15 +1,30 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UnboxedTuples #-}+ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Net.Types ( IPv4(..) , IPv4Range(..)+ , Mac(..) ) where import qualified Net.Internal as Internal import qualified Data.Aeson as Aeson import qualified Data.Aeson.Types as Aeson import qualified Data.Attoparsec.Text as AT+import qualified Data.Vector.Generic as GVector+import qualified Data.Vector.Unboxed as UVector+import qualified Data.Vector.Primitive as PVector+import qualified Data.Vector.Generic.Mutable as MGVector+import qualified Data.Vector.Unboxed.Mutable as MUVector+import qualified Data.Vector.Primitive.Mutable as MPVector+import Data.Primitive.Types (Prim)+import Data.Bits ((.|.),shiftL) import Data.Coerce (coerce) import Control.Monad import Data.Word@@ -20,7 +35,7 @@ -- | A 32-bit Internet Protocol address. newtype IPv4 = IPv4 { getIPv4 :: Word32 }- deriving (Eq,Ord,Show,Read,Enum,Bounded,Hashable,Generic)+ deriving (Eq,Ord,Show,Read,Enum,Bounded,Hashable,Generic,Prim) -- | The length should be between 0 and 32. These bounds are inclusive. -- This expectation is not in any way enforced by this library because@@ -54,27 +69,70 @@ mkIPv4Range w len = IPv4Range (IPv4 w) len {-# INLINE mkIPv4Range #-} --- newtype instance UVector.MVector s IPv4 = MV_IPv4 (UVector.MVector s Word32)------ instance MVector UVector.MVector IPv4 where--- basicLength = coerce (basicLength :: UVector.MVector s Word32 -> Int)--- basicUnsafeSlice = coerce (basicUnsafeSlice :: Int -> Int -> UVector.MVector s Word32 -> UVector.MVector s Word32)--- basicInitialize :: forall m. PrimMonad m => UVector.MVector (PrimState m) IPv4 -> m ()--- basicInitialize = coerce (basicInitialize :: PrimMonad m => UVector.MVector (PrimState m) Word32 -> m ())--- basicUnsafeReplicate :: forall m. PrimMonad m => Int -> IPv4 -> m (UVector.MVector (PrimState m) IPv4)--- basicUnsafeReplicate i (IPv4 w) = fmap coerce (basicUnsafeReplicate i w :: m (UVector.MVector (PrimState m) Word32))--- basicUnsafeRead :: forall m. PrimMonad m => UVector.MVector (PrimState m) IPv4 -> Int -> m IPv4--- basicUnsafeRead v i = fmap coerce (basicUnsafeRead (coerce v :: UVector.MVector (PrimState m) Word32) i :: m Word32)--- basicUnsafeWrite :: forall m. PrimMonad m => UVector.MVector (PrimState m) IPv4 -> Int -> IPv4 -> m ()--- basicUnsafeWrite = coerce (basicUnsafeWrite :: UVector.MVector (PrimState m) Word32 -> Int -> Word32 -> m ())--- basicClear :: forall m. PrimMonad m => UVector.MVector (PrimState m) IPv4 -> m ()--- basicClear = coerce (basicClear :: UVector.MVector (PrimState m) Word32 -> m ())--- basicSet :: forall m. PrimMonad m => UVector.MVector (PrimState m) IPv4 -> IPv4 -> m ()--- basicSet = coerce (basicSet :: UVector.MVector (PrimState m) Word32 -> Word32 -> m ())--- basicUnsafeCopy :: forall m. PrimMonad m => UVector.MVector (PrimState m) IPv4 -> UVector.MVector (PrimState m) IPv4 -> m ()--- basicUnsafeCopy = coerce (basicUnsafeCopy :: UVector.MVector (PrimState m) Word32 -> UVector.MVector (PrimState m) Word32 -> m ())--- basicUnsafeMove :: forall m. PrimMonad m => UVector.MVector (PrimState m) IPv4 -> UVector.MVector (PrimState m) IPv4 -> m ()--- basicUnsafeMove = coerce (basicUnsafeMove :: UVector.MVector (PrimState m) Word32 -> UVector.MVector (PrimState m) Word32 -> m ())--- basicUnsafeGrow :: forall m. PrimMonad m => UVector.MVector (PrimState m) IPv4 -> Int -> m (UVector.MVector (PrimState m) IPv4)--- basicUnsafeGrow (MV_IPv4 v) i = fmap coerce (basicUnsafeGrow v i)+newtype instance UVector.MVector s IPv4 = MV_IPv4 (PVector.MVector s IPv4)+newtype instance UVector.Vector IPv4 = V_IPv4 (PVector.Vector IPv4) +instance UVector.Unbox IPv4++instance MGVector.MVector UVector.MVector IPv4 where+ {-# INLINE basicLength #-}+ {-# INLINE basicUnsafeSlice #-}+ {-# INLINE basicOverlaps #-}+ {-# INLINE basicUnsafeNew #-}+ {-# INLINE basicInitialize #-}+ {-# INLINE basicUnsafeReplicate #-}+ {-# INLINE basicUnsafeRead #-}+ {-# INLINE basicUnsafeWrite #-}+ {-# INLINE basicClear #-}+ {-# INLINE basicSet #-}+ {-# INLINE basicUnsafeCopy #-}+ {-# INLINE basicUnsafeGrow #-}+ basicLength (MV_IPv4 v) = MGVector.basicLength v+ basicUnsafeSlice i n (MV_IPv4 v) = MV_IPv4 $ MGVector.basicUnsafeSlice i n v+ basicOverlaps (MV_IPv4 v1) (MV_IPv4 v2) = MGVector.basicOverlaps v1 v2+ basicUnsafeNew n = MV_IPv4 `liftM` MGVector.basicUnsafeNew n+ basicInitialize (MV_IPv4 v) = MGVector.basicInitialize v+ basicUnsafeReplicate n x = MV_IPv4 `liftM` MGVector.basicUnsafeReplicate n x+ basicUnsafeRead (MV_IPv4 v) i = MGVector.basicUnsafeRead v i+ basicUnsafeWrite (MV_IPv4 v) i x = MGVector.basicUnsafeWrite v i x+ basicClear (MV_IPv4 v) = MGVector.basicClear v+ basicSet (MV_IPv4 v) x = MGVector.basicSet v x+ basicUnsafeCopy (MV_IPv4 v1) (MV_IPv4 v2) = MGVector.basicUnsafeCopy v1 v2+ basicUnsafeMove (MV_IPv4 v1) (MV_IPv4 v2) = MGVector.basicUnsafeMove v1 v2+ basicUnsafeGrow (MV_IPv4 v) n = MV_IPv4 `liftM` MGVector.basicUnsafeGrow v n++instance GVector.Vector UVector.Vector IPv4 where+ {-# INLINE basicUnsafeFreeze #-}+ {-# INLINE basicUnsafeThaw #-}+ {-# INLINE basicLength #-}+ {-# INLINE basicUnsafeSlice #-}+ {-# INLINE basicUnsafeIndexM #-}+ {-# INLINE elemseq #-}+ basicUnsafeFreeze (MV_IPv4 v) = V_IPv4 `liftM` GVector.basicUnsafeFreeze v+ basicUnsafeThaw (V_IPv4 v) = MV_IPv4 `liftM` GVector.basicUnsafeThaw v+ basicLength (V_IPv4 v) = GVector.basicLength v+ basicUnsafeSlice i n (V_IPv4 v) = V_IPv4 $ GVector.basicUnsafeSlice i n v+ basicUnsafeIndexM (V_IPv4 v) i = GVector.basicUnsafeIndexM v i+ basicUnsafeCopy (MV_IPv4 mv) (V_IPv4 v) = GVector.basicUnsafeCopy mv v+ elemseq _ = seq++data Mac = Mac+ { macA :: {-# UNPACK #-} !Word16+ , macB :: {-# UNPACK #-} !Word32+ }+ deriving (Eq,Ord,Show,Read,Generic)++instance Hashable Mac++instance ToJSON Mac where+ toJSON (Mac a b) = Aeson.String (Internal.macToText a b)++instance FromJSON Mac where+ parseJSON = Internal.attoparsecParseJSON+ (Internal.macTextParser macFromOctets' <* AT.endOfInput)++macFromOctets' :: Word16 -> Word16 -> Word32 -> Word32 -> Word32 -> Word32 -> Mac+macFromOctets' a b c d e f = Mac+ ( shiftL a 8 .|. b )+ ( shiftL c 24 .|. shiftL d 16 .|. shiftL e 8 .|. f )+{-# INLINE macFromOctets' #-}