packages feed

ghcjs-base 0.8.0.4 → 0.8.1.0

raw patch · 4 files changed

+256/−2 lines, 4 filesdep ~time

Dependency ranges changed: time

Files

+ ChangeLog.md view
@@ -0,0 +1,13 @@+# Revision history for ghcjs-base++## 0.8.1.0++* `GHCJS.Int53`: `Int53` and `Word53`, integers a JavaScript Number holds+  exactly (up to 2^53 - 1), with checked (`toInt53`), saturating+  (`clampInt53`) and literal (`int53`) conversions and no `Num` instance.+  jsaddle has the same module for native GHC.+* `PToJSVal`, `PFromJSVal`, `ToJSVal` and `FromJSVal` instances for+  `Object` and `SomeJSArray` (`JSArray`, `MutableJSArray`) in+  `GHCJS.Marshal.Internal`; `fromJSVal` is `Nothing` for `null` and+  `undefined`.  Packages with their own orphan instances for these types+  need to drop them.
+ GHCJS/Int53.hs view
@@ -0,0 +1,184 @@+-----------------------------------------------------------------------------+--+-- Module      :  GHCJS.Int53+-- License     :  MIT+--+-- | Integers that a JavaScript Number holds exactly.+--+-- A JavaScript Number is a double, so it represents every integer of+-- magnitude up to @2^53 - 1@ (@Number.MAX_SAFE_INTEGER@) exactly and loses+-- precision beyond that.  Web IDL's @long long@ and @unsigned long long@+-- are such Numbers (its editors have proposed renaming them @int53@ /+-- @uint53@, <https://github.com/whatwg/webidl/issues/33>), and without+-- @[EnforceRange]@ a browser silently reduces an out of range argument+-- modulo @2^64@.+--+-- 'Int53' and 'Word53' make that range part of the type.  They have no+-- 'Num' instance on purpose: do arithmetic in 'Int64', 'Integer', 'Double'+-- or any other numeric type and convert back with a checked conversion,+-- so the place where a value could go out of range is explicit.+--+-- Using them with the DOM bindings (jsaddle-dom / ghcjs-dom 0.10, where+-- every @long long@ is an 'Int53' and every @unsigned long long@ a+-- 'Word53'):+--+-- > size <- Blob.getSize blob                  -- Word53+-- > let half = fromWord53 size `div` (2 :: Integer)+-- > -- (toInt53 gives Maybe Int53: Nothing when out of range)+-- > part <- Blob.slice blob (Just (int53 0)) (toInt53 half) (Nothing :: Maybe Text)+--+-- Small literals go through 'int53' / 'word53' (every 'Int32' / 'Word32'+-- fits); computed values through 'toInt53' / 'toWord53' (or 'clampInt53'+-- / 'clampWord53' to saturate instead).+--+-- jsaddle provides a module with the same name and API for native GHC+-- (@Language.Javascript.JSaddle.Int53@ re-exports whichever applies); keep+-- the two in step.+--+-----------------------------------------------------------------------------+module GHCJS.Int53 (+  -- * Signed+    Int53+  , int53+  , toInt53+  , clampInt53+  , fromInt53+  , minInt53+  , maxInt53+  -- * Unsigned+  , Word53+  , word53+  , toWord53+  , clampWord53+  , fromWord53+  , maxWord53+) where++import Data.Int (Int32, Int64)+import Data.Word (Word32, Word64)++import GHCJS.Marshal (ToJSVal(..), FromJSVal(..))+import GHCJS.Marshal.Pure (PToJSVal(..), PFromJSVal(..))++-- | An integer in the range @[-(2^53 - 1), 2^53 - 1]@.+newtype Int53 = Int53 Int64 deriving (Eq, Ord)++-- | An integer in the range @[0, 2^53 - 1]@.+newtype Word53 = Word53 Word64 deriving (Eq, Ord)++-- | @2^53 - 1@ (@Number.MAX_SAFE_INTEGER@)+safeMax :: Integer+safeMax = 2 ^ (53 :: Int) - 1++minInt53, maxInt53 :: Int53+minInt53 = Int53 (fromInteger (negate safeMax))+maxInt53 = Int53 (fromInteger safeMax)++maxWord53 :: Word53+maxWord53 = Word53 (fromInteger safeMax)++instance Bounded Int53 where+    minBound = minInt53+    maxBound = maxInt53++instance Bounded Word53 where+    minBound = Word53 0+    maxBound = maxWord53++-- | Shown (and read) as a plain number.+instance Show Int53 where+    showsPrec p (Int53 i) = showsPrec p i++instance Show Word53 where+    showsPrec p (Word53 w) = showsPrec p w++instance Read Int53 where+    readsPrec p s = [ (x, rest) | (i, rest) <- readsPrec p s, Just x <- [toInt53 (i :: Integer)] ]++instance Read Word53 where+    readsPrec p s = [ (x, rest) | (i, rest) <- readsPrec p s, Just x <- [toWord53 (i :: Integer)] ]++-- | Every 'Int32' fits (use it for literals: @int53 0@).+int53 :: Int32 -> Int53+int53 = Int53 . fromIntegral++-- | Every 'Word32' fits (use it for literals: @word53 0@).+word53 :: Word32 -> Word53+word53 = Word53 . fromIntegral++-- | 'Nothing' when out of range.+toInt53 :: Integral a => a -> Maybe Int53+toInt53 a+    | abs i <= safeMax = Just (Int53 (fromInteger i))+    | otherwise = Nothing+  where i = toInteger a++-- | 'Nothing' when out of range.+toWord53 :: Integral a => a -> Maybe Word53+toWord53 a+    | i >= 0 && i <= safeMax = Just (Word53 (fromInteger i))+    | otherwise = Nothing+  where i = toInteger a++-- | Saturating conversion (like Web IDL's @[Clamp]@, without rounding).+clampInt53 :: Integral a => a -> Int53+clampInt53 a = Int53 (fromInteger (max (negate safeMax) (min safeMax (toInteger a))))++-- | Saturating conversion (like Web IDL's @[Clamp]@, without rounding).+clampWord53 :: Integral a => a -> Word53+clampWord53 a = Word53 (fromInteger (max 0 (min safeMax (toInteger a))))++-- | Always exact for 'Int64', 'Integer' and 'Double' (and for any type+-- wide enough for the value).+fromInt53 :: Num b => Int53 -> b+fromInt53 (Int53 i) = fromIntegral i++-- | Always exact for 'Word64', 'Int64', 'Integer' and 'Double' (and for any+-- type wide enough for the value).+fromWord53 :: Num b => Word53 -> b+fromWord53 (Word53 w) = fromIntegral w++fromDouble :: (Integer -> Maybe a) -> Double -> Maybe a+fromDouble f d+    | isNaN d || isInfinite d = Nothing+    | fromInteger i == d = f i+    | otherwise = Nothing+  where i = truncate d++-- | A JavaScript Number (exact).+instance PToJSVal Int53 where+    pToJSVal (Int53 i) = pToJSVal (fromIntegral i :: Double)+    {-# INLINE pToJSVal #-}++-- | A JavaScript Number (exact).+instance PToJSVal Word53 where+    pToJSVal (Word53 w) = pToJSVal (fromIntegral w :: Double)+    {-# INLINE pToJSVal #-}++-- | Unchecked: truncates (and saturates) whatever Number it is given.+instance PFromJSVal Int53 where+    pFromJSVal v = clampInt53 (truncate (pFromJSVal v :: Double) :: Integer)+    {-# INLINE pFromJSVal #-}++-- | Unchecked: truncates (and saturates) whatever Number it is given.+instance PFromJSVal Word53 where+    pFromJSVal v = clampWord53 (truncate (pFromJSVal v :: Double) :: Integer)+    {-# INLINE pFromJSVal #-}++instance ToJSVal Int53 where+    toJSVal = return . pToJSVal+    {-# INLINE toJSVal #-}++instance ToJSVal Word53 where+    toJSVal = return . pToJSVal+    {-# INLINE toJSVal #-}++-- | 'Nothing' unless the value is a Number holding an integer in range.+instance FromJSVal Int53 where+    fromJSVal v = (>>= fromDouble toInt53) <$> fromJSVal v+    fromJSValUnchecked v = fromJSVal v >>= maybe (fail "fromJSValUnchecked: not an Int53") return++-- | 'Nothing' unless the value is a Number holding an integer in range.+instance FromJSVal Word53 where+    fromJSVal v = (>>= fromDouble toWord53) <$> fromJSVal v+    fromJSValUnchecked v = fromJSVal v >>= maybe (fail "fromJSValUnchecked: not a Word53") return
GHCJS/Marshal/Internal.hs view
@@ -258,3 +258,54 @@  packJSS :: String -> JSString packJSS = JSS.JSString . Prim.toJSString++-- -----------------------------------------------------------------------------+-- Instances for ghcjs-base's own JSVal newtypes.  They live here, with the+-- classes, so they are not orphans and need no extra imports.  jsaddle+-- provides the same instances for native GHC.++instance PToJSVal Object where+  pToJSVal (OI.Object v) = v+  {-# INLINE pToJSVal #-}++-- | Unchecked: wraps any value.+instance PFromJSVal Object where+  pFromJSVal = OI.Object+  {-# INLINE pFromJSVal #-}++instance ToJSVal Object where+  toJSVal (OI.Object v) = return v+  {-# INLINE toJSVal #-}++-- | 'Nothing' for @null@ and @undefined@ (as for the ghcjs-dom types);+-- 'fromJSValUnchecked' wraps any value.+instance FromJSVal Object where+  fromJSVal v+    | F.isNull v || F.isUndefined v = return Nothing+    | otherwise = return (Just (OI.Object v))+  {-# INLINE fromJSVal #-}+  fromJSValUnchecked = return . OI.Object+  {-# INLINE fromJSValUnchecked #-}++instance PToJSVal (AI.SomeJSArray m) where+  pToJSVal (AI.SomeJSArray v) = v+  {-# INLINE pToJSVal #-}++-- | Unchecked: wraps any value.+instance PFromJSVal (AI.SomeJSArray m) where+  pFromJSVal = AI.SomeJSArray+  {-# INLINE pFromJSVal #-}++instance ToJSVal (AI.SomeJSArray m) where+  toJSVal (AI.SomeJSArray v) = return v+  {-# INLINE toJSVal #-}++-- | 'Nothing' for @null@ and @undefined@; 'fromJSValUnchecked' wraps any+-- value (no @Array.isArray@ check, like the other JSVal newtypes).+instance FromJSVal (AI.SomeJSArray m) where+  fromJSVal v+    | F.isNull v || F.isUndefined v = return Nothing+    | otherwise = return (Just (AI.SomeJSArray v))+  {-# INLINE fromJSVal #-}+  fromJSValUnchecked = return . AI.SomeJSArray+  {-# INLINE fromJSValUnchecked #-}
ghcjs-base.cabal view
@@ -1,10 +1,15 @@ cabal-version:       3.0 name:                ghcjs-base-version:             0.8.0.4+version:             0.8.1.0 synopsis:            base library for GHCJS+description:+  JavaScript types, marshalling (GHCJS.Marshal), foreign helpers and+  JavaScript.* data structure bindings for the GHC JavaScript backend+  (and legacy GHCJS). homepage:            http://github.com/ghcjs/ghcjs-base license:             MIT license-file:        LICENSE+extra-doc-files:     ChangeLog.md author:              Luite Stegeman maintainer:          stegeman@gmail.com category:            Web@@ -70,6 +75,7 @@                    GHCJS.Foreign                    GHCJS.Foreign.Export                    GHCJS.Foreign.Internal+                   GHCJS.Int53                    GHCJS.Marshal                    GHCJS.Marshal.Internal                    GHCJS.Marshal.Pure@@ -134,7 +140,7 @@                    scientific           >= 0.3.7 && < 0.4,                    vector               >= 0.10 && < 0.14,                    containers           >= 0.5  && < 0.9,-                   time                 >= 1.5  && < 1.15,+                   time                 >= 1.5  && < 1.16,                    hashable             >= 1.2  && < 1.6,                    unordered-containers >= 0.2  && < 0.3,                    attoparsec           >= 0.11 && < 0.15,