{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ViewPatterns #-}
module PlutusCore.Value (
Value,
K,
k,
unK,
maxKeyLen,
Quantity,
quantity,
unQuantity,
zeroQuantity,
addQuantity,
negativeAmounts,
NestedMap,
unpack,
pack,
empty,
fromList,
toList,
toFlatList,
totalSize,
maxInnerSize,
insertCoin,
deleteCoin,
scaleValue,
lookupCoin,
valueContains,
unionValue,
valueData,
unValueData,
) where
import Codec.Serialise qualified as CBOR
import Control.DeepSeq (NFData)
import Data.Bifunctor
import Data.Bitraversable
import Data.ByteString (ByteString)
import Data.ByteString qualified as B
import Data.ByteString.Base64 qualified as Base64
import Data.Foldable (find)
import Data.Hashable (Hashable (..))
import Data.IntMap.Strict (IntMap)
import Data.IntMap.Strict qualified as IntMap
import Data.Map.Merge.Strict qualified as M
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as Map
import Data.Monoid (All (..))
import Data.Text.Encoding qualified as Text
import GHC.Generics
import GHC.Stack (HasCallStack, callStack, getCallStack)
import PlutusCore.Builtin.Result
import PlutusCore.Data (Data (..))
import PlutusCore.Flat qualified as Flat
import PlutusPrelude (Pretty (..))
maxKeyLen :: Int
maxKeyLen :: Int
maxKeyLen = Int
32
{-# INLINE maxKeyLen #-}
newtype K = UnsafeK {K -> ByteString
unK :: ByteString}
deriving newtype (K -> K -> Bool
(K -> K -> Bool) -> (K -> K -> Bool) -> Eq K
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: K -> K -> Bool
== :: K -> K -> Bool
$c/= :: K -> K -> Bool
/= :: K -> K -> Bool
Eq, Eq K
Eq K =>
(K -> K -> Ordering)
-> (K -> K -> Bool)
-> (K -> K -> Bool)
-> (K -> K -> Bool)
-> (K -> K -> Bool)
-> (K -> K -> K)
-> (K -> K -> K)
-> Ord K
K -> K -> Bool
K -> K -> Ordering
K -> K -> K
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: K -> K -> Ordering
compare :: K -> K -> Ordering
$c< :: K -> K -> Bool
< :: K -> K -> Bool
$c<= :: K -> K -> Bool
<= :: K -> K -> Bool
$c> :: K -> K -> Bool
> :: K -> K -> Bool
$c>= :: K -> K -> Bool
>= :: K -> K -> Bool
$cmax :: K -> K -> K
max :: K -> K -> K
$cmin :: K -> K -> K
min :: K -> K -> K
Ord, Int -> K -> ShowS
[K] -> ShowS
K -> String
(Int -> K -> ShowS) -> (K -> String) -> ([K] -> ShowS) -> Show K
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> K -> ShowS
showsPrec :: Int -> K -> ShowS
$cshow :: K -> String
show :: K -> String
$cshowList :: [K] -> ShowS
showList :: [K] -> ShowS
Show, Eq K
Eq K => (Int -> K -> Int) -> (K -> Int) -> Hashable K
Int -> K -> Int
K -> Int
forall a. Eq a => (Int -> a -> Int) -> (a -> Int) -> Hashable a
$chashWithSalt :: Int -> K -> Int
hashWithSalt :: Int -> K -> Int
$chash :: K -> Int
hash :: K -> Int
Hashable, K -> ()
(K -> ()) -> NFData K
forall a. (a -> ()) -> NFData a
$crnf :: K -> ()
rnf :: K -> ()
NFData)
deriving stock ((forall x. K -> Rep K x) -> (forall x. Rep K x -> K) -> Generic K
forall x. Rep K x -> K
forall x. K -> Rep K x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. K -> Rep K x
from :: forall x. K -> Rep K x
$cto :: forall x. Rep K x -> K
to :: forall x. Rep K x -> K
Generic)
k :: ByteString -> Maybe K
k :: ByteString -> Maybe K
k ByteString
b = if ByteString -> Int
B.length ByteString
b Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
maxKeyLen then K -> Maybe K
forall a. a -> Maybe a
Just (ByteString -> K
UnsafeK ByteString
b) else Maybe K
forall a. Maybe a
Nothing
{-# INLINEABLE k #-}
instance Flat.Flat K where
encode :: K -> Encoding
encode (UnsafeK ByteString
b) = ByteString -> Encoding
forall a. Flat a => a -> Encoding
Flat.encode ByteString
b
{-# INLINE encode #-}
decode :: Get K
decode = do
ByteString
b <- Get ByteString
forall a. Flat a => Get a
Flat.decode
Get K -> (K -> Get K) -> Maybe K -> Get K
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Get K
forall a. String -> Get a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Get K) -> String -> Get K
forall a b. (a -> b) -> a -> b
$ String
"Invalid Value key: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> [Word8] -> String
forall a. Show a => a -> String
show (ByteString -> [Word8]
B.unpack ByteString
b)) K -> Get K
forall a. a -> Get a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteString -> Maybe K
k ByteString
b)
{-# INLINEABLE decode #-}
instance CBOR.Serialise K where
encode :: K -> Encoding
encode (UnsafeK ByteString
b) = ByteString -> Encoding
forall a. Serialise a => a -> Encoding
CBOR.encode ByteString
b
{-# INLINE encode #-}
decode :: forall s. Decoder s K
decode = do
ByteString
b <- Decoder s ByteString
forall s. Decoder s ByteString
forall a s. Serialise a => Decoder s a
CBOR.decode
Decoder s K -> (K -> Decoder s K) -> Maybe K -> Decoder s K
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Decoder s K
forall a. String -> Decoder s a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Decoder s K) -> String -> Decoder s K
forall a b. (a -> b) -> a -> b
$ String
"Invalid Value key: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> [Word8] -> String
forall a. Show a => a -> String
show (ByteString -> [Word8]
B.unpack ByteString
b)) K -> Decoder s K
forall a. a -> Decoder s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteString -> Maybe K
k ByteString
b)
{-# INLINEABLE decode #-}
newtype Quantity = UnsafeQuantity {Quantity -> Integer
unQuantity :: Integer}
deriving newtype (Quantity -> Quantity -> Bool
(Quantity -> Quantity -> Bool)
-> (Quantity -> Quantity -> Bool) -> Eq Quantity
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Quantity -> Quantity -> Bool
== :: Quantity -> Quantity -> Bool
$c/= :: Quantity -> Quantity -> Bool
/= :: Quantity -> Quantity -> Bool
Eq, Eq Quantity
Eq Quantity =>
(Quantity -> Quantity -> Ordering)
-> (Quantity -> Quantity -> Bool)
-> (Quantity -> Quantity -> Bool)
-> (Quantity -> Quantity -> Bool)
-> (Quantity -> Quantity -> Bool)
-> (Quantity -> Quantity -> Quantity)
-> (Quantity -> Quantity -> Quantity)
-> Ord Quantity
Quantity -> Quantity -> Bool
Quantity -> Quantity -> Ordering
Quantity -> Quantity -> Quantity
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Quantity -> Quantity -> Ordering
compare :: Quantity -> Quantity -> Ordering
$c< :: Quantity -> Quantity -> Bool
< :: Quantity -> Quantity -> Bool
$c<= :: Quantity -> Quantity -> Bool
<= :: Quantity -> Quantity -> Bool
$c> :: Quantity -> Quantity -> Bool
> :: Quantity -> Quantity -> Bool
$c>= :: Quantity -> Quantity -> Bool
>= :: Quantity -> Quantity -> Bool
$cmax :: Quantity -> Quantity -> Quantity
max :: Quantity -> Quantity -> Quantity
$cmin :: Quantity -> Quantity -> Quantity
min :: Quantity -> Quantity -> Quantity
Ord, Int -> Quantity -> ShowS
[Quantity] -> ShowS
Quantity -> String
(Int -> Quantity -> ShowS)
-> (Quantity -> String) -> ([Quantity] -> ShowS) -> Show Quantity
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Quantity -> ShowS
showsPrec :: Int -> Quantity -> ShowS
$cshow :: Quantity -> String
show :: Quantity -> String
$cshowList :: [Quantity] -> ShowS
showList :: [Quantity] -> ShowS
Show, Quantity -> ()
(Quantity -> ()) -> NFData Quantity
forall a. (a -> ()) -> NFData a
$crnf :: Quantity -> ()
rnf :: Quantity -> ()
NFData, Eq Quantity
Eq Quantity =>
(Int -> Quantity -> Int) -> (Quantity -> Int) -> Hashable Quantity
Int -> Quantity -> Int
Quantity -> Int
forall a. Eq a => (Int -> a -> Int) -> (a -> Int) -> Hashable a
$chashWithSalt :: Int -> Quantity -> Int
hashWithSalt :: Int -> Quantity -> Int
$chash :: Quantity -> Int
hash :: Quantity -> Int
Hashable)
deriving stock ((forall x. Quantity -> Rep Quantity x)
-> (forall x. Rep Quantity x -> Quantity) -> Generic Quantity
forall x. Rep Quantity x -> Quantity
forall x. Quantity -> Rep Quantity x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Quantity -> Rep Quantity x
from :: forall x. Quantity -> Rep Quantity x
$cto :: forall x. Rep Quantity x -> Quantity
to :: forall x. Rep Quantity x -> Quantity
Generic)
instance CBOR.Serialise Quantity where
encode :: Quantity -> Encoding
encode (UnsafeQuantity Integer
i) = Integer -> Encoding
forall a. Serialise a => a -> Encoding
CBOR.encode Integer
i
{-# INLINE encode #-}
decode :: forall s. Decoder s Quantity
decode = do
Integer
i <- Decoder s Integer
forall s. Decoder s Integer
forall a s. Serialise a => Decoder s a
CBOR.decode
case Integer -> Maybe Quantity
quantity Integer
i of
Just Quantity
q -> Quantity -> Decoder s Quantity
forall a. a -> Decoder s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Quantity
q
Maybe Quantity
Nothing -> String -> Decoder s Quantity
forall a. String -> Decoder s a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Decoder s Quantity) -> String -> Decoder s Quantity
forall a b. (a -> b) -> a -> b
$ String
"Quantity out of signed 128-bit integer bounds: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Integer -> String
forall a. Show a => a -> String
show Integer
i
{-# INLINEABLE decode #-}
instance Flat.Flat Quantity where
encode :: Quantity -> Encoding
encode (UnsafeQuantity Integer
i) = Integer -> Encoding
forall a. Flat a => a -> Encoding
Flat.encode Integer
i
{-# INLINE encode #-}
decode :: Get Quantity
decode = do
Integer
i <- Get Integer
forall a. Flat a => Get a
Flat.decode
case Integer -> Maybe Quantity
quantity Integer
i of
Just Quantity
q -> Quantity -> Get Quantity
forall a. a -> Get a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Quantity
q
Maybe Quantity
Nothing -> String -> Get Quantity
forall a. String -> Get a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Get Quantity) -> String -> Get Quantity
forall a b. (a -> b) -> a -> b
$ String
"Quantity out of signed 128-bit integer bounds: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Integer -> String
forall a. Show a => a -> String
show Integer
i
{-# INLINEABLE decode #-}
instance Pretty Quantity where
pretty :: forall ann. Quantity -> Doc ann
pretty (UnsafeQuantity Integer
i) = Integer -> Doc ann
forall ann. Integer -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty Integer
i
instance Bounded Quantity where
minBound :: Quantity
minBound = Integer -> Quantity
UnsafeQuantity (-(Integer
2 Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ (Integer
127 :: Integer)))
{-# INLINE minBound #-}
maxBound :: Quantity
maxBound = Integer -> Quantity
UnsafeQuantity (Integer
2 Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ (Integer
127 :: Integer) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
1)
{-# INLINE maxBound #-}
quantity :: Integer -> Maybe Quantity
quantity :: Integer -> Maybe Quantity
quantity Integer
i
| Integer
i Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Quantity -> Integer
unQuantity Quantity
forall a. Bounded a => a
minBound Bool -> Bool -> Bool
&& Integer
i Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Quantity -> Integer
unQuantity Quantity
forall a. Bounded a => a
maxBound = Quantity -> Maybe Quantity
forall a. a -> Maybe a
Just (Integer -> Quantity
UnsafeQuantity Integer
i)
| Bool
otherwise = Maybe Quantity
forall a. Maybe a
Nothing
{-# INLINEABLE quantity #-}
zeroQuantity :: Quantity
zeroQuantity :: Quantity
zeroQuantity = Integer -> Quantity
UnsafeQuantity Integer
0
{-# INLINE zeroQuantity #-}
addQuantity :: Quantity -> Quantity -> Maybe Quantity
addQuantity :: Quantity -> Quantity -> Maybe Quantity
addQuantity (UnsafeQuantity Integer
x) (UnsafeQuantity Integer
y) = Integer -> Maybe Quantity
quantity (Integer
x Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
y)
{-# INLINEABLE addQuantity #-}
scaleQuantity :: Integer -> Quantity -> Maybe Quantity
scaleQuantity :: Integer -> Quantity -> Maybe Quantity
scaleQuantity Integer
x (UnsafeQuantity Integer
y) = Integer -> Maybe Quantity
quantity (Integer
x Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
y)
{-# INLINEABLE scaleQuantity #-}
type NestedMap = Map K (Map K Quantity)
data Value
= Value
!NestedMap
!(IntMap Int)
{-# UNPACK #-} !Int
{-# UNPACK #-} !Int
deriving stock (Value -> Value -> Bool
(Value -> Value -> Bool) -> (Value -> Value -> Bool) -> Eq Value
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Value -> Value -> Bool
== :: Value -> Value -> Bool
$c/= :: Value -> Value -> Bool
/= :: Value -> Value -> Bool
Eq, Int -> Value -> ShowS
[Value] -> ShowS
Value -> String
(Int -> Value -> ShowS)
-> (Value -> String) -> ([Value] -> ShowS) -> Show Value
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Value -> ShowS
showsPrec :: Int -> Value -> ShowS
$cshow :: Value -> String
show :: Value -> String
$cshowList :: [Value] -> ShowS
showList :: [Value] -> ShowS
Show, (forall x. Value -> Rep Value x)
-> (forall x. Rep Value x -> Value) -> Generic Value
forall x. Rep Value x -> Value
forall x. Value -> Rep Value x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Value -> Rep Value x
from :: forall x. Value -> Rep Value x
$cto :: forall x. Rep Value x -> Value
to :: forall x. Rep Value x -> Value
Generic)
deriving anyclass (Value -> ()
(Value -> ()) -> NFData Value
forall a. (a -> ()) -> NFData a
$crnf :: Value -> ()
rnf :: Value -> ()
NFData)
instance Hashable Value where
hash :: Value -> Int
hash = NestedMap -> Int
forall a. Hashable a => a -> Int
hash (NestedMap -> Int) -> (Value -> NestedMap) -> Value -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> NestedMap
unpack
{-# INLINE hash #-}
hashWithSalt :: Int -> Value -> Int
hashWithSalt Int
salt = Int -> NestedMap -> Int
forall a. Hashable a => Int -> a -> Int
hashWithSalt Int
salt (NestedMap -> Int) -> (Value -> NestedMap) -> Value -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> NestedMap
unpack
{-# INLINE hashWithSalt #-}
instance CBOR.Serialise Value where
encode :: Value -> Encoding
encode (Value NestedMap
v IntMap Int
_ Int
_ Int
_) = NestedMap -> Encoding
forall a. Serialise a => a -> Encoding
CBOR.encode NestedMap
v
{-# INLINE encode #-}
decode :: forall s. Decoder s Value
decode = NestedMap -> Value
pack (NestedMap -> Value) -> Decoder s NestedMap -> Decoder s Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Decoder s NestedMap
forall s. Decoder s NestedMap
forall a s. Serialise a => Decoder s a
CBOR.decode
{-# INLINE decode #-}
instance Flat.Flat Value where
encode :: Value -> Encoding
encode (Value NestedMap
v IntMap Int
_ Int
_ Int
_) = NestedMap -> Encoding
forall a. Flat a => a -> Encoding
Flat.encode NestedMap
v
{-# INLINE encode #-}
decode :: Get Value
decode = NestedMap -> Value
pack (NestedMap -> Value) -> Get NestedMap -> Get Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get NestedMap
forall a. Flat a => Get a
Flat.decode
{-# INLINE decode #-}
unpack :: Value -> NestedMap
unpack :: Value -> NestedMap
unpack (Value NestedMap
v IntMap Int
_ Int
_ Int
_) = NestedMap
v
{-# INLINE unpack #-}
pack :: NestedMap -> Value
pack :: NestedMap -> Value
pack = NestedMap -> Value
pack' (NestedMap -> Value)
-> (NestedMap -> NestedMap) -> NestedMap -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NestedMap -> NestedMap
normalize
{-# INLINE pack #-}
pack' :: NestedMap -> Value
pack' :: NestedMap -> Value
pack' NestedMap
v = NestedMap -> IntMap Int -> Int -> Int -> Value
Value NestedMap
v IntMap Int
sizes Int
size Int
neg
where
(IntMap Int
sizes, Int
size, Int
neg) = ((IntMap Int, Int, Int)
-> Map K Quantity -> (IntMap Int, Int, Int))
-> (IntMap Int, Int, Int) -> NestedMap -> (IntMap Int, Int, Int)
forall a b k. (a -> b -> a) -> a -> Map k b -> a
Map.foldl' (IntMap Int, Int, Int) -> Map K Quantity -> (IntMap Int, Int, Int)
forall {a} {k}.
Num a =>
(IntMap a, Int, Int) -> Map k Quantity -> (IntMap a, Int, Int)
alg (IntMap Int
forall a. Monoid a => a
mempty, Int
0, Int
0) NestedMap
v
alg :: (IntMap a, Int, Int) -> Map k Quantity -> (IntMap a, Int, Int)
alg (IntMap a
ss, Int
s, Int
n) Map k Quantity
inner =
( (Maybe a -> Maybe a) -> Int -> IntMap a -> IntMap a
forall a. (Maybe a -> Maybe a) -> Int -> IntMap a -> IntMap a
IntMap.alter (Maybe a -> (a -> Maybe a) -> Maybe a -> Maybe a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (a -> Maybe a
forall a. a -> Maybe a
Just a
1) (a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> (a -> a) -> a -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> a -> a
forall a. Num a => a -> a -> a
+ a
1))) (Map k Quantity -> Int
forall k a. Map k a -> Int
Map.size Map k Quantity
inner) IntMap a
ss
, Int
s Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Map k Quantity -> Int
forall k a. Map k a -> Int
Map.size Map k Quantity
inner
, Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Map k Quantity -> Int
forall k a. Map k a -> Int
Map.size ((Quantity -> Bool) -> Map k Quantity -> Map k Quantity
forall a k. (a -> Bool) -> Map k a -> Map k a
Map.filter (Quantity -> Quantity -> Bool
forall a. Ord a => a -> a -> Bool
< Quantity
zeroQuantity) Map k Quantity
inner)
)
{-# INLINEABLE pack' #-}
totalSize :: Value -> Int
totalSize :: Value -> Int
totalSize (Value NestedMap
_ IntMap Int
_ Int
size Int
_) = Int
size
{-# INLINE totalSize #-}
maxInnerSize :: Value -> Int
maxInnerSize :: Value -> Int
maxInnerSize (Value NestedMap
_ IntMap Int
sizes Int
_ Int
_) = Int -> ((Int, Int) -> Int) -> Maybe (Int, Int) -> Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int
0 (Int, Int) -> Int
forall a b. (a, b) -> a
fst (IntMap Int -> Maybe (Int, Int)
forall a. IntMap a -> Maybe (Int, a)
IntMap.lookupMax IntMap Int
sizes)
{-# INLINE maxInnerSize #-}
negativeAmounts :: Value -> Int
negativeAmounts :: Value -> Int
negativeAmounts (Value NestedMap
_ IntMap Int
_ Int
_ Int
neg) = Int
neg
{-# INLINE negativeAmounts #-}
empty :: Value
empty :: Value
empty = NestedMap -> IntMap Int -> Int -> Int -> Value
Value NestedMap
forall a. Monoid a => a
mempty IntMap Int
forall a. Monoid a => a
mempty Int
0 Int
0
{-# INLINE empty #-}
toList :: Value -> [(K, [(K, Quantity)])]
toList :: Value -> [(K, [(K, Quantity)])]
toList = Map K [(K, Quantity)] -> [(K, [(K, Quantity)])]
forall k a. Map k a -> [(k, a)]
Map.toList (Map K [(K, Quantity)] -> [(K, [(K, Quantity)])])
-> (Value -> Map K [(K, Quantity)])
-> Value
-> [(K, [(K, Quantity)])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Map K Quantity -> [(K, Quantity)])
-> NestedMap -> Map K [(K, Quantity)]
forall a b k. (a -> b) -> Map k a -> Map k b
Map.map Map K Quantity -> [(K, Quantity)]
forall k a. Map k a -> [(k, a)]
Map.toList (NestedMap -> Map K [(K, Quantity)])
-> (Value -> NestedMap) -> Value -> Map K [(K, Quantity)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> NestedMap
unpack
{-# INLINEABLE toList #-}
toFlatList :: Value -> [(K, K, Quantity)]
toFlatList :: Value -> [(K, K, Quantity)]
toFlatList (Value -> [(K, [(K, Quantity)])]
toList -> [(K, [(K, Quantity)])]
xs) = [(K
c, K
t, Quantity
a) | (K
c, [(K, Quantity)]
ys) <- [(K, [(K, Quantity)])]
xs, (K
t, Quantity
a) <- [(K, Quantity)]
ys]
{-# INLINEABLE toFlatList #-}
fromList :: [(K, [(K, Quantity)])] -> BuiltinResult Value
fromList :: [(K, [(K, Quantity)])] -> BuiltinResult Value
fromList [(K, [(K, Quantity)])]
xs = do
let outerMap :: NestedMap
outerMap =
(Map K Quantity -> Map K Quantity -> Map K Quantity)
-> [(K, Map K Quantity)] -> NestedMap
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith
((Quantity -> Quantity -> Quantity)
-> Map K Quantity -> Map K Quantity -> Map K Quantity
forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
Map.unionWith Quantity -> Quantity -> Quantity
unsafeAddQuantity)
(([(K, Quantity)] -> Map K Quantity)
-> (K, [(K, Quantity)]) -> (K, Map K Quantity)
forall b c a. (b -> c) -> (a, b) -> (a, c)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second ((Quantity -> Quantity -> Quantity)
-> [(K, Quantity)] -> Map K Quantity
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith Quantity -> Quantity -> Quantity
unsafeAddQuantity) ((K, [(K, Quantity)]) -> (K, Map K Quantity))
-> [(K, [(K, Quantity)])] -> [(K, Map K Quantity)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(K, [(K, Quantity)])]
xs)
NestedMap -> Value
pack (NestedMap -> Value)
-> BuiltinResult NestedMap -> BuiltinResult Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> HasCallStack => NestedMap -> BuiltinResult NestedMap
NestedMap -> BuiltinResult NestedMap
validateQuantities NestedMap
outerMap
{-# INLINEABLE fromList #-}
unsafeAddQuantity :: Quantity -> Quantity -> Quantity
unsafeAddQuantity :: Quantity -> Quantity -> Quantity
unsafeAddQuantity (UnsafeQuantity Integer
x) (UnsafeQuantity Integer
y) = Integer -> Quantity
UnsafeQuantity (Integer
x Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
y)
{-# INLINE unsafeAddQuantity #-}
validateQuantities :: HasCallStack => NestedMap -> BuiltinResult NestedMap
validateQuantities :: HasCallStack => NestedMap -> BuiltinResult NestedMap
validateQuantities NestedMap
nestedMap =
case (Quantity -> Bool) -> [Quantity] -> Maybe Quantity
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find Quantity -> Bool
isOutOfBounds [Quantity]
allQuantities of
Just (UnsafeQuantity Integer
i) -> String -> BuiltinResult NestedMap
forall a. String -> BuiltinResult a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> BuiltinResult NestedMap)
-> String -> BuiltinResult NestedMap
forall a b. (a -> b) -> a -> b
$ String
context String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
": quantity out of bounds: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Integer -> String
forall a. Show a => a -> String
show Integer
i
Maybe Quantity
Nothing -> NestedMap -> BuiltinResult NestedMap
forall a. a -> BuiltinResult a
forall (f :: * -> *) a. Applicative f => a -> f a
pure NestedMap
nestedMap
where
allQuantities :: [Quantity]
allQuantities = (Map K Quantity -> [Quantity]) -> [Map K Quantity] -> [Quantity]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Map K Quantity -> [Quantity]
forall k a. Map k a -> [a]
Map.elems ([Map K Quantity] -> [Quantity]) -> [Map K Quantity] -> [Quantity]
forall a b. (a -> b) -> a -> b
$ NestedMap -> [Map K Quantity]
forall k a. Map k a -> [a]
Map.elems NestedMap
nestedMap
isOutOfBounds :: Quantity -> Bool
isOutOfBounds (UnsafeQuantity Integer
i) =
Integer
i Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Quantity -> Integer
unQuantity Quantity
forall a. Bounded a => a
minBound Bool -> Bool -> Bool
|| Integer
i Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Quantity -> Integer
unQuantity Quantity
forall a. Bounded a => a
maxBound
context :: String
context = case CallStack -> [(String, SrcLoc)]
getCallStack CallStack
HasCallStack => CallStack
callStack of
(String
fnName, SrcLoc
_):[(String, SrcLoc)]
_ -> String
fnName
[] -> String
"<unknown>"
{-# INLINEABLE validateQuantities #-}
normalize :: NestedMap -> NestedMap
normalize :: NestedMap -> NestedMap
normalize = (Map K Quantity -> Bool) -> NestedMap -> NestedMap
forall a k. (a -> Bool) -> Map k a -> Map k a
Map.filter (Bool -> Bool
not (Bool -> Bool)
-> (Map K Quantity -> Bool) -> Map K Quantity -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map K Quantity -> Bool
forall k a. Map k a -> Bool
Map.null) (NestedMap -> NestedMap)
-> (NestedMap -> NestedMap) -> NestedMap -> NestedMap
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Map K Quantity -> Map K Quantity) -> NestedMap -> NestedMap
forall a b k. (a -> b) -> Map k a -> Map k b
Map.map ((Quantity -> Bool) -> Map K Quantity -> Map K Quantity
forall a k. (a -> Bool) -> Map k a -> Map k a
Map.filter (Quantity -> Quantity -> Bool
forall a. Eq a => a -> a -> Bool
/= Quantity
zeroQuantity))
{-# INLINEABLE normalize #-}
instance Pretty Value where
pretty :: forall ann. Value -> Doc ann
pretty = [(Text, [(Text, Quantity)])] -> Doc ann
forall ann. [(Text, [(Text, Quantity)])] -> Doc ann
forall a ann. Pretty a => a -> Doc ann
pretty ([(Text, [(Text, Quantity)])] -> Doc ann)
-> (Value -> [(Text, [(Text, Quantity)])]) -> Value -> Doc ann
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((K, [(K, Quantity)]) -> (Text, [(Text, Quantity)]))
-> [(K, [(K, Quantity)])] -> [(Text, [(Text, Quantity)])]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((K -> Text)
-> ([(K, Quantity)] -> [(Text, Quantity)])
-> (K, [(K, Quantity)])
-> (Text, [(Text, Quantity)])
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap K -> Text
toText (((K, Quantity) -> (Text, Quantity))
-> [(K, Quantity)] -> [(Text, Quantity)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((K -> Text) -> (K, Quantity) -> (Text, Quantity)
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first K -> Text
toText))) ([(K, [(K, Quantity)])] -> [(Text, [(Text, Quantity)])])
-> (Value -> [(K, [(K, Quantity)])])
-> Value
-> [(Text, [(Text, Quantity)])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> [(K, [(K, Quantity)])]
toList
where
toText :: K -> Text
toText = ByteString -> Text
Text.decodeLatin1 (ByteString -> Text) -> (K -> ByteString) -> K -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
Base64.encode (ByteString -> ByteString) -> (K -> ByteString) -> K -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. K -> ByteString
unK
insertCoin :: ByteString -> ByteString -> Integer -> Value -> BuiltinResult Value
insertCoin :: ByteString -> ByteString -> Integer -> Value -> BuiltinResult Value
insertCoin ByteString
unsafeCurrency ByteString
unsafeToken Integer
unsafeAmount v :: Value
v@(Value NestedMap
outer IntMap Int
sizes Int
size Int
neg)
| Integer
unsafeAmount Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0 = Value -> BuiltinResult Value
forall a. a -> BuiltinResult a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Value -> BuiltinResult Value) -> Value -> BuiltinResult Value
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> Value -> Value
deleteCoin ByteString
unsafeCurrency ByteString
unsafeToken Value
v
| Bool
otherwise = case (ByteString -> Maybe K
k ByteString
unsafeCurrency, ByteString -> Maybe K
k ByteString
unsafeToken, Integer -> Maybe Quantity
quantity Integer
unsafeAmount) of
(Maybe K
Nothing, Maybe K
_, Maybe Quantity
_) -> String -> BuiltinResult Value
forall a. String -> BuiltinResult a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> BuiltinResult Value) -> String -> BuiltinResult Value
forall a b. (a -> b) -> a -> b
$ String
"insertCoin: invalid currency: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> [Word8] -> String
forall a. Show a => a -> String
show (ByteString -> [Word8]
B.unpack ByteString
unsafeCurrency)
(Maybe K
_, Maybe K
Nothing, Maybe Quantity
_) -> String -> BuiltinResult Value
forall a. String -> BuiltinResult a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> BuiltinResult Value) -> String -> BuiltinResult Value
forall a b. (a -> b) -> a -> b
$ String
"insertCoin: invalid token: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> [Word8] -> String
forall a. Show a => a -> String
show (ByteString -> [Word8]
B.unpack ByteString
unsafeToken)
(Maybe K
_, Maybe K
_, Maybe Quantity
Nothing) -> String -> BuiltinResult Value
forall a. String -> BuiltinResult a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> BuiltinResult Value) -> String -> BuiltinResult Value
forall a b. (a -> b) -> a -> b
$ String
"insertCoin: quantity out of bounds: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Integer -> String
forall a. Show a => a -> String
show Integer
unsafeAmount
(Just K
currency, Just K
token, Just Quantity
qty) ->
let f
:: Maybe (Map K Quantity)
-> (
Either Int Quantity
, Maybe (Map K Quantity)
)
f :: Maybe (Map K Quantity)
-> (Either Int Quantity, Maybe (Map K Quantity))
f = \case
Maybe (Map K Quantity)
Nothing -> (Int -> Either Int Quantity
forall a b. a -> Either a b
Left Int
0, Map K Quantity -> Maybe (Map K Quantity)
forall a. a -> Maybe a
Just (K -> Quantity -> Map K Quantity
forall k a. k -> a -> Map k a
Map.singleton K
token Quantity
qty))
Just Map K Quantity
inner ->
let (Maybe Quantity
mOldQuantity, Map K Quantity
inner') =
(K -> Quantity -> Quantity -> Quantity)
-> K
-> Quantity
-> Map K Quantity
-> (Maybe Quantity, Map K Quantity)
forall k a.
Ord k =>
(k -> a -> a -> a) -> k -> a -> Map k a -> (Maybe a, Map k a)
Map.insertLookupWithKey (\K
_ Quantity
_ Quantity
_ -> Quantity
qty) K
token Quantity
qty Map K Quantity
inner
in (Either Int Quantity
-> (Quantity -> Either Int Quantity)
-> Maybe Quantity
-> Either Int Quantity
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Int -> Either Int Quantity
forall a b. a -> Either a b
Left (Map K Quantity -> Int
forall k a. Map k a -> Int
Map.size Map K Quantity
inner)) Quantity -> Either Int Quantity
forall a b. b -> Either a b
Right Maybe Quantity
mOldQuantity, Map K Quantity -> Maybe (Map K Quantity)
forall a. a -> Maybe a
Just Map K Quantity
inner')
(Either Int Quantity
res, NestedMap
outer') = (Maybe (Map K Quantity)
-> (Either Int Quantity, Maybe (Map K Quantity)))
-> K -> NestedMap -> (Either Int Quantity, NestedMap)
forall (f :: * -> *) k a.
(Functor f, Ord k) =>
(Maybe a -> f (Maybe a)) -> k -> Map k a -> f (Map k a)
Map.alterF Maybe (Map K Quantity)
-> (Either Int Quantity, Maybe (Map K Quantity))
f K
currency NestedMap
outer
(IntMap Int
sizes', Int
size', Int
neg') = case Either Int Quantity
res of
Left Int
oldSize ->
( Int -> Int -> IntMap Int -> IntMap Int
updateSizes Int
oldSize (Int
oldSize Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) IntMap Int
sizes
, Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
, if Quantity
qty Quantity -> Quantity -> Bool
forall a. Ord a => a -> a -> Bool
< Quantity
zeroQuantity then Int
neg Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 else Int
neg
)
Right Quantity
oldQuantity ->
( IntMap Int
sizes
, Int
size
, if Quantity
oldQuantity Quantity -> Quantity -> Bool
forall a. Ord a => a -> a -> Bool
< Quantity
zeroQuantity Bool -> Bool -> Bool
&& Quantity
qty Quantity -> Quantity -> Bool
forall a. Ord a => a -> a -> Bool
> Quantity
zeroQuantity
then Int
neg Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
else
if Quantity
oldQuantity Quantity -> Quantity -> Bool
forall a. Ord a => a -> a -> Bool
> Quantity
zeroQuantity Bool -> Bool -> Bool
&& Quantity
qty Quantity -> Quantity -> Bool
forall a. Ord a => a -> a -> Bool
< Quantity
zeroQuantity
then Int
neg Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
else Int
neg
)
in Value -> BuiltinResult Value
forall a. a -> BuiltinResult a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Value -> BuiltinResult Value) -> Value -> BuiltinResult Value
forall a b. (a -> b) -> a -> b
$ NestedMap -> IntMap Int -> Int -> Int -> Value
Value NestedMap
outer' IntMap Int
sizes' Int
size' Int
neg'
{-# INLINEABLE insertCoin #-}
deleteCoin :: ByteString -> ByteString -> Value -> Value
deleteCoin :: ByteString -> ByteString -> Value -> Value
deleteCoin (ByteString -> K
UnsafeK -> K
currency) (ByteString -> K
UnsafeK -> K
token) (Value NestedMap
outer IntMap Int
sizes Int
size Int
neg) =
NestedMap -> IntMap Int -> Int -> Int -> Value
Value NestedMap
outer' IntMap Int
sizes' Int
size' Int
neg'
where
(Maybe (Int, Quantity)
mold, NestedMap
outer') = (Maybe (Map K Quantity)
-> (Maybe (Int, Quantity), Maybe (Map K Quantity)))
-> K -> NestedMap -> (Maybe (Int, Quantity), NestedMap)
forall (f :: * -> *) k a.
(Functor f, Ord k) =>
(Maybe a -> f (Maybe a)) -> k -> Map k a -> f (Map k a)
Map.alterF Maybe (Map K Quantity)
-> (Maybe (Int, Quantity), Maybe (Map K Quantity))
f K
currency NestedMap
outer
(IntMap Int
sizes', Int
size', Int
neg') = case Maybe (Int, Quantity)
mold of
Just (Int
oldSize, Quantity
oldQuantity) ->
( Int -> Int -> IntMap Int -> IntMap Int
updateSizes Int
oldSize (Int
oldSize Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) IntMap Int
sizes
, Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1
, if Quantity
oldQuantity Quantity -> Quantity -> Bool
forall a. Ord a => a -> a -> Bool
< Quantity
zeroQuantity then Int
neg Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 else Int
neg
)
Maybe (Int, Quantity)
Nothing -> (IntMap Int
sizes, Int
size, Int
neg)
f
:: Maybe (Map K Quantity)
-> (
Maybe (Int, Quantity)
, Maybe (Map K Quantity)
)
f :: Maybe (Map K Quantity)
-> (Maybe (Int, Quantity), Maybe (Map K Quantity))
f = \case
Maybe (Map K Quantity)
Nothing -> (Maybe (Int, Quantity)
forall a. Maybe a
Nothing, Maybe (Map K Quantity)
forall a. Maybe a
Nothing)
Just Map K Quantity
inner ->
let (Maybe Quantity
qty, Map K Quantity
inner') = (K -> Quantity -> Maybe Quantity)
-> K -> Map K Quantity -> (Maybe Quantity, Map K Quantity)
forall k a.
Ord k =>
(k -> a -> Maybe a) -> k -> Map k a -> (Maybe a, Map k a)
Map.updateLookupWithKey (\K
_ Quantity
_ -> Maybe Quantity
forall a. Maybe a
Nothing) K
token Map K Quantity
inner
in ((Map K Quantity -> Int
forall k a. Map k a -> Int
Map.size Map K Quantity
inner,) (Quantity -> (Int, Quantity))
-> Maybe Quantity -> Maybe (Int, Quantity)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Quantity
qty, if Map K Quantity -> Bool
forall k a. Map k a -> Bool
Map.null Map K Quantity
inner' then Maybe (Map K Quantity)
forall a. Maybe a
Nothing else Map K Quantity -> Maybe (Map K Quantity)
forall a. a -> Maybe a
Just Map K Quantity
inner')
lookupCoin :: ByteString -> ByteString -> Value -> Integer
lookupCoin :: ByteString -> ByteString -> Value -> Integer
lookupCoin (ByteString -> K
UnsafeK -> K
currency) (ByteString -> K
UnsafeK -> K
token) (Value -> NestedMap
unpack -> NestedMap
outer) =
case K -> NestedMap -> Maybe (Map K Quantity)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup K
currency NestedMap
outer of
Maybe (Map K Quantity)
Nothing -> Integer
0
Just Map K Quantity
inner -> Quantity -> Integer
unQuantity (Quantity -> Integer) -> Quantity -> Integer
forall a b. (a -> b) -> a -> b
$ Quantity -> K -> Map K Quantity -> Quantity
forall k a. Ord k => a -> k -> Map k a -> a
Map.findWithDefault Quantity
zeroQuantity K
token Map K Quantity
inner
valueContains :: Value -> Value -> BuiltinResult Bool
valueContains :: Value -> Value -> BuiltinResult Bool
valueContains Value
v1 Value
v2
| Value -> Int
negativeAmounts Value
v1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 = String -> BuiltinResult Bool
forall a. String -> BuiltinResult a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"valueContains: first value contains negative amounts"
| Value -> Int
negativeAmounts Value
v2 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 = String -> BuiltinResult Bool
forall a. String -> BuiltinResult a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"valueContains: second value contains negative amounts"
| Bool
otherwise = Bool -> BuiltinResult Bool
forall a. a -> BuiltinResult a
BuiltinSuccess (Bool -> BuiltinResult Bool)
-> (All -> Bool) -> All -> BuiltinResult Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. All -> Bool
getAll (All -> BuiltinResult Bool) -> All -> BuiltinResult Bool
forall a b. (a -> b) -> a -> b
$ (K -> Map K Quantity -> All -> All) -> All -> NestedMap -> All
forall k a b. (k -> a -> b -> b) -> b -> Map k a -> b
Map.foldrWithKey K -> Map K Quantity -> All -> All
go All
forall a. Monoid a => a
mempty (Value -> NestedMap
unpack Value
v2)
where
go :: K -> Map K Quantity -> All -> All
go :: K -> Map K Quantity -> All -> All
go K
c Map K Quantity
inner = All -> All -> All
forall a. Semigroup a => a -> a -> a
(<>) ((K -> Quantity -> All -> All) -> All -> Map K Quantity -> All
forall k a b. (k -> a -> b -> b) -> b -> Map k a -> b
Map.foldrWithKey K -> Quantity -> All -> All
goInner All
forall a. Monoid a => a
mempty Map K Quantity
inner)
where
goInner :: K -> Quantity -> All -> All
goInner :: K -> Quantity -> All -> All
goInner K
t Quantity
a2 = All -> All -> All
forall a. Semigroup a => a -> a -> a
(<>) (Bool -> All
All (ByteString -> ByteString -> Value -> Integer
lookupCoin (K -> ByteString
unK K
c) (K -> ByteString
unK K
t) Value
v1 Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Quantity -> Integer
unQuantity Quantity
a2))
{-# INLINEABLE valueContains #-}
unionValue :: Value -> Value -> BuiltinResult Value
unionValue :: Value -> Value -> BuiltinResult Value
unionValue (Value -> NestedMap
unpack -> NestedMap
vA) (Value -> NestedMap
unpack -> NestedMap
vB) =
NestedMap -> Value
pack' (NestedMap -> Value)
-> BuiltinResult NestedMap -> BuiltinResult Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
WhenMissing BuiltinResult K (Map K Quantity) (Map K Quantity)
-> WhenMissing BuiltinResult K (Map K Quantity) (Map K Quantity)
-> WhenMatched
BuiltinResult K (Map K Quantity) (Map K Quantity) (Map K Quantity)
-> NestedMap
-> NestedMap
-> BuiltinResult NestedMap
forall (f :: * -> *) k a c b.
(Applicative f, Ord k) =>
WhenMissing f k a c
-> WhenMissing f k b c
-> WhenMatched f k a b c
-> Map k a
-> Map k b
-> f (Map k c)
M.mergeA
WhenMissing BuiltinResult K (Map K Quantity) (Map K Quantity)
forall (f :: * -> *) k x. Applicative f => WhenMissing f k x x
M.preserveMissing
WhenMissing BuiltinResult K (Map K Quantity) (Map K Quantity)
forall (f :: * -> *) k x. Applicative f => WhenMissing f k x x
M.preserveMissing
( (K
-> Map K Quantity
-> Map K Quantity
-> BuiltinResult (Maybe (Map K Quantity)))
-> WhenMatched
BuiltinResult K (Map K Quantity) (Map K Quantity) (Map K Quantity)
forall (f :: * -> *) k x y z.
Applicative f =>
(k -> x -> y -> f (Maybe z)) -> WhenMatched f k x y z
M.zipWithMaybeAMatched \K
_ Map K Quantity
innerA Map K Quantity
innerB ->
(Map K Quantity -> Maybe (Map K Quantity))
-> BuiltinResult (Map K Quantity)
-> BuiltinResult (Maybe (Map K Quantity))
forall a b. (a -> b) -> BuiltinResult a -> BuiltinResult b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Map K Quantity
inner -> if Map K Quantity -> Bool
forall k a. Map k a -> Bool
Map.null Map K Quantity
inner then Maybe (Map K Quantity)
forall a. Maybe a
Nothing else Map K Quantity -> Maybe (Map K Quantity)
forall a. a -> Maybe a
Just Map K Quantity
inner) (BuiltinResult (Map K Quantity)
-> BuiltinResult (Maybe (Map K Quantity)))
-> BuiltinResult (Map K Quantity)
-> BuiltinResult (Maybe (Map K Quantity))
forall a b. (a -> b) -> a -> b
$
WhenMissing BuiltinResult K Quantity Quantity
-> WhenMissing BuiltinResult K Quantity Quantity
-> WhenMatched BuiltinResult K Quantity Quantity Quantity
-> Map K Quantity
-> Map K Quantity
-> BuiltinResult (Map K Quantity)
forall (f :: * -> *) k a c b.
(Applicative f, Ord k) =>
WhenMissing f k a c
-> WhenMissing f k b c
-> WhenMatched f k a b c
-> Map k a
-> Map k b
-> f (Map k c)
M.mergeA
WhenMissing BuiltinResult K Quantity Quantity
forall (f :: * -> *) k x. Applicative f => WhenMissing f k x x
M.preserveMissing
WhenMissing BuiltinResult K Quantity Quantity
forall (f :: * -> *) k x. Applicative f => WhenMissing f k x x
M.preserveMissing
( (K -> Quantity -> Quantity -> BuiltinResult (Maybe Quantity))
-> WhenMatched BuiltinResult K Quantity Quantity Quantity
forall (f :: * -> *) k x y z.
Applicative f =>
(k -> x -> y -> f (Maybe z)) -> WhenMatched f k x y z
M.zipWithMaybeAMatched \K
_ Quantity
x Quantity
y ->
case Quantity -> Quantity -> Maybe Quantity
addQuantity Quantity
x Quantity
y of
Just Quantity
z -> Maybe Quantity -> BuiltinResult (Maybe Quantity)
forall a. a -> BuiltinResult a
forall (f :: * -> *) a. Applicative f => a -> f a
pure if Quantity
z Quantity -> Quantity -> Bool
forall a. Eq a => a -> a -> Bool
== Quantity
zeroQuantity then Maybe Quantity
forall a. Maybe a
Nothing else Quantity -> Maybe Quantity
forall a. a -> Maybe a
Just Quantity
z
Maybe Quantity
Nothing ->
String -> BuiltinResult (Maybe Quantity)
forall a. String -> BuiltinResult a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"unionValue: quantity is out of the signed 128-bit integer bounds"
)
Map K Quantity
innerA
Map K Quantity
innerB
)
NestedMap
vA
NestedMap
vB
{-# INLINEABLE unionValue #-}
valueData :: Value -> Data
valueData :: Value -> Data
valueData = [(Data, Data)] -> Data
Map ([(Data, Data)] -> Data)
-> (Value -> [(Data, Data)]) -> Value -> Data
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((K, Map K Quantity) -> (Data, Data))
-> [(K, Map K Quantity)] -> [(Data, Data)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((K -> Data)
-> (Map K Quantity -> Data) -> (K, Map K Quantity) -> (Data, Data)
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap (ByteString -> Data
B (ByteString -> Data) -> (K -> ByteString) -> K -> Data
forall b c a. (b -> c) -> (a -> b) -> a -> c
. K -> ByteString
unK) Map K Quantity -> Data
tokensData) ([(K, Map K Quantity)] -> [(Data, Data)])
-> (Value -> [(K, Map K Quantity)]) -> Value -> [(Data, Data)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NestedMap -> [(K, Map K Quantity)]
forall k a. Map k a -> [(k, a)]
Map.toList (NestedMap -> [(K, Map K Quantity)])
-> (Value -> NestedMap) -> Value -> [(K, Map K Quantity)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> NestedMap
unpack
where
tokensData :: Map K Quantity -> Data
tokensData :: Map K Quantity -> Data
tokensData = [(Data, Data)] -> Data
Map ([(Data, Data)] -> Data)
-> (Map K Quantity -> [(Data, Data)]) -> Map K Quantity -> Data
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((K, Quantity) -> (Data, Data))
-> [(K, Quantity)] -> [(Data, Data)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((K -> Data) -> (Quantity -> Data) -> (K, Quantity) -> (Data, Data)
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap (ByteString -> Data
B (ByteString -> Data) -> (K -> ByteString) -> K -> Data
forall b c a. (b -> c) -> (a -> b) -> a -> c
. K -> ByteString
unK) (Integer -> Data
I (Integer -> Data) -> (Quantity -> Integer) -> Quantity -> Data
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Quantity -> Integer
unQuantity)) ([(K, Quantity)] -> [(Data, Data)])
-> (Map K Quantity -> [(K, Quantity)])
-> Map K Quantity
-> [(Data, Data)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map K Quantity -> [(K, Quantity)]
forall k a. Map k a -> [(k, a)]
Map.toList
{-# INLINEABLE valueData #-}
unValueData :: Data -> BuiltinResult Value
unValueData :: Data -> BuiltinResult Value
unValueData =
(NestedMap -> Value)
-> BuiltinResult NestedMap -> BuiltinResult Value
forall a b. (a -> b) -> BuiltinResult a -> BuiltinResult b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap NestedMap -> Value
pack (BuiltinResult NestedMap -> BuiltinResult Value)
-> (Data -> BuiltinResult NestedMap) -> Data -> BuiltinResult Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. \case
Map [(Data, Data)]
cs -> do
NestedMap
outerMap <-
(Map K Quantity -> Map K Quantity -> Map K Quantity)
-> [(K, Map K Quantity)] -> NestedMap
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith ((Quantity -> Quantity -> Quantity)
-> Map K Quantity -> Map K Quantity -> Map K Quantity
forall k a. Ord k => (a -> a -> a) -> Map k a -> Map k a -> Map k a
Map.unionWith Quantity -> Quantity -> Quantity
unsafeAddQuantity) ([(K, Map K Quantity)] -> NestedMap)
-> BuiltinResult [(K, Map K Quantity)] -> BuiltinResult NestedMap
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((Data, Data) -> BuiltinResult (K, Map K Quantity))
-> [(Data, Data)] -> BuiltinResult [(K, Map K Quantity)]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse ((Data -> BuiltinResult K)
-> (Data -> BuiltinResult (Map K Quantity))
-> (Data, Data)
-> BuiltinResult (K, Map K Quantity)
forall (f :: * -> *) a c b d.
Applicative f =>
(a -> f c) -> (b -> f d) -> (a, b) -> f (c, d)
forall (t :: * -> * -> *) (f :: * -> *) a c b d.
(Bitraversable t, Applicative f) =>
(a -> f c) -> (b -> f d) -> t a b -> f (t c d)
bitraverse Data -> BuiltinResult K
unB Data -> BuiltinResult (Map K Quantity)
unTokens) [(Data, Data)]
cs
HasCallStack => NestedMap -> BuiltinResult NestedMap
NestedMap -> BuiltinResult NestedMap
validateQuantities NestedMap
outerMap
Data
_ -> String -> BuiltinResult NestedMap
forall a. String -> BuiltinResult a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"unValueData: non-Map constructor"
where
unB :: Data -> BuiltinResult K
unB :: Data -> BuiltinResult K
unB = \case
B ByteString
b -> BuiltinResult K
-> (K -> BuiltinResult K) -> Maybe K -> BuiltinResult K
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> BuiltinResult K
forall a. String -> BuiltinResult a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> BuiltinResult K) -> String -> BuiltinResult K
forall a b. (a -> b) -> a -> b
$ String
"unValueData: invalid key: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> [Word8] -> String
forall a. Show a => a -> String
show (ByteString -> [Word8]
B.unpack ByteString
b)) K -> BuiltinResult K
forall a. a -> BuiltinResult a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ByteString -> Maybe K
k ByteString
b)
Data
_ -> String -> BuiltinResult K
forall a. String -> BuiltinResult a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"unValueData: non-B constructor"
unQ :: Data -> BuiltinResult Quantity
unQ :: Data -> BuiltinResult Quantity
unQ = \case
I Integer
i -> Quantity -> BuiltinResult Quantity
forall a. a -> BuiltinResult a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Integer -> Quantity
UnsafeQuantity Integer
i)
Data
_ -> String -> BuiltinResult Quantity
forall a. String -> BuiltinResult a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"unValueData: non-I constructor"
unTokens :: Data -> BuiltinResult (Map K Quantity)
unTokens :: Data -> BuiltinResult (Map K Quantity)
unTokens = \case
Map [(Data, Data)]
ts -> ([(K, Quantity)] -> Map K Quantity)
-> BuiltinResult [(K, Quantity)] -> BuiltinResult (Map K Quantity)
forall a b. (a -> b) -> BuiltinResult a -> BuiltinResult b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Quantity -> Quantity -> Quantity)
-> [(K, Quantity)] -> Map K Quantity
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith Quantity -> Quantity -> Quantity
unsafeAddQuantity) (((Data, Data) -> BuiltinResult (K, Quantity))
-> [(Data, Data)] -> BuiltinResult [(K, Quantity)]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse ((Data -> BuiltinResult K)
-> (Data -> BuiltinResult Quantity)
-> (Data, Data)
-> BuiltinResult (K, Quantity)
forall (f :: * -> *) a c b d.
Applicative f =>
(a -> f c) -> (b -> f d) -> (a, b) -> f (c, d)
forall (t :: * -> * -> *) (f :: * -> *) a c b d.
(Bitraversable t, Applicative f) =>
(a -> f c) -> (b -> f d) -> t a b -> f (t c d)
bitraverse Data -> BuiltinResult K
unB Data -> BuiltinResult Quantity
unQ) [(Data, Data)]
ts)
Data
_ -> String -> BuiltinResult (Map K Quantity)
forall a. String -> BuiltinResult a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"unValueData: non-Map constructor"
{-# INLINEABLE unValueData #-}
updateSizes :: Int -> Int -> IntMap Int -> IntMap Int
updateSizes :: Int -> Int -> IntMap Int -> IntMap Int
updateSizes Int
old Int
new = IntMap Int -> IntMap Int
dec (IntMap Int -> IntMap Int)
-> (IntMap Int -> IntMap Int) -> IntMap Int -> IntMap Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IntMap Int -> IntMap Int
inc
where
inc :: IntMap Int -> IntMap Int
inc =
if Int
new Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
then IntMap Int -> IntMap Int
forall a. a -> a
id
else (Maybe Int -> Maybe Int) -> Int -> IntMap Int -> IntMap Int
forall a. (Maybe a -> Maybe a) -> Int -> IntMap a -> IntMap a
IntMap.alter (Maybe Int -> (Int -> Maybe Int) -> Maybe Int -> Maybe Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
1) (Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> (Int -> Int) -> Int -> Maybe Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1))) Int
new
dec :: IntMap Int -> IntMap Int
dec =
if Int
old Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
then IntMap Int -> IntMap Int
forall a. a -> a
id
else (Int -> Maybe Int) -> Int -> IntMap Int -> IntMap Int
forall a. (a -> Maybe a) -> Int -> IntMap a -> IntMap a
IntMap.update (\Int
n -> if Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
1 then Maybe Int
forall a. Maybe a
Nothing else Int -> Maybe Int
forall a. a -> Maybe a
Just (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)) Int
old
{-# INLINEABLE updateSizes #-}
scaleValue :: Integer -> Value -> BuiltinResult Value
scaleValue :: Integer -> Value -> BuiltinResult Value
scaleValue Integer
c (Value NestedMap
outer IntMap Int
sizes Int
size Int
neg)
| Integer
c Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
0 = do
NestedMap
outer' <- NestedMap -> BuiltinResult NestedMap
go NestedMap
outer
Value -> BuiltinResult Value
forall a. a -> BuiltinResult a
BuiltinSuccess (Value -> BuiltinResult Value) -> Value -> BuiltinResult Value
forall a b. (a -> b) -> a -> b
$ NestedMap -> IntMap Int -> Int -> Int -> Value
Value NestedMap
outer' IntMap Int
sizes Int
size Int
neg
| Integer
c Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
0 = do
NestedMap
outer' <- NestedMap -> BuiltinResult NestedMap
go NestedMap
outer
Value -> BuiltinResult Value
forall a. a -> BuiltinResult a
BuiltinSuccess (Value -> BuiltinResult Value) -> Value -> BuiltinResult Value
forall a b. (a -> b) -> a -> b
$ NestedMap -> IntMap Int -> Int -> Int -> Value
Value NestedMap
outer' IntMap Int
sizes Int
size (Int
size Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
neg)
| Bool
otherwise = Value -> BuiltinResult Value
forall a. a -> BuiltinResult a
BuiltinSuccess Value
empty
where
go :: NestedMap -> BuiltinResult NestedMap
go :: NestedMap -> BuiltinResult NestedMap
go NestedMap
x = (Map K Quantity -> BuiltinResult (Map K Quantity))
-> NestedMap -> BuiltinResult NestedMap
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Map K a -> f (Map K b)
traverse ((Quantity -> BuiltinResult Quantity)
-> Map K Quantity -> BuiltinResult (Map K Quantity)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Map K a -> f (Map K b)
traverse Quantity -> BuiltinResult Quantity
goScale) NestedMap
x
goScale :: Quantity -> BuiltinResult Quantity
goScale :: Quantity -> BuiltinResult Quantity
goScale Quantity
x =
case Integer -> Quantity -> Maybe Quantity
scaleQuantity Integer
c Quantity
x of
Maybe Quantity
Nothing ->
String -> BuiltinResult Quantity
forall a. String -> BuiltinResult a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> BuiltinResult Quantity)
-> String -> BuiltinResult Quantity
forall a b. (a -> b) -> a -> b
$
String
"scaleValue: quantity out of bounds: "
String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Integer -> String
forall a. Show a => a -> String
show Integer
c String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" * " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Integer -> String
forall a. Show a => a -> String
show (Quantity -> Integer
unQuantity Quantity
x)
Just Quantity
q -> Quantity -> BuiltinResult Quantity
forall a. a -> BuiltinResult a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Quantity
q