-- THIS FILE WAS AUTOMATICALLY GENERATED BY AENEAS
-- [tutorial]
import Aeneas
open Aeneas Aeneas.Std Result ControlFlow Error
set_option linter.dupNamespace false
set_option linter.hashCommand false
set_option linter.unusedVariables false

/- You can set the `maxHeartbeats` value with the `-max-heartbeats` CLI option -/
set_option maxHeartbeats 1000000

/- You can set the `maxRecDepth` value with the `-max-recdepth` CLI option -/
set_option maxRecDepth 2048

namespace tutorial

/-- [tutorial::choose]:
    Source: 'src/lib.rs', lines 1:0-7:1
    Visibility: public -/
def choose
  {T : Type} (b : Bool) (x : T) (y : T) : Result (T × (T → (T × T))) := do
  if b
  then let back := fun x1 => (x1, y)
       ok (x, back)
  else let back := fun y1 => (x, y1)
       ok (y, back)

/-- [tutorial::mul2_add1]:
    Source: 'src/lib.rs', lines 9:0-11:1
    Visibility: public -/
def mul2_add1 (x : Std.U32) : Result Std.U32 := do
  let i ← x + x
  i + 1#u32

/-- [tutorial::mul2_add1_add]:
    Source: 'src/lib.rs', lines 13:0-15:1
    Visibility: public -/
def mul2_add1_add (x : Std.U32) (y : Std.U32) : Result Std.U32 := do
  let i ← mul2_add1 x
  i + y

/-- [tutorial::incr]:
    Source: 'src/lib.rs', lines 17:0-19:1
    Visibility: public -/
def incr (x : Std.U32) : Result Std.U32 := do
  x + 1#u32

/-- [tutorial::use_incr]:
    Source: 'src/lib.rs', lines 21:0-26:1
    Visibility: public -/
def use_incr : Result Unit := do
  let x ← incr 0#u32
  let x1 ← incr x
  let _ ← incr x1
  ok ()

/-- [tutorial::CList]
    Source: 'src/lib.rs', lines 30:0-33:1
    Visibility: public -/
@[discriminant isize]
inductive CList (T : Type) where
| CCons : T → CList T → CList T
| CNil : CList T

/-- [tutorial::list_nth]:
    Source: 'src/lib.rs', lines 35:0-48:1
    Visibility: public -/
def list_nth {T : Type} (l : CList T) (i : Std.U32) : Result T := do
  match l with
  | CList.CCons x tl =>
    if i = 0#u32
    then ok x
    else let i1 ← i - 1#u32
         list_nth tl i1
  | CList.CNil => fail panic
partial_fixpoint

/-- [tutorial::list_nth_mut]:
    Source: 'src/lib.rs', lines 50:0-63:1
    Visibility: public -/
def list_nth_mut
  {T : Type} (l : CList T) (i : Std.U32) : Result (T × (T → CList T)) := do
  match l with
  | CList.CCons x tl =>
    if i = 0#u32
    then let back := fun t => CList.CCons t tl
         ok (x, back)
    else
      let i1 ← i - 1#u32
      let (x1, list_nth_mut_back) ← list_nth_mut tl i1
      let back := fun t => let tl1 := list_nth_mut_back t
                           CList.CCons x tl1
      ok (x1, back)
  | CList.CNil => fail panic
partial_fixpoint

/-- [tutorial::list_nth1]: loop 0:
    Source: 'src/lib.rs', lines 66:4-74:1
    Visibility: public -/
@[rust_loop]
def list_nth1_loop {T : Type} (l : CList T) (i : Std.U32) : Result T := do
  match l with
  | CList.CCons x tl =>
    if i = 0#u32
    then ok x
    else let i1 ← i - 1#u32
         list_nth1_loop tl i1
  | CList.CNil => fail panic
partial_fixpoint

/-- [tutorial::list_nth1]:
    Source: 'src/lib.rs', lines 65:0-74:1
    Visibility: public -/
@[reducible]
def list_nth1 {T : Type} (l : CList T) (i : Std.U32) : Result T := do
  list_nth1_loop l i

/-- [tutorial::i32_id]:
    Source: 'src/lib.rs', lines 76:0-83:1
    Visibility: public -/
