use std::convert::TryInto;
use std::convert::TryFrom;
fn main() {
	// typed/size/repeat initialization
	let val = 42;
	let mut ia: [usize; 5] = [val; 5];

	// typed/size/individual initialization
	let fval = 42.2;
	let fa: [f64; 5] = [1.2, fval, 5.6, 7.3, 9.1];

	// enumerating range/type
	for i in 0..ia.len() { print!("{:?} ", ia[i] ); } println!("");  // 42 42 42
	for fv in fa { print!("{:?} ", fv ); } println!("");  // 1.2 42.2 5.6
	for i in 0..=1 { ia[i] = i; }    // mutable changes
	for iv in ia { print!("{:?} ", iv ); } println!("");  // 0 1 42

	// 2 dimensional (matrix), fixed-size
	const ROWS: usize = 4;
	const COLS: usize = 6;
	let mut fmatrix: [[f64; COLS]; ROWS] = [[0.; COLS]; ROWS];
	for r in 0 .. ROWS {
		for c in 0 .. COLS {
			fmatrix[r][c] = r as f64 + c as f64;
		}
		println!( "{:?}", fmatrix[r] );
	}
	
	let mut slice2: &[f64] = &fmatrix[3][2 ..= 4];
	println!( "{:?}", slice2 );
	slice2 = &fmatrix[1 ..= 3][1];
	println!( "{:?}", slice2 );

	// implicit type/size, print entire array and length
	println!( "{:?} {:?}", ia, ia.len() );
	ia = [5; 5];
	println!( "{:?} {:?}", ia, ia.len() );
	ia = [1, 2, 3, 4, 5];
	println!( "{:?} {:?}", ia, ia.len() );

	// array copy
	let ia2: [usize; 5];
	ia2 = ia;
	println!( "copy = {:?} ", ia2 ); // 0 1 42 

	let mut numbers = [1, 2, 3, 4, 5];
	// pass array by value
	fn update1( mut arr:[i32; 5] ) {
		for i in 0 .. arr.len() { arr[i] = 0; }
		println!( "function update {:?}", arr );
	}
	update1( numbers );

	// pass array by reference
	fn update2( arr: & mut [i32; 5] ) {
		for i in 0 .. arr.len() { arr[i] = 0; }
		println!( "function update {:?}", arr );
	}
	update2( &mut numbers );

	// slice is barrowing a subset of an array, dimension bounds can be expressions
	println!( "slice {:?}", &ia[0..3] ); // fixed bounds, [1, 2, 3]
	println!( "slice {:?}", &ia[ia.len() - 2 .. ia.len()] ); // variable bounds, [4, 5]
	println!( "slice {:?}", &ia[ia.len() - 2 .. ] ); // drop upper bound, [4, 5]
	println!( "slice {:?}", &ia[.. ia.len() - 2 ] ); // drop lower bound, [1, 2, 3]
	println!( "slice {:?}", &ia[..] ); // drop both bound, [1, 2, 3, 4, 5]

	let slice: &[f64];
	slice = &fa[0 ..= 1];
	println!( "slice = {:?}", slice ); // [1.2, 42.2]
	let mut fa2: [f64; 2] = <[f64; 2]>::try_from( slice ).unwrap(); // convert slice to array
	println!( "fa2 {:?}", fa2 ); // [1.2, 42.2]
	fa2 = (& fa[2 ..= 3]).try_into().unwrap(); // convert slice to array
	println!( "fa2 {:?}", fa2 ); // [1.2, 42.2]

	// pass (all) slice by reference
	fn zero( arr: & mut [usize] ){
		for i in 0 .. arr.len() { arr[i] = 0; }
		println!( "function update {:?}", arr );
	}
	zero( & mut ia[0..5] );
	zero( & mut ia[0..3] );

	let mut vec: Vec< Vec<usize> > = Vec::new();
	for r in 0 .. ROWS {
		let mut row: Vec<usize> = Vec::new();
		for c in 0 .. COLS {
			row.push(r + c);
		}
		vec.push(row);
	}
	for r in 0 .. 4 {
		for c in 0 .. 4 {
			print!("{} ", vec[r][c]);
		}
		println!("");
	}

	// 2 dimensional (matrix), variable-size (C++ vector) array of array, heap allocated
	let (rows, cols) = (4, 6);
	let mut matrix = vec![vec![0; cols]; rows];
	for r in 0 .. rows {
		for c in 0 .. cols {
			matrix[r][c] = r + c;
			print!("{} ", matrix[r][c]);
		}
		println!("");
	}

	let mut slice3: &[usize] = &matrix[3][2 ..= 4];
	println!( "{:?}", slice3 );
	slice3 = &matrix[1 ..= 3][1];
	println!( "{:?}", slice3 );

	fn f<const N: usize>( arg: [usize; N] ) {
		for r in 0 .. arg.len() {
			print!( "{} ", arg[r] );
		}
		println!("");
	}
	f( ia );
}

// Local Variables: //
// tab-width: 4 //
// compile-command: "rustc arrays.rs" //
// End: //
