{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE DeriveGeneric #-}

-- |
-- Module      : Unicode.Char.General.Blocks
-- Copyright   : (c) 2020 Composewell Technologies and Contributors
-- License     : Apache-2.0
-- Maintainer  : streamly@composewell.com
-- Stability   : experimental
--
-- Unicode [blocks](https://www.unicode.org/glossary/#block) related functions.
--
-- @since 0.3.1

module Unicode.Char.General.Blocks
    ( -- * Blocks
      B.Block(..)
    , block
      -- * Blocks definitions
    , BlockDefinition(..)
    , blockDefinition
    )

where

import GHC.Exts (Char (..), Int (..), dataToTag#, tagToEnum#)

import Unicode.Internal.Bits (unpackCString#)
import qualified Unicode.Internal.Char.Blocks as B

-- | Character [block](https://www.unicode.org/glossary/#block), if defined.
--
-- @since 0.3.1
{-# INLINE block #-}
block :: Char -> Maybe B.Block
block :: Char -> Maybe Block
block (C# Char#
c#) = case Char# -> Int#
B.block Char#
c# of
    Int#
-1# -> Maybe Block
forall a. Maybe a
Nothing
    Int#
b#  -> Block -> Maybe Block
forall a. a -> Maybe a
Just (Int# -> Block
forall a. Int# -> a
tagToEnum# Int#
b# :: B.Block)

-- | Block definition: range and name.
--
-- @since 0.3.1
data BlockDefinition = BlockDefinition
    { BlockDefinition -> (Int, Int)
blockRange :: !(Int, Int) -- ^ Range
    , BlockDefinition -> String
blockName :: !String      -- ^ Name
    } deriving (BlockDefinition -> BlockDefinition -> Bool
(BlockDefinition -> BlockDefinition -> Bool)
-> (BlockDefinition -> BlockDefinition -> Bool)
-> Eq BlockDefinition
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BlockDefinition -> BlockDefinition -> Bool
== :: BlockDefinition -> BlockDefinition -> Bool
$c/= :: BlockDefinition -> BlockDefinition -> Bool
/= :: BlockDefinition -> BlockDefinition -> Bool
Eq, Eq BlockDefinition
Eq BlockDefinition
-> (BlockDefinition -> BlockDefinition -> Ordering)
-> (BlockDefinition -> BlockDefinition -> Bool)
-> (BlockDefinition -> BlockDefinition -> Bool)
-> (BlockDefinition -> BlockDefinition -> Bool)
-> (BlockDefinition -> BlockDefinition -> Bool)
-> (BlockDefinition -> BlockDefinition -> BlockDefinition)
-> (BlockDefinition -> BlockDefinition -> BlockDefinition)
-> Ord BlockDefinition
BlockDefinition -> BlockDefinition -> Bool
BlockDefinition -> BlockDefinition -> Ordering
BlockDefinition -> BlockDefinition -> BlockDefinition
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: BlockDefinition -> BlockDefinition -> Ordering
compare :: BlockDefinition -> BlockDefinition -> Ordering
$c< :: BlockDefinition -> BlockDefinition -> Bool
< :: BlockDefinition -> BlockDefinition -> Bool
$c<= :: BlockDefinition -> BlockDefinition -> Bool
<= :: BlockDefinition -> BlockDefinition -> Bool
$c> :: BlockDefinition -> BlockDefinition -> Bool
> :: BlockDefinition -> BlockDefinition -> Bool
$c>= :: BlockDefinition -> BlockDefinition -> Bool
>= :: BlockDefinition -> BlockDefinition -> Bool
$cmax :: BlockDefinition -> BlockDefinition -> BlockDefinition
max :: BlockDefinition -> BlockDefinition -> BlockDefinition
$cmin :: BlockDefinition -> BlockDefinition -> BlockDefinition
min :: BlockDefinition -> BlockDefinition -> BlockDefinition
Ord, Int -> BlockDefinition -> ShowS
[BlockDefinition] -> ShowS
BlockDefinition -> String
(Int -> BlockDefinition -> ShowS)
-> (BlockDefinition -> String)
-> ([BlockDefinition] -> ShowS)
-> Show BlockDefinition
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BlockDefinition -> ShowS
showsPrec :: Int -> BlockDefinition -> ShowS
$cshow :: BlockDefinition -> String
show :: BlockDefinition -> String
$cshowList :: [BlockDefinition] -> ShowS
showList :: [BlockDefinition] -> ShowS
Show)

-- | Block definition
--
-- @since 0.3.1
blockDefinition :: B.Block -> BlockDefinition
blockDefinition :: Block -> BlockDefinition
blockDefinition Block
b = case Int# -> (# Int#, Int#, Addr# #)
B.blockDefinition (Block -> Int#
forall a. a -> Int#
dataToTag# Block
b) of
    (# Int#
lower#, Int#
upper#, Addr#
name# #) -> (Int, Int) -> String -> BlockDefinition
BlockDefinition (Int, Int)
range String
name
        where
        !range :: (Int, Int)
range = (Int# -> Int
I# Int#
lower#, Int# -> Int
I# Int#
upper#)
        -- Note: names are ASCII. See Unicode Standard 15.0.0, section 3.4.
        !name :: String
name = Addr# -> String
unpackCString# Addr#
name#