hs-bindgen-1.0.0.0: src-internal/HsBindgen/Instances.hs
-- | Instance resolution types
--
-- Intended for qualified import.
--
-- > import HsBindgen.Instances qualified as Inst
module HsBindgen.Instances (
-- * Core types
TypeClass(..)
, Dependency(..)
, Strategy(..)
, Constraint(..)
, Instance(..)
-- * Supported instances
, SupportedInstances(..)
, SupportedStrategies(..)
) where
import Data.Map.Strict qualified as Map
import Data.Ord qualified as Ord
import Data.Set qualified as Set
import Text.SimplePrettyPrint qualified as PP
import HsBindgen.Imports
import HsBindgen.Language.Haskell qualified as Hs
import HsBindgen.Util.Tracer (PrettyForTrace (prettyForTrace))
{-------------------------------------------------------------------------------
Core types
-------------------------------------------------------------------------------}
-- | Type class
data TypeClass =
Bitfield
| Bits
| Bounded
| CEnum
| Enum
| Eq
| FiniteBits
| Flam_Offset
| Floating
| Fractional
| FromFunPtr
| Generic
| HasCBitfield -- Indicates instances for all bit fields
| HasCField -- Indicates instances for all non-bit fields
| HasFFIType
-- | 'GHC.Records.HasField'
--
-- Indicates instances for all fields (except for union fields in some
-- cases, see TODO below).
--
-- TODO <https://github.com/well-typed/hs-bindgen/issues/1447#issuecomment-4809540458>:
-- a union field can only be given a @HasField@ instance if the field's type
-- has a @Storable@ instance. @HasField@ instances for some but not all
-- union fields can currently not be represented in the 'TypeClass'
-- datatype.
| HasField
-- | 'GHC.Records.Compat.HasField' instance
--
-- Indicates instances for all fields.
| HasFieldCompat
-- | 'GHC.Records.HasField' for the pointer manipulation API
--
-- Indicates instances for all fields.
| HasFieldPtr
| Integral
| IsArray
| IsStruct
| IsUnion
| Ix
| Num
| Ord
| Prim
| Read
| ReadRaw
| Real
| RealFloat
| RealFrac
| SequentialCEnum
| Show
| StaticSize
| Storable
| ToFunPtr
| WriteRaw
deriving stock (Bounded, Enum, Eq, Generic, Read, Show)
-- Order lexicographically, even if somebody adds a constructor out of place
instance Ord TypeClass where
compare = Ord.comparing show
instance PrettyForTrace TypeClass where
prettyForTrace = PP.show
--------------------------------------------------------------------------------
-- | Relationship between an instance and dependencies of a type
data Dependency =
-- | An instance depends on instances of dependencies
Dependent
| -- | An instance does not depend on instances of dependencies
Independent
deriving stock (Eq, Generic, Show)
--------------------------------------------------------------------------------
-- | Strategy used to generate/derive an instance
data Strategy =
-- | @hs-bindgen@ decides how to generate/derive an instance
HsBindgen
| -- | Derive an instance using the @newtype@ strategy
Newtype
| -- | Derive an instance using the @stock@ strategy
Stock
deriving stock (Bounded, Enum, Eq, Generic, Ord, Show)
instance PrettyForTrace Strategy where
prettyForTrace = PP.show
--------------------------------------------------------------------------------
-- | Constraint of an instance
data Constraint = Constraint {
clss :: TypeClass
, ref :: Hs.ExtRef
}
deriving stock (Eq, Generic, Ord, Show)
--------------------------------------------------------------------------------
-- | Resolved instance
data Instance = Instance {
clss :: TypeClass
, strategy :: Strategy
, constraints :: [Constraint]
}
deriving stock (Eq, Generic, Ord, Show)
{-------------------------------------------------------------------------------
Supported instances
-------------------------------------------------------------------------------}
-- | Supported instances
--
-- This type tracks the instances that may be generated/derived in generated
-- bindings. The 'Default' instance of this type specifies the instances and
-- strategies that are supported by this version of @hs-bindgen@.
--
-- If we decide to allow users to configure this, to change which instances are
-- generated/derived by default, then we should probably provide an API that
-- ensures that a subset of the supported API is configured.
--
-- Per-type configuration, overriding these defaults, is done using prescriptive
-- binding specifications.
data SupportedInstances = SupportedInstances {
-- | Supported instances for @struct@ types
struct :: Map TypeClass SupportedStrategies
, -- | Supported instances for @union@ types
union :: Map TypeClass SupportedStrategies
, -- | Supported instances for @enum@ types
enum :: Map TypeClass SupportedStrategies
, -- | Supported instances for @typedef@ types
typedef :: Map TypeClass SupportedStrategies
, -- | Supported instances for types with Haskell @emptydata@ representation
emptydata :: Map TypeClass SupportedStrategies
}
deriving stock (Show)
-- | Supported strategies for a specific instance
data SupportedStrategies = SupportedStrategies {
-- | Relationship between the instance and dependencies of the type
dependency :: Dependency
, -- | Supported strategies to generate/derive the instance
--
-- This set must not be empty.
strategies :: Set Strategy
, -- | Default strategy to generate/derive the instance
--
-- A 'Just' value indicates that the instance may be generated/derived by
-- default, with the specified strategy. A 'Nothing' value indicates that
-- the instance may /not/ be generated/derived by default.
--
-- If specified, the strategy must be a member of 'strategies'.
defStrategy :: Maybe Strategy
}
deriving stock (Show)
instance Default SupportedInstances where
def =
SupportedInstances{
struct = Map.fromList [
mkDef Eq Dependent Stock []
, mkDef Flam_Offset Independent HsBindgen []
, mkDef Generic Independent Stock []
, mkDef HasCBitfield Independent HsBindgen []
, mkDef HasCField Independent HsBindgen []
, mkDef HasField Independent HsBindgen []
, mkDef HasFieldCompat Independent HsBindgen []
, mkDef HasFieldPtr Independent HsBindgen []
, mkDef IsStruct Dependent HsBindgen []
, mkOpt Ord Dependent [Stock]
, mkDef ReadRaw Dependent HsBindgen []
, mkDef Show Dependent Stock []
, mkDef StaticSize Dependent HsBindgen []
, mkDef Storable Dependent HsBindgen []
, mkDef WriteRaw Dependent HsBindgen []
]
, union = Map.fromList [
mkDef Generic Independent Stock []
, mkDef HasCBitfield Independent HsBindgen []
, mkDef HasCField Independent HsBindgen []
, mkDef HasField Independent HsBindgen []
, mkDef HasFieldCompat Independent HsBindgen []
, mkDef HasFieldPtr Independent HsBindgen []
, mkDef IsUnion Dependent Newtype []
, mkDef ReadRaw Independent HsBindgen []
, mkDef StaticSize Independent HsBindgen []
, mkDef Storable Independent HsBindgen []
, mkDef WriteRaw Independent HsBindgen []
]
, enum = Map.fromList [
mkOpt Bounded Independent [HsBindgen, Newtype]
, mkDef CEnum Independent HsBindgen []
, mkOpt Enum Independent [HsBindgen, Newtype]
, mkDef Eq Dependent Stock []
, mkDef Generic Independent Stock []
, mkDef HasCField Independent HsBindgen []
, mkDef HasFFIType Dependent Newtype []
, mkDef HasField Independent HsBindgen []
, mkDef HasFieldCompat Independent HsBindgen []
, mkDef HasFieldPtr Independent HsBindgen []
, mkDef Ord Dependent Stock []
, mkDef Prim Independent HsBindgen []
, mkDef Read Independent HsBindgen [Newtype, Stock]
, mkDef ReadRaw Independent HsBindgen []
, mkDef SequentialCEnum Independent HsBindgen []
, mkDef Show Independent HsBindgen [Newtype, Stock]
, mkDef StaticSize Independent HsBindgen []
, mkDef Storable Independent HsBindgen []
, mkDef WriteRaw Independent HsBindgen []
]
, typedef = Map.fromList [
mkDef Bitfield Dependent Newtype []
, mkDef Bits Dependent Newtype []
, mkDef Bounded Dependent Newtype []
, mkDef Enum Dependent Newtype []
, mkDef Eq Dependent Stock []
, mkDef FiniteBits Dependent Newtype []
, mkDef Floating Dependent Newtype []
, mkDef Fractional Dependent Newtype []
, mkDef FromFunPtr Independent HsBindgen []
, mkDef Generic Independent Stock []
, mkDef HasCField Independent HsBindgen []
, mkDef HasFFIType Dependent Newtype []
, mkDef HasField Independent HsBindgen []
, mkDef HasFieldCompat Independent HsBindgen []
, mkDef HasFieldPtr Independent HsBindgen []
, mkDef Integral Dependent Newtype []
-- TODO: instance resolution for 'IsArray' is currently
-- special-cased because for 'IsArray' instances we don't have to
-- check all dependencies. See issue #1739.
, mkDef IsArray Dependent Newtype []
, mkDef Ix Dependent Newtype []
, mkDef Num Dependent Newtype []
, mkDef Ord Dependent Stock []
, mkDef Prim Dependent Newtype []
, mkDef Read Dependent Stock [Newtype]
, mkDef ReadRaw Dependent Newtype []
, mkDef Real Dependent Newtype []
, mkDef RealFloat Dependent Newtype []
, mkDef RealFrac Dependent Newtype []
, mkDef Show Dependent Stock [Newtype]
, mkDef StaticSize Dependent Newtype []
, mkDef Storable Dependent Newtype []
, mkDef ToFunPtr Independent HsBindgen []
, mkDef WriteRaw Dependent Newtype []
]
, emptydata = Map.fromList [
mkDef StaticSize Independent HsBindgen []
]
}
where
mkDef ::
TypeClass
-> Dependency
-> Strategy
-> [Strategy]
-> (TypeClass, SupportedStrategies)
mkDef cls dep strat strats = (cls,) $ SupportedStrategies{
dependency = dep
, strategies = Set.fromList $ strat : strats
, defStrategy = Just strat
}
mkOpt ::
TypeClass
-> Dependency
-> [Strategy]
-> (TypeClass, SupportedStrategies)
mkOpt cls dep strats = (cls,) $ SupportedStrategies{
dependency = dep
, strategies = Set.fromList strats
, defStrategy = Nothing
}