-- THIS FILE WAS AUTOMATICALLY GENERATED BY AENEAS
-- [array]: function definitions
import Base
import Array.Types
open Primitives

namespace array

/- [array::array_to_shared_slice_]: forward function -/
def array_to_shared_slice_
  (T0 : Type) (s : Array T0 (Usize.ofInt 32)) : Result (Slice T0) :=
  Array.to_slice_shared T0 (Usize.ofInt 32) s

/- [array::array_to_mut_slice_]: forward function -/
def array_to_mut_slice_
  (T0 : Type) (s : Array T0 (Usize.ofInt 32)) : Result (Slice T0) :=
  Array.to_slice_mut T0 (Usize.ofInt 32) s

/- [array::array_to_mut_slice_]: backward function 0 -/
def array_to_mut_slice__back
  (T0 : Type) (s : Array T0 (Usize.ofInt 32)) (ret0 : Slice T0) :
  Result (Array T0 (Usize.ofInt 32))
  :=
  Array.to_slice_mut_back T0 (Usize.ofInt 32) s ret0

/- [array::array_len]: forward function -/
def array_len (T0 : Type) (s : Array T0 (Usize.ofInt 32)) : Result Usize :=
  do
    let s0 ← Array.to_slice_shared T0 (Usize.ofInt 32) s
    let i := Slice.len T0 s0
    Result.ret i

/- [array::shared_array_len]: forward function -/
def shared_array_len
  (T0 : Type) (s : Array T0 (Usize.ofInt 32)) : Result Usize :=
  do
    let s0 ← Array.to_slice_shared T0 (Usize.ofInt 32) s
    let i := Slice.len T0 s0
    Result.ret i

/- [array::shared_slice_len]: forward function -/
def shared_slice_len (T0 : Type) (s : Slice T0) : Result Usize :=
  let i := Slice.len T0 s
  Result.ret i

/- [array::index_array_shared]: forward function -/
def index_array_shared
  (T0 : Type) (s : Array T0 (Usize.ofInt 32)) (i : Usize) : Result T0 :=
  Array.index_shared T0 (Usize.ofInt 32) s i

/- [array::index_array_u32]: forward function -/
def index_array_u32
  (s : Array U32 (Usize.ofInt 32)) (i : Usize) : Result U32 :=
  Array.index_shared U32 (Usize.ofInt 32) s i

/- [array::index_array_copy]: forward function -/
def index_array_copy (x : Array U32 (Usize.ofInt 32)) : Result U32 :=
  Array.index_shared U32 (Usize.ofInt 32) x (Usize.ofInt 0)

/- [array::index_mut_array]: forward function -/
def index_mut_array
  (T0 : Type) (s : Array T0 (Usize.ofInt 32)) (i : Usize) : Result T0 :=
  Array.index_mut T0 (Usize.ofInt 32) s i

/- [array::index_mut_array]: backward function 0 -/
def index_mut_array_back
  (T0 : Type) (s : Array T0 (Usize.ofInt 32)) (i : Usize) (ret0 : T0) :
  Result (Array T0 (Usize.ofInt 32))
  :=
  Array.index_mut_back T0 (Usize.ofInt 32) s i ret0

/- [array::index_slice]: forward function -/
def index_slice (T0 : Type) (s : Slice T0) (i : Usize) : Result T0 :=
  Slice.index_shared T0 s i

/- [array::index_mut_slice]: forward function -/
def index_mut_slice (T0 : Type) (s : Slice T0) (i : Usize) : Result T0 :=
  Slice.index_mut T0 s i

/- [array::index_mut_slice]: backward function 0 -/
def index_mut_slice_back
  (T0 : Type) (s : Slice T0) (i : Usize) (ret0 : T0) : Result (Slice T0) :=
  Slice.index_mut_back T0 s i ret0

/- [array::slice_subslice_shared_]: forward function -/
def slice_subslice_shared_
  (x : Slice U32) (y : Usize) (z : Usize) : Result (Slice U32) :=
  Slice.subslice_shared U32 x (Range.mk y z)

/- [array::slice_subslice_mut_]: forward function -/
def slice_subslice_mut_
  (x : Slice U32) (y : Usize) (z : Usize) : Result (Slice U32) :=
  Slice.subslice_mut U32 x (Range.mk y z)

/- [array::slice_subslice_mut_]: backward function 0 -/
def slice_subslice_mut__back
  (x : Slice U32) (y : Usize) (z : Usize) (ret0 : Slice U32) :
  Result (Slice U32)
  :=
  Slice.subslice_mut_back U32 x (Range.mk y z) ret0

