diff --git a/ip.cabal b/ip.cabal
--- a/ip.cabal
+++ b/ip.cabal
@@ -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
diff --git a/src/Net/IPv4.hs b/src/Net/IPv4.hs
--- a/src/Net/IPv4.hs
+++ b/src/Net/IPv4.hs
@@ -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
 
diff --git a/src/Net/Internal.hs b/src/Net/Internal.hs
--- a/src/Net/Internal.hs
+++ b/src/Net/Internal.hs
@@ -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' #-}
 
diff --git a/src/Net/Mac.hs b/src/Net/Mac.hs
--- a/src/Net/Mac.hs
+++ b/src/Net/Mac.hs
@@ -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 #-}
 
 
diff --git a/src/Net/Mac/ByteString/Char8.hs b/src/Net/Mac/ByteString/Char8.hs
--- a/src/Net/Mac/ByteString/Char8.hs
+++ b/src/Net/Mac/ByteString/Char8.hs
@@ -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)
diff --git a/src/Net/Mac/Text.hs b/src/Net/Mac/Text.hs
--- a/src/Net/Mac/Text.hs
+++ b/src/Net/Mac/Text.hs
@@ -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
 
diff --git a/src/Net/Types.hs b/src/Net/Types.hs
--- a/src/Net/Types.hs
+++ b/src/Net/Types.hs
@@ -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' #-}
