-- |
-- Stability   :  Ultra-Violence
-- Portability :  I'm too young to die
-- Instances for dealing with the usual data.

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, OverloadedStrings, ViewPatterns #-}

module Network.NineP.File.Instances
	( Convertible
	, ReadRef
	, WriteRef
	) where

import Control.Concurrent.Chan
import Control.Monad
import Control.Exception
import Data.ByteString.Lazy.Char8 (ByteString)
import qualified Data.ByteString.Lazy.Char8 as B
import Data.Char
import Data.Convertible.Base
import Data.Convertible.Instances
import Data.StateRef
import Data.Typeable
import Network.NineP.File

-- How do I avoid writing that?
trim :: [Char] -> [Char]
trim [Char]
xs = [Char] -> [Char] -> [Char]
dropSpaceTail [Char]
"" forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isSpace [Char]
xs

dropSpaceTail :: [Char] -> [Char] -> [Char]
dropSpaceTail [Char]
maybeStuff [Char]
"" = [Char]
""
dropSpaceTail [Char]
maybeStuff (Char
x:[Char]
xs)
        | Char -> Bool
isSpace Char
x = [Char] -> [Char] -> [Char]
dropSpaceTail (Char
xforall a. a -> [a] -> [a]
:[Char]
maybeStuff) [Char]
xs
        | forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
maybeStuff = Char
x forall a. a -> [a] -> [a]
: [Char] -> [Char] -> [Char]
dropSpaceTail [Char]
"" [Char]
xs
        | Bool
otherwise       = forall a. [a] -> [a]
reverse [Char]
maybeStuff forall a. [a] -> [a] -> [a]
++ Char
x forall a. a -> [a] -> [a]
: [Char] -> [Char] -> [Char]
dropSpaceTail [Char]
"" [Char]
xs

-- | @'read'@ in @'Maybe'@.
safeRead :: (Read a) => String -> Maybe a
safeRead :: forall a. Read a => [Char] -> Maybe a
safeRead (forall a. Read a => ReadS a
reads -> [(a
v,[Char]
"")]) = forall a. a -> Maybe a
Just a
v
safeRead [Char]
_ = forall a. Maybe a
Nothing

instance Convertible ByteString ByteString where
	safeConvert :: ByteString -> ConvertResult ByteString
safeConvert = forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> a
id

instance Convertible () ByteString where
	safeConvert :: () -> ConvertResult ByteString
safeConvert ()
x = forall a b.
(Show a, Typeable a, Typeable b) =>
[Char] -> a -> ConvertResult b
convError [Char]
"impossible to read that" ()
x
instance Convertible ByteString () where
	safeConvert :: ByteString -> ConvertResult ()
safeConvert ByteString
_ = forall a b. b -> Either a b
Right ()

instance Convertible ByteString Bool where
	safeConvert :: ByteString -> ConvertResult Bool
safeConvert ByteString
s
		| [Char]
l forall a. Eq a => a -> a -> Bool
== [Char]
"1" = forall a b. b -> Either a b
Right Bool
True
		| [Char]
l forall a. Eq a => a -> a -> Bool
== [Char]
"true" = forall a b. b -> Either a b
Right Bool
True
		| [Char]
l forall a. Eq a => a -> a -> Bool
== [Char]
"0" = forall a b. b -> Either a b
Right Bool
False
		| [Char]
l forall a. Eq a => a -> a -> Bool
== [Char]
"false" = forall a b. b -> Either a b
Right Bool
False
		| Bool
otherwise = forall a b.
(Show a, Typeable a, Typeable b) =>
[Char] -> a -> ConvertResult b
convError [Char]
"doesn't look like a boolean value" [Char]
l
			where l :: [Char]
l = [Char] -> [Char]
trim forall a b. (a -> b) -> a -> b
$ ByteString -> [Char]
B.unpack ByteString
s
instance Convertible Bool ByteString where
	safeConvert :: Bool -> ConvertResult ByteString
safeConvert Bool
True = forall a b. b -> Either a b
Right ByteString
"true"
	safeConvert Bool
False = forall a b. b -> Either a b
Right ByteString
"false"

instance (Show a, Num a) => Convertible a ByteString where
	safeConvert :: a -> ConvertResult ByteString
safeConvert = forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> ByteString
B.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> [Char]
show 
instance (Read a, Num a, Typeable a) => Convertible ByteString a where
	safeConvert :: ByteString -> ConvertResult a
safeConvert ByteString
s = forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall a b.
(Show a, Typeable a, Typeable b) =>
[Char] -> a -> ConvertResult b
convError [Char]
"doesn't look like an integral value" [Char]
l) forall a. a -> a
id forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM forall a b. b -> Either a b
Right forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall a. Read a => [Char] -> Maybe a
safeRead [Char]
l
			where l :: [Char]
l = [Char] -> [Char]
trim forall a b. (a -> b) -> a -> b
$ ByteString -> [Char]
B.unpack ByteString
s

-- TODO sane error
instance ReadRef () m ByteString where
    readReference :: () -> m ByteString
readReference = forall a e. Exception e => e -> a
throw forall a b. (a -> b) -> a -> b
$ ArithException
Underflow
instance Monad m => WriteRef () m ByteString where
    writeReference :: () -> ByteString -> m ()
writeReference ()
_ = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => a -> m a
return ()

instance MonadIO m => ReadRef (Chan a) m a where
    readReference :: Chan a -> m a
readReference = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Chan a -> IO a
readChan
instance MonadIO m => WriteRef (Chan a) m a where
    writeReference :: Chan a -> a -> m ()
writeReference Chan a
r = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Chan a -> a -> IO ()
writeChan Chan a
r