def i32_id (i : Std.I32) : Result Std.I32 := do
  if i = 0#i32
  then ok 0#i32
  else let i1 ← i - 1#i32
       let i2 ← i32_id i1
       i2 + 1#i32
partial_fixpoint

mutual

/-- [tutorial::even]:
    Source: 'src/lib.rs', lines 85:0-92:1
    Visibility: public -/
def even (i : Std.U32) : Result Bool := do
  if i = 0#u32
  then ok true
  else let i1 ← i - 1#u32
       odd i1
partial_fixpoint

/-- [tutorial::odd]:
    Source: 'src/lib.rs', lines 94:0-101:1
    Visibility: public -/
def odd (i : Std.U32) : Result Bool := do
  if i = 0#u32
  then ok false
  else let i1 ← i - 1#u32
       even i1
partial_fixpoint

end

/-- Trait declaration: [tutorial::Counter]
    Source: 'src/lib.rs', lines 105:0-107:1
    Visibility: public -/
structure Counter (Self : Type) where
  incr : Self → Result (Std.Usize × Self)

/-- [tutorial::{impl tutorial::Counter for usize}::incr]:
    Source: 'src/lib.rs', lines 110:4-114:5
    Visibility: public -/
def Usize.Insts.TutorialCounter.incr
  (self : Std.Usize) : Result (Std.Usize × Std.Usize) := do
  let self1 ← self + 1#usize
  ok (self, self1)

/-- Trait implementation: [tutorial::{impl tutorial::Counter for usize}]
    Source: 'src/lib.rs', lines 109:0-115:1 -/
@[reducible]
def Usize.Insts.TutorialCounter : Counter Std.Usize := {
  incr := Usize.Insts.TutorialCounter.incr
}

/-- [tutorial::use_counter]:
    Source: 'src/lib.rs', lines 117:0-119:1
    Visibility: public -/
def use_counter
  {T : Type} (CounterInst : Counter T) (cnt : T) :
  Result (Std.Usize × T)
  := do
  CounterInst.incr cnt

/-- [tutorial::list_nth_mut1]: loop 0:
    Source: 'src/lib.rs', lines 124:4-132:1
    Visibility: public -/
@[rust_loop]
def list_nth_mut1_loop
  {T : Type} (l : CList T) (i : Std.U32) : Result (T × (T → CList T)) := do
  match l with
  | CList.CCons x tl =>
    if i = 0#u32
    then ok (x, fun t => CList.CCons t tl)
    else
      let i1 ← i - 1#u32
      let (t, back) ← list_nth_mut1_loop tl i1
      let back1 := fun t1 => let c := back t1
                             CList.CCons x c
      ok (t, back1)
  | CList.CNil => fail panic
partial_fixpoint

/-- [tutorial::list_nth_mut1]:
    Source: 'src/lib.rs', lines 123:0-132:1
    Visibility: public -/
@[reducible]
def list_nth_mut1
  {T : Type} (l : CList T) (i : Std.U32) : Result (T × (T → CList T)) := do
  list_nth_mut1_loop l i

/-- [tutorial::list_tail]: loop 0:
    Source: 'src/lib.rs', lines 135:4-137:5
    Visibility: public -/
@[rust_loop]
def list_tail_loop
  {T : Type} (l : CList T) : Result (CList T → CList T) := do
  match l with
  | CList.CCons t tl =>
    let back ← list_tail_loop tl
    ok (fun c => let c1 := back c
                 CList.CCons t c1)
  | CList.CNil => ok (fun c => c)
partial_fixpoint

/-- [tutorial::list_tail]:
    Source: 'src/lib.rs', lines 134:0-139:1
    Visibility: public -/
def list_tail
  {T : Type} (l : CList T) : Result ((CList T) × (CList T → CList T)) := do
  let back ← list_tail_loop l
  ok (CList.CNil, back)

/-- [tutorial::append_in_place]:
    Source: 'src/lib.rs', lines 141:0-144:1
    Visibility: public -/
def append_in_place
  {T : Type} (l0 : CList T) (l1 : CList T) : Result (CList T) := do
  let (_, list_tail_back) ← list_tail l0
  ok (list_tail_back l1)

/-- [tutorial::reverse]: loop 0:
    Source: 'src/lib.rs', lines 148:4-152:5
    Visibility: public -/
