{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE DerivingStrategies #-} module Way.Type where import Data.IntSet (IntSet) import qualified Data.IntSet as Set import Data.List import Data.Maybe import Development.Shake.Classes import Hadrian.Utilities -- Note: order of constructors is important for compatibility with the old build -- system, e.g. we want "thr_p", not "p_thr" (see instance Show Way). -- | A 'WayUnit' is a single way of building source code, for example with -- profiling enabled, or dynamically linked. data WayUnit = Threaded | Debug | Profiling | Logging | Dynamic deriving (Bounded, Enum, Eq, Ord) -- TODO: get rid of non-derived Show instances instance Show WayUnit where show unit = case unit of Threaded -> "thr" Debug -> "debug" Profiling -> "p" Logging -> "l" Dynamic -> "dyn" -- TODO: get rid of non-derived Read instance instance Read WayUnit where readsPrec _ = \case "thr" -> [(Threaded,"")] "debug" -> [(Debug,"")] "p" -> [(Profiling,"")] "l" -> [(Logging,"")] "dyn" -> [(Dynamic,"")] _ -> [] -- | Collection of 'WayUnit's that stands for the different ways source code -- is to be built. newtype Way = Way IntSet deriving newtype (Semigroup, Monoid) instance Binary Way where put (Way w) = put w get = Way <$> get instance Hashable Way where hashWithSalt salt = hashWithSalt salt . show instance NFData Way where rnf (Way s) = s `seq` () -- | Construct a 'Way' from multiple 'WayUnit's. Inverse of 'wayToUnits'. wayFromUnits :: [WayUnit] -> Way wayFromUnits = Way . Set.fromList . map fromEnum -- | Split a 'Way' into its 'WayUnit' building blocks. -- Inverse of 'wayFromUnits'. wayToUnits :: Way -> [WayUnit] wayToUnits (Way set) = map toEnum . Set.elems $ set -- | Check whether a 'Way' contains a certain 'WayUnit'. wayUnit :: WayUnit -> Way -> Bool wayUnit unit (Way set) = fromEnum unit `Set.member` set -- | Add a 'WayUnit' to a 'Way' addWayUnit :: WayUnit -> Way -> Way addWayUnit unit (Way set) = Way . Set.insert (fromEnum unit) $ set -- | Remove a 'WayUnit' from 'Way'. removeWayUnit :: WayUnit -> Way -> Way removeWayUnit unit (Way set) = Way . Set.delete (fromEnum unit) $ set instance Show Way where show way = if null tag then "v" else tag where tag = intercalate "_" . map show . wayToUnits $ way instance Read Way where readsPrec _ s = if s == "v" then [(wayFromUnits [], "")] else result where uniqueReads token = case reads token of [(unit, "")] -> Just unit _ -> Nothing units = map uniqueReads . words . replaceEq '_' ' ' $ s result = if Nothing `elem` units then [] else [(wayFromUnits . map fromJust $ units, "")] instance Eq Way where Way a == Way b = a == b instance Ord Way where compare (Way a) (Way b) = compare a b