rt (empty) → 0.1.0.0
raw patch · 7 files changed
+208/−0 lines, 7 filesdep +base
Dependencies added: base
Files
- CHANGELOG.md +5/−0
- LICENSE +28/−0
- rt.cabal +79/−0
- src/Control/Monad/RT.hs +17/−0
- src/Control/Monad/RT/Unsafe.hs +15/−0
- src/Data/Ref.hs +42/−0
- src/Data/Ref/Impl.hs +22/−0
+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for rt++## 0.1.0.0 -- 2024-04-08++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,28 @@+BSD 3-Clause License++Copyright (c) 2024, Jamie Willis++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice, this+ list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright notice,+ this list of conditions and the following disclaimer in the documentation+ and/or other materials provided with the distribution.++3. Neither the name of the copyright holder nor the names of its+ contributors may be used to endorse or promote products derived from+ this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ rt.cabal view
@@ -0,0 +1,79 @@+cabal-version: 3.0+-- The cabal-version field refers to the version of the .cabal specification,+-- and can be different from the cabal-install (the tool) version and the+-- Cabal (the library) version you are using. As such, the Cabal (the library)+-- version used must be equal or greater than the version stated in this field.+-- Starting from the specification version 2.2, the cabal-version field must be+-- the first thing in the cabal file.++-- Initial package description 'rt' generated by+-- 'cabal init'. For further documentation, see:+-- http://haskell.org/cabal/users-guide/+--+-- The name of the package.+name: rt++-- The package version.+-- See the Haskell package versioning policy (PVP) for standards+-- guiding when and how versions should be incremented.+-- https://pvp.haskell.org+-- PVP summary: +-+------- breaking API changes+-- | | +----- non-breaking API additions+-- | | | +--- code changes with no API change+version: 0.1.0.0++-- A short (one-line) description of the package.+synopsis: A more fine-grained version of state threads (ST)++-- A longer description of the package.+description: Introduces the RT monad, which can be used to have more fine-grained STRefs without an extra parameter+ in the monad.++-- URL for the project homepage or repository.+homepage: https://github.com/j-mie6/reference-threads++-- The license under which the package is released.+license: BSD-3-Clause++-- The file containing the license text.+license-file: LICENSE++-- The package author(s).+author: Jamie Willis++-- An email address to which users can send suggestions, bug reports, and patches.+maintainer: j.willis19@imperial.ac.uk++copyright: (c) 2024-present Jamie Willis+category: Control+build-type: Simple++-- Extra doc files to be distributed with the package, such as a CHANGELOG or a README.+extra-doc-files: CHANGELOG.md++source-repository head+ type: git+ location: git://github.com/j-mie6/reference-threads.git++common warnings+ ghc-options: -Wall++library+ -- Import common warning flags.+ import: warnings++ -- Modules exported by the library.+ exposed-modules: Control.Monad.RT+ Control.Monad.RT.Unsafe+ Data.Ref+ Data.Ref.Impl+ --Data.Array.RT++ -- Other library packages from which modules are imported.+ build-depends: base >=4.14 && < 5++ -- Directories containing source files.+ hs-source-dirs: src++ -- Base language which the package is written in.+ default-language: Haskell2010
+ src/Control/Monad/RT.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE MagicHash, UnboxedTuples #-}+module Control.Monad.RT (RT, module Control.Monad.RT) where++import Control.Monad.RT.Unsafe++import GHC.Base (runRW#)+import GHC.IO (IO(IO))+import Data.Coerce (coerce)++{-# INLINE runRT #-}+runRT :: RT a -> a+runRT (RT mx) = case runRW# mx of (# _, x #) -> x++{-# INLINE rtToIO #-}+rtToIO :: RT a -> IO a+rtToIO = coerce
+ src/Control/Monad/RT/Unsafe.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE Unsafe #-}+{-# LANGUAGE UnboxedTuples, MagicHash, DerivingVia, DataKinds #-}+module Control.Monad.RT.Unsafe (module Control.Monad.RT.Unsafe) where++import GHC.Base (State#, RealWorld)+import GHC.IO (IO(IO))+import Data.Coerce (coerce)++-- do the instances by hand?+newtype RT a = RT (State# RealWorld -> (# State# RealWorld, a #))+ deriving (Functor, Applicative, Monad) via IO++{-# INLINE unsafeIOToRT #-}+unsafeIOToRT :: IO a -> RT a+unsafeIOToRT = coerce
+ src/Data/Ref.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE MagicHash, UnboxedTuples, RankNTypes, TypeOperators #-}+module Data.Ref (Ref, module Data.Ref) where++import Control.Monad.RT.Unsafe (RT(RT))+import Data.Ref.Impl (Ref(Ref))++import GHC.Base (newMutVar#, readMutVar#, writeMutVar#)++import GHC.IORef (IORef(IORef))+import GHC.STRef (STRef(STRef))++import Data.Type.Equality ((:~:)(Refl))+import Unsafe.Coerce (unsafeCoerce)+++{-# INLINABLE newRef #-}+newRef :: a -> (forall r. Ref r a -> RT b) -> RT b+newRef x k = RT $ \s# ->+ case newMutVar# x s# of+ (# s'#, ref# #) -> let RT k' = k (Ref ref#) in k' s'#++{-# INLINE readRef #-}+readRef :: Ref r a -> RT a+readRef (Ref ref#) = RT $ \s# -> readMutVar# ref# s#++{-# INLINABLE writeRef #-}+writeRef :: Ref r a -> a -> RT ()+writeRef (Ref ref#) x = RT $ \s# ->+ case writeMutVar# ref# x s# of+ s'# -> (# s'#, () #)++-- unsafeFromIORef?+{-# INLINE fromIORef #-}+fromIORef :: IORef a -> Ref r a+fromIORef (IORef (STRef ref#)) = Ref ref#++-- returns a proof that if two references are equal, they must have the same lifetime+lifetimeEqual :: Ref r1 a -> Ref r2 a -> Maybe (r1 :~: r2)+lifetimeEqual (Ref ref1#) ref2+ | Ref ref1# == ref2 = Just (unsafeCoerce Refl)+ | otherwise = Nothing
+ src/Data/Ref/Impl.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE DataKinds, MagicHash, RoleAnnotations #-}+module Data.Ref.Impl (module Data.Ref.Impl) where++import GHC.Base (MutVar#, RealWorld, sameMutVar#, isTrue#)++{-+The `r` parameter is deliberately nominal here, which prevents the use of+coerce to "safely" escape the lifetime of a reference:++> escape :: a -> RT (Ref r a)+> escape x = newRef x (return . coerce)++Would compile if the annotation was left as phantom (which is the inferred).+This is clearly not something we want to allow, so nominal it is.+-}+type role Ref nominal representational+-- Don't even expose the constructor, then it's pretty much safe?+data Ref r a = Ref (MutVar# RealWorld a)++-- It's nice that two references must clearly have the same lifetime to be equal+instance Eq (Ref r a) where+ Ref ref1# == Ref ref2# = isTrue# (sameMutVar# ref1# ref2#)