\begin{code}
{-# OPTIONS --safe #-}

module Data.Fin where

open import Level
open import Data.Nat
open import Data.Sigma

private
  variable n : ℕ

module DisplayDef where
  open import Data.Empty using (⊥)
  open import Data.Unit  using (⊤)
  open import Data.Sum   using (_⊎_)
\end{code}
%<*fin-display-def>
\begin{code}
  Fin : ℕ → Type
  Fin zero     = ⊥
  Fin (suc n)  = ⊤ ⊎ Fin n
\end{code}
%</fin-display-def>
\begin{code}
data Fin : ℕ → Type where
  zero  : Fin (suc n)
  suc   : Fin n → Fin (suc n)

open import Decidable
open import Data.Bool
open import Path

module DiscreteFin where
  _≡ᴮ_ : Fin n → Fin n → Bool
  zero  ≡ᴮ zero  = true
  suc x ≡ᴮ suc y = x ≡ᴮ y
  _     ≡ᴮ _     = false

  sound : (x y : Fin n) → T (x ≡ᴮ y) → x ≡ y
  sound zero    zero    p = refl
  sound (suc x) (suc y) p = cong suc (sound x y p)

  complete : (x : Fin n) → T (x ≡ᴮ x)
  complete zero    = _
  complete (suc x) = complete x

discreteFin : Discrete (Fin n)
discreteFin = from-bool-eq record { DiscreteFin }

open import HLevels

isSetFin : isSet (Fin n)
isSetFin = Discrete→isSet discreteFin

open import Data.Nat.Order

FinFromℕ : ∀ m n → m < n → Fin n
FinFromℕ zero    (suc n) p = zero
FinFromℕ (suc m) (suc n) p = suc (FinFromℕ m n p)

FinToℕ : Fin n → Σ[ m ⦂ ℕ ] × m < n
FinToℕ zero    = zero , _
FinToℕ (suc x) = let x′ , p = FinToℕ x in suc x′ , p

open import Literals.Number

instance
  numberFin : ∀ {n} → Number (Fin n)
  numberFin {n} = record
    { Constraint = λ m → T (m <ᵇ n)
    ; fromNat    = λ m {{pr}} → FinFromℕ m n pr
    }

open import Data.Unit

_ : Fin 5
_ = 3

_ : Fin 1
_ = 0
\end{code}