Skip to content

Newtype #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 1, 2022
Merged
Show file tree
Hide file tree
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ Bugfixes:

Other improvements:

- `UInt64.unsafeFromInt` (#5 by @jamesdbrock)
- `newtype` wrappers for `Int64`, `UInt64` (#5 by @jamesdbrock)

## [v1.0.0](https://github.com/purescript-contrib/purescript-int64/releases/tag/v1.0.0) - 2022-05-07

Initial release.
1 change: 0 additions & 1 deletion spago-dev.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ conf //
{ sources = [ "src/**/*.purs", "test/**/*.purs", ]
, dependencies = conf.dependencies #
[ "spec"
, "psci-support"
, "aff"
, "quickcheck-laws"
, "assert"
Expand Down
1 change: 1 addition & 0 deletions spago.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
, "functions"
, "maybe"
, "quickcheck"
, "unsafe-coerce"
]
, packages = ./packages.dhall
, sources = [ "src/**/*.purs", ]
Expand Down
95 changes: 59 additions & 36 deletions src/Data/Int64.purs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
-- | Signed two’s-complement 64-bit integers and operations.
-- |
-- | All of the usual arithmetic operations are supplied by typeclass
-- | instances from typeclasses in the __Prelude__.
-- |
-- | The `Show` instance will suffix a lowercase ‘l’ for “long”.
-- | instances.
-- |
-- | #### Usage
-- |
Expand Down Expand Up @@ -46,9 +44,9 @@
-- | 23
-- | ```
module Data.Int64
( module R
, fromLowHighBits
( Int64
, fromInt
, fromLowHighBits
, fromNumber
, fromString
, fromStringAs
Expand All @@ -64,6 +62,7 @@ module Data.Int64
, quot
, rem
, toUnsigned
, toSigned
, and
, (.&.)
, or
Expand All @@ -76,121 +75,145 @@ module Data.Int64
, complement
) where

import Data.Int (Parity, Radix)
import Data.Int64.Internal (Int64) as R
import Data.Int64.Internal (Int64, UInt64)
import Prelude

import Data.Int (Parity, Radix, decimal)
import Data.Int64.Internal as Internal
import Data.Maybe (Maybe)
import Data.UInt64 (UInt64)
import Test.QuickCheck (class Arbitrary)
import Unsafe.Coerce (unsafeCoerce)

-- | Signed two’s-complement 64-bit integer.
newtype Int64 = Int64 (Internal.Long' Internal.Signed)

-- | The `Show` instance will suffix a lowercase ‘l’ for “long”.
-- | (See `toString`.)
instance Show Int64 where
show (Int64 (Internal.Long' l)) = Internal.toString_ l decimal <> "l"

derive newtype instance Eq Int64
derive newtype instance Ord Int64
derive newtype instance Bounded Int64
derive newtype instance Semiring Int64
derive newtype instance Ring Int64
derive newtype instance CommutativeRing Int64
derive newtype instance EuclideanRing Int64
derive newtype instance Arbitrary Int64

-- | Creates an `Int64` from an `Int` value.
fromInt :: Int -> Int64
fromInt = Internal.signedLongFromInt
fromInt a = Int64 (Internal.signedLongFromInt a)

-- | Creates an `Int64` from a `Number` value. The number must already be an
-- | integer and fall within the valid range of values for the `Int64` type
-- | otherwise `Nothing` is returned.
fromNumber :: Number -> Maybe Int64
fromNumber = Internal.fromNumber
fromNumber n = Int64 <$> Internal.fromNumber n

-- | Creates an `Int64` from low and high bits represented as `Int`.
fromLowHighBits :: Int -> Int -> Int64
fromLowHighBits = Internal.fromLowHighBits
fromLowHighBits a b = Int64 (Internal.fromLowHighBits a b)

-- | Reads an `Int64` from a `String` value. The number must parse as an integer
-- | and fall within the valid range of values for the `Int64` type, otherwise
-- | `Nothing` is returned.
fromString :: String -> Maybe Int64
fromString = Internal.fromString
fromString s = Int64 <$> Internal.fromString s

-- | Like `fromString`, but the integer can be specified in a different base.
fromStringAs :: Radix -> String -> Maybe Int64
fromStringAs = Internal.fromStringAs
fromStringAs r s = Int64 <$> Internal.fromStringAs r s

-- | Get the low (least significant) bits of an `Int64` as an `Int`.
lowBits :: Int64 -> Int
lowBits = Internal.lowBits
lowBits (Int64 a) = Internal.lowBits a

-- | Get the high (most significant) bits of an `Int64` as an `Int`.
highBits :: Int64 -> Int
highBits = Internal.highBits
highBits (Int64 a) = Internal.highBits a

-- | Creates an `Int` if the `Int64` value is within the range of `Int64`.
toInt :: Int64 -> Maybe Int
toInt = Internal.toInt
toInt (Int64 a) = Internal.toInt a

-- | Like `show`, but omits the `l` suffix.
toString :: Int64 -> String
toString = Internal.toString
toString (Int64 a) = Internal.toString a

-- | Like `toStringAs`, but the integer can be specified in a different base.
-- | Like `toString`, but the integer can be specified in a different base.
toStringAs :: Radix -> Int64 -> String
toStringAs = Internal.toStringAs
toStringAs r (Int64 a) = Internal.toStringAs r a

-- | Creates a `Number` value from a `Int64`. Values not within
-- | `Number.MIN_SAFE_INTEGER` and `Number.MAX_SAFE_INTEGER` will lose precision.
toNumber :: Int64 -> Number
toNumber = Internal.toNumber
toNumber (Int64 a) = Internal.toNumber a

-- | Returns whether a `Int64` is `Even` or `Odd`.
parity :: Int64 -> Parity
parity = Internal.parity
parity (Int64 a) = Internal.parity a

-- | Returns whether a `Int64` is an even number.
-- | Returns true if an even number.
even :: Int64 -> Boolean
even = Internal.even
even (Int64 a) = Internal.even a

-- | Returns whether a `Int64` is an odd number.
-- | Returns true if an odd number.
odd :: Int64 -> Boolean
odd = Internal.odd
odd (Int64 a) = Internal.odd a

-- | The `quot` function provides _truncating_ long division (see the
-- | documentation for the `EuclideanRing` class). It is identical to `div` in
-- | the `EuclideanRing Int` instance if the dividend is positive, but will be
-- | slightly different if the dividend is negative.
quot :: Int64 -> Int64 -> Int64
quot = Internal.quot
quot (Int64 a) (Int64 b) = Int64 (Internal.quot a b)

-- | The `rem` function provides the remainder after _truncating_ long
-- | division (see the documentation for the `EuclideanRing` class). It is
-- | identical to `mod` in the `EuclideanRing Int` instance if the dividend is
-- | positive, but will be slightly different if the dividend is negative.
rem :: Int64 -> Int64 -> Int64
rem = Internal.rem
rem (Int64 a) (Int64 b) = Int64 (Internal.rem a b)

-- | Converts to a `UInt64` by reading the bits as a 64 bit unsigned integer.
-- | Converts to a `UInt64` by casting the bits as a 64-bit unsigned integer.
toUnsigned :: Int64 -> UInt64
toUnsigned = Internal.signedToUnsigned
toUnsigned (Int64 a) = unsafeCoerce (Internal.signedToUnsigned a)

-- | Converts to an `Int64` by casting the bits as a 2’s-complement 64-bit signed integer.
toSigned :: UInt64 -> Int64
toSigned a = Int64 (Internal.unsignedToSigned (unsafeCoerce a))

-- | Bitwise AND.
and :: Int64 -> Int64 -> Int64
and = Internal.and
and (Int64 a) (Int64 b) = Int64 (Internal.and a b)

infixl 10 and as .&.

-- | Bitwise OR.
or :: Int64 -> Int64 -> Int64
or = Internal.or
or (Int64 a) (Int64 b) = Int64 (Internal.or a b)

infixl 10 or as .|.

-- | Bitwise XOR.
xor :: Int64 -> Int64 -> Int64
xor = Internal.xor
xor (Int64 a) (Int64 b) = Int64 (Internal.xor a b)

infixl 10 xor as .^.

-- | Bitwise shift left.
shl :: Int64 -> Int64 -> Int64
shl = Internal.shl
shl (Int64 a) (Int64 b) = Int64 (Internal.shl a b)

-- | Bitwise shift right.
shr :: Int64 -> Int64 -> Int64
shr = Internal.shr
shr (Int64 a) (Int64 b) = Int64 (Internal.shr a b)

-- | Bitwise zero-fill shift right.
zshr :: Int64 -> Int64 -> Int64
zshr = Internal.zshr
zshr (Int64 a) (Int64 b) = Int64 (Internal.zshr a b)

-- | Bitwise NOT.
complement :: Int64 -> Int64
complement = Internal.complement
complement (Int64 a) = Int64 (Internal.complement a)
15 changes: 4 additions & 11 deletions src/Data/Int64/Internal.purs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
module Data.Int64.Internal
( Int64
, IsLittleEndian(..)
( IsLittleEndian(..)
, IsUnsigned(..)
, Long
, Long'
, Long'(..)
, SignProxy(..)
, Signed
, Signedness
, UInt64
, Unsigned
, add_
, and
Expand Down Expand Up @@ -141,14 +139,9 @@ instance infoUnsigned :: SInfo Unsigned where
if high == 0 && low > 0 then Just low
else Nothing

-- | Newtype wrapper for the foreign JavaScript `Long` object.
newtype Long' (s :: Signedness) = Long' Long

-- | Unsigned 64-bit integer.
type UInt64 = Long' Unsigned

-- | Signed two’s-complement 64-bit integer.
type Int64 = Long' Signed

instance showLong' :: Show (Long' s) where
show (Long' l) = show l

Expand Down Expand Up @@ -337,7 +330,7 @@ foreign import isWholeNumber_ :: Number -> Boolean

-- FFI.purs from here

-- A 64 bit two's-complement integer
-- | The foreign JavaScript `Long` object.
foreign import data Long :: Type

instance showLong :: Show Long where
Expand Down
Loading