{-# LANGUAGE AllowAmbiguousTypes #-}

module FlatBuffers.Internal.FileIdentifier
  ( HasFileIdentifier(..)
  , FileIdentifier(unFileIdentifier)
  , fileIdentifier
  , fileIdentifier'
  , unsafeFileIdentifier
  , unsafeFileIdentifier'
  ) where


import           Data.ByteString                ( ByteString )
import qualified Data.ByteString                as BS
import           Data.Text                      ( Text )
import qualified Data.Text.Encoding             as T

import           FlatBuffers.Internal.Constants ( fileIdentifierSize )

-- | An identifier that's used to "mark" a buffer.
-- To add this marker to a buffer, use `FlatBuffers.encodeWithFileIdentifier`.
-- To check whether a buffer contains the marker before decoding it, use `FlatBuffers.checkFileIdentifier`.
--
-- For more information on file identifiers, see :
--
-- * The [library's docs](https://github.com/dcastro/haskell-flatbuffers#file-identifiers)
-- * Section "File identification and extension" of the [official docs](https://google.github.io/flatbuffers/flatbuffers_guide_writing_schema.html)
newtype FileIdentifier = FileIdentifier { FileIdentifier -> ByteString
unFileIdentifier :: ByteString }
  deriving (FileIdentifier -> FileIdentifier -> Bool
(FileIdentifier -> FileIdentifier -> Bool)
-> (FileIdentifier -> FileIdentifier -> Bool) -> Eq FileIdentifier
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FileIdentifier -> FileIdentifier -> Bool
$c/= :: FileIdentifier -> FileIdentifier -> Bool
== :: FileIdentifier -> FileIdentifier -> Bool
$c== :: FileIdentifier -> FileIdentifier -> Bool
Eq, Int -> FileIdentifier -> ShowS
[FileIdentifier] -> ShowS
FileIdentifier -> String
(Int -> FileIdentifier -> ShowS)
-> (FileIdentifier -> String)
-> ([FileIdentifier] -> ShowS)
-> Show FileIdentifier
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FileIdentifier] -> ShowS
$cshowList :: [FileIdentifier] -> ShowS
show :: FileIdentifier -> String
$cshow :: FileIdentifier -> String
showsPrec :: Int -> FileIdentifier -> ShowS
$cshowsPrec :: Int -> FileIdentifier -> ShowS
Show)

-- | Encodes the input text as UTF-8 and returns a @Just FileIdentifier@ if it has exactly 4 bytes,
-- otherwise `Nothing`.
fileIdentifier :: Text -> Maybe FileIdentifier
fileIdentifier :: Text -> Maybe FileIdentifier
fileIdentifier = ByteString -> Maybe FileIdentifier
fileIdentifier' (ByteString -> Maybe FileIdentifier)
-> (Text -> ByteString) -> Text -> Maybe FileIdentifier
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
T.encodeUtf8

-- | Returns a @Just FileIdentifier@ if the input `ByteString` has exactly 4 bytes,
-- otherwise `Nothing`.
fileIdentifier' :: ByteString -> Maybe FileIdentifier
fileIdentifier' :: ByteString -> Maybe FileIdentifier
fileIdentifier' ByteString
bs =
  if ByteString -> Int
BS.length ByteString
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
forall a. Num a => a
fileIdentifierSize
    then Maybe FileIdentifier
forall a. Maybe a
Nothing
    else FileIdentifier -> Maybe FileIdentifier
forall a. a -> Maybe a
Just (ByteString -> FileIdentifier
FileIdentifier ByteString
bs)

-- | Constructs a new `FileIdentifier` without checking its length.
unsafeFileIdentifier :: Text -> FileIdentifier
unsafeFileIdentifier :: Text -> FileIdentifier
unsafeFileIdentifier = ByteString -> FileIdentifier
unsafeFileIdentifier' (ByteString -> FileIdentifier)
-> (Text -> ByteString) -> Text -> FileIdentifier
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
T.encodeUtf8

-- | Constructs a new `FileIdentifier` without checking its length.
unsafeFileIdentifier' :: ByteString -> FileIdentifier
unsafeFileIdentifier' :: ByteString -> FileIdentifier
unsafeFileIdentifier' = ByteString -> FileIdentifier
FileIdentifier

-- | Associates a type with a file identifier.
-- To create an association, declare a @root_type@ and @file_identifier@ in your schema.
--
-- > table Player {}
-- > root_type Player;
-- > file_identifier "PLYR";
class HasFileIdentifier a where
  getFileIdentifier :: FileIdentifier