{-# LANGUAGE BangPatterns #-}

module Codec.Serialise.Internal.GeneralisedUTF8
    ( encodeGenUTF8
    , UTF8Encoding(..)
    , decodeGenUTF8
      -- * Utilities
    , isSurrogate
    , isValid
    ) where

import Control.Monad.ST
import Data.Bits
import Data.Char
import Data.Word
import qualified Codec.CBOR.ByteArray.Sliced as BAS
import Data.Primitive.ByteArray

data UTF8Encoding = ConformantUTF8 | GeneralisedUTF8
                  deriving (Int -> UTF8Encoding -> ShowS
[UTF8Encoding] -> ShowS
UTF8Encoding -> String
(Int -> UTF8Encoding -> ShowS)
-> (UTF8Encoding -> String)
-> ([UTF8Encoding] -> ShowS)
-> Show UTF8Encoding
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UTF8Encoding] -> ShowS
$cshowList :: [UTF8Encoding] -> ShowS
show :: UTF8Encoding -> String
$cshow :: UTF8Encoding -> String
showsPrec :: Int -> UTF8Encoding -> ShowS
$cshowsPrec :: Int -> UTF8Encoding -> ShowS
Show, UTF8Encoding -> UTF8Encoding -> Bool
(UTF8Encoding -> UTF8Encoding -> Bool)
-> (UTF8Encoding -> UTF8Encoding -> Bool) -> Eq UTF8Encoding
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UTF8Encoding -> UTF8Encoding -> Bool
$c/= :: UTF8Encoding -> UTF8Encoding -> Bool
== :: UTF8Encoding -> UTF8Encoding -> Bool
$c== :: UTF8Encoding -> UTF8Encoding -> Bool
Eq)

-- | Is a 'Char' a UTF-16 surrogate?
isSurrogate :: Char -> Bool
isSurrogate :: Char -> Bool
isSurrogate c :: Char
c = Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= '\xd800' Bool -> Bool -> Bool
&& Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= '\xdfff'

-- | Encode a string as (generalized) UTF-8. In addition to the encoding, we
-- return a flag indicating whether the encoded string contained any surrogate
-- characters, in which case the output is generalized UTF-8.
encodeGenUTF8 :: String -> (BAS.SlicedByteArray, UTF8Encoding)
encodeGenUTF8 :: String -> (SlicedByteArray, UTF8Encoding)
encodeGenUTF8 st :: String
st = (forall s. ST s (SlicedByteArray, UTF8Encoding))
-> (SlicedByteArray, UTF8Encoding)
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s (SlicedByteArray, UTF8Encoding))
 -> (SlicedByteArray, UTF8Encoding))
-> (forall s. ST s (SlicedByteArray, UTF8Encoding))
-> (SlicedByteArray, UTF8Encoding)
forall a b. (a -> b) -> a -> b
$ do
    -- We slightly over-allocate such that we won't need to copy in the
    -- ASCII-only case.
    MutableByteArray s
ba <- Int -> ST s (MutableByteArray (PrimState (ST s)))
forall (m :: * -> *).
PrimMonad m =>
Int -> m (MutableByteArray (PrimState m))
newByteArray (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
st Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 4)
    MutableByteArray s
-> UTF8Encoding
-> Int
-> String
-> ST s (SlicedByteArray, UTF8Encoding)
forall s.
MutableByteArray s
-> UTF8Encoding
-> Int
-> String
-> ST s (SlicedByteArray, UTF8Encoding)
go MutableByteArray s
ba UTF8Encoding
ConformantUTF8 0 String
st
  where
    go :: MutableByteArray s -> UTF8Encoding
       -> Int -> [Char]
       -> ST s (BAS.SlicedByteArray, UTF8Encoding)
    go :: MutableByteArray s
-> UTF8Encoding
-> Int
-> String
-> ST s (SlicedByteArray, UTF8Encoding)
go ba :: MutableByteArray s
ba !UTF8Encoding
enc !Int
off  [] = do
        ByteArray
ba' <- MutableByteArray (PrimState (ST s)) -> ST s ByteArray
forall (m :: * -> *).
PrimMonad m =>
MutableByteArray (PrimState m) -> m ByteArray
unsafeFreezeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
ba
        (SlicedByteArray, UTF8Encoding)
-> ST s (SlicedByteArray, UTF8Encoding)
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteArray -> Int -> Int -> SlicedByteArray
BAS.SBA ByteArray
ba' 0 Int
off, UTF8Encoding
enc)
    go ba :: MutableByteArray s
ba enc :: UTF8Encoding
enc off :: Int
off  (c :: Char
c:cs :: String
cs)
      | Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 4 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
cap = do
        -- We ran out of room; reallocate and copy
        MutableByteArray s
