diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # Revision history for byteslice
 
+## 0.2.10.0 -- 2023-05-01
+
+* Add `equals13`, `equals14`, `equals15`.
+* Add `Show` instances for `BytesN` and `ByteArrayN`.
+* Add `equalsCStringCaseInsensitive` for ascii text.
+
 ## 0.2.9.0 -- 2022-12-08
 
 * Add `toShortText`, `toShortTextU`, and `toText` to `Data.Byte.Text.Ascii`.
diff --git a/byteslice.cabal b/byteslice.cabal
--- a/byteslice.cabal
+++ b/byteslice.cabal
@@ -1,6 +1,6 @@
 cabal-version: 2.4
 name: byteslice
-version: 0.2.9.0
+version: 0.2.10.0
 synopsis: Slicing managed and unmanaged memory
 description:
   This library provides types that allow the user to talk about a slice of
@@ -25,6 +25,7 @@
   exposed-modules:
     Data.Bytes
     Data.Bytes.Chunks
+    Data.Bytes.Encode.BigEndian
     Data.Bytes.Internal
     Data.Bytes.Mutable
     Data.Bytes.Text.Ascii
@@ -38,12 +39,13 @@
     Data.Bytes.Byte
     Data.Bytes.Pure
     Data.Bytes.IO
+    Data.Bytes.Internal.Show
     Reps
     Cstrlen
   build-depends:
     , base >=4.14 && <5
     , bytestring >=0.10.8 && <0.12
-    , primitive >=0.7.4 && <0.8
+    , primitive >=0.7.4 && <0.10
     , primitive-unlifted >=0.1.2 && <0.2
     , primitive-addr >=0.1 && <0.2
     , run-st >=0.1.1 && <0.2
