(module vec_i64 (export empty append len at singleton append2 append3 pair triple is_empty index_or first_or last_or index_option first_option last_option index_of_option last_index_of_option contains sum concat take drop reverse subvec insert_at insert_range replace_at replace_range remove_at remove_range))

(fn empty () -> (vec i64)
  (std.vec.i64.empty))

(fn append ((values (vec i64)) (value i64)) -> (vec i64)
  (std.vec.i64.append values value))

(fn len ((values (vec i64))) -> i32
  (std.vec.i64.len values))

(fn at ((values (vec i64)) (position i32)) -> i64
  (std.vec.i64.index values position))

(fn singleton ((value i64)) -> (vec i64)
  (append (empty) value))

(fn append2 ((values (vec i64)) (first i64) (second i64)) -> (vec i64)
  (append (append values first) second))

(fn append3 ((values (vec i64)) (first i64) (second i64) (third i64)) -> (vec i64)
  (append (append2 values first second) third))

(fn pair ((first i64) (second i64)) -> (vec i64)
  (append2 (empty) first second))

(fn triple ((first i64) (second i64) (third i64)) -> (vec i64)
  (append3 (empty) first second third))

(fn is_empty ((values (vec i64))) -> bool
  (= (len values) 0))

(fn index_or ((values (vec i64)) (position i32) (fallback i64)) -> i64
  (if (< position 0)
    fallback
    (if (< position (len values))
      (at values position)
      fallback)))

(fn first_or ((values (vec i64)) (fallback i64)) -> i64
  (index_or values 0 fallback))

(fn last_or ((values (vec i64)) (fallback i64)) -> i64
  (if (is_empty values)
    fallback
    (at values (- (len values) 1))))

(fn index_option ((values (vec i64)) (position i32)) -> (option i64)
  (if (< position 0)
    (none i64)
    (if (< position (len values))
      (some i64 (at values position))
      (none i64))))

(fn first_option ((values (vec i64))) -> (option i64)
  (index_option values 0))

(fn last_option ((values (vec i64))) -> (option i64)
  (if (is_empty values)
    (none i64)
    (some i64 (at values (- (len values) 1)))))

(fn index_of_option_loop ((values (vec i64)) (target i64) (position i32) (values_len i32)) -> (option i32)
  (if (< position values_len)
    (if (= (at values position) target)
      (some i32 position)
      (index_of_option_loop values target (+ position 1) values_len))
    (none i32)))

(fn index_of_option ((values (vec i64)) (target i64)) -> (option i32)
  (index_of_option_loop values target 0 (len values)))

(fn last_index_of_option_loop ((values (vec i64)) (target i64) (position i32) (values_len i32) (found (option i32))) -> (option i32)
  (if (< position values_len)
    (if (= (at values position) target)
      (last_index_of_option_loop values target (+ position 1) values_len (some i32 position))
      (last_index_of_option_loop values target (+ position 1) values_len found))
    found))

(fn last_index_of_option ((values (vec i64)) (target i64)) -> (option i32)
  (last_index_of_option_loop values target 0 (len values) (none i32)))

(fn contains_loop ((values (vec i64)) (target i64) (position i32) (values_len i32)) -> bool
  (if (< position values_len)
    (if (= (at values position) target)
      true
      (contains_loop values target (+ position 1) values_len))
    false))

(fn contains ((values (vec i64)) (target i64)) -> bool
  (contains_loop values target 0 (len values)))

(fn sum_loop ((values (vec i64)) (position i32) (values_len i32) (total i64)) -> i64
  (if (< position values_len)
    (sum_loop values (+ position 1) values_len (+ total (at values position)))
    total))

(fn sum ((values (vec i64))) -> i64
  (sum_loop values 0 (len values) 0i64))

(fn concat_loop ((built (vec i64)) (right (vec i64)) (position i32) (right_len i32)) -> (vec i64)
  (if (< position right_len)
    (concat_loop (append built (at right position)) right (+ position 1) right_len)
    built))

(fn concat ((left (vec i64)) (right (vec i64))) -> (vec i64)
  (let right_len i32 (len right))
  (concat_loop left right 0 right_len))

(fn take_loop ((values (vec i64)) (position i32) (limit i32) (built (vec i64))) -> (vec i64)
  (if (< position limit)
    (take_loop values (+ position 1) limit (append built (at values position)))
    built))

(fn take ((values (vec i64)) (count i32)) -> (vec i64)
  (let values_len i32 (len values))
  (if (< count 0)
    (empty)
    (if (< count values_len)
      (take_loop values 0 count (empty))
      values)))

(fn drop_loop ((values (vec i64)) (position i32) (values_len i32) (built (vec i64))) -> (vec i64)
  (if (< position values_len)
    (drop_loop values (+ position 1) values_len (append built (at values position)))
    built))

(fn drop ((values (vec i64)) (count i32)) -> (vec i64)
  (let values_len i32 (len values))
  (if (< count 0)
    values
    (if (< count values_len)
      (drop_loop values count values_len (empty))
      (empty))))

(fn reverse_loop ((values (vec i64)) (position i32) (built (vec i64))) -> (vec i64)
  (if (< position 0)
    built
    (reverse_loop values (- position 1) (append built (at values position)))))

(fn reverse ((values (vec i64))) -> (vec i64)
  (reverse_loop values (- (len values) 1) (empty)))

(fn subvec ((values (vec i64)) (start i32) (end_exclusive i32)) -> (vec i64)
  (if (< start 0)
    (empty)
    (if (< start end_exclusive)
      (take (drop values start) (- end_exclusive start))
      (empty))))

(fn insert_at ((values (vec i64)) (position i32) (value i64)) -> (vec i64)
  (if (< position 0)
    values
    (if (< position (len values))
      (concat (append (take values position) value) (drop values position))
      (if (= position (len values))
        (append values value)
        values))))

(fn insert_range ((values (vec i64)) (position i32) (inserted (vec i64))) -> (vec i64)
  (if (< position 0)
    values
    (if (< position (len values))
      (concat (concat (take values position) inserted) (drop values position))
      (if (= position (len values))
        (concat values inserted)
        values))))

(fn replace_at ((values (vec i64)) (position i32) (replacement i64)) -> (vec i64)
  (if (< position 0)
    values
    (if (< position (len values))
      (concat (append (take values position) replacement) (drop values (+ position 1)))
      values)))

(fn replace_range ((values (vec i64)) (start i32) (end_exclusive i32) (replacement (vec i64))) -> (vec i64)
  (let values_len i32 (len values))
  (if (< start 0)
    values
    (if (< start values_len)
      (if (< start end_exclusive)
        (concat (concat (take values start) replacement) (drop values end_exclusive))
        values)
      values)))

(fn remove_at ((values (vec i64)) (position i32)) -> (vec i64)
  (if (< position 0)
    values
    (if (< position (len values))
      (concat (take values position) (drop values (+ position 1)))
      values)))

(fn remove_range ((values (vec i64)) (start i32) (end_exclusive i32)) -> (vec i64)
  (let values_len i32 (len values))
  (if (< start 0)
    values
    (if (< start values_len)
      (if (< start end_exclusive)
        (concat (take values start) (drop values end_exclusive))
        values)
      values)))
