packages feed

filepather-0.8.0.0: src/System/FilePather/Repetition.hs

{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -Wall #-}

{- | Whether a step may appear more than once in a trail.

A 'Repetition' is a sum: its constructors are named 'once' and 'repeatable'.
-}
module System.FilePather.Repetition (
  -- * Type
  Repetition (..),

  -- * Optics
  RepetitionLike (..),
  lawNamesRepetition,
  InheritRepetition,
  inheritRepetition,
) where

import Control.DeepSeq (NFData)
import Control.Lens (Choice, Optic, prism', review)
import Data.Data (Data)
import Data.Functor.Const (Const)
import GHC.Generics (Generic)
import System.FilePather.Name.Once (OnceLike (..))
import System.FilePather.Name.Repeatable (RepeatableLike (..))

{- | Whether a step may appear more than once in a trail. A step that may
not is stopped with 'System.FilePather.Cycle.CycleRepeatsStep' when it is
already in the trail.

@since 0.7.0.0
-}
data Repetition
  = -- | The step may appear once in a trail ('once').
    Once
  | -- | The step may appear any number of times in a trail ('repeatable').
    Repeatable
  deriving stock (Eq, Ord, Show, Generic, Data)
  deriving anyclass (NFData)

{- | The class of 'Repetition'.

@since 0.8.0.0
-}
class RepetitionLike p f x x' where
  repetition ::
    Optic p f x x' Repetition Repetition

{- | Identity

@since 0.8.0.0
-}
instance (x' ~ Repetition) => RepetitionLike p f Repetition x' where
  repetition =
    id
  {-# INLINE repetition #-}

{- | Prism

@since 0.8.0.0
-}
instance (Choice p, Applicative f, x' ~ Repetition) => OnceLike p f Repetition x' where
  once =
    prism' (\() -> Once) (\case Once -> Just (); Repeatable -> Nothing)
  {-# INLINE once #-}

{- | Prism

@since 0.8.0.0
-}
instance (Choice p, Applicative f, x' ~ Repetition) => RepeatableLike p f Repetition x' where
  repeatable =
    prism' (\() -> Repeatable) (\case Repeatable -> Just (); Once -> Nothing)
  {-# INLINE repeatable #-}

{- | Rebuild a value using only the name of each constructor.

Laws:

> lawNamesRepetition == id

@since 0.8.0.0
-}
lawNamesRepetition :: Repetition -> Repetition
lawNamesRepetition = \case
  Once -> review once ()
  Repeatable -> review repeatable ()

{- | The classes that a data type holding 'Repetition' inherits.

@since 0.8.0.0
-}
type InheritRepetition s =
  ( RepetitionLike (->) (Const ()) s s
  , OnceLike (->) (Const ()) s s
  , RepeatableLike (->) (Const ()) s s
  )

{- | Check, where it is applied, that @s@ inherits every name of 'Repetition'.

@since 0.8.0.0
-}
inheritRepetition :: (InheritRepetition s) => proxy s -> ()
inheritRepetition _ =
  ()