@[rust_loop]
def reverse_loop
  {T : Type} (l : CList T) (out : CList T) : Result (CList T) := do
  match l with
  | CList.CCons hd tl => reverse_loop tl (CList.CCons hd out)
  | CList.CNil => ok out
partial_fixpoint

/-- [tutorial::reverse]:
    Source: 'src/lib.rs', lines 146:0-154:1
    Visibility: public -/
@[reducible]
def reverse {T : Type} (l : CList T) : Result (CList T) := do
  reverse_loop l CList.CNil

/-- [tutorial::zero]: loop 0:
    Source: 'src/lib.rs', lines 164:4-167:5
    Visibility: public -/
@[rust_loop]
def zero_loop
  (x : alloc.vec.Vec Std.U32) (i : Std.Usize) :
  Result (alloc.vec.Vec Std.U32)
  := do
  let i1 := alloc.vec.Vec.len x
  if i < i1
  then
    let (_, index_mut_back) ←
      alloc.vec.Vec.index_mut (core.slice.index.SliceIndexUsizeSlice Std.U32) x
        i
    let i2 ← i + 1#usize
    let x1 := index_mut_back 0#u32
    zero_loop x1 i2
  else ok x
partial_fixpoint

/-- [tutorial::zero]:
    Source: 'src/lib.rs', lines 162:0-168:1
    Visibility: public -/
@[reducible]
def zero (x : alloc.vec.Vec Std.U32) : Result (alloc.vec.Vec Std.U32) := do
  zero_loop x 0#usize

/-- [tutorial::add_no_overflow]: loop 0:
    Source: 'src/lib.rs', lines 177:4-180:5
    Visibility: public -/
@[rust_loop]
def add_no_overflow_loop
  (x : alloc.vec.Vec Std.U32) (y : alloc.vec.Vec Std.U32) (i : Std.Usize) :
  Result (alloc.vec.Vec Std.U32)
  := do
  let i1 := alloc.vec.Vec.len x
  if i < i1
  then
    let i2 ←
      alloc.vec.Vec.index (core.slice.index.SliceIndexUsizeSlice Std.U32) y i
    let (i3, index_mut_back) ←
      alloc.vec.Vec.index_mut (core.slice.index.SliceIndexUsizeSlice Std.U32) x
        i
    let i4 ← i3 + i2
    let i5 ← i + 1#usize
    let x1 := index_mut_back i4
    add_no_overflow_loop x1 y i5
  else ok x
partial_fixpoint

/-- [tutorial::add_no_overflow]:
    Source: 'src/lib.rs', lines 175:0-181:1
    Visibility: public -/
@[reducible]
def add_no_overflow
  (x : alloc.vec.Vec Std.U32) (y : alloc.vec.Vec Std.U32) :
  Result (alloc.vec.Vec Std.U32)
  := do
  add_no_overflow_loop x y 0#usize

/-- [tutorial::add_with_carry]: loop 0:
    Source: 'src/lib.rs', lines 190:4-197:5
    Visibility: public -/
@[rust_loop]
def add_with_carry_loop
  (x : alloc.vec.Vec Std.U32) (y : alloc.vec.Vec Std.U32) (c0 : Std.U8)
  (i : Std.Usize) :
  Result (Std.U8 × (alloc.vec.Vec Std.U32))
  := do
  let i1 := alloc.vec.Vec.len x
  if i < i1
  then
    let i2 ←
      alloc.vec.Vec.index (core.slice.index.SliceIndexUsizeSlice Std.U32) x i
    let i3 ← lift (UScalar.cast .U32 c0)
    let (sum, c1) ← lift (core.num.U32.overflowing_add i2 i3)
    let i4 ←
      alloc.vec.Vec.index (core.slice.index.SliceIndexUsizeSlice Std.U32) y i
    let (sum1, c2) ← lift (core.num.U32.overflowing_add sum i4)
    let i5 ← lift (UScalar.cast_fromBool .U8 c1)
    let i6 ← lift (UScalar.cast_fromBool .U8 c2)
    let c01 ← i5 + i6
    let (_, index_mut_back) ←
      alloc.vec.Vec.index_mut (core.slice.index.SliceIndexUsizeSlice Std.U32) x
        i
    let i7 ← i + 1#usize
    let x1 := index_mut_back sum1
    add_with_carry_loop x1 y c01 i7
  else ok (c0, x)