diff --git a/src/Data/Bytes/Encode/BigEndian.hs b/src/Data/Bytes/Encode/BigEndian.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Bytes/Encode/BigEndian.hs
@@ -0,0 +1,77 @@
+{-# language BangPatterns #-}
+{-# language TypeApplications #-}
+
+module Data.Bytes.Encode.BigEndian
+  ( word16
+  , word32
+  , word64
+  , int16
+  , int32
+  , int64
+  ) where
+
+import Control.Monad.ST.Run (runByteArrayST)
+import Data.Bits (unsafeShiftR)
+import Data.Bytes.Types (Bytes)
+import Data.Int (Int16,Int32,Int64)
+import Data.Primitive (ByteArray)
+import Data.Word (Word8,Word16,Word32,Word64)
+
+import qualified Data.Bytes.Pure as Pure
+import qualified Data.Primitive as PM
+
+-- | Encode a 32-bit signed integer as 4 bytes.
+int32 :: Int32 -> Bytes
+{-# inline int32 #-}
+int32 = word32 . fromIntegral @Int32 @Word32 
+
+-- | Encode a 32-bit unsigned integer as 4 bytes.
+word32 :: Word32 -> Bytes
+word32 !w = Pure.fromByteArray (word32U w)
+
+word32U :: Word32 -> ByteArray
+word32U !w = runByteArrayST $ do
+  arr <- PM.newByteArray 4
+  PM.writeByteArray arr 0 (fromIntegral @Word32 @Word8 (unsafeShiftR w 24))
+  PM.writeByteArray arr 1 (fromIntegral @Word32 @Word8 (unsafeShiftR w 16))
+  PM.writeByteArray arr 2 (fromIntegral @Word32 @Word8 (unsafeShiftR w 8))
+  PM.writeByteArray arr 3 (fromIntegral @Word32 @Word8 w)
+  PM.unsafeFreezeByteArray arr
+
+-- | Encode a 16-bit signed integer as 4 bytes.
+int16 :: Int16 -> Bytes
+{-# inline int16 #-}
+int16 = word16 . fromIntegral @Int16 @Word16 
+
+-- | Encode a 16-bit unsigned integer as 4 bytes.
+word16 :: Word16 -> Bytes
+word16 !w = Pure.fromByteArray (word16U w)
+
+word16U :: Word16 -> ByteArray
+word16U !w = runByteArrayST $ do
+  arr <- PM.newByteArray 2
+  PM.writeByteArray arr 0 (fromIntegral @Word16 @Word8 (unsafeShiftR w 8))
+  PM.writeByteArray arr 1 (fromIntegral @Word16 @Word8 w)
+  PM.unsafeFreezeByteArray arr
+
+-- | Encode a 16-bit signed integer as 4 bytes.
+int64 :: Int64 -> Bytes
+{-# inline int64 #-}
+int64 = word64 . fromIntegral @Int64 @Word64 
+
+-- | Encode a 16-bit unsigned integer as 4 bytes.
+word64 :: Word64 -> Bytes
+word64 !w = Pure.fromByteArray (word64U w)
+
+word64U :: Word64 -> ByteArray
+word64U !w = runByteArrayST $ do
+  arr <- PM.newByteArray 8
+  PM.writeByteArray arr 0 (fromIntegral @Word64 @Word8 (unsafeShiftR w 56))
+  PM.writeByteArray arr 1 (fromIntegral @Word64 @Word8 (unsafeShiftR w 48))
+  PM.writeByteArray arr 2 (fromIntegral @Word64 @Word8 (unsafeShiftR w 40))
+  PM.writeByteArray arr 3 (fromIntegral @Word64 @Word8 (unsafeShiftR w 32))
+  PM.writeByteArray arr 4 (fromIntegral @Word64 @Word8 (unsafeShiftR w 24))
+  PM.writeByteArray arr 5 (fromIntegral @Word64 @Word8 (unsafeShiftR w 16))
+  PM.writeByteArray arr 6 (fromIntegral @Word64 @Word8 (unsafeShiftR w 8))
+  PM.writeByteArray arr 7 (fromIntegral @Word64 @Word8 w)
+  PM.unsafeFreezeByteArray arr
diff --git a/src/Data/Bytes/Internal.hs b/src/Data/Bytes/Internal.hs
--- a/src/Data/Bytes/Internal.hs
+++ b/src/Data/Bytes/Internal.hs
@@ -12,13 +12,11 @@
 
 import Control.Monad.ST (runST)
 import Control.Monad.ST.Run (runByteArrayST)
-import Data.Bits ((.&.),unsafeShiftR)
-import Data.Char (ord)
 import Data.Primitive (ByteArray(..))
 import Data.Word (Word8)
-import GHC.Base (unsafeChr)
 import GHC.Exts (Int(I#),unsafeCoerce#,sameMutableByteArray#)
 import GHC.Exts (isTrue#,compareByteArrays#,IsList(..))
+import Data.Bytes.Internal.Show (showsSlice)
 
 import qualified Data.List as L
 import qualified Data.Foldable as F
@@ -43,26 +41,7 @@
   else []
 
 instance Show Bytes where
-  showsPrec _ (Bytes arr off len) s = if len == 0
-    then showString "[]" s
-    else showString "[0x"
-       $ showHexDigits (PM.indexByteArray arr off)
-       $ showLoop (off + 1) (len - 1) arr
-       $ showChar ']'
-       $ s
-
-showLoop :: Int -> Int -> ByteArray -> String -> String
-showLoop !ix !len !arr s = if len > 0
-  then ',':'0':'x':showHexDigits (PM.indexByteArray arr ix) (showLoop (ix + 1) (len - 1) arr s)
-  else s
-
-showHexDigits :: Word8 -> String -> String
-showHexDigits !w s = word4ToChar (unsafeShiftR w 4) : word4ToChar (0x0F .&. w) : s
-
-word4ToChar :: Word8 -> Char
-word4ToChar w = if w < 10
-  then unsafeChr (ord '0' + fromIntegral w)
-  else unsafeChr (ord 'a' + (fromIntegral w) - 10)
+  showsPrec _ (Bytes arr off len) s = showsSlice arr off len s
 
 instance Eq Bytes where
   Bytes arr1 off1 len1 == Bytes arr2 off2 len2
diff --git a/src/Data/Bytes/Internal/Show.hs b/src/Data/Bytes/Internal/Show.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Bytes/Internal/Show.hs
@@ -0,0 +1,35 @@
+{-# language BangPatterns #-}
+
+module Data.Bytes.Internal.Show
+  ( showsSlice
+  ) where
+
+import Data.Bits ((.&.),unsafeShiftR)
+import Data.Char (ord)
+import Data.Primitive (ByteArray)
+import Data.Word (Word8)
+import GHC.Base (unsafeChr)
+
+import qualified Data.Primitive as PM
+
+showsSlice :: ByteArray -> Int -> Int -> String -> String
+showsSlice arr off len s = if len == 0
+  then showString "[]" s
+  else showString "[0x"
+     $ showHexDigitsWord8 (PM.indexByteArray arr off)
+     $ showHexLoop (off + 1) (len - 1) arr
+     $ showChar ']'
+     $ s
+
+showHexLoop :: Int -> Int -> ByteArray -> String -> String
+showHexLoop !ix !len !arr s = if len > 0
+  then ',':'0':'x':showHexDigitsWord8 (PM.indexByteArray arr ix) (showHexLoop (ix + 1) (len - 1) arr s)
+  else s
+
+showHexDigitsWord8 :: Word8 -> String -> String
+showHexDigitsWord8 !w s = word4ToChar (unsafeShiftR w 4) : word4ToChar (0x0F .&. w) : s
+
+word4ToChar :: Word8 -> Char
+word4ToChar w = if w < 10
+  then unsafeChr (ord '0' + fromIntegral w)
+  else unsafeChr (ord 'a' + (fromIntegral w) - 10)
diff --git a/src/Data/Bytes/Text/Ascii.hs b/src/Data/Bytes/Text/Ascii.hs
--- a/src/Data/Bytes/Text/Ascii.hs
+++ b/src/Data/Bytes/Text/Ascii.hs
@@ -1,5 +1,7 @@
 {-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE BinaryLiterals #-}
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE NumericUnderscores #-}
 {-# LANGUAGE TypeApplications #-}
 
 -- | This module treats 'Bytes' data as holding ASCII text. Providing bytes
@@ -11,6 +13,7 @@
 module Data.Bytes.Text.Ascii
   ( fromString
   , decodeDecWord
+  , equalsCStringCaseInsensitive
   , toShortText
   , toShortTextU
 #if MIN_VERSION_text(2,0,0)
@@ -18,6 +21,7 @@
 #endif
   ) where
 
+import Data.Bits ((.&.))
 import Data.ByteString.Short.Internal (ShortByteString(SBS))
 import Data.Bytes.Text.Latin1 (decodeDecWord)
 import Data.Bytes.Types (Bytes(Bytes))
@@ -26,9 +30,12 @@
 import Data.Text (Text)
 import Data.Text.Short (ShortText)
 import Data.Word (Word8)
+import Foreign.C.String (CString)
+import Foreign.Ptr (Ptr,plusPtr,castPtr)
 
 import qualified Data.Bytes.Pure as Bytes
 import qualified Data.Primitive as PM
+import qualified Data.Primitive.Ptr as PM
 import qualified Data.Text.Array as A
 import qualified Data.Text.Internal as I
 import qualified Data.Text.Short.Unsafe as TS
@@ -67,3 +74,17 @@
   True -> Just (I.Text (A.ByteArray arr) off len)
   False -> Nothing
 #endif
+
+-- | Is the byte sequence equal to the @NUL@-terminated C String?
+-- The C string must be a constant.
+equalsCStringCaseInsensitive :: CString -> Bytes -> Bool
+{-# inline equalsCStringCaseInsensitive #-}
+equalsCStringCaseInsensitive !ptr0 (Bytes arr off0 len0) = go (castPtr ptr0 :: Ptr Word8) off0 len0 where
+  go !ptr !off !len = case len of
+    0 -> PM.indexOffPtr ptr 0 == (0 :: Word8)
+    _ -> case PM.indexOffPtr ptr 0 of
+      0 -> False
+      c ->
+        (c .&. 0b1101_1111) == (PM.indexByteArray arr off .&. 0b1101_1111)
+        &&
+        go (plusPtr ptr 1) (off + 1) (len - 1)
diff --git a/src/Data/Bytes/Text/Latin1.hs b/src/Data/Bytes/Text/Latin1.hs
--- a/src/Data/Bytes/Text/Latin1.hs
+++ b/src/Data/Bytes/Text/Latin1.hs
@@ -35,6 +35,9 @@
   , equals10
   , equals11
   , equals12
+  , equals13
+  , equals14
+  , equals15
   ) where
 
 import Prelude hiding (length)
@@ -215,6 +218,60 @@
         c9 == indexCharArray arr (off + 9) &&
         c10 == indexCharArray arr (off + 10) &&
         c11 == indexCharArray arr (off + 11)
+  _ -> False
+
+equals13 :: Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Bytes -> Bool
+equals13 !c0 !c1 !c2 !c3 !c4 !c5 !c6 !c7 !c8 !c9 !c10 !c11 !c12 (Bytes arr off len) = case len of
+  13 -> c0 == indexCharArray arr off &&
+        c1 == indexCharArray arr (off + 1) &&
+        c2 == indexCharArray arr (off + 2) &&
+        c3 == indexCharArray arr (off + 3) &&
+        c4 == indexCharArray arr (off + 4) &&
+        c5 == indexCharArray arr (off + 5) &&
+        c6 == indexCharArray arr (off + 6) &&
+        c7 == indexCharArray arr (off + 7) &&
+        c8 == indexCharArray arr (off + 8) &&
+        c9 == indexCharArray arr (off + 9) &&
+        c10 == indexCharArray arr (off + 10) &&
+        c11 == indexCharArray arr (off + 11) &&
+        c12 == indexCharArray arr (off + 12)
+  _ -> False
+
+equals14 :: Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Bytes -> Bool
+equals14 !c0 !c1 !c2 !c3 !c4 !c5 !c6 !c7 !c8 !c9 !c10 !c11 !c12 !c13 (Bytes arr off len) = case len of
+  14 -> c0 == indexCharArray arr off &&
+        c1 == indexCharArray arr (off + 1) &&
+        c2 == indexCharArray arr (off + 2) &&
+        c3 == indexCharArray arr (off + 3) &&
+        c4 == indexCharArray arr (off + 4) &&
+        c5 == indexCharArray arr (off + 5) &&
+        c6 == indexCharArray arr (off + 6) &&
+        c7 == indexCharArray arr (off + 7) &&
+        c8 == indexCharArray arr (off + 8) &&
+        c9 == indexCharArray arr (off + 9) &&
+        c10 == indexCharArray arr (off + 10) &&
+        c11 == indexCharArray arr (off + 11) &&
+        c12 == indexCharArray arr (off + 12) &&
+        c13 == indexCharArray arr (off + 13)
+  _ -> False
+
+equals15 :: Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Char -> Bytes -> Bool
+equals15 !c0 !c1 !c2 !c3 !c4 !c5 !c6 !c7 !c8 !c9 !c10 !c11 !c12 !c13 !c14 (Bytes arr off len) = case len of
+  15 -> c0 == indexCharArray arr off &&
+        c1 == indexCharArray arr (off + 1) &&
+        c2 == indexCharArray arr (off + 2) &&
+        c3 == indexCharArray arr (off + 3) &&
+        c4 == indexCharArray arr (off + 4) &&
+        c5 == indexCharArray arr (off + 5) &&
+        c6 == indexCharArray arr (off + 6) &&
+        c7 == indexCharArray arr (off + 7) &&
+        c8 == indexCharArray arr (off + 8) &&
+        c9 == indexCharArray arr (off + 9) &&
+        c10 == indexCharArray arr (off + 10) &&
+        c11 == indexCharArray arr (off + 11) &&
+        c12 == indexCharArray arr (off + 12) &&
+        c13 == indexCharArray arr (off + 13) &&
+        c14 == indexCharArray arr (off + 14)
   _ -> False
 
 indexCharArray :: ByteArray -> Int -> Char
diff --git a/src/Data/Bytes/Types.hs b/src/Data/Bytes/Types.hs
--- a/src/Data/Bytes/Types.hs
+++ b/src/Data/Bytes/Types.hs
@@ -1,8 +1,10 @@
 {-# language BangPatterns #-}
 {-# language DataKinds #-}
+{-# language PolyKinds #-}
 {-# language MagicHash #-}
 {-# language TypeFamilies #-}
 {-# language DuplicateRecordFields #-}
+{-# language ScopedTypeVariables #-}
 
 module Data.Bytes.Types
   ( Bytes(..)
@@ -16,8 +18,11 @@
 import Data.Bytes.Internal (Bytes(..))
 import Data.Primitive (ByteArray(..),MutableByteArray(..))
 import Data.Primitive.Addr (Addr)
-import GHC.TypeNats (Nat)
+import GHC.TypeNats (Nat,KnownNat,natVal)
 import Reps (Bytes#(..))
+import Data.Bytes.Internal.Show (showsSlice)
+import Data.Proxy (Proxy(Proxy))
+import GHC.Natural (naturalToInteger)
 
 -- | A slice of a 'ByteArray' whose compile-time-known length is represented
 -- by a phantom type variable. Consumers of this data constructor must be
@@ -27,12 +32,22 @@
   , offset :: {-# UNPACK #-} !Int
   }
 
+instance KnownNat n => Show (BytesN n) where
+  showsPrec _ (BytesN arr off) s =
+    let len = fromInteger (naturalToInteger (natVal (Proxy :: Proxy n)))
+     in showsSlice arr off len s
+
 -- | A 'ByteArray' whose compile-time-known length is represented
 -- by a phantom type variable. Consumers of this data constructor must be
 -- careful to preserve the expected invariant.
 newtype ByteArrayN (n :: Nat) = ByteArrayN
   { array :: ByteArray
   }
+
+instance KnownNat n => Show (ByteArrayN n) where
+  showsPrec _ (ByteArrayN arr) s =
+    let len = fromInteger (naturalToInteger (natVal (Proxy :: Proxy n)))
+     in showsSlice arr 0 len s
 
 -- | A slice of a 'MutableByteArray'.
 data MutableBytes s = MutableBytes