/- [array::array_to_slice_shared_]: forward function -/
def array_to_slice_shared_
  (x : Array U32 (Usize.ofInt 32)) : Result (Slice U32) :=
  Array.to_slice_shared U32 (Usize.ofInt 32) x

/- [array::array_to_slice_mut_]: forward function -/
def array_to_slice_mut_
  (x : Array U32 (Usize.ofInt 32)) : Result (Slice U32) :=
  Array.to_slice_mut U32 (Usize.ofInt 32) x

/- [array::array_to_slice_mut_]: backward function 0 -/
def array_to_slice_mut__back
  (x : Array U32 (Usize.ofInt 32)) (ret0 : Slice U32) :
  Result (Array U32 (Usize.ofInt 32))
  :=
  Array.to_slice_mut_back U32 (Usize.ofInt 32) x ret0

/- [array::array_subslice_shared_]: forward function -/
def array_subslice_shared_
  (x : Array U32 (Usize.ofInt 32)) (y : Usize) (z : Usize) :
  Result (Slice U32)
  :=
  Array.subslice_shared U32 (Usize.ofInt 32) x (Range.mk y z)

/- [array::array_subslice_mut_]: forward function -/
def array_subslice_mut_
  (x : Array U32 (Usize.ofInt 32)) (y : Usize) (z : Usize) :
  Result (Slice U32)
  :=
  Array.subslice_mut U32 (Usize.ofInt 32) x (Range.mk y z)

/- [array::array_subslice_mut_]: backward function 0 -/
def array_subslice_mut__back
  (x : Array U32 (Usize.ofInt 32)) (y : Usize) (z : Usize) (ret0 : Slice U32) :
  Result (Array U32 (Usize.ofInt 32))
  :=
  Array.subslice_mut_back U32 (Usize.ofInt 32) x (Range.mk y z) ret0

/- [array::index_slice_0]: forward function -/
def index_slice_0 (T0 : Type) (s : Slice T0) : Result T0 :=
  Slice.index_shared T0 s (Usize.ofInt 0)

/- [array::index_array_0]: forward function -/
def index_array_0 (T0 : Type) (s : Array T0 (Usize.ofInt 32)) : Result T0 :=
  Array.index_shared T0 (Usize.ofInt 32) s (Usize.ofInt 0)

/- [array::index_index_array]: forward function -/
def index_index_array
  (s : Array (Array U32 (Usize.ofInt 32)) (Usize.ofInt 32)) (i : Usize)
  (j : Usize) :
  Result U32
  :=
  do
    let a ←
      Array.index_shared (Array U32 (Usize.ofInt 32)) (Usize.ofInt 32) s i
    Array.index_shared U32 (Usize.ofInt 32) a j

/- [array::update_update_array]: forward function -/
def update_update_array
  (s : Array (Array U32 (Usize.ofInt 32)) (Usize.ofInt 32)) (i : Usize)
  (j : Usize) :
  Result Unit
  :=
  do
    let a ← Array.index_mut (Array U32 (Usize.ofInt 32)) (Usize.ofInt 32) s i
    let a0 ← Array.index_mut_back U32 (Usize.ofInt 32) a j (U32.ofInt 0)
    let _ ←
      Array.index_mut_back (Array U32 (Usize.ofInt 32)) (Usize.ofInt 32) s i a0
    Result.ret ()

/- [array::array_local_deep_copy]: forward function -/
def array_local_deep_copy (x : Array U32 (Usize.ofInt 32)) : Result Unit :=
  Result.ret ()

/- [array::take_array]: forward function -/
def take_array (a : Array U32 (Usize.ofInt 2)) : Result Unit :=
  Result.ret ()

/- [array::take_array_borrow]: forward function -/
def take_array_borrow (a : Array U32 (Usize.ofInt 2)) : Result Unit :=
  Result.ret ()

/- [array::take_slice]: forward function -/
def take_slice (s : Slice U32) : Result Unit :=
  Result.ret ()

/- [array::take_mut_slice]: merged forward/backward function
   (there is a single backward function, and the forward function returns ()) -/
def take_mut_slice (s : Slice U32) : Result (Slice U32) :=
  Result.ret s

/- [array::take_all]: forward function -/
def take_all : Result Unit :=
  do
    let _ ←
      take_array
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ])
    let _ ←
      take_array_borrow
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ])
    let s ←
      Array.to_slice_shared U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ])
    let _ ← take_slice s
    let s0 ←
      Array.to_slice_mut U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ])
    let s1 ← take_mut_slice s0
    let _ ←
      Array.to_slice_mut_back U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ]) s1
    Result.ret ()

/- [array::index_array]: forward function -/
def index_array (x : Array U32 (Usize.ofInt 2)) : Result U32 :=
  Array.index_shared U32 (Usize.ofInt 2) x (Usize.ofInt 0)

