packages feed

monoidmap-internal 0.3.0.0 → 0.4.0.0

raw patch · 10 files changed

+404/−198 lines, 10 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Data.MonoidMap.Internal: NonNullMap :: Map k (NonNull v) -> NonNullMap k v
- Data.MonoidMap.Internal: applyNonNull :: (v -> a) -> NonNull v -> a
- Data.MonoidMap.Internal: applyNonNull2 :: (v1 -> v2 -> a) -> NonNull v1 -> NonNull v2 -> a
- Data.MonoidMap.Internal: data NonNull v
- Data.MonoidMap.Internal: fromMap :: MonoidNull v => Map k v -> Map k (NonNull v)
- Data.MonoidMap.Internal: fromMapWith :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)
- Data.MonoidMap.Internal: fromMapWith_mapMaybe :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)
- Data.MonoidMap.Internal: fromMapWith_map_filter :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)
- Data.MonoidMap.Internal: fromMapWith_map_filter_if_any_null :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)
- Data.MonoidMap.Internal: fromMap_filter :: MonoidNull v => Map k v -> Map k (NonNull v)
- Data.MonoidMap.Internal: fromMap_filter_if_any_null :: MonoidNull v => Map k v -> Map k (NonNull v)
- Data.MonoidMap.Internal: fromMap_mapMaybe :: MonoidNull v => Map k v -> Map k (NonNull v)
- Data.MonoidMap.Internal: fromNonNullMap :: Map k (NonNull v) -> Map k v
- Data.MonoidMap.Internal: instance (Control.DeepSeq.NFData k, Control.DeepSeq.NFData v) => Control.DeepSeq.NFData (Data.MonoidMap.Internal.NonNullMap k v)
- Data.MonoidMap.Internal: instance (GHC.Classes.Eq k, GHC.Classes.Eq v) => GHC.Classes.Eq (Data.MonoidMap.Internal.NonNullMap k v)
- Data.MonoidMap.Internal: instance (GHC.Show.Show k, GHC.Show.Show v) => GHC.Show.Show (Data.MonoidMap.Internal.NonNullMap k v)
- Data.MonoidMap.Internal: instance (NoThunks.Class.NoThunks k, NoThunks.Class.NoThunks v) => NoThunks.Class.NoThunks (Data.MonoidMap.Internal.NonNullMap k v)
- Data.MonoidMap.Internal: instance Control.DeepSeq.NFData v => Control.DeepSeq.NFData (Data.MonoidMap.Internal.NonNull v)
- Data.MonoidMap.Internal: instance Data.Bifoldable.Bifoldable Data.MonoidMap.Internal.NonNullMap
- Data.MonoidMap.Internal: instance Data.Foldable.Foldable (Data.MonoidMap.Internal.NonNullMap k)
- Data.MonoidMap.Internal: instance Data.Functor.Classes.Eq2 Data.MonoidMap.Internal.NonNullMap
- Data.MonoidMap.Internal: instance Data.Functor.Classes.Show2 Data.MonoidMap.Internal.NonNullMap
- Data.MonoidMap.Internal: instance GHC.Classes.Eq k => Data.Functor.Classes.Eq1 (Data.MonoidMap.Internal.NonNullMap k)
- Data.MonoidMap.Internal: instance GHC.Show.Show k => Data.Functor.Classes.Show1 (Data.MonoidMap.Internal.NonNullMap k)
- Data.MonoidMap.Internal: maybeNonNull :: MonoidNull v => v -> Maybe (NonNull v)
- Data.MonoidMap.Internal: newtype NonNullMap k v
+ Data.MonoidMap.Internal.NonNull: apply :: (v -> a) -> NonNull v -> a
+ Data.MonoidMap.Internal.NonNull: apply2 :: (v1 -> v2 -> a) -> NonNull v1 -> NonNull v2 -> a
+ Data.MonoidMap.Internal.NonNull: data NonNull v
+ Data.MonoidMap.Internal.NonNull: nonNull :: MonoidNull v => v -> Maybe (NonNull v)
+ Data.MonoidMap.Internal.NonNull: unwrap :: NonNull v -> v
+ Data.MonoidMap.Internal.NonNullMap: NonNullMap :: Map k (NonNull v) -> NonNullMap k v
+ Data.MonoidMap.Internal.NonNullMap: fromMap :: MonoidNull v => Map k v -> NonNullMap k v
+ Data.MonoidMap.Internal.NonNullMap: fromMapWith :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2
+ Data.MonoidMap.Internal.NonNullMap: newtype NonNullMap k v
+ Data.MonoidMap.Internal.NonNullMap: toMap :: NonNullMap k v -> Map k v
+ Data.MonoidMap.Internal.NonNullMap.FromMap: fromMap_filter :: MonoidNull v => Map k v -> NonNullMap k v
+ Data.MonoidMap.Internal.NonNullMap.FromMap: fromMap_filter_if_any_null :: MonoidNull v => Map k v -> NonNullMap k v
+ Data.MonoidMap.Internal.NonNullMap.FromMap: fromMap_mapMaybe :: MonoidNull v => Map k v -> NonNullMap k v
+ Data.MonoidMap.Internal.NonNullMap.FromMapWith: fromMapWith_mapMaybe :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2
+ Data.MonoidMap.Internal.NonNullMap.FromMapWith: fromMapWith_map_filter :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2
+ Data.MonoidMap.Internal.NonNullMap.FromMapWith: fromMapWith_map_filter_if_any_null :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2