partial_fixpoint

/-- [tutorial::add_with_carry]:
    Source: 'src/lib.rs', lines 186:0-199:1
    Visibility: public -/
@[reducible]
def add_with_carry
  (x : alloc.vec.Vec Std.U32) (y : alloc.vec.Vec Std.U32) :
  Result (Std.U8 × (alloc.vec.Vec Std.U32))
  := do
  add_with_carry_loop x y 0#u8 0#usize

/-- [tutorial::max]:
    Source: 'src/lib.rs', lines 201:0-203:1 -/
def max (x : Std.Usize) (y : Std.Usize) : Result Std.Usize := do
  if x > y
  then ok x
  else ok y

/-- [tutorial::get_or_zero]:
    Source: 'src/lib.rs', lines 205:0-207:1 -/
def get_or_zero
  (y : alloc.vec.Vec Std.U32) (i : Std.Usize) : Result Std.U32 := do
  let i1 := alloc.vec.Vec.len y
  if i < i1
  then alloc.vec.Vec.index (core.slice.index.SliceIndexUsizeSlice Std.U32) y i
  else ok 0#u32

/-- [tutorial::add]: loop 0:
    Source: 'src/lib.rs', lines 221:4-229:5
    Visibility: public -/
@[rust_loop]
def add_loop
  (x : alloc.vec.Vec Std.U32) (y : alloc.vec.Vec Std.U32) (max1 : Std.Usize)
  (c0 : Std.U8) (i : Std.Usize) :
  Result ((alloc.vec.Vec Std.U32) × Std.U8)
  := do
  if i < max1
  then
    let yi ← get_or_zero y i
    let i1 ←
      alloc.vec.Vec.index (core.slice.index.SliceIndexUsizeSlice Std.U32) x i
    let i2 ← lift (UScalar.cast .U32 c0)
    let (sum, c1) ← lift (core.num.U32.overflowing_add i1 i2)
    let (sum1, c2) ← lift (core.num.U32.overflowing_add sum yi)
    let i3 ← lift (UScalar.cast_fromBool .U8 c1)
    let i4 ← lift (UScalar.cast_fromBool .U8 c2)
    let c01 ← i3 + i4
    let (_, index_mut_back) ←
      alloc.vec.Vec.index_mut (core.slice.index.SliceIndexUsizeSlice Std.U32) x
        i
    let i5 ← i + 1#usize
    let x1 := index_mut_back sum1
    add_loop x1 y max1 c01 i5
  else ok (x, c0)
partial_fixpoint

/-- [tutorial::add]:
    Source: 'src/lib.rs', lines 214:0-235:1
    Visibility: public -/
def add
  (x : alloc.vec.Vec Std.U32) (y : alloc.vec.Vec Std.U32) :
  Result (alloc.vec.Vec Std.U32)
  := do
  let i := alloc.vec.Vec.len x
  let i1 := alloc.vec.Vec.len y
  let max1 ← max i i1
  let x1 ← alloc.vec.Vec.resize core.clone.CloneU32 x max1 0#u32
  let (x2, c0) ← add_loop x1 y max1 0#u8 0#usize
  if c0 != 0#u8
  then let i2 ← lift (UScalar.cast .U32 c0)
       alloc.vec.Vec.push x2 i2
  else ok x2

/-- Trait declaration: [tutorial::Hash]
    Source: 'src/lib.rs', lines 250:0-252:1 -/
structure Hash (Self : Type) where
  hash : Std.U32 → Result Std.U32

/-- [tutorial::pseudo_random]: loop 0:
    Source: 'src/lib.rs', lines 258:2-260:3
    Visibility: public -/
@[rust_loop]
def pseudo_random_loop
  {T : Type} (HashInst : Hash T) (state : Std.U32) : Result Std.U32 := do
  if state < 100#u32
  then let state1 ← HashInst.hash state
       pseudo_random_loop HashInst state1
  else ok state
partial_fixpoint

/-- [tutorial::pseudo_random]:
    Source: 'src/lib.rs', lines 255:0-262:1
    Visibility: public -/
@[reducible]
def pseudo_random {T : Type} (HashInst : Hash T) : Result Std.U32 := do
  pseudo_random_loop HashInst 0#u32

end tutorial
