    -- |
    -- Module      : Unicode.Char.Case.Compat
    -- Copyright   : (c) 2020 Composewell Technologies and Contributors
    -- License     : Apache-2.0
    -- Maintainer  : streamly@composewell.com
    -- Stability   : experimental
    --
    -- Compatibility module for case and case mapping related functions.
    --
    -- The functions of this module are drop-in replacement for those in "Data.Char".
    -- They are similar but not identical to some functions in "Unicode.Char.Case",
    -- therefore they are placed in a separate module in order to avoid ambiguity.
    --
    module Unicode.Char.Case.Compat
        ( -- * Predicates
          isUpper
        , isLower
          -- * Case conversion
        , toUpper
        , toLower
        , toTitle
        ) where

    import Data.Char (ord)
    import qualified Unicode.Internal.Char.UnicodeData.GeneralCategory as UC
    import qualified Unicode.Internal.Char.UnicodeData.SimpleLowerCaseMapping as C
    import qualified Unicode.Internal.Char.UnicodeData.SimpleTitleCaseMapping as C
    import qualified Unicode.Internal.Char.UnicodeData.SimpleUpperCaseMapping as C

    -- | Selects upper-case or title-case alphabetic Unicode characters (letters).
    -- Title case is used by a small number of letter ligatures like the
    -- single-character form of /Lj/.
    --
    -- It matches characters with general category
    -- 'Unicode.Char.General.UppercaseLetter' and
    -- 'Unicode.Char.General.TitlecaseLetter'.
    --
    -- See: 'Unicode.Char.Case.isUpperCase' for the /full upper/ case predicate.
    --
    -- prop> isUpper c == Data.Char.isUpper c
    --
    -- @since 0.3.0
    isUpper :: Char -> Bool
    isUpper :: Char -> Bool
    isUpper Char
    c =
        -- NOTE: The guard constant is updated at each Unicode revision.
        --       It must be < 0x40000 to be accepted by generalCategoryPlanes0To3.
        Int
    cp Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int
    UC.MaxIsUpper Bool -> Bool -> Bool
    &&
        case Int -> Int
    UC.generalCategoryPlanes0To3 Int
    cp of
            Int
    UC.UppercaseLetter -> Bool
    True
            Int
    UC.TitlecaseLetter -> Bool
    True
            Int
    _                  -> Bool
    False
        where !cp :: Int
    cp = Char -> Int
    ord Char
    c

    -- | Selects lower-case alphabetic Unicode characters (letters).
    --
    -- It matches characters with general category 'Unicode.Char.Case.LowercaseLetter'.
    --
    -- See: 'Unicode.Char.Case.isLowerCase' for the /full/ lower case predicate.
    --
    -- prop> isLower c == Data.Char.isLower c
    --
    -- @since 0.3.0
    isLower :: Char -> Bool
    isLower :: Char -> Bool
    isLower Char
    c =
        -- NOTE: The guard constant is updated at each Unicode revision.
        --       It must be < 0x40000 to be accepted by generalCategoryPlanes0To3.
        Int
    cp Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int
    UC.MaxIsLower Bool -> Bool -> Bool
    &&
        case Int -> Int
    UC.generalCategoryPlanes0To3 Int
    cp of
            Int
    UC.LowercaseLetter -> Bool
    True
            Int
    _                  -> Bool
    False
        where !cp :: Int
    cp = Char -> Int
    ord Char
    c

    -- | Convert a letter to the corresponding upper-case letter, if any.
    -- Any other character is returned unchanged.
    --
    -- It uses the character property @Simple_Uppercase_Mapping@.
    --
    -- See: 'Unicode.Char.Case.upperCaseMapping' and
    -- 'Unicode.Char.Case.toUpperString' for /full/ upper case conversion.
    --
    -- prop> toUpper c == Data.Char.toUpper c
    --
    -- @since 0.3.0
    {-# INLINE toUpper #-}
    toUpper :: Char -> Char
    toUpper :: Char -> Char
    toUpper = Char -> Char
    C.toSimpleUpperCase

    -- | Convert a letter to the corresponding lower-case letter, if any.
    -- Any other character is returned unchanged.
    --
    -- It uses the character property @Simple_Lowercase_Mapping@.
    --
    -- See: 'Unicode.Char.Case.lowerCaseMapping' and
    -- 'Unicode.Char.Case.toLowerString' for /full/ lower case conversion.
    --
    -- prop> toLower c == Data.Char.toLower c
    --
    -- @since 0.3.0
    {-# INLINE toLower #-}
    toLower :: Char -> Char
    toLower :: Char -> Char
    toLower = Char -> Char
    C.toSimpleLowerCase

    -- | Convert a letter to the corresponding title-case or upper-case letter,
    -- if any. (Title case differs from upper case only for a small number of
    -- ligature letters.) Any other character is returned unchanged.
    --
    -- It uses the character property @Simple_Titlecase_Mapping@.
    --
    -- See: 'Unicode.Char.Case.titleCaseMapping' and
    -- 'Unicode.Char.Case.toTitleString' for /full/ title case conversion.
    --
    -- prop> toTitle c == Data.Char.toTitle c
    --
    -- @since 0.3.0
    {-# INLINE toTitle #-}
    toTitle :: Char -> Char
    toTitle :: Char -> Char
    toTitle = Char -> Char
    C.toSimpleTitleCase