Files

CHANGELOG.md view
@@ -1,3 +1,34 @@+# 0.4.0.0++- Revised the module structure of the package, replacing the+  `Data.MonoidMap.Internal` module with the following modules:++  - `Data.MonoidMap.Internal.NonNull`+  - `Data.MonoidMap.Internal.NonNullMap`+  - `Data.MonoidMap.Internal.NonNullMap.FromMap`+  - `Data.MonoidMap.Internal.NonNullMap.FromMapWith`++  The new structure has the following aims:++  - To confine the data constructor of `NonNull` to two small private+    modules, making the code that maintains the `NonNull` invariant+    a little easier to audit.++  - To dedicate each public module to a single type, with functions named+    for qualified import. Several functions have been renamed accordingly:+    for example, `maybeNonNull` is now `NonNull.nonNull`, and+    `fromNonNullMap` is now `NonNullMap.toMap`.++  - To move the alternative `fromMap*` and `fromMapWith*` implementations,+    which exist only for benchmarking, into their own modules, so that+    they no longer clutter the main API.++- Changed `fromMap`, `fromMapWith`, and `toMap` to accept or return values+  of type `NonNullMap k v` instead of `Map k (NonNull v)`.++- Added documentation for the `NonNull` and `NonNullMap` types and their+  functions.+ # 0.3.0.0  - Moved the `MonoidMap` type, its instances, and all of its functions to
components/monoidmap-internal-benchmark/Main.hs view
@@ -36,7 +36,9 @@     ( Benchmark, bcompare, bench, bgroup, defaultMain, nf )  import qualified Data.Map.Strict as OMap-import qualified Data.MonoidMap.Internal as MMap+import qualified Data.MonoidMap.Internal.NonNullMap as MMap+import qualified Data.MonoidMap.Internal.NonNullMap.FromMap as MMap+import qualified Data.MonoidMap.Internal.NonNullMap.FromMapWith as MMap  main :: IO () main = do
− components/monoidmap-internal/Data/MonoidMap/Internal.hs
@@ -1,195 +0,0 @@-{-# LANGUAGE RoleAnnotations #-}-{- HLINT ignore "Avoid lambda" -}-{- HLINT ignore "Avoid lambda using `infix`" -}-{- HLINT ignore "Redundant bracket" -}-{- HLINT ignore "Use camelCase" -}---- |--- Copyright: © 2022–2026 Jonathan Knowles--- License: Apache-2.0------ Provides /internal/ support for the @monoidmap@ package.------ This module defines the 'NonNull' type of values that are not 'C.null',--- and functions for constructing maps of 'NonNull' values from ordinary maps.----module Data.MonoidMap.Internal-    (-    -- * Types-      NonNull-    , NonNullMap (..)--    -- * Non-null values-    , maybeNonNull-    , applyNonNull-    , applyNonNull2--    -- * Non-null maps-    , fromNonNullMap--    -- * Construction-    , fromMap-    , fromMapWith--    -- ** Implementations-    , fromMap_filter-    , fromMap_filter_if_any_null-    , fromMap_mapMaybe-    , fromMapWith_mapMaybe-    , fromMapWith_map_filter-    , fromMapWith_map_filter_if_any_null-    )-    where--import Prelude--import Control.DeepSeq-    ( NFData )-import Data.Bifoldable-    ( Bifoldable )-import Data.Coerce-    ( coerce )-import Data.Functor.Classes-    ( Eq1, Eq2, Show1, Show2 )-import Data.Map.Strict-    ( Map )-import Data.Monoid.Null-    ( MonoidNull )-import NoThunks.Class-    ( NoThunks )--import qualified Data.Foldable as F-import qualified Data.Map.Strict as Map-import qualified Data.Monoid.Null as C------------------------------------------------------------------------------------- Non-null values-----------------------------------------------------------------------------------newtype NonNull v = UnsafeNonNull v-    deriving newtype NFData---- Without an explicit type role annotation, the following role would be--- inferred:------     type role NonNull representational------ However, the validity of a 'NonNull' value depends on a property of its--- type: its 'mempty' value. A representational role would allow users to--- coerce between types with the same representation but different 'mempty'--- values, even without access to the 'NonNull' constructor.------ For example, users could coerce a 'NonNull' ('Sum' 'Int') to a 'NonNull'--- ('Product' 'Int'), and thereby construct a 'NonNull' value that is 'mempty'.------ So we must instead choose a nominal role.----type role NonNull nominal--maybeNonNull :: MonoidNull v => v -> Maybe (NonNull v)-maybeNonNull !v-    | C.null  v = Nothing-    | otherwise = Just (UnsafeNonNull v)-{-# INLINE maybeNonNull #-}--applyNonNull :: (v -> a) -> (NonNull v -> a)-applyNonNull = coerce-{-# INLINE applyNonNull #-}--applyNonNull2 :: (v1 -> v2 -> a) -> (NonNull v1 -> NonNull v2 -> a)-applyNonNull2 = coerce-{-# INLINE applyNonNull2 #-}--fromNonNullMap :: Map k (NonNull v) -> Map k v-fromNonNullMap = coerce-{-# INLINE fromNonNullMap #-}---- | /Unsafely/ converts an ordinary map into a map of non-null values.------ This function /expects/ but does /not/ check that no value in the given map--- is 'C.null'. It must only be applied to maps that satisfy this condition.----unsafeToNonNullMap :: Map k v -> Map k (NonNull v)-unsafeToNonNullMap = coerce-{-# INLINE unsafeToNonNullMap #-}------------------------------------------------------------------------------------- Non-null maps------------------------------------------------------------------------------------- A map of non-null values.------ Types with the same representation as 'NonNullMap' (such as 'MonoidMap')--- can derive their instances via this type, without needing access to the--- constructor of 'NonNull'.----newtype NonNullMap k v = NonNullMap (Map k (NonNull v))-    deriving (Eq, Show, NFData, NoThunks) via Map k v-    deriving (Eq1, Show1, Foldable) via Map k-    deriving (Eq2, Show2, Bifoldable) via Map---- Strictly speaking, this type role annotation is redundant, as:------ - The type parameter 'k' already has a nominal role inherited from 'Map'.--- - The type parameter 'v' already has a nominal role inherited from 'NonNull'.------ But we reassert these roles here, so that they cannot be silently weakened--- by a future change to the representation of 'NonNullMap'.----type role NonNullMap nominal nominal------------------------------------------------------------------------------------- Construction------------------------------------------------------------------------------------- | Constructs a map of non-null values from an ordinary 'Map', removing all---   'C.null' values.------ This function selects which of the @fromMap_*@ implementations below is used--- by the public @fromMap@ function of the @monoidmap@ package.----fromMap :: MonoidNull v => Map k v -> Map k (NonNull v)-fromMap = fromMap_filter_if_any_null-{-# INLINE fromMap #-}--fromMap_filter :: MonoidNull v => Map k v -> Map k (NonNull v)-fromMap_filter = unsafeToNonNullMap . Map.filter (\(!v) -> not (C.null v))-{-# INLINABLE fromMap_filter #-}--fromMap_filter_if_any_null :: MonoidNull v => Map k v -> Map k (NonNull v)-fromMap_filter_if_any_null m-    | F.any (\(!v) -> C.null v) m =-        unsafeToNonNullMap $ Map.filter (\(!v) -> not (C.null v)) m-    | otherwise =-        unsafeToNonNullMap m-{-# INLINABLE fromMap_filter_if_any_null #-}--fromMap_mapMaybe :: MonoidNull v => Map k v -> Map k (NonNull v)-fromMap_mapMaybe = Map.mapMaybe maybeNonNull-{-# INLINABLE fromMap_mapMaybe #-}---- | Constructs a map of non-null values from an ordinary 'Map', applying the---   given function to all values, and removing all 'C.null' values.------ This function selects which of the @fromMapWith_*@ implementations below is--- used by the public @fromMapWith@ function of the @monoidmap@ package.----fromMapWith-    :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)-fromMapWith = fromMapWith_mapMaybe-{-# INLINE fromMapWith #-}--fromMapWith_mapMaybe-    :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)-fromMapWith_mapMaybe f = Map.mapMaybe (maybeNonNull . f)-{-# INLINABLE fromMapWith_mapMaybe #-}--fromMapWith_map_filter-    :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)-fromMapWith_map_filter f = fromMap_filter . Map.map f-{-# INLINABLE fromMapWith_map_filter #-}--fromMapWith_map_filter_if_any_null-    :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> Map k (NonNull v2)-fromMapWith_map_filter_if_any_null f = fromMap_filter_if_any_null . Map.map f-{-# INLINABLE fromMapWith_map_filter_if_any_null #-}
+ components/monoidmap-internal/Data/MonoidMap/Internal/NonNull.hs view
@@ -0,0 +1,49 @@+-- |+-- Copyright: © 2022–2026 Jonathan Knowles+-- License: Apache-2.0+--+-- Provides the 'NonNull' type and related functions.+--+-- This module is intended to be imported qualified:+--+-- @+-- import Data.MonoidMap.Internal.NonNull (NonNull)+-- import Data.MonoidMap.Internal.NonNull qualified as NonNull+-- @+--+module Data.MonoidMap.Internal.NonNull+    (+    -- * Type+      NonNull++    -- * Construction+    , nonNull++    -- * Deconstruction+    , unwrap++    -- * Function application+    , apply+    , apply2+    )+    where++import Prelude hiding+    ( null )++import Data.Monoid.Null+    ( MonoidNull (null) )+import Data.MonoidMap.Internal.NonNull.Unsafe+    ( NonNull, nonNull, unwrap )++-- | Applies a function on ordinary values to a 'NonNull' value.+--+apply :: (v -> a) -> (NonNull v -> a)+apply f = f . unwrap+{-# INLINE apply #-}++-- | Applies a binary function on ordinary values to two 'NonNull' values.+--+apply2 :: (v1 -> v2 -> a) -> (NonNull v1 -> NonNull v2 -> a)+apply2 f v1 v2 = f (unwrap v1) (unwrap v2)+{-# INLINE apply2 #-}
+ components/monoidmap-internal/Data/MonoidMap/Internal/NonNull/Unsafe.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE RoleAnnotations #-}++-- |+-- Copyright: © 2022–2026 Jonathan Knowles+-- License: Apache-2.0+--+-- Defines the 'NonNull' type, together with the primitive operations on+-- 'NonNull' values that need access to its data constructor.+--+module Data.MonoidMap.Internal.NonNull.Unsafe+    ( NonNull (UnsafeNonNull)+    , nonNull+    , unwrap+    )+    where++import Prelude hiding+    ( null )++import Control.DeepSeq+    ( NFData )+import Data.Monoid.Null+    ( MonoidNull (null) )++-- | A value that is not 'null'.+--+newtype NonNull v = UnsafeNonNull v+    deriving newtype NFData++-- Without an explicit type role annotation, the following role would be+-- inferred:+--+--     type role NonNull representational+--+-- However, the validity of a 'NonNull' value depends on a property of its+-- type: its 'mempty' value. A representational role would allow users to+-- coerce between types with the same representation but different 'mempty'+-- values, even without access to the 'NonNull' constructor.+--+-- For example, users could coerce a 'NonNull' ('Sum' 'Int') to a 'NonNull'+-- ('Product' 'Int'), and thereby construct a 'NonNull' value that is 'mempty'.+--+-- So we must instead choose a nominal role.+--+type role NonNull nominal++-- | Converts a value into a 'NonNull' value, returning 'Nothing' if the+--   value is 'null'.+--+nonNull :: MonoidNull v => v -> Maybe (NonNull v)+nonNull !v+    | null v    = Nothing+    | otherwise = Just (UnsafeNonNull v)+{-# INLINE nonNull #-}++-- | Extracts the value from a 'NonNull' value.+--+unwrap :: NonNull v -> v+unwrap (UnsafeNonNull v) = v+{-# INLINE unwrap #-}
+ components/monoidmap-internal/Data/MonoidMap/Internal/NonNullMap.hs view
@@ -0,0 +1,68 @@+-- |+-- Copyright: © 2022–2026 Jonathan Knowles+-- License: Apache-2.0+--+-- Provides the 'NonNullMap' type and related functions.+--+-- This module is intended to be imported qualified:+--+-- @+-- import Data.MonoidMap.Internal.NonNullMap (NonNullMap (..))+-- import Data.MonoidMap.Internal.NonNullMap qualified as NonNullMap+-- @+--+module Data.MonoidMap.Internal.NonNullMap+    (+    -- * Type+      NonNullMap (..)++    -- * Construction+    , fromMap+    , fromMapWith++    -- * Deconstruction+    , toMap+    )+    where++import Prelude hiding+    ( null )++import Data.Map.Strict+    ( Map )+import Data.Monoid.Null+    ( MonoidNull (null) )+import Data.MonoidMap.Internal.NonNull+    ( NonNull )+import Data.MonoidMap.Internal.NonNullMap.FromMap+    ( fromMap_filter_if_any_null )+import Data.MonoidMap.Internal.NonNullMap.FromMapWith+    ( fromMapWith_mapMaybe )+import Data.MonoidMap.Internal.NonNullMap.Unsafe+    ( NonNullMap (..), toMap )++--------------------------------------------------------------------------------+-- Construction+--------------------------------------------------------------------------------++-- | Constructs a 'NonNullMap' from an ordinary 'Map', removing all+--   'null' values.+--+-- This function selects which of the implementations in+-- "Data.MonoidMap.Internal.NonNullMap.FromMap" is used by the public @fromMap@+-- function of the @monoidmap@ package.+--+fromMap :: MonoidNull v => Map k v -> NonNullMap k v+fromMap = fromMap_filter_if_any_null+{-# INLINE fromMap #-}++-- | Constructs a 'NonNullMap' from an ordinary 'Map', applying the given+--   function to all values, and removing all 'null' values.+--+-- This function selects which of the implementations in+-- "Data.MonoidMap.Internal.NonNullMap.FromMapWith" is used by the public+-- @fromMapWith@ function of the @monoidmap@ package.+--+fromMapWith :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2+fromMapWith = fromMapWith_mapMaybe+{-# INLINE fromMapWith #-}
+ components/monoidmap-internal/Data/MonoidMap/Internal/NonNullMap/FromMap.hs view
@@ -0,0 +1,57 @@+{- HLINT ignore "Avoid lambda" -}+{- HLINT ignore "Avoid lambda using `infix`" -}+{- HLINT ignore "Redundant bracket" -}+{- HLINT ignore "Use camelCase" -}++-- |+-- Copyright: © 2022–2026 Jonathan Knowles+-- License: Apache-2.0+--+-- Provides alternative implementations of @fromMap@, which constructs a+-- map of 'NonNull' values from an ordinary map.+--+-- These implementations are exported so that they can be benchmarked against+-- one another.+--+module Data.MonoidMap.Internal.NonNullMap.FromMap+    ( fromMap_filter+    , fromMap_filter_if_any_null+    , fromMap_mapMaybe+    )+    where++import Prelude hiding+    ( null )++import Data.Map.Strict+    ( Map )+import Data.Monoid.Null+    ( MonoidNull (null) )+import Data.MonoidMap.Internal.NonNull+    ( NonNull, nonNull )+import Data.MonoidMap.Internal.NonNullMap.Unsafe+    ( NonNullMap (..)+    , unsafeFromMap+    )++import qualified Data.Foldable as F+import qualified Data.Map.Strict as Map++fromMap_filter+    :: MonoidNull v => Map k v -> NonNullMap k v+fromMap_filter = unsafeFromMap . Map.filter (\(!v) -> not (null v))+{-# INLINABLE fromMap_filter #-}++fromMap_filter_if_any_null+    :: MonoidNull v => Map k v -> NonNullMap k v+fromMap_filter_if_any_null m+    | F.any (\(!v) -> null v) m =+        unsafeFromMap $ Map.filter (\(!v) -> not (null v)) m+    | otherwise =+        unsafeFromMap m+{-# INLINABLE fromMap_filter_if_any_null #-}++fromMap_mapMaybe+    :: MonoidNull v => Map k v -> NonNullMap k v+fromMap_mapMaybe = NonNullMap . Map.mapMaybe nonNull+{-# INLINABLE fromMap_mapMaybe #-}
+ components/monoidmap-internal/Data/MonoidMap/Internal/NonNullMap/FromMapWith.hs view
@@ -0,0 +1,51 @@+{- HLINT ignore "Use camelCase" -}++-- |+-- Copyright: © 2022–2026 Jonathan Knowles+-- License: Apache-2.0+--+-- Provides alternative implementations of @fromMapWith@, which constructs a+-- map of 'NonNull' values from an ordinary map, applying a function to all+-- values.+--+-- These implementations are exported so that they can be benchmarked against+-- one another.+--+module Data.MonoidMap.Internal.NonNullMap.FromMapWith+    ( fromMapWith_mapMaybe+    , fromMapWith_map_filter+    , fromMapWith_map_filter_if_any_null+    )+    where++import Prelude++import Data.Map.Strict+    ( Map )+import Data.Monoid.Null+    ( MonoidNull )+import Data.MonoidMap.Internal.NonNull+    ( NonNull, nonNull )+import Data.MonoidMap.Internal.NonNullMap.FromMap+    ( fromMap_filter+    , fromMap_filter_if_any_null+    )+import Data.MonoidMap.Internal.NonNullMap.Unsafe+    ( NonNullMap (..) )++import qualified Data.Map.Strict as Map++fromMapWith_mapMaybe+    :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2+fromMapWith_mapMaybe f = NonNullMap . Map.mapMaybe (nonNull . f)+{-# INLINABLE fromMapWith_mapMaybe #-}++fromMapWith_map_filter+    :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2+fromMapWith_map_filter f = fromMap_filter . Map.map f+{-# INLINABLE fromMapWith_map_filter #-}++fromMapWith_map_filter_if_any_null+    :: MonoidNull v2 => (v1 -> v2) -> Map k v1 -> NonNullMap k v2+fromMapWith_map_filter_if_any_null f = fromMap_filter_if_any_null . Map.map f+{-# INLINABLE fromMapWith_map_filter_if_any_null #-}
+ components/monoidmap-internal/Data/MonoidMap/Internal/NonNullMap/Unsafe.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE RoleAnnotations #-}++-- |+-- Copyright: © 2022–2026 Jonathan Knowles+-- License: Apache-2.0+--+-- Defines the 'NonNullMap' type, together with the primitive operations on+-- 'NonNullMap' that need access to the data constructor of 'NonNull'.+--+module Data.MonoidMap.Internal.NonNullMap.Unsafe+    ( NonNullMap (..)+    , toMap+    , unsafeFromMap+    )+    where++import Prelude++import Control.DeepSeq+    ( NFData )+import Data.Bifoldable+    ( Bifoldable )+import Data.Coerce+    ( coerce )+import Data.Functor.Classes+    ( Eq1, Eq2, Show1, Show2 )+import Data.Map.Strict+    ( Map )+import Data.MonoidMap.Internal.NonNull.Unsafe+    ( NonNull (UnsafeNonNull) )+import NoThunks.Class+    ( NoThunks )++-- | A map of 'NonNull' values.+--+-- Other types with the same representation (such as @MonoidMap@ from the+-- @monoidmap@ package) can derive instances via this type, without access+-- to the data constructor of 'NonNull'.+--+newtype NonNullMap k v = NonNullMap (Map k (NonNull v))+    --+    -- Here we take great care to only derive instances that consume values.+    --+    -- It's risky to derive an instance that produces values, as the derived+    -- instance may not necessarily respect the 'NonNull' invariant.+    --+    -- For example, the 'Read' instance for 'Map', given appropriate input,+    -- will quite happily produce maps with 'mempty' values.+    --+    deriving (Eq, Show, NFData, NoThunks) via Map k v+    deriving (Eq1, Show1, Foldable) via Map k+    deriving (Eq2, Show2, Bifoldable) via Map++-- Strictly speaking, this type role annotation is redundant, as:+--+-- - The type parameter 'k' already has a nominal role inherited from 'Map'.+-- - The type parameter 'v' already has a nominal role inherited from 'NonNull'.+--+-- But we reassert these roles here, so that they cannot be silently weakened+-- by a future change to the representation of 'NonNullMap'.+--+type role NonNullMap nominal nominal++-- | Converts a 'NonNullMap' into an ordinary map.+--+toMap :: NonNullMap k v -> Map k v+toMap = coerce+{-# INLINE toMap #-}++-- | /Unsafely/ converts an ordinary map into a 'NonNullMap'.+--+-- This function /expects/ but does /not/ check that no value in the given map+-- is null. It must only be applied to maps that satisfy this condition.+--+unsafeFromMap :: Map k v -> NonNullMap k v+unsafeFromMap = coerce+{-# INLINE unsafeFromMap #-}
monoidmap-internal.cabal view
@@ -1,6 +1,6 @@ cabal-version:  3.0 name:           monoidmap-internal-version:        0.3.0.0+version:        0.4.0.0 homepage:       https://github.com/jonathanknowles/monoidmap/tree/HEAD/packages/monoidmap-internal bug-reports:    https://github.com/jonathanknowles/monoidmap/issues license:        Apache-2.0@@ -65,7 +65,13 @@     hs-source-dirs:         components/monoidmap-internal     exposed-modules:-        Data.MonoidMap.Internal+        Data.MonoidMap.Internal.NonNull+        Data.MonoidMap.Internal.NonNullMap+        Data.MonoidMap.Internal.NonNullMap.FromMap+        Data.MonoidMap.Internal.NonNullMap.FromMapWith+    other-modules:+        Data.MonoidMap.Internal.NonNull.Unsafe+        Data.MonoidMap.Internal.NonNullMap.Unsafe     default-language:         Haskell2010