Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions src/Foreign/Generic/Class.purs
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,26 @@ module Foreign.Generic.Class where
import Prelude

import Control.Alt ((<|>))
import Control.Bind (bindFlipped)
import Control.Monad.Except (except, mapExcept)
import Data.Array ((..), zipWith, length)
import Data.Bifunctor (lmap)
import Data.Either (Either(..))
import Data.Either (Either(..), either)
import Data.Generic.Rep (Argument(..), Constructor(..), NoArguments(..), NoConstructors, Product(..), Sum(..))
import Data.Generic.Rep (class Generic, from, to)
import Data.Identity (Identity(..))
import Data.List (List(..), (:))
import Data.List as List
import Data.Maybe (Maybe(..), maybe)
import Data.Newtype (unwrap)
import Data.Set (Set)
import Data.Set as Set
import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol)
import Data.Traversable (sequence)
import Data.Tuple (Tuple(..))
import Foreign (F, Foreign, ForeignError(..), fail, readArray, readBoolean, readChar, readInt, readNumber, readString, unsafeToForeign)
import Foreign.Generic.Internal (readObject)
import Foreign.Index (index)
import Foreign.Index (index, readProp)
import Foreign.NullOrUndefined (readNullOrUndefined, null)
import Foreign.Object (Object)
import Foreign.Object as Object
Expand Down Expand Up @@ -112,6 +117,16 @@ instance numberDecode :: Decode Number where
instance intDecode :: Decode Int where
decode = readInt

instance eitherDecode :: (Decode a, Decode b) => Decode (Either a b) where
decode val =
Left <$> (readProp "Left" val >>= decode)
<|> Right <$> (readProp "Right" val >>= decode)

instance tupleDecode :: (Decode a, Decode b) => Decode (Tuple a b) where
decode = readArray >=> case _ of
[a, b] -> Tuple <$> decode a <*> decode b
_ -> except $ Left $ pure $ ForeignError "Decode tuple: array has incorrect length"

instance identityDecode :: Decode a => Decode (Identity a) where
decode = map Identity <<< decode

Expand All @@ -123,6 +138,15 @@ instance arrayDecode :: Decode a => Decode (Array a) where
readElement :: Int -> Foreign -> F a
readElement i value = mapExcept (lmap (map (ErrorAtIndex i))) (decode value)

instance setDecode :: (Decode a, Ord a) => Decode (Set a) where
decode = (decode :: _ -> F (Array a)) >>> bindFlipped arrayToSetNoDuplicates
where
arrayToSetNoDuplicates :: Array a -> F (Set a)
arrayToSetNoDuplicates array = case Set.fromFoldable array of
set
| length array == Set.size set -> pure set
_ -> except $ Left $ pure $ ForeignError "Decode set: The foreign value contains duplicates"

instance maybeDecode :: Decode a => Decode (Maybe a) where
decode = readNullOrUndefined decode

Expand Down Expand Up @@ -180,9 +204,20 @@ instance identityEncode :: Encode a => Encode (Identity a) where
instance arrayEncode :: Encode a => Encode (Array a) where
encode = unsafeToForeign <<< map encode

instance setEncode :: (Encode a, Ord a) => Encode (Set a) where
encode = (Set.toUnfoldable :: Set a -> Array a) >>> encode

instance maybeEncode :: Encode a => Encode (Maybe a) where
encode = maybe null encode

instance eitherEncode :: (Encode a, Encode b) => Encode (Either a b) where
encode = case _ of
Left value -> unsafeToForeign $ {"Left": encode value }
Right value -> unsafeToForeign $ { "Right": encode value }

instance tupleEncode :: (Encode a, Encode b) => Encode (Tuple a b) where
encode (Tuple a b) = encode [encode a, encode b]

instance objectEncode :: Encode v => Encode (Object v) where
encode = unsafeToForeign <<< Object.mapWithKey (\_ -> encode)

Expand Down