#![no_std]
#![no_main]

use core::ptr::slice_from_raw_parts_mut;
use user_lib::*;
use user_lib::syscall::sys_sbrk;

#[no_mangle]
fn main() -> i32 {
    println!("Test sbrk start.");

    // 设置申请颗粒度
    const PAGE_SIZE: usize = 0x1000;

    // 查看当前堆 end
    let origin_brk = sys_sbrk(0);
    println!("origin break point = {:x}", origin_brk);

    // 申请一页
    let brk = sys_sbrk(PAGE_SIZE as i32);
    if brk != origin_brk {
        return -1;
    }

    // 申请一页之后 查看堆 end
    let brk = sys_sbrk(0);
    println!("one page allocated,  break point = {:x}", brk);
    println!("try write to allocated page");

    // 得到 申请的堆 的字节数组, 并写入为1
    let new_page = unsafe {
        &mut *slice_from_raw_parts_mut(origin_brk as usize as *const u8 as *mut u8, PAGE_SIZE)
    };
    for pos in 0..PAGE_SIZE {
        new_page[pos] = 1;
    }
    println!("write ok");

    // 再申请10页内存 并得到当前 堆end
    sys_sbrk(PAGE_SIZE as i32 * 10);
    let brk = sys_sbrk(0);
    println!("10 page allocated,  break point = {:x}", brk);

    // 释放 11页(之前已经申请了 1 + 10页了)
    sys_sbrk(PAGE_SIZE as i32 * -11);
    let brk = sys_sbrk(0);
    println!("11 page DEALLOCATED,  break point = {:x}", brk);
    println!("try DEALLOCATED more one page, should be failed.");

    // 继续释放1页, 非法释放的测试
    let ret = sys_sbrk(PAGE_SIZE as i32 * -1);
    if ret != -1 {
        println!("Test sbrk failed!");
        return -1;
    }

    println!("Test sbrk almost OK!");
    println!("now write to deallocated page, should cause page fault.");
    for pos in 0..PAGE_SIZE {
        new_page[pos] = 2;
    }
    println!("{:?}", new_page);
    // 不应该走到这里
    0
}