/- [array::index_array_borrow]: forward function -/
def index_array_borrow (x : Array U32 (Usize.ofInt 2)) : Result U32 :=
  Array.index_shared U32 (Usize.ofInt 2) x (Usize.ofInt 0)

/- [array::index_slice_u32_0]: forward function -/
def index_slice_u32_0 (x : Slice U32) : Result U32 :=
  Slice.index_shared U32 x (Usize.ofInt 0)

/- [array::index_mut_slice_u32_0]: forward function -/
def index_mut_slice_u32_0 (x : Slice U32) : Result U32 :=
  Slice.index_shared U32 x (Usize.ofInt 0)

/- [array::index_mut_slice_u32_0]: backward function 0 -/
def index_mut_slice_u32_0_back (x : Slice U32) : Result (Slice U32) :=
  do
    let _ ← Slice.index_shared U32 x (Usize.ofInt 0)
    Result.ret x

/- [array::index_all]: forward function -/
def index_all : Result U32 :=
  do
    let i ←
      index_array
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ])
    let i0 ←
      index_array
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ])
    let i1 ← i + i0
    let i2 ←
      index_array_borrow
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ])
    let i3 ← i1 + i2
    let s ←
      Array.to_slice_shared U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ])
    let i4 ← index_slice_u32_0 s
    let i5 ← i3 + i4
    let s0 ←
      Array.to_slice_mut U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ])
    let i6 ← index_mut_slice_u32_0 s0
    let i7 ← i5 + i6
    let s1 ← index_mut_slice_u32_0_back s0
    let _ ←
      Array.to_slice_mut_back U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ]) s1
    Result.ret i7

/- [array::update_array]: forward function -/
def update_array (x : Array U32 (Usize.ofInt 2)) : Result Unit :=
  do
    let _ ←
      Array.index_mut_back U32 (Usize.ofInt 2) x (Usize.ofInt 0) (U32.ofInt 1)
    Result.ret ()

/- [array::update_array_mut_borrow]: merged forward/backward function
   (there is a single backward function, and the forward function returns ()) -/
def update_array_mut_borrow
  (x : Array U32 (Usize.ofInt 2)) : Result (Array U32 (Usize.ofInt 2)) :=
  Array.index_mut_back U32 (Usize.ofInt 2) x (Usize.ofInt 0) (U32.ofInt 1)

/- [array::update_mut_slice]: merged forward/backward function
   (there is a single backward function, and the forward function returns ()) -/
def update_mut_slice (x : Slice U32) : Result (Slice U32) :=
  Slice.index_mut_back U32 x (Usize.ofInt 0) (U32.ofInt 1)

/- [array::update_all]: forward function -/
def update_all : Result Unit :=
  do
    let _ ←
      update_array
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ])
    let x ←
      update_array_mut_borrow
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ])
    let s ← Array.to_slice_mut U32 (Usize.ofInt 2) x
    let s0 ← update_mut_slice s
    let _ ← Array.to_slice_mut_back U32 (Usize.ofInt 2) x s0
    Result.ret ()

/- [array::range_all]: forward function -/
def range_all : Result Unit :=
  do
    let s ←
      Array.subslice_mut U32 (Usize.ofInt 4)
        (Array.make U32 (Usize.ofInt 4) [
          (U32.ofInt 0), (U32.ofInt 0), (U32.ofInt 0), (U32.ofInt 0)
          ]) (Range.mk (Usize.ofInt 1) (Usize.ofInt 3))
    let s0 ← update_mut_slice s
    let _ ←
      Array.subslice_mut_back U32 (Usize.ofInt 4)
        (Array.make U32 (Usize.ofInt 4) [
          (U32.ofInt 0), (U32.ofInt 0), (U32.ofInt 0), (U32.ofInt 0)
          ]) (Range.mk (Usize.ofInt 1) (Usize.ofInt 3)) s0
    Result.ret ()

/- [array::deref_array_borrow]: forward function -/
def deref_array_borrow (x : Array U32 (Usize.ofInt 2)) : Result U32 :=
  Array.index_shared U32 (Usize.ofInt 2) x (Usize.ofInt 0)

/- [array::deref_array_mut_borrow]: forward function -/
def deref_array_mut_borrow (x : Array U32 (Usize.ofInt 2)) : Result U32 :=
  Array.index_shared U32 (Usize.ofInt 2) x (Usize.ofInt 0)

/- [array::deref_array_mut_borrow]: backward function 0 -/
def deref_array_mut_borrow_back
  (x : Array U32 (Usize.ofInt 2)) : Result (Array U32 (Usize.ofInt 2)) :=
  do
    let _ ← Array.index_shared U32 (Usize.ofInt 2) x (Usize.ofInt 0)
    Result.ret x