ba' <- Int -> ST s (MutableByteArray (PrimState (ST s)))
forall (m :: * -> *).
PrimMonad m =>
Int -> m (MutableByteArray (PrimState m))
newByteArray (Int
cap Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
cap Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` 2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1)
        MutableByteArray (PrimState (ST s))
-> Int
-> MutableByteArray (PrimState (ST s))
-> Int
-> Int
-> ST s ()
forall (m :: * -> *).
PrimMonad m =>
MutableByteArray (PrimState m)
-> Int -> MutableByteArray (PrimState m) -> Int -> Int -> m ()
copyMutableByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
ba' 0 MutableByteArray s
MutableByteArray (PrimState (ST s))
ba 0 Int
off
        MutableByteArray s
-> UTF8Encoding
-> Int
-> String
-> ST s (SlicedByteArray, UTF8Encoding)
forall s.
MutableByteArray s
-> UTF8Encoding
-> Int
-> String
-> ST s (SlicedByteArray, UTF8Encoding)
go MutableByteArray s
ba' UTF8Encoding
enc Int
off (Char
cChar -> ShowS
forall a. a -> [a] -> [a]
:String
cs)

      | Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= '\x10000' = do
        MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
ba (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+0) (0xf0 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (0x07 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Int -> Word8
shiftedByte 18))
        MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
ba (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) (0x80 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (0x3f Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Int -> Word8
shiftedByte 12))
        MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
ba (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+2) (0x80 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (0x3f Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Int -> Word8
shiftedByte  6))
        MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
ba (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+3) (0x80 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (0x3f Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Int -> Word8
shiftedByte  0))
        MutableByteArray s
-> UTF8Encoding
-> Int
-> String
-> ST s (SlicedByteArray, UTF8Encoding)
forall s.
MutableByteArray s
-> UTF8Encoding
-> Int
-> String
-> ST s (SlicedByteArray, UTF8Encoding)
go MutableByteArray s
ba UTF8Encoding
enc (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+4) String
cs

      | Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= '\x0800'  = do
        MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
ba (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+0) (0xe0 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (0x0f Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Int -> Word8
shiftedByte 12))
        MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
ba (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) (0x80 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (0x3f Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Int -> Word8
shiftedByte  6))
        MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
ba (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+2) (0x80 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (0x3f Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Int -> Word8
shiftedByte  0))

        -- Is this a surrogate character?
        let enc' :: UTF8Encoding
enc'
              | Char -> Bool
isSurrogate Char
c = UTF8Encoding
GeneralisedUTF8
              | Bool
otherwise     = UTF8Encoding
enc
        MutableByteArray s
-> UTF8Encoding
-> Int
-> String
-> ST s (SlicedByteArray, UTF8Encoding)
forall s.
MutableByteArray s
-> UTF8Encoding
-> Int
-> String
-> ST s (SlicedByteArray, UTF8Encoding)
go MutableByteArray s
ba UTF8Encoding
enc' (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+3) String
cs

      | Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= '\x0080'  = do
        MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
ba (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+0) (0xc0 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (0x1f Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Int -> Word8
shiftedByte  6))
        MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
ba (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) (0x80 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (0x3f Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Int -> Word8
shiftedByte  0))
        MutableByteArray s
-> UTF8Encoding
-> Int
-> String
-> ST s (SlicedByteArray, UTF8Encoding)
forall s.
MutableByteArray s
-> UTF8Encoding
-> Int
-> String
-> ST s (SlicedByteArray, UTF8Encoding)
go MutableByteArray s
ba UTF8Encoding
enc (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+2) String
cs

      | Char
c Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= '\x007f'  = do
        MutableByteArray (PrimState (ST s)) -> Int -> Word8 -> ST s ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray s
MutableByteArray (PrimState (ST s))
ba Int
off (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n :: Word8)
        MutableByteArray s
-> UTF8Encoding
-> Int
-> String
-> ST s (SlicedByteArray, UTF8Encoding)
forall s.
MutableByteArray s
-> UTF8Encoding
-> Int
-> String
-> ST s (SlicedByteArray, UTF8Encoding)
go MutableByteArray s
ba UTF8Encoding
enc (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+1) String
cs

      | Bool
otherwise      = String -> ST s (SlicedByteArray, UTF8Encoding)
forall a. HasCallStack => String -> a
error "encodeGenUTF8: Impossible"
      where
        cap :: Int
cap = MutableByteArray s -> Int
forall s. MutableByteArray s -> Int
sizeofMutableByteArray MutableByteArray s
ba
        n :: Int
n = Char -> Int
ord Char
c
        shiftedByte :: Int -> Word8
        shiftedByte :: Int -> Word8
shiftedByte shft :: Int
shft = Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word8) -> Int -> Word8
forall a b. (a -> b) -> a -> b
$ Int
n Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftR` Int
shft

decodeGenUTF8 :: ByteArray -> String
decodeGenUTF8 :: ByteArray -> String
decodeGenUTF8 ba :: ByteArray
ba = Int -> String
go 0
  where
    !len :: Int
len = ByteArray -> Int
sizeofByteArray ByteArray
ba

    index :: Int -> Int
    index :: Int -> Int
index i :: Int
i = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteArray
ba ByteArray -> Int -> Word8
forall a. Prim a => ByteArray -> Int -> a
`indexByteArray` Int
i :: Word8)

    go :: Int -> String
go !Int
off
      | Int
off Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
len = []

      | Int
n0 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. 0xf8 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 0xf0 =
        let n1 :: Int
n1 = Int -> Int
index (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1)
            n2 :: Int
