{-# LANGUAGE
  DataKinds,
  ScopedTypeVariables,
  TypeApplications #-}
-- | Unsafe functions that will throw errors if misused.
module DiffLoc.Unsafe
  ( -- ** Inverting monoid actions
    (.-.)

    -- ** Smart constructors for 'IndexFrom'
  , indexFrom
  , indexFrom0
  , indexFrom1

    -- ** Smart constructor for 'Offset'
  , offset
  ) where

import Data.Maybe (fromMaybe)
import Data.Proxy (Proxy(..))
import GHC.Stack (HasCallStack)
import GHC.TypeNats (KnownNat, natVal)
import DiffLoc.Shift (Amor(Trans, (.-.?)))
import DiffLoc.Index (IndexFrom, Offset, indexFromM, offsetM)

infixl 6 .-.

-- | An unsafe variant of @('.-.?')@ which throws an exception on @Nothing@.
-- This operator may appear in class laws, imposing an implicit requirement
-- that its operands must be ordered.
(.-.) :: HasCallStack => Amor p => p -> p -> Trans p
p
i .-. :: forall p. (HasCallStack, Amor p) => p -> p -> Trans p
.-. p
j = forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => [Char] -> a
error [Char]
"undefined vector") (p
i forall p. Amor p => p -> p -> Maybe (Trans p)
.-.? p
j)

-- | Constructor for 'IndexFrom'. The index must be greater than the origin,
-- otherwise an error is raised.
--
-- @
-- origin <= indexFrom i
-- @
indexFrom :: forall n a. (HasCallStack, KnownNat n, Num a, Ord a) => a -> IndexFrom n a
indexFrom :: forall (n :: Nat) a.
(HasCallStack, KnownNat n, Num a, Ord a) =>
a -> IndexFrom n a
indexFrom a
i = forall a. a -> Maybe a -> a
fromMaybe forall {a}. a
err (forall (n :: Nat) a.
(KnownNat n, Num a, Ord a) =>
a -> Maybe (IndexFrom n a)
indexFromM a
i)
  where err :: a
err = forall a. HasCallStack => [Char] -> a
error ([Char]
"IndexFrom must not be less than origin " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> [Char]
show (forall (n :: Nat) (proxy :: Nat -> *). KnownNat n => proxy n -> Nat
natVal @n forall {k} (t :: k). Proxy t
Proxy))

-- | 'indexFrom' specialized to 0-indexing.
indexFrom0 :: (HasCallStack, Num a, Ord a) => a -> IndexFrom 0 a
indexFrom0 :: forall a. (HasCallStack, Num a, Ord a) => a -> IndexFrom 0 a
indexFrom0 = forall (n :: Nat) a.
(HasCallStack, KnownNat n, Num a, Ord a) =>
a -> IndexFrom n a
indexFrom

-- | 'indexFrom' specialized to 1-indexing.
indexFrom1 :: (HasCallStack, Num a, Ord a) => a -> IndexFrom 1 a
indexFrom1 :: forall a. (HasCallStack, Num a, Ord a) => a -> IndexFrom 1 a
indexFrom1 = forall (n :: Nat) a.
(HasCallStack, KnownNat n, Num a, Ord a) =>
a -> IndexFrom n a
indexFrom

-- | Construct an 'Offset'. The offset must be nonnegative, otherwise
-- an error is raised.
offset :: (HasCallStack, Num a, Ord a) => a -> Offset a
offset :: forall a. (HasCallStack, Num a, Ord a) => a -> Offset a
offset a
i = forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => [Char] -> a
error [Char]
"Offset must not be negative") (forall a. (Num a, Ord a) => a -> Maybe (Offset a)
offsetM a
i)