From 1cb9de63f71f6b9dc5a18b32a764fd1d75530e3d Mon Sep 17 00:00:00 2001 From: "Carsten Csiky (csicar)" Date: Sat, 5 Sep 2020 15:49:58 +0200 Subject: [PATCH 1/3] Add `Either` and `Maybe` de/encode instances --- src/Foreign/Generic/Class.purs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Foreign/Generic/Class.purs b/src/Foreign/Generic/Class.purs index 9370082..ece99e9 100644 --- a/src/Foreign/Generic/Class.purs +++ b/src/Foreign/Generic/Class.purs @@ -6,8 +6,9 @@ import Control.Alt ((<|>)) 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 @@ -15,9 +16,10 @@ import Data.Maybe (Maybe(..), maybe) import Data.Newtype (unwrap) 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 @@ -112,6 +114,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 @@ -183,6 +195,14 @@ instance arrayEncode :: Encode a => Encode (Array a) where 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 $ Record.insert (SProxy:: SProxy "Left") (encode value) {} + Right value -> unsafeToForeign $ Record.insert (SProxy:: SProxy "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) From d8ac7f743f8e70bf96f7c1eb7a9d34f377f9b8a9 Mon Sep 17 00:00:00 2001 From: "Carsten Csiky (csicar)" Date: Wed, 16 Sep 2020 11:47:29 +0200 Subject: [PATCH 2/3] Add encode and decode instance for `Set` --- src/Foreign/Generic/Class.purs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Foreign/Generic/Class.purs b/src/Foreign/Generic/Class.purs index ece99e9..f442d5c 100644 --- a/src/Foreign/Generic/Class.purs +++ b/src/Foreign/Generic/Class.purs @@ -3,6 +3,7 @@ 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) @@ -14,6 +15,8 @@ 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(..)) @@ -135,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 @@ -192,6 +204,9 @@ 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 From 989eee8a3d52b852bf9033c224018ec244bc8098 Mon Sep 17 00:00:00 2001 From: "Carsten Csiky (csicar)" Date: Mon, 21 Sep 2020 13:52:22 +0200 Subject: [PATCH 3/3] Simplify code for encoding of Either --- src/Foreign/Generic/Class.purs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Foreign/Generic/Class.purs b/src/Foreign/Generic/Class.purs index f442d5c..d9b7b8e 100644 --- a/src/Foreign/Generic/Class.purs +++ b/src/Foreign/Generic/Class.purs @@ -212,8 +212,8 @@ instance maybeEncode :: Encode a => Encode (Maybe a) where instance eitherEncode :: (Encode a, Encode b) => Encode (Either a b) where encode = case _ of - Left value -> unsafeToForeign $ Record.insert (SProxy:: SProxy "Left") (encode value) {} - Right value -> unsafeToForeign $ Record.insert (SProxy:: SProxy "Right") (encode value) {} + 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]