n2 = Int -> Int
index (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 2)
            n3 :: Int
n3 = Int -> Int
index (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 3)
            c :: Char
c  = Int -> Char
chr (Int -> Char) -> Int -> Char
forall a b. (a -> b) -> a -> b
$  (Int
n0 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. 0x07) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` 18
                    Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
n1 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. 0x3f) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` 12
                    Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
n2 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. 0x3f) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL`  6
                    Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
n3 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. 0x3f)
        in Char
c Char -> ShowS
forall a. a -> [a] -> [a]
: Int -> String
go (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 4)

      | Int
n0 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. 0xf0 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 0xe0 =
        let n1 :: Int
n1 = Int -> Int
index (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1)
            n2 :: Int
n2 = Int -> Int
index (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 2)
            c :: Char
c  = Int -> Char
chr (Int -> Char) -> Int -> Char
forall a b. (a -> b) -> a -> b
$  (Int
n0 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. 0x0f) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` 12
                    Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
n1 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. 0x3f) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL`  6
                    Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
n2 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. 0x3f)
        in Char
c Char -> ShowS
forall a. a -> [a] -> [a]
: Int -> String
go (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 3)

      | Int
n0 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. 0xe0 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 0xc0 =
        let n1 :: Int
n1 = Int -> Int
index (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1)
            c :: Char
c  = Int -> Char
chr (Int -> Char) -> Int -> Char
forall a b. (a -> b) -> a -> b
$  (Int
n0 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. 0x1f) Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL`  6
                    Int -> Int -> Int
forall a. Bits a => a -> a -> a
.|. (Int
n1 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. 0x3f)
        in Char
c Char -> ShowS
forall a. a -> [a] -> [a]
: Int -> String
go (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 2)

      | Bool
otherwise =
        let c :: Char
c =  Int -> Char
chr (Int -> Char) -> Int -> Char
forall a b. (a -> b) -> a -> b
$  (Int
n0 Int -> Int -> Int
forall a. Bits a => a -> a -> a
.&. 0x7f)
        in Char
c Char -> ShowS
forall a. a -> [a] -> [a]
: Int -> String
go (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1)
      where !n0 :: Int
n0 = Int -> Int
index Int
off

-- | Is the given byte sequence valid under the given encoding?
isValid :: UTF8Encoding -> [Word8] -> Bool
isValid :: UTF8Encoding -> [Word8] -> Bool
isValid encoding :: UTF8Encoding
encoding = [Word8] -> Bool
forall a. (Ord a, Num a) => [a] -> Bool
go
  where
    go :: [a] -> Bool
go [] = Bool
True
    go (b0 :: a
b0:bs :: [a]
bs)
      | a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x00 0x7f a
b0 = [a] -> Bool
go [a]
bs
    go (b0 :: a
b0:b1 :: a
b1:bs :: [a]
bs)
      | a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0xc2 0xdf a
b0
      , a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x80 0xbf a
b1 = [a] -> Bool
go [a]
bs
    go (0xe0:b1 :: a
b1:b2 :: a
b2:bs :: [a]
bs)
      | a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0xa0 0xbf a
b1
      , a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x80 0xbf a
b2 = [a] -> Bool
go [a]
bs
    go (0xed:b1 :: a
b1:_)
      -- surrogate range
      | UTF8Encoding
encoding UTF8Encoding -> UTF8Encoding -> Bool
forall a. Eq a => a -> a -> Bool
== UTF8Encoding
ConformantUTF8
      , a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0xa0 0xbf a
b1
      = Bool
False
    go (b0 :: a
b0:b1 :: a
b1:b2 :: a
b2:bs :: [a]
bs)
      | a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0xe1 0xef a
b0
      , a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x80 0xbf a
b1
      , a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x80 0xbf a
b2 = [a] -> Bool
go [a]
bs
    go (0xf0:b1 :: a
b1:b2 :: a
b2:b3 :: a
b3:bs :: [a]
bs)
      | a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x90 0xbf a
b1
      , a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x80 0xbf a
b2
      , a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x80 0xbf a
b3 = [a] -> Bool
go [a]
bs
    go (b0 :: a
b0:b1 :: a
b1:b2 :: a
b2:b3 :: a
b3:bs :: [a]
bs)
      | a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0xf1 0xf3 a
b0
      , a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x80 0xbf a
b1
      , a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x80 0xbf a
b2
      , a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x80 0xbf a
b3 = [a] -> Bool
go [a]
bs
    go (0xf4:b1 :: a
b1:b2 :: a
b2:b3 :: a
b3:bs :: [a]
bs)
      | a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x80 0x8f a
b1
      , a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x80 0xbf a
b2
      , a -> a -> a -> Bool
forall a. Ord a => a -> a -> a -> Bool
inRange 0x80 0xbf a
b3 = [a] -> Bool
go [a]
bs
    go _ = Bool
False

inRange :: Ord a => a -> a -> a -> Bool
inRange :: a -> a -> a -> Bool
inRange lower :: a
lower upper :: a
upper x :: a
x = a
lower a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
x Bool -> Bool -> Bool
&& a
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
upper