/- [array::take_array_t]: forward function -/
def take_array_t (a : Array T (Usize.ofInt 2)) : Result Unit :=
  Result.ret ()

/- [array::non_copyable_array]: forward function -/
def non_copyable_array : Result Unit :=
  do
    let _ ← take_array_t (Array.make T (Usize.ofInt 2) [ T.A, T.B ])
    Result.ret ()

/- [array::sum]: loop 0: forward function -/
divergent def sum_loop (s : Slice U32) (sum0 : U32) (i : Usize) : Result U32 :=
  let i0 := Slice.len U32 s
  if i < i0
  then
    do
      let i1 ← Slice.index_shared U32 s i
      let sum1 ← sum0 + i1
      let i2 ← i + (Usize.ofInt 1)
      sum_loop s sum1 i2
  else Result.ret sum0

/- [array::sum]: forward function -/
def sum (s : Slice U32) : Result U32 :=
  sum_loop s (U32.ofInt 0) (Usize.ofInt 0)

/- [array::sum2]: loop 0: forward function -/
divergent def sum2_loop
  (s : Slice U32) (s2 : Slice U32) (sum0 : U32) (i : Usize) : Result U32 :=
  let i0 := Slice.len U32 s
  if i < i0
  then
    do
      let i1 ← Slice.index_shared U32 s i
      let i2 ← Slice.index_shared U32 s2 i
      let i3 ← i1 + i2
      let sum1 ← sum0 + i3
      let i4 ← i + (Usize.ofInt 1)
      sum2_loop s s2 sum1 i4
  else Result.ret sum0

/- [array::sum2]: forward function -/
def sum2 (s : Slice U32) (s2 : Slice U32) : Result U32 :=
  let i := Slice.len U32 s
  let i0 := Slice.len U32 s2
  if not (i = i0)
  then Result.fail Error.panic
  else sum2_loop s s2 (U32.ofInt 0) (Usize.ofInt 0)

/- [array::f0]: forward function -/
def f0 : Result Unit :=
  do
    let s ←
      Array.to_slice_mut U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 1), (U32.ofInt 2) ])
    let s0 ← Slice.index_mut_back U32 s (Usize.ofInt 0) (U32.ofInt 1)
    let _ ←
      Array.to_slice_mut_back U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 1), (U32.ofInt 2) ]) s0
    Result.ret ()

/- [array::f1]: forward function -/
def f1 : Result Unit :=
  do
    let _ ←
      Array.index_mut_back U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 1), (U32.ofInt 2) ])
        (Usize.ofInt 0) (U32.ofInt 1)
    Result.ret ()

/- [array::f2]: forward function -/
def f2 (i : U32) : Result Unit :=
  Result.ret ()

/- [array::f4]: forward function -/
def f4
  (x : Array U32 (Usize.ofInt 32)) (y : Usize) (z : Usize) :
  Result (Slice U32)
  :=
  Array.subslice_shared U32 (Usize.ofInt 32) x (Range.mk y z)

/- [array::f3]: forward function -/
def f3 : Result U32 :=
  do
    let i ←
      Array.index_shared U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 1), (U32.ofInt 2) ])
        (Usize.ofInt 0)
    let _ ← f2 i
    let b := Array.repeat U32 (Usize.ofInt 32) (U32.ofInt 0)
    let s ←
      Array.to_slice_shared U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 1), (U32.ofInt 2) ])
    let s0 ← f4 b (Usize.ofInt 16) (Usize.ofInt 18)
    sum2 s s0

/- [array::SZ] -/
def sz_body : Result Usize := Result.ret (Usize.ofInt 32)
def sz_c : Usize := eval_global sz_body (by simp)

/- [array::f5]: forward function -/
def f5 (x : Array U32 (Usize.ofInt 32)) : Result U32 :=
  Array.index_shared U32 (Usize.ofInt 32) x (Usize.ofInt 0)

/- [array::ite]: forward function -/
def ite : Result Unit :=
  do
    let s ←
      Array.to_slice_mut U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ])
    let s0 ←
      Array.to_slice_mut U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ])
    let s1 ← index_mut_slice_u32_0_back s0
    let _ ←
      Array.to_slice_mut_back U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ]) s1
    let s2 ← index_mut_slice_u32_0_back s
    let _ ←
      Array.to_slice_mut_back U32 (Usize.ofInt 2)
        (Array.make U32 (Usize.ofInt 2) [ (U32.ofInt 0), (U32.ofInt 0) ]) s2
    Result.ret ()

/- [array::array]: forward function -/
def array (LEN : Usize) : Result (Array U8 LEN) :=
  let a := Array.repeat U8 LEN (U8.ofInt 0)
  Result.ret a

end array
