packages feed

simple-pango-0.1.0.1: src/Graphics/Pango/Basic/ScriptsAndLanguages/PangoScript/Internal.hsc

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE BlockArguments, LambdaCase, TupleSections #-}
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Graphics.Pango.Basic.ScriptsAndLanguages.PangoScript.Internal (
	-- * FUNCTION
	pangoScriptForUnichar, pangoScriptGetSampleLanguage, pangoScriptForText,
	-- * ENUM
	module Graphics.Pango.Basic.ScriptsAndLanguages.PangoScript.Enum,
	) where

import Foreign.Ptr
import Foreign.Marshal
import Foreign.Storable
import Foreign.C.Types
import Foreign.C.String
import Control.Exception
import Data.Traversable
import Data.Bool
import Data.Word
import Data.Int
import Data.Char
import System.IO.Unsafe

import Graphics.Pango.Basic.ScriptsAndLanguages.PangoLanguage.Internal
import Graphics.Pango.Basic.ScriptsAndLanguages.PangoScript.Enum

import qualified Data.Text as T
import qualified Data.Text.Foreign as T
import qualified Data.Text.Foreign.StringPartial as T

#include <pango/pango.h>

pangoScriptForUnichar :: Char -> PangoScript
pangoScriptForUnichar c = unsafePerformIO
	$ PangoScript <$> c_pango_script_for_unichar (fromIntegral $ ord c)

foreign import ccall "pango_script_for_unichar" c_pango_script_for_unichar ::
	#{type gunichar} -> IO #{type PangoScript}

pangoScriptGetSampleLanguage :: PangoScript -> IO (Maybe PangoLanguage)
pangoScriptGetSampleLanguage (PangoScript s) =
	nullable Nothing (Just . PangoLanguage_)
		<$> c_pango_script_get_sample_language s

foreign import ccall "pango_script_get_sample_language"
	c_pango_script_get_sample_language ::
	#{type PangoScript} -> IO (Ptr PangoLanguage)

pattern NullPtr :: Ptr a
pattern NullPtr <- ((== nullPtr) -> True) where NullPtr = nullPtr

nullable :: b -> (Ptr a -> b) -> Ptr a -> b
nullable d f = \case NullPtr -> d; p -> f p

pangoScriptForText :: T.Text -> [(T.Text, PangoScript)]
pangoScriptForText t = unsafePerformIO $ withPangoScriptIter t \i -> do
	rss <- pangoScriptIterGetRanges i
	for rss \(r, s) -> (, s) <$> T.peekCStringPart r

data PangoScriptIter

withPangoScriptIter :: T.Text -> (Ptr PangoScriptIter -> IO a) -> IO a
withPangoScriptIter t f = T.withCStringLen t \(cs, l) -> bracket
	(c_pango_script_iter_new cs $ fromIntegral l) c_pango_script_iter_free f

foreign import ccall "pango_script_iter_new" c_pango_script_iter_new ::
	CString -> CInt -> IO (Ptr PangoScriptIter)

foreign import ccall "pango_script_iter_free" c_pango_script_iter_free ::
	Ptr PangoScriptIter -> IO ()

pangoScriptIterGetRanges :: Ptr PangoScriptIter -> IO [(T.CStringPart, PangoScript)]
pangoScriptIterGetRanges i = unsafeInterleaveIO do
	rs@(r, _) <- pangoScriptIterGetRange i
	(\r' e f -> T.emptyOrCStringPart e f r') r (pure [])
		$ pangoScriptIterNext i
			>>= bool (pure [rs]) ((rs :) <$> pangoScriptIterGetRanges i)

pangoScriptIterGetRange :: Ptr PangoScriptIter -> IO (T.CStringPart, PangoScript)
pangoScriptIterGetRange i = alloca \st -> alloca \ed -> alloca \s -> do
	c_pango_script_iter_get_range i st ed s
	(,) <$> ((,) <$> peek st <*> peek ed) <*> (PangoScript <$> peek s)

foreign import ccall "pango_script_iter_get_range" c_pango_script_iter_get_range ::
	Ptr PangoScriptIter -> Ptr CString -> Ptr CString -> Ptr #{type PangoScript} -> IO ()

pangoScriptIterNext :: Ptr PangoScriptIter -> IO Bool
pangoScriptIterNext i = (<$> c_pango_script_iter_next i) \case
	#{const FALSE} -> False; #{const TRUE} -> True
	_ -> error "never occur"

foreign import ccall "pango_script_iter_next" c_pango_script_iter_next ::
	Ptr PangoScriptIter -> IO #{type gboolean}