<commit_before>use graphics::*;

// Local crate.
use Vector2d = vector2d::Vector2d;

static EPSILON: f64 = 0.0000000001;

pub fn area(contour: &[Vector2d]) -> f64 {
    let n = contour.len();
    let mut A = 0.0_f64;

    for i in range(0, n) {
        let q = i;
        let p = (i + n - 1) % n;
        A += contour.get(p).unwrap().get_x() * contour.get(q).unwrap().get_y()
            - contour.get(q).unwrap().get_x() * contour.get(p).unwrap().get_y();
    }

    A * 0.5_f64
}

/// InsideTriangle decides if a point P is Inside of the triangle
/// defined by A, B, C.
pub fn inside_triangle(
    Ax: f64, Ay: f64,
    Bx: f64, By: f64,
    Cx: f64, Cy: f64,
    Px: f64, Py: f64
) -> bool {

    let ax = Cx - Bx;
    let ay = Cy - By;
    let bx = Ax - Cx;
    let by = Ay - Cy;
    let cx = Bx - Ax;
    let cy = By - Ay;
    let apx = Px - Ax;
    let apy = Py - Ay;
    let bpx = Px - Bx;
    let bpy = Py - By;
    let cpx = Px - Cx;
    let cpy = Py - Cy;

    let aCROSSbp = ax*bpy - ay*bpx;
    let cCROSSap = cx*apy - cy*apx;
    let bCROSScp = bx*cpy - by*cpx;

    (
        (aCROSSbp >= 0.0_f64)
        && (bCROSScp >= 0.0_f64)
        && (cCROSSap >= 0.0_f64)
    )
}

pub fn snip(
    contour: &[Vector2d],
    triangle: [uint, ..3],
    n: uint,
    V: &mut Vec<uint>
) -> bool {
    let u = triangle[0];
    let v = triangle[1];
    let w = triangle[2];

    let Ax = contour.get(*V.get(u)).unwrap().get_x();
    let Ay = contour.get(*V.get(u)).unwrap().get_y();

    let Bx = contour.get(*V.get(v)).unwrap().get_x();
    let By = contour.get(*V.get(v)).unwrap().get_y();

    let Cx = contour.get(*V.get(w)).unwrap().get_x();
    let Cy = contour.get(*V.get(w)).unwrap().get_y();

    if EPSILON > (((Bx-Ax)*(Cy-Ay)) - ((By-Ay)*(Cx-Ax))) {
        return false;
    }

    for p in range(0, n) {
        if (p == u) || (p == v) || (p == w) { continue; }

        let Px = contour.get(*V.get(p)).unwrap().get_x();
        let Py = contour.get(*V.get(p)).unwrap().get_y();

        if inside_triangle(Ax,Ay,Bx,By,Cx,Cy,Px,Py) { return false; }
    }

    return true;
}

pub fn process(
    contour: &[Vector2d]
) -> Option<Vec<Vector2d>> {
    /* allocate and initialize list of Vertices in polygon */

    let n = contour.len();
    if n < 3 { return None; }

    let mut result: Vec<Vector2d> = Vec::new();
    let mut V: Vec<uint> = Vec::with_capacity(n);

    /* we want a counter-clockwise polygon in V */

    // Computes the area which has opposite signs
    // whether the polygon is clock-wise or counter-clockwise.
    if 0.0_f64 < area(contour) {
        for v in range(0, n) { V.push(v); }
    } else {
        for v in range(0, n) { V.push((n-1)-v); }
    }

    let mut number_of_vertices = n;

    /*  remove nv-2 Vertices, creating 1 triangle every time */
    let mut count = 2 * number_of_vertices;   /* error detection */

    let mut m = 0;
    let mut v = number_of_vertices - 1;
    while number_of_vertices > 2 {
        /* if we loop, it is probably a non-simple polygon */
        if count <= 0 {
            //** Triangulate: ERROR - probable bad polygon!
            return None;
        }

        count -= 1;

        /* three consecutive vertices in current polygon, <u,v,w> */
        let triangle = [
            v,
            vecmath::modular_offset_index(number_of_vertices, v, 1),
            vecmath::modular_offset_index(number_of_vertices, v, 2)
        ];
        v = triangle[1];

        if snip(contour, triangle, number_of_vertices, &mut V) {
            for &i in triangle.iter() {
                result.push(*contour.get(*V.get(i)).unwrap());
            }

            m += 1;

            /* remove v from remaining polygon */
            for i in range(0, number_of_vertices - 3) {
                let s = v + i;
                let t = v + i + 1;

                *V.get_mut(s) = *V.get(t);
            }

            // "Removed" a vertex.
            number_of_vertices -= 1;

            /* resest error detection counter */
            count = 2 * number_of_vertices;
        }
    }

    Some(result)
}

<commit_msg>Replace with better name<commit_after>use graphics::*;

// Local crate.
use Vector2d = vector2d::Vector2d;

static EPSILON: f64 = 0.0000000001;

pub fn area(contour: &[Vector2d]) -> f64 {
    let n = contour.len();
    let mut A = 0.0_f64;

    for i in range(0, n) {
        let q = i;
        let p = (i + n - 1) % n;
        A += contour.get(p).unwrap().get_x() * contour.get(q).unwrap().get_y()
            - contour.get(q).unwrap().get_x() * contour.get(p).unwrap().get_y();
    }

    A * 0.5_f64
}

/// InsideTriangle decides if a point P is Inside of the triangle
/// defined by A, B, C.
pub fn inside_triangle(
    Ax: f64, Ay: f64,
    Bx: f64, By: f64,
    Cx: f64, Cy: f64,
    Px: f64, Py: f64
) -> bool {

    let ax = Cx - Bx;
    let ay = Cy - By;
    let bx = Ax - Cx;
    let by = Ay - Cy;
    let cx = Bx - Ax;
    let cy = By - Ay;
    let apx = Px - Ax;
    let apy = Py - Ay;
    let bpx = Px - Bx;
    let bpy = Py - By;
    let cpx = Px - Cx;
    let cpy = Py - Cy;

    let aCROSSbp = ax*bpy - ay*bpx;
    let cCROSSap = cx*apy - cy*apx;
    let bCROSScp = bx*cpy - by*cpx;

    (
        (aCROSSbp >= 0.0_f64)
        && (bCROSScp >= 0.0_f64)
        && (cCROSSap >= 0.0_f64)
    )
}

pub fn snip(
    contour: &[Vector2d],
    triangle: [uint, ..3],
    n: uint,
    V: &mut Vec<uint>
) -> bool {
    let u = triangle[0];
    let v = triangle[1];
    let w = triangle[2];

    let Ax = contour.get(*V.get(u)).unwrap().get_x();
    let Ay = contour.get(*V.get(u)).unwrap().get_y();

    let Bx = contour.get(*V.get(v)).unwrap().get_x();
    let By = contour.get(*V.get(v)).unwrap().get_y();

    let Cx = contour.get(*V.get(w)).unwrap().get_x();
    let Cy = contour.get(*V.get(w)).unwrap().get_y();

    if EPSILON > (((Bx-Ax)*(Cy-Ay)) - ((By-Ay)*(Cx-Ax))) {
        return false;
    }

    for p in range(0, n) {
        if (p == u) || (p == v) || (p == w) { continue; }

        let Px = contour.get(*V.get(p)).unwrap().get_x();
        let Py = contour.get(*V.get(p)).unwrap().get_y();

        if inside_triangle(Ax,Ay,Bx,By,Cx,Cy,Px,Py) { return false; }
    }

    return true;
}

pub fn process(
    contour: &[Vector2d]
) -> Option<Vec<Vector2d>> {
    /* allocate and initialize list of Vertices in polygon */

    let n = contour.len();
    if n < 3 { return None; }

    let mut result: Vec<Vector2d> = Vec::new();
    let mut vertex_indices: Vec<uint> = Vec::with_capacity(n);

    /* we want a counter-clockwise polygon in V */

    // Computes the area which has opposite signs
    // whether the polygon is clock-wise or counter-clockwise.
    if 0.0_f64 < area(contour) {
        for v in range(0, n) { vertex_indices.push(v); }
    } else {
        for v in range(0, n) { vertex_indices.push((n-1)-v); }
    }

    let mut number_of_vertices = n;

    /*  remove nv-2 Vertices, creating 1 triangle every time */
    let mut count = 2 * number_of_vertices;   /* error detection */

    let mut m = 0;
    let mut v = number_of_vertices - 1;
    while number_of_vertices > 2 {
        /* if we loop, it is probably a non-simple polygon */
        if count <= 0 {
            //** Triangulate: ERROR - probable bad polygon!
            return None;
        }

        count -= 1;

        /* three consecutive vertices in current polygon, <u,v,w> */
        let triangle = [
            v,
            vecmath::modular_offset_index(number_of_vertices, v, 1),
            vecmath::modular_offset_index(number_of_vertices, v, 2)
        ];
        v = triangle[1];

        if snip(contour, triangle, number_of_vertices, &mut vertex_indices) {
            for &i in triangle.iter() {
                result.push(*contour.get(*vertex_indices.get(i)).unwrap());
            }

            m += 1;

            /* remove v from remaining polygon */
            for i in range(0, number_of_vertices - 3) {
                let s = v + i;
                let t = v + i + 1;

                *vertex_indices.get_mut(s) = *vertex_indices.get(t);
            }

            // "Removed" a vertex.
            number_of_vertices -= 1;

            /* resest error detection counter */
            count = 2 * number_of_vertices;
        }
    }

    Some(result)
}

<|endoftext|>


<commit_before>use crate::convert::TryInto;
use crate::fmt;
use crate::io;
use crate::mem;
use crate::ptr;

use crate::sys::process::process_common::*;
use crate::sys::process::zircon::{zx_handle_t, Handle};

use libc::{c_int, size_t};

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

impl Command {
    pub fn spawn(
        &mut self,
        default: Stdio,
        needs_stdin: bool,
    ) -> io::Result<(Process, StdioPipes)> {
        let envp = self.capture_env();

        if self.saw_nul() {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "nul byte found in provided data",
            ));
        }

        let (ours, theirs) = self.setup_io(default, needs_stdin)?;

        let process_handle = unsafe { self.do_exec(theirs, envp.as_ref())? };

        Ok((Process { handle: Handle::new(process_handle) }, ours))
    }

    pub fn exec(&mut self, default: Stdio) -> io::Error {
        if self.saw_nul() {
            return io::Error::new(io::ErrorKind::InvalidInput, "nul byte found in provided data");
        }

        match self.setup_io(default, true) {
            Ok((_, _)) => {
                // FIXME: This is tough because we don't support the exec syscalls
                unimplemented!();
            }
            Err(e) => e,
        }
    }

    unsafe fn do_exec(
        &mut self,
        stdio: ChildPipes,
        maybe_envp: Option<&CStringArray>,
    ) -> io::Result<zx_handle_t> {
        use crate::sys::process::zircon::*;

        let envp = match maybe_envp {
            // None means to clone the current environment, which is done in the
            // flags below.
            None => ptr::null(),
            Some(envp) => envp.as_ptr(),
        };

        let make_action = |local_io: &ChildStdio, target_fd| -> io::Result<fdio_spawn_action_t> {
            if let Some(local_fd) = local_io.fd() {
                Ok(fdio_spawn_action_t {
                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
                    local_fd,
                    target_fd,
                    ..Default::default()
                })
            } else {
                if let ChildStdio::Null = local_io {
                    // acts as no-op
                    return Ok(Default::default());
                }

                let mut handle = ZX_HANDLE_INVALID;
                let status = fdio_fd_clone(target_fd, &mut handle);
                if status == ERR_INVALID_ARGS || status == ERR_NOT_SUPPORTED {
                    // This descriptor is closed; skip it rather than generating an
                    // error.
                    return Ok(Default::default());
                }
                zx_cvt(status)?;

                let mut cloned_fd = 0;
                zx_cvt(fdio_fd_create(handle, &mut cloned_fd))?;

                Ok(fdio_spawn_action_t {
                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
                    local_fd: cloned_fd as i32,
                    target_fd,
                    ..Default::default()
                })
            }
        };

        // Clone stdin, stdout, and stderr
        let action1 = make_action(&stdio.stdin, 0)?;
        let action2 = make_action(&stdio.stdout, 1)?;
        let action3 = make_action(&stdio.stderr, 2)?;
        let actions = [action1, action2, action3];

        // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc
        // always consumes transferred file descriptors.
        mem::forget(stdio);

        for callback in self.get_closures().iter_mut() {
            callback()?;
        }

        let mut process_handle: zx_handle_t = 0;
        zx_cvt(fdio_spawn_etc(
            ZX_HANDLE_INVALID,
            FDIO_SPAWN_CLONE_JOB
                | FDIO_SPAWN_CLONE_LDSVC
                | FDIO_SPAWN_CLONE_NAMESPACE
                | FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null
                | FDIO_SPAWN_CLONE_UTC_CLOCK,
            self.get_program_cstr().as_ptr(),
            self.get_argv().as_ptr(),
            envp,
            actions.len() as size_t,
            actions.as_ptr(),
            &mut process_handle,
            ptr::null_mut(),
        ))?;
        // FIXME: See if we want to do something with that err_msg

        Ok(process_handle)
    }
}

////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////

pub struct Process {
    handle: Handle,
}

impl Process {
    pub fn id(&self) -> u32 {
        self.handle.raw() as u32
    }

    pub fn kill(&mut self) -> io::Result<()> {
        use crate::sys::process::zircon::*;

        unsafe {
            zx_cvt(zx_task_kill(self.handle.raw()))?;
        }

        Ok(())
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        use crate::default::Default;
        use crate::sys::process::zircon::*;

        let mut proc_info: zx_info_process_t = Default::default();
        let mut actual: size_t = 0;
        let mut avail: size_t = 0;

        unsafe {
            zx_cvt(zx_object_wait_one(
                self.handle.raw(),
                ZX_TASK_TERMINATED,
                ZX_TIME_INFINITE,
                ptr::null_mut(),
            ))?;
            zx_cvt(zx_object_get_info(
                self.handle.raw(),
                ZX_INFO_PROCESS,
                &mut proc_info as *mut _ as *mut libc::c_void,
                mem::size_of::<zx_info_process_t>(),
                &mut actual,
                &mut avail,
            ))?;
        }
        if actual != 1 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Failed to get exit status of process",
            ));
        }
        Ok(ExitStatus(proc_info.return_code))
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        use crate::default::Default;
        use crate::sys::process::zircon::*;

        let mut proc_info: zx_info_process_t = Default::default();
        let mut actual: size_t = 0;
        let mut avail: size_t = 0;

        unsafe {
            let status =
                zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED, 0, ptr::null_mut());
            match status {
                0 => {} // Success
                x if x == ERR_TIMED_OUT => {
                    return Ok(None);
                }
                _ => {
                    panic!("Failed to wait on process handle: {}", status);
                }
            }
            zx_cvt(zx_object_get_info(
                self.handle.raw(),
                ZX_INFO_PROCESS,
                &mut proc_info as *mut _ as *mut libc::c_void,
                mem::size_of::<zx_info_process_t>(),
                &mut actual,
                &mut avail,
            ))?;
        }
        if actual != 1 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Failed to get exit status of process",
            ));
        }
        Ok(Some(ExitStatus(proc_info.return_code)))
    }
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitStatus(i64);

impl ExitStatus {
    pub fn success(&self) -> bool {
        self.code() == Some(0)
    }

    pub fn code(&self) -> Option<i32> {
        // FIXME: support extracting return code as an i64
        self.0.try_into().ok()
    }

    pub fn signal(&self) -> Option<i32> {
        None
    }

    // FIXME: The actually-Unix implementation in process_unix.rs uses WSTOPSIG, WCOREDUMP et al.
    // I infer from the implementation of `success`, `code` and `signal` above that these are not
    // available on Fuchsia.
    //
    // It does not appear that Fuchsia is Unix-like enough to implement ExitStatus (or indeed many
    // other things from std::os::unix) properly.  This veneer is always going to be a bdoge.  So
    // while I don't know if these implementations are actually correct, I think they will do for
    // now at least.
    pub fn core_dumped(&self) -> bool {
        false
    }
    pub fn stopped_signal(&self) -> Option<i32> {
        None
    }
    pub fn continued(&self) -> bool {
        false
    }

    pub fn into_raw(&self) -> c_int {
        // We don't know what someone who calls into_raw() will do with this value, but it should
        // have the conventional Unix representation.  Despite the fact that this is not
        // standardised in SuS or POSIX, all Unix systems encode the signal and exit status the
        // same way.  (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every
        // Unix.)
        //
        // The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may
        // do their own shifting and masking, or even pass the status to another computer running a
        // different Unix variant.
        //
        // The other view would be to say that the caller on Fuchsia ought to know that `into_raw`
        // will give a raw Fuchsia status (whatever that is - I don't know, personally).  That is
        // not possible here becaause we must return a c_int because that's what Unix (including
        // SuS and POSIX) say a wait status is, but Fuchsia apparently uses a u64, so it won't
        // necessarily fit.
        //
        // It seems to me that that the right answer would be to provide std::os::fuchsia with its
        // own ExitStatusExt, rather that trying to provide a not very convincing imitation of
        // Unix.  Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia.  But
        // fixing this up that is beyond the scope of my efforts now.
        let exit_status_as_if_unix: u8 = self.0.try_into().expect("Fuchsia process return code bigger than 8 bits, but std::os::unix::ExitStatusExt::into_raw() was called to try to covert the value into a traditional Unix-style wait status, which cannot represent values greater than 255.");
        let wait_status_as_if_unix = (exit_status_as_if_unix as c_int) << 8;
        wait_status_as_if_unix
    }
}

/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
impl From<c_int> for ExitStatus {
    fn from(a: c_int) -> ExitStatus {
        ExitStatus(a as i64)
    }
}

impl fmt::Display for ExitStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "exit code: {}", self.0)
    }
}
<commit_msg>Fix typos in Fuchsia unix_process_wait_more<commit_after>use crate::convert::TryInto;
use crate::fmt;
use crate::io;
use crate::mem;
use crate::ptr;

use crate::sys::process::process_common::*;
use crate::sys::process::zircon::{zx_handle_t, Handle};

use libc::{c_int, size_t};

////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////

impl Command {
    pub fn spawn(
        &mut self,
        default: Stdio,
        needs_stdin: bool,
    ) -> io::Result<(Process, StdioPipes)> {
        let envp = self.capture_env();

        if self.saw_nul() {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "nul byte found in provided data",
            ));
        }

        let (ours, theirs) = self.setup_io(default, needs_stdin)?;

        let process_handle = unsafe { self.do_exec(theirs, envp.as_ref())? };

        Ok((Process { handle: Handle::new(process_handle) }, ours))
    }

    pub fn exec(&mut self, default: Stdio) -> io::Error {
        if self.saw_nul() {
            return io::Error::new(io::ErrorKind::InvalidInput, "nul byte found in provided data");
        }

        match self.setup_io(default, true) {
            Ok((_, _)) => {
                // FIXME: This is tough because we don't support the exec syscalls
                unimplemented!();
            }
            Err(e) => e,
        }
    }

    unsafe fn do_exec(
        &mut self,
        stdio: ChildPipes,
        maybe_envp: Option<&CStringArray>,
    ) -> io::Result<zx_handle_t> {
        use crate::sys::process::zircon::*;

        let envp = match maybe_envp {
            // None means to clone the current environment, which is done in the
            // flags below.
            None => ptr::null(),
            Some(envp) => envp.as_ptr(),
        };

        let make_action = |local_io: &ChildStdio, target_fd| -> io::Result<fdio_spawn_action_t> {
            if let Some(local_fd) = local_io.fd() {
                Ok(fdio_spawn_action_t {
                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
                    local_fd,
                    target_fd,
                    ..Default::default()
                })
            } else {
                if let ChildStdio::Null = local_io {
                    // acts as no-op
                    return Ok(Default::default());
                }

                let mut handle = ZX_HANDLE_INVALID;
                let status = fdio_fd_clone(target_fd, &mut handle);
                if status == ERR_INVALID_ARGS || status == ERR_NOT_SUPPORTED {
                    // This descriptor is closed; skip it rather than generating an
                    // error.
                    return Ok(Default::default());
                }
                zx_cvt(status)?;

                let mut cloned_fd = 0;
                zx_cvt(fdio_fd_create(handle, &mut cloned_fd))?;

                Ok(fdio_spawn_action_t {
                    action: FDIO_SPAWN_ACTION_TRANSFER_FD,
                    local_fd: cloned_fd as i32,
                    target_fd,
                    ..Default::default()
                })
            }
        };

        // Clone stdin, stdout, and stderr
        let action1 = make_action(&stdio.stdin, 0)?;
        let action2 = make_action(&stdio.stdout, 1)?;
        let action3 = make_action(&stdio.stderr, 2)?;
        let actions = [action1, action2, action3];

        // We don't want FileDesc::drop to be called on any stdio. fdio_spawn_etc
        // always consumes transferred file descriptors.
        mem::forget(stdio);

        for callback in self.get_closures().iter_mut() {
            callback()?;
        }

        let mut process_handle: zx_handle_t = 0;
        zx_cvt(fdio_spawn_etc(
            ZX_HANDLE_INVALID,
            FDIO_SPAWN_CLONE_JOB
                | FDIO_SPAWN_CLONE_LDSVC
                | FDIO_SPAWN_CLONE_NAMESPACE
                | FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null
                | FDIO_SPAWN_CLONE_UTC_CLOCK,
            self.get_program_cstr().as_ptr(),
            self.get_argv().as_ptr(),
            envp,
            actions.len() as size_t,
            actions.as_ptr(),
            &mut process_handle,
            ptr::null_mut(),
        ))?;
        // FIXME: See if we want to do something with that err_msg

        Ok(process_handle)
    }
}

////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////

pub struct Process {
    handle: Handle,
}

impl Process {
    pub fn id(&self) -> u32 {
        self.handle.raw() as u32
    }

    pub fn kill(&mut self) -> io::Result<()> {
        use crate::sys::process::zircon::*;

        unsafe {
            zx_cvt(zx_task_kill(self.handle.raw()))?;
        }

        Ok(())
    }

    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        use crate::default::Default;
        use crate::sys::process::zircon::*;

        let mut proc_info: zx_info_process_t = Default::default();
        let mut actual: size_t = 0;
        let mut avail: size_t = 0;

        unsafe {
            zx_cvt(zx_object_wait_one(
                self.handle.raw(),
                ZX_TASK_TERMINATED,
                ZX_TIME_INFINITE,
                ptr::null_mut(),
            ))?;
            zx_cvt(zx_object_get_info(
                self.handle.raw(),
                ZX_INFO_PROCESS,
                &mut proc_info as *mut _ as *mut libc::c_void,
                mem::size_of::<zx_info_process_t>(),
                &mut actual,
                &mut avail,
            ))?;
        }
        if actual != 1 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Failed to get exit status of process",
            ));
        }
        Ok(ExitStatus(proc_info.return_code))
    }

    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
        use crate::default::Default;
        use crate::sys::process::zircon::*;

        let mut proc_info: zx_info_process_t = Default::default();
        let mut actual: size_t = 0;
        let mut avail: size_t = 0;

        unsafe {
            let status =
                zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED, 0, ptr::null_mut());
            match status {
                0 => {} // Success
                x if x == ERR_TIMED_OUT => {
                    return Ok(None);
                }
                _ => {
                    panic!("Failed to wait on process handle: {}", status);
                }
            }
            zx_cvt(zx_object_get_info(
                self.handle.raw(),
                ZX_INFO_PROCESS,
                &mut proc_info as *mut _ as *mut libc::c_void,
                mem::size_of::<zx_info_process_t>(),
                &mut actual,
                &mut avail,
            ))?;
        }
        if actual != 1 {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "Failed to get exit status of process",
            ));
        }
        Ok(Some(ExitStatus(proc_info.return_code)))
    }
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitStatus(i64);

impl ExitStatus {
    pub fn success(&self) -> bool {
        self.code() == Some(0)
    }

    pub fn code(&self) -> Option<i32> {
        // FIXME: support extracting return code as an i64
        self.0.try_into().ok()
    }

    pub fn signal(&self) -> Option<i32> {
        None
    }

    // FIXME: The actually-Unix implementation in process_unix.rs uses WSTOPSIG, WCOREDUMP et al.
    // I infer from the implementation of `success`, `code` and `signal` above that these are not
    // available on Fuchsia.
    //
    // It does not appear that Fuchsia is Unix-like enough to implement ExitStatus (or indeed many
    // other things from std::os::unix) properly.  This veneer is always going to be a bodge.  So
    // while I don't know if these implementations are actually correct, I think they will do for
    // now at least.
    pub fn core_dumped(&self) -> bool {
        false
    }
    pub fn stopped_signal(&self) -> Option<i32> {
        None
    }
    pub fn continued(&self) -> bool {
        false
    }

    pub fn into_raw(&self) -> c_int {
        // We don't know what someone who calls into_raw() will do with this value, but it should
        // have the conventional Unix representation.  Despite the fact that this is not
        // standardised in SuS or POSIX, all Unix systems encode the signal and exit status the
        // same way.  (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every
        // Unix.)
        //
        // The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may
        // do their own shifting and masking, or even pass the status to another computer running a
        // different Unix variant.
        //
        // The other view would be to say that the caller on Fuchsia ought to know that `into_raw`
        // will give a raw Fuchsia status (whatever that is - I don't know, personally).  That is
        // not possible here becaause we must return a c_int because that's what Unix (including
        // SuS and POSIX) say a wait status is, but Fuchsia apparently uses a u64, so it won't
        // necessarily fit.
        //
        // It seems to me that that the right answer would be to provide std::os::fuchsia with its
        // own ExitStatusExt, rather that trying to provide a not very convincing imitation of
        // Unix.  Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia.  But
        // fixing this up that is beyond the scope of my efforts now.
        let exit_status_as_if_unix: u8 = self.0.try_into().expect("Fuchsia process return code bigger than 8 bits, but std::os::unix::ExitStatusExt::into_raw() was called to try to convert the value into a traditional Unix-style wait status, which cannot represent values greater than 255.");
        let wait_status_as_if_unix = (exit_status_as_if_unix as c_int) << 8;
        wait_status_as_if_unix
    }
}

/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
impl From<c_int> for ExitStatus {
    fn from(a: c_int) -> ExitStatus {
        ExitStatus(a as i64)
    }
}

impl fmt::Display for ExitStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "exit code: {}", self.0)
    }
}
<|endoftext|>


<commit_before>use tcod::colors::{Color};
use tcod::pathfinding::AStar;

use traits::{Renderable, Movable, Position};
use Direction;
use point::Point;
use map::Map;
use unit_type::UnitType;

use std::cmp::min;
use std::collections::VecDeque;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum AttackResult {
    Dead,
    Alive,
    NoEffect,
}

#[derive(Debug, PartialEq)]
pub struct Unit<'a> {
    position: Point<i16>,
    unit_type: &'a UnitType,
    cur_hp: u8,
}

impl<'a> Unit<'a> {
    pub fn new(pos: Point<i16>, unit_type: &'a UnitType) -> Unit<'a> {
        let cur_hp = unit_type.get_max_hp();
        Unit {
            position: pos,
            unit_type: unit_type,
            cur_hp: cur_hp,
        }
    }

    pub fn is_blocking(&self) -> bool {
        self.unit_type.get_is_blocking()
    }

    pub fn get_name(&self) -> &str {
        &self.unit_type.get_name()
    }

    pub fn get_hp(&self) -> u8 {
        self.cur_hp
    }

    fn get_step_towards(&mut self, map: &Map, npcs: &mut &VecDeque<Unit<'a>>, target: Point<i16>) -> Point<i16> {
        let mut path_map = map.get_pathfinding_map();

        for npc in npcs.iter() {
            if npc == self {
                continue;
            }

            let pos = npc.get_position();
            path_map.set(pos.x as i32, pos.y as i32, false, npc.is_blocking());
        }

        // We could (probably should) cache this, but with so few units in view
        // at any one time, we'll just re-calculate every turn.
        let mut path = AStar::new_from_map(path_map, 0.0);
        let cur_pos = self.get_position();
        path.find((cur_pos.x as i32, cur_pos.y as i32), (target.x as i32, target.y as i32));

        // Path length check is to stop the AI from walking way around the map.
        if !path.is_empty() && path.len() < 25 {
            let (x, y) = path.walk_one_step(true).expect("Pathfinding failed.");
            Point{ x: x as i16, y: y as i16}
        } else {
            // Old, bad, pathfinding as backup.
            let delta = target - cur_pos;
            let dist = delta.radius();

            let new_pos = Point {
                x: (delta.x as f64 / dist).round() as i16,
                y: (delta.y as f64 / dist).round() as i16,
            };
            new_pos + cur_pos
        }
    }

    pub fn take_turn(&mut self, map: &Map, mut npcs: &VecDeque<Unit<'a>>, player: &mut Unit) {
        if !map.point_in_fov(self.get_position()) {
            return;
        }

        if (self.get_position() - player.get_position()).radius() >= 2.0 {
            let new_pos = self.get_step_towards(map, &mut npcs, player.get_position());
            self.move_to(new_pos);
        } else if player.get_hp() > 0 {
            self.attack(player);
        }
    }

    pub fn take_damage(&mut self, damage: u8) -> AttackResult {
        if let Some(new_hp) = self.cur_hp.checked_sub(damage) {
            self.cur_hp = new_hp;
            AttackResult::Alive
        } else {
            self.cur_hp = 0;
            AttackResult::Dead
        }
    }

    pub fn attack(&self, target: &mut Unit) -> AttackResult {
        if let Some(damage) = self.unit_type.get_attack().checked_sub(target.unit_type.get_defence()) {
            println!("{} attacks {} for {} damage.", self.get_name(), target.get_name(), damage);
            target.take_damage(damage)
        } else {
            println!("{} attacks {}, but it has no effect!", self.get_name(), target.get_name());
            AttackResult::NoEffect
        }
    }

    pub fn heal(&mut self, amount: u8) {
        self.cur_hp = min(amount, self.unit_type.get_max_hp());
    }
}

impl<'a> Position for Unit<'a> {
    fn get_x(&self) -> i16 {
        self.position.x
    }

    fn get_y(&self) -> i16 {
        self.position.y
    }
}

impl<'a> Renderable for Unit<'a> {
    fn get_color(&self) -> Color {
        self.unit_type.get_color()
    }

    fn get_glyph(&self) -> char {
        self.unit_type.get_glyph()
    }
}

impl<'a> Movable for Unit<'a> {
    fn move_to(&mut self, pos: Point<i16>){
        self.position = pos;
    }
    fn nudge(&mut self, dir: Direction){
        self.position = self.position + dir.to_rel_point();
    }
}<commit_msg>Moved cache comment further up.<commit_after>use tcod::colors::{Color};
use tcod::pathfinding::AStar;

use traits::{Renderable, Movable, Position};
use Direction;
use point::Point;
use map::Map;
use unit_type::UnitType;

use std::cmp::min;
use std::collections::VecDeque;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum AttackResult {
    Dead,
    Alive,
    NoEffect,
}

#[derive(Debug, PartialEq)]
pub struct Unit<'a> {
    position: Point<i16>,
    unit_type: &'a UnitType,
    cur_hp: u8,
}

impl<'a> Unit<'a> {
    pub fn new(pos: Point<i16>, unit_type: &'a UnitType) -> Unit<'a> {
        let cur_hp = unit_type.get_max_hp();
        Unit {
            position: pos,
            unit_type: unit_type,
            cur_hp: cur_hp,
        }
    }

    pub fn is_blocking(&self) -> bool {
        self.unit_type.get_is_blocking()
    }

    pub fn get_name(&self) -> &str {
        &self.unit_type.get_name()
    }

    pub fn get_hp(&self) -> u8 {
        self.cur_hp
    }

    fn get_step_towards(&mut self, map: &Map, npcs: &mut &VecDeque<Unit<'a>>, target: Point<i16>) -> Point<i16> {
        // We could (probably should) cache this, but with so few units in view
        // at any one time, we'll just re-calculate every turn.
        let mut path_map = map.get_pathfinding_map();

        for npc in npcs.iter() {
            if npc == self {
                continue;
            }

            let pos = npc.get_position();
            path_map.set(pos.x as i32, pos.y as i32, false, npc.is_blocking());
        }

        let mut path = AStar::new_from_map(path_map, 0.0);
        let cur_pos = self.get_position();
        path.find((cur_pos.x as i32, cur_pos.y as i32), (target.x as i32, target.y as i32));

        // Path length check is to stop the AI from walking way around the map.
        if !path.is_empty() && path.len() < 25 {
            let (x, y) = path.walk_one_step(true).expect("Pathfinding failed.");
            Point{ x: x as i16, y: y as i16}
        } else {
            // Old, bad, pathfinding as backup.
            let delta = target - cur_pos;
            let dist = delta.radius();

            let new_pos = Point {
                x: (delta.x as f64 / dist).round() as i16,
                y: (delta.y as f64 / dist).round() as i16,
            };
            new_pos + cur_pos
        }
    }

    pub fn take_turn(&mut self, map: &Map, mut npcs: &VecDeque<Unit<'a>>, player: &mut Unit) {
        if !map.point_in_fov(self.get_position()) {
            return;
        }

        if (self.get_position() - player.get_position()).radius() >= 2.0 {
            let new_pos = self.get_step_towards(map, &mut npcs, player.get_position());
            self.move_to(new_pos);
        } else if player.get_hp() > 0 {
            self.attack(player);
        }
    }

    pub fn take_damage(&mut self, damage: u8) -> AttackResult {
        if let Some(new_hp) = self.cur_hp.checked_sub(damage) {
            self.cur_hp = new_hp;
            AttackResult::Alive
        } else {
            self.cur_hp = 0;
            AttackResult::Dead
        }
    }

    pub fn attack(&self, target: &mut Unit) -> AttackResult {
        if let Some(damage) = self.unit_type.get_attack().checked_sub(target.unit_type.get_defence()) {
            println!("{} attacks {} for {} damage.", self.get_name(), target.get_name(), damage);
            target.take_damage(damage)
        } else {
            println!("{} attacks {}, but it has no effect!", self.get_name(), target.get_name());
            AttackResult::NoEffect
        }
    }

    pub fn heal(&mut self, amount: u8) {
        self.cur_hp = min(amount, self.unit_type.get_max_hp());
    }
}

impl<'a> Position for Unit<'a> {
    fn get_x(&self) -> i16 {
        self.position.x
    }

    fn get_y(&self) -> i16 {
        self.position.y
    }
}

impl<'a> Renderable for Unit<'a> {
    fn get_color(&self) -> Color {
        self.unit_type.get_color()
    }

    fn get_glyph(&self) -> char {
        self.unit_type.get_glyph()
    }
}

impl<'a> Movable for Unit<'a> {
    fn move_to(&mut self, pos: Point<i16>){
        self.position = pos;
    }
    fn nudge(&mut self, dir: Direction){
        self.position = self.position + dir.to_rel_point();
    }
}<|endoftext|>


<commit_before>extern mod xlib;
extern mod cairo;

use azure::{AzDrawTargetRef, AzFloat, struct__AzRect, struct__AzColor};
use test::xlib::xlib::XExposeEvent;
use test::xlib::xlib::bindgen::{XOpenDisplay, XDefaultScreen, XRootWindow};
use test::xlib::xlib::bindgen::{XBlackPixel, XCreateSimpleWindow, XStoreName};
use test::xlib::xlib::bindgen::{XSelectInput, XCloseDisplay, XNextEvent, XDefaultVisual};
use test::xlib::xlib::bindgen::{XMapWindow};
use azure::bindgen::{AzCreateColorPattern, AzDrawTargetFillRect, AzReleaseColorPattern};
use azure::bindgen::{AzSanityCheck, AzCreateDrawTargetForCairoSurface, AzReleaseDrawTarget};
use azure::bindgen::{AzDrawTargetGetSize};
use test::cairo::cairo::{CAIRO_FORMAT_RGB24};
use test::cairo::cairo::bindgen::{cairo_image_surface_create, cairo_surface_destroy};
use test::cairo::cairo_xlib::bindgen::{cairo_xlib_surface_create};

use core::libc::{c_uint, c_long, c_int};

#[test]
fn sanity_check() {
    AzSanityCheck();
}

const SIZEX: c_uint = 400 as c_uint;
const SIZEY: c_uint = 400 as c_uint;

const ExposureMask: c_long = (1 << 15) as c_long;
const ButtonPressMask: c_long = (1 << 2) as c_long;

const Expose: c_int = 12 as c_int;
const ButtonPress: c_int = 4 as c_int;

type XEventStub = {
    type_: c_int,
    padding: (
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int,
        int, int, int, int, int, int, int, int
    )
};

fn xexpose(event: *XEventStub) -> *XExposeEvent {
    unsafe {
        cast::reinterpret_cast(&ptr::addr_of(&(*event).padding))
    }
}

#[test]
#[ignore]
fn cairo_it_up() {
    let dpy = XOpenDisplay(ptr::null());
    assert(ptr::is_not_null(dpy));
    let scr = XDefaultScreen(dpy);
    let rootwin = XRootWindow(dpy, scr);
    let win = XCreateSimpleWindow(
        dpy, rootwin, 1 as c_int, 1 as c_int, SIZEX, SIZEY, 0 as c_uint,
        XBlackPixel(dpy, scr), XBlackPixel(dpy, scr));
    str::as_c_str(~"test", |cstr| XStoreName(dpy, win, cstr));
    XSelectInput(dpy, win, ExposureMask | ButtonPressMask);
    XMapWindow(dpy, win);

    let cs = cairo_xlib_surface_create(
        dpy, win, XDefaultVisual(dpy, 0 as c_int),
        SIZEX as c_int, SIZEY as c_int);

    let e = {
        type_: 0 as c_int,
        padding: (
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        )
    };
    let ep = ptr::addr_of(&e);

    let dt = AzCreateDrawTargetForCairoSurface(cs, ptr::to_unsafe_ptr(&{ width: SIZEX as c_int, height: SIZEY as c_int }));

    loop {
        unsafe {
            XNextEvent(dpy, cast::reinterpret_cast(&ep));
            log(error, *ep);
            log(error, *xexpose(ep));
            if e.type_ == Expose && (*xexpose(ep)).count < 1 as c_int {
                paint(dt);
            } else if e.type_ == ButtonPress {
                break;
            } else {
                paint(dt);
            }
        }
    }

    AzReleaseDrawTarget(dt);
    cairo_surface_destroy(cs);
    XCloseDisplay(dpy);
}

fn paint(dt: AzDrawTargetRef) {
    log(error, "painting");
    let rect = struct__AzRect {
        x: 200f as AzFloat,
        y: 200f as AzFloat,
        width: 100f as AzFloat,
        height: 100f as AzFloat
    };
    let color = struct__AzColor {
        r: 0f as AzFloat,
        g: 1f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    unsafe {
        let pattern = AzCreateColorPattern(ptr::addr_of(&color));
        AzDrawTargetFillRect(
            dt,
            ptr::addr_of(&rect),
            cast::reinterpret_cast(&pattern));
        AzReleaseColorPattern(pattern);
    }
}

#[test]
#[ignore(reason="busted on linux 32 bit")]
fn test_draw_target_get_size() {
    use libc::types::common::c99::int32_t;
    let surface = cairo_image_surface_create(
        CAIRO_FORMAT_RGB24, 100 as c_int, 200 as c_int);
    assert surface.is_not_null();
    let dt = AzCreateDrawTargetForCairoSurface(surface, ptr::to_unsafe_ptr(&{ width: SIZEX as c_int, height: SIZEY as c_int }));
    assert dt.is_not_null();
    let size = AzDrawTargetGetSize(dt);
    assert size.width == 100 as int32_t;
    assert size.height == 200 as int32_t;
    AzReleaseDrawTarget(dt);
    cairo_surface_destroy(surface);
}

#[test]
#[ignore]
fn fonts() {
    use cairo;
    use cairo::cairo::*;
    use cairo::cairo::bindgen::*;

    let dpy = XOpenDisplay(ptr::null());
    assert(ptr::is_not_null(dpy));
    let scr = XDefaultScreen(dpy);
    let rootwin = XRootWindow(dpy, scr);
    let win = XCreateSimpleWindow(
        dpy, rootwin, 1 as c_int, 1 as c_int, SIZEX, SIZEY, 0 as c_uint,
        XBlackPixel(dpy, scr), XBlackPixel(dpy, scr));
    str::as_c_str(~"test", |cstr| XStoreName(dpy, win, cstr));
    XSelectInput(dpy, win, ExposureMask | ButtonPressMask);
    XMapWindow(dpy, win);

    let cs = cairo_xlib_surface_create(
        dpy, win, XDefaultVisual(dpy, 0 as c_int),
        SIZEX as c_int, SIZEY as c_int);

    let e = {
        type_: 0 as c_int,
        padding: (
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
        )
    };
    let ep = ptr::addr_of(&e);

    loop {
        unsafe {
            XNextEvent(dpy, cast::reinterpret_cast(&ep));
            log(error, *ep);
            log(error, *xexpose(ep));
            if e.type_ == Expose && (*xexpose(ep)).count < 1 as c_int {
                paint(cs);
            } else if e.type_ == ButtonPress {
                break;
            } else {
                paint(cs);
            }
        }
    }

    cairo_surface_destroy(cs);
    XCloseDisplay(dpy);

    fn paint(surf: *cairo_surface_t) {
        use libc::c_double;
        use cairo;
        use cairo::cairo::*;
        use cairo::cairo::bindgen::*;

        let cr: *cairo_t = cairo_create(surf);
        assert cr.is_not_null();

        cairo_set_source_rgb(cr, 0.5 as c_double, 0.1 as c_double, 0.1 as c_double);
        cairo_paint(cr);

        let te: cairo_text_extents_t = {
            x_bearing: 0 as c_double,
            y_bearing: 0 as c_double,
            width: 0 as c_double,
            height: 0 as c_double,
            x_advance: 0 as c_double,
            y_advance: 0 as c_double
        };
        cairo_set_source_rgb(cr, 0.9 as c_double, 0.5 as c_double, 0.5 as c_double);
        str::as_c_str(~"Georgia", |fontname| {
            cairo_select_font_face(cr, fontname, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
        });
        cairo_set_font_size(cr, 20.2 as c_double);
        str::as_c_str(~"a", |text| {
            cairo_text_extents(cr, text, ptr::addr_of(&te));
            cairo_move_to(
                cr,
                (100.0 + 0.5) as c_double -
                te.width / (2.0 as c_double) - te.x_bearing,
                (100.0 + 0.5) as c_double -
                te.height / (2.0 as c_double) - te.y_bearing);
            cairo_show_text(cr, text);
        });

        cairo_destroy(cr);
    }
}

<commit_msg>Fix tests<commit_after>use azure::bindgen::AzSanityCheck;

#[test]
fn sanity_check() {
    unsafe { AzSanityCheck() };
}
<|endoftext|>


<commit_before>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

fn read_char(rd: &mut MemReader) -> char {
  match rd.read_byte() {
    Some(b) => b as char,
    None => fail!()
  }
}

fn read_char_opt(rd: &mut MemReader) -> Option<char> {
  match rd.read_byte() {
    Some(b) => Some(b as char),
    None => None
  }
}

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>) // XXX: This is no value
}

// parse values recursivly
fn parse_value(rd: &mut MemReader) -> Value {
    enum State {
        st_value,
        st_number,
        st_got_number
    }

    let mut state: State = st_value;
    let mut val: ~str = ~"";

    loop {
        match state {
            st_value => {
                if rd.eof() { fail!() }
                let ch = read_char(rd);
                match ch {
                    '\r' | '\n' | ' ' | '\t' => { }
                    '0' .. '9' => {
                        val.push_char(ch);
                        state = st_number;
                    }
                    't' => {
                        assert!(read_char(rd) == 'r');
                        assert!(read_char(rd) == 'u');
                        assert!(read_char(rd) == 'e');
                        return True
                    }
                    'f' => {
                        assert!(read_char(rd) == 'a');
                        assert!(read_char(rd) == 'l');
                        assert!(read_char(rd) == 's');
                        assert!(read_char(rd) == 'e');
                        return False
                    }
                    '"' => {
                        loop {
                            let ch = read_char(rd);
                            if ch == '"' {
                                break;
                            }
                            val.push_char(ch);
                        }
                        return String(val)
                    }
                    _ => { fail!() }
                }
            }
            st_got_number => {
                return Unsigned(from_str(val).unwrap())
            }
            st_number => {
                if rd.eof() {
                    state = st_got_number;
                } else {
                    let ch = read_char(rd);
                    match ch {
                        '\r' | '\n' | ' ' | '\t' => { state = st_got_number }
                        '#' => { skip_comment(rd); state = st_got_number }
                        '0' .. '9' => {
                            val.push_char(ch);
                        }
                        _ => { fail!() }
                    }
                }
            }
        }
    }
}

// We must be already within the '#"
fn skip_comment(rd: &mut MemReader) {
    loop {
        if rd.eof() { return }
        match read_char(rd) {
            '\n' => { return }
            _ => { }
        }
    }
}

trait Visitor {
    fn section(&mut self, name: &str, is_array: bool) -> bool;
    fn pair(&mut self, key: &str, val: Value) -> bool;
}

struct TOMLVisitor {
    root: HashMap<~str, Value>,
    current_path: ~str,
    is_array: bool
}

impl TOMLVisitor {
    fn new() -> TOMLVisitor {
        TOMLVisitor { root: HashMap::new(), current_path: ~"", is_array: false }
    }
    fn get_root<'a>(&'a self) -> &'a HashMap<~str, Value> {
        return &self.root;
    }
}

impl Visitor for TOMLVisitor {
    fn section(&mut self, name: &str, is_array: bool) -> bool {
        debug!("Section: {} (is_array={})", name, is_array);
        self.is_array = is_array;
        self.current_path = name.to_owned();
        return true
    }
    fn pair(&mut self, key: &str, val: Value) -> bool {
        debug!("Pair: {} {:s}", key, val.to_str());
        let mut m = self.root.find_or_insert(self.current_path.clone(), Map(HashMap::new())); // XXX: remove clone
        match *m {
            Map(ref mut map) => {
                let ok = map.insert(key.to_owned(), val);
                return ok
            }
            _ => { return false }
        }
    }
}

fn parse<V: Visitor>(rd: &mut MemReader, visitor: &mut V) -> bool {
    enum State {
        st_toplevel,
        st_comment,
        st_section,
        st_section_or_double_section,
        st_double_section,
        st_ident,
        st_assign_wanted,
        st_value_wanted
    }

    let mut state = st_toplevel;
    let mut buf: ~str = ~"";

    let mut current_char: Option<char> = read_char_opt(rd);

    loop {
        match state {
            st_toplevel => {
                if current_char.is_none() { return true }
                let ch = current_char.unwrap();
                match ch {
                    // ignore whitespace
                    '\r' | '\n' | ' ' | '\t' => { }

                    // comment
                    '#' => { state = st_comment }

                    // section
                    '[' => { state = st_section_or_double_section }

                    // identifier
                    'a' .. 'z' | 'A' .. 'Z' | '_' => {
                        state = st_ident;
                        buf.push_char(ch)
                    }

                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_comment => {
                if current_char.is_none() { return true }
                match current_char.unwrap() {
                    '\n' => { state = st_toplevel }
                    _ => { }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_section_or_double_section => {
                if current_char.is_none() { return false }
                let ch = current_char.unwrap();
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_'=> {
                        buf.push_char(ch);
                        state = st_section;
                    }
                    '[' => {
                        state = st_double_section;
                    }
                    ']' => {
                        // empty section
                        assert!(buf.len() == 0);
                        visitor.section(buf, false);
                        buf.truncate(0);
                        state = st_toplevel;
                    }
                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_double_section => {
                if current_char.is_none() { return false }
                let ch = current_char.unwrap();
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_'=> {
                        buf.push_char(ch);
                    }
                    ']' => {
                        current_char = read_char_opt(rd); // advance
                        match current_char {
                            Some(']') => {}
                            _         => {return false} // error
                        }
                        visitor.section(buf, true);
                        buf.truncate(0);
                        state = st_toplevel;
                    }
                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_section => {
                if current_char.is_none() { return false }
                let ch = current_char.unwrap();
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_'=> {
                        buf.push_char(ch);
                    }
                    ']' => {
                        visitor.section(buf, false);
                        buf.truncate(0);
                        state = st_toplevel;
                    }
                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_ident => {
                if current_char.is_none() { return false }
                let ch = current_char.unwrap();
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_'=> {
                        buf.push_char(ch);
                    }

                    '\r' | '\n' | ' ' | '\t' => { state = st_assign_wanted }

                    '=' => { state = st_value_wanted }

                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_assign_wanted => {
                if current_char.is_none() { return false }
                match current_char.unwrap() {
                    '\r' | '\n' | ' ' | '\t' => { }
                    '=' => { state = st_value_wanted }
                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_value_wanted => {
                visitor.pair(buf, parse_value(rd));
                buf.truncate(0);
                state = st_toplevel;
                current_char = read_char_opt(rd); // advance
            }
        }
    }

    assert!(false);
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut rd = MemReader::new(contents);
  let mut visitor = TOMLVisitor::new();
  parse(&mut rd, &mut visitor);
  println!("{:s}", visitor.get_root().to_str());
}
<commit_msg>Get rid of st_comment<commit_after>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

fn read_char(rd: &mut MemReader) -> char {
  match rd.read_byte() {
    Some(b) => b as char,
    None => fail!()
  }
}

fn read_char_opt(rd: &mut MemReader) -> Option<char> {
  match rd.read_byte() {
    Some(b) => Some(b as char),
    None => None
  }
}

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>) // XXX: This is no value
}

// parse values recursivly
fn parse_value(rd: &mut MemReader) -> Value {
    enum State {
        st_value,
        st_number,
        st_got_number
    }

    let mut state: State = st_value;
    let mut val: ~str = ~"";

    loop {
        match state {
            st_value => {
                if rd.eof() { fail!() }
                let ch = read_char(rd);
                match ch {
                    '\r' | '\n' | ' ' | '\t' => { }
                    '0' .. '9' => {
                        val.push_char(ch);
                        state = st_number;
                    }
                    't' => {
                        assert!(read_char(rd) == 'r');
                        assert!(read_char(rd) == 'u');
                        assert!(read_char(rd) == 'e');
                        return True
                    }
                    'f' => {
                        assert!(read_char(rd) == 'a');
                        assert!(read_char(rd) == 'l');
                        assert!(read_char(rd) == 's');
                        assert!(read_char(rd) == 'e');
                        return False
                    }
                    '"' => {
                        loop {
                            let ch = read_char(rd);
                            if ch == '"' {
                                break;
                            }
                            val.push_char(ch);
                        }
                        return String(val)
                    }
                    _ => { fail!() }
                }
            }
            st_got_number => {
                return Unsigned(from_str(val).unwrap())
            }
            st_number => {
                if rd.eof() {
                    state = st_got_number;
                } else {
                    let ch = read_char(rd);
                    match ch {
                        '\r' | '\n' | ' ' | '\t' => { state = st_got_number }
                        '#' => { skip_comment(rd); state = st_got_number }
                        '0' .. '9' => {
                            val.push_char(ch);
                        }
                        _ => { fail!() }
                    }
                }
            }
        }
    }
}

// We must be already within the '#"
fn skip_comment(rd: &mut MemReader) {
    loop {
        if rd.eof() { return }
        match read_char(rd) {
            '\n' => { return }
            _ => { }
        }
    }
}

trait Visitor {
    fn section(&mut self, name: &str, is_array: bool) -> bool;
    fn pair(&mut self, key: &str, val: Value) -> bool;
}

struct TOMLVisitor {
    root: HashMap<~str, Value>,
    current_path: ~str,
    is_array: bool
}

impl TOMLVisitor {
    fn new() -> TOMLVisitor {
        TOMLVisitor { root: HashMap::new(), current_path: ~"", is_array: false }
    }
    fn get_root<'a>(&'a self) -> &'a HashMap<~str, Value> {
        return &self.root;
    }
}

impl Visitor for TOMLVisitor {
    fn section(&mut self, name: &str, is_array: bool) -> bool {
        debug!("Section: {} (is_array={})", name, is_array);
        self.is_array = is_array;
        self.current_path = name.to_owned();
        return true
    }
    fn pair(&mut self, key: &str, val: Value) -> bool {
        debug!("Pair: {} {:s}", key, val.to_str());
        let mut m = self.root.find_or_insert(self.current_path.clone(), Map(HashMap::new())); // XXX: remove clone
        match *m {
            Map(ref mut map) => {
                let ok = map.insert(key.to_owned(), val);
                return ok
            }
            _ => { return false }
        }
    }
}

fn parse<V: Visitor>(rd: &mut MemReader, visitor: &mut V) -> bool {
    enum State {
        st_toplevel,
        st_section,
        st_section_or_double_section,
        st_double_section,
        st_ident,
        st_assign_wanted,
        st_value_wanted
    }

    let mut state = st_toplevel;
    let mut buf: ~str = ~"";

    let mut current_char: Option<char> = read_char_opt(rd);

    loop {
        match state {
            st_toplevel => {
                if current_char.is_none() { return true }
                let ch = current_char.unwrap();
                match ch {
                    // ignore whitespace
                    '\r' | '\n' | ' ' | '\t' => { }

                    // comment
                    '#' => {
                        // skip to end of line
                        loop {
                            current_char = read_char_opt(rd);
                            match current_char {
                                Some('\n') => { break }
                                None => { return true }
                                _ => { /* skip */ }
                            }
                        }
                    }

                    // section
                    '[' => { state = st_section_or_double_section }

                    // identifier
                    'a' .. 'z' | 'A' .. 'Z' | '_' => {
                        state = st_ident;
                        buf.push_char(ch)
                    }

                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_section_or_double_section => {
                if current_char.is_none() { return false }
                let ch = current_char.unwrap();
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_'=> {
                        buf.push_char(ch);
                        state = st_section;
                    }
                    '[' => {
                        state = st_double_section;
                    }
                    ']' => {
                        // empty section
                        assert!(buf.len() == 0);
                        visitor.section(buf, false);
                        buf.truncate(0);
                        state = st_toplevel;
                    }
                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_double_section => {
                if current_char.is_none() { return false }
                let ch = current_char.unwrap();
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_'=> {
                        buf.push_char(ch);
                    }
                    ']' => {
                        current_char = read_char_opt(rd); // advance
                        match current_char {
                            Some(']') => {}
                            _         => {return false} // error
                        }
                        visitor.section(buf, true);
                        buf.truncate(0);
                        state = st_toplevel;
                    }
                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_section => {
                if current_char.is_none() { return false }
                let ch = current_char.unwrap();
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_'=> {
                        buf.push_char(ch);
                    }
                    ']' => {
                        visitor.section(buf, false);
                        buf.truncate(0);
                        state = st_toplevel;
                    }
                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_ident => {
                if current_char.is_none() { return false }
                let ch = current_char.unwrap();
                match ch {
                    'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_'=> {
                        buf.push_char(ch);
                    }

                    '\r' | '\n' | ' ' | '\t' => { state = st_assign_wanted }

                    '=' => { state = st_value_wanted }

                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_assign_wanted => {
                if current_char.is_none() { return false }
                match current_char.unwrap() {
                    '\r' | '\n' | ' ' | '\t' => { }
                    '=' => { state = st_value_wanted }
                    _ => { return false }
                }
                current_char = read_char_opt(rd); // advance
            }
            st_value_wanted => {
                visitor.pair(buf, parse_value(rd));
                buf.truncate(0);
                state = st_toplevel;
                current_char = read_char_opt(rd); // advance
            }
        }
    }

    assert!(false);
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut rd = MemReader::new(contents);
  let mut visitor = TOMLVisitor::new();
  parse(&mut rd, &mut visitor);
  println!("{:s}", visitor.get_root().to_str());
}
<|endoftext|>


<commit_before>use core::intrinsics;

// NOTE This function and the ones below are implemented using assembly because they using a custom
// calling convention which can't be implemented using a normal Rust function
#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_uidivmod() {
    asm!("push {lr}
          sub sp, sp, #4
          mov r2, sp
          bl __udivmodsi4
          ldr r1, [sp]
          add sp, sp, #4
          pop {pc}");
    intrinsics::unreachable();
}

#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_uldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __udivmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}");
    intrinsics::unreachable();
}

#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_idivmod() {
    asm!("push {r0, r1, r4, lr}
          bl __divsi3
          pop {r1, r2}
          muls r2, r2, r0
          subs r1, r1, r2
          pop {r4, pc}");
    intrinsics::unreachable();
}

#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_ldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __divmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}");
    intrinsics::unreachable();
}

// TODO: These two functions should be defined as aliases
#[cfg_attr(not(test), no_mangle)]
pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 {
    ::int::udiv::__udivsi3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 {
    ::int::sdiv::__divsi3(a, b)
}

extern "C" {
    fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
    fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
    fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8;
}

// FIXME: The `*4` and `*8` variants should be defined as aliases.

#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}

#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}

// Note the different argument order
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}

#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memclr(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}

#[cfg(test)]
mod tests {
    use quickcheck::TestResult;
    use qc::{U32, U64};

    quickcheck!{
        fn uldivmod(n: U64, d: U64) -> TestResult {
            let (n, d) = (n.0, d.0);
            if d == 0 {
                TestResult::discard()
            } else {
                let q: u64;
                let r: u64;
                unsafe {
                    // The inline asm is a bit tricky here, LLVM will allocate
                    // both r0 and r1 when we specify a 64-bit value for {r0}.
                    asm!("bl __aeabi_uldivmod"
                         : "={r0}" (q), "={r2}" (r)
                         : "{r0}" (n), "{r2}" (d)
                         : "r12", "lr", "flags");
                }
                TestResult::from_bool(q == n / d && r == n % d)
            }
        }

        fn uidivmod(n: U32, d: U32) -> TestResult {
            let (n, d) = (n.0, d.0);
            if d == 0 {
                TestResult::discard()
            } else {
                let q: u32;
                let r: u32;
                unsafe {
                    asm!("bl __aeabi_uidivmod"
                         : "={r0}" (q), "={r1}" (r)
                         : "{r0}" (n), "{r1}" (d)
                         : "r2", "r3", "r12", "lr", "flags");
                }
                TestResult::from_bool(q == n / d && r == n % d)
            }
        }

        fn ldivmod(n: U64, d: U64) -> TestResult {
            let (n, d) = (n.0 as i64, d.0 as i64);
            if d == 0 {
                TestResult::discard()
            } else {
                let q: i64;
                let r: i64;
                unsafe {
                    // The inline asm is a bit tricky here, LLVM will allocate
                    // both r0 and r1 when we specify a 64-bit value for {r0}.
                    asm!("bl __aeabi_ldivmod"
                         : "={r0}" (q), "={r2}" (r)
                         : "{r0}" (n), "{r2}" (d)
                         : "r12", "lr", "flags");
                }
                TestResult::from_bool(q == n / d && r == n % d)
            }
        }

        fn idivmod(n: U32, d: U32) -> TestResult {
            let (n, d) = (n.0 as i32, d.0 as i32);
            if d == 0 {
                TestResult::discard()
            } else {
                let q: i32;
                let r: i32;
                unsafe {
                    asm!("bl __aeabi_idivmod"
                         : "={r0}" (q), "={r1}" (r)
                         : "{r0}" (n), "{r1}" (d)
                         : "r2", "r3", "r12", "lr", "flags");
                }
                TestResult::from_bool(q == n / d && r == n % d)
            }
        }
    }
}
<commit_msg>avoid division overflow in idivmod test<commit_after>use core::intrinsics;

// NOTE This function and the ones below are implemented using assembly because they using a custom
// calling convention which can't be implemented using a normal Rust function
#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_uidivmod() {
    asm!("push {lr}
          sub sp, sp, #4
          mov r2, sp
          bl __udivmodsi4
          ldr r1, [sp]
          add sp, sp, #4
          pop {pc}");
    intrinsics::unreachable();
}

#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_uldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __udivmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}");
    intrinsics::unreachable();
}

#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_idivmod() {
    asm!("push {r0, r1, r4, lr}
          bl __divsi3
          pop {r1, r2}
          muls r2, r2, r0
          subs r1, r1, r2
          pop {r4, pc}");
    intrinsics::unreachable();
}

#[naked]
#[cfg_attr(not(test), no_mangle)]
pub unsafe fn __aeabi_ldivmod() {
    asm!("push {r4, lr}
          sub sp, sp, #16
          add r4, sp, #8
          str r4, [sp]
          bl __divmoddi4
          ldr r2, [sp, #8]
          ldr r3, [sp, #12]
          add sp, sp, #16
          pop {r4, pc}");
    intrinsics::unreachable();
}

// TODO: These two functions should be defined as aliases
#[cfg_attr(not(test), no_mangle)]
pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 {
    ::int::udiv::__udivsi3(a, b)
}

#[cfg_attr(not(test), no_mangle)]
pub extern "C" fn __aeabi_idiv(a: i32, b: i32) -> i32 {
    ::int::sdiv::__divsi3(a, b)
}

extern "C" {
    fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
    fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
    fn memset(dest: *mut u8, c: i32, n: usize) -> *mut u8;
}

// FIXME: The `*4` and `*8` variants should be defined as aliases.

#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memcpy8(dest: *mut u8, src: *const u8, n: usize) {
    memcpy(dest, src, n);
}

#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memmove(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memmove4(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memmove8(dest: *mut u8, src: *const u8, n: usize) {
    memmove(dest, src, n);
}

// Note the different argument order
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memset8(dest: *mut u8, n: usize, c: i32) {
    memset(dest, c, n);
}

#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memclr(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memclr4(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}
#[cfg_attr(not(test), no_mangle)]
pub unsafe extern "C" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
    memset(dest, 0, n);
}

#[cfg(test)]
mod tests {
    use quickcheck::TestResult;
    use qc::{U32, U64};

    quickcheck!{
        fn uldivmod(n: U64, d: U64) -> TestResult {
            let (n, d) = (n.0, d.0);
            if d == 0 {
                TestResult::discard()
            } else {
                let q: u64;
                let r: u64;
                unsafe {
                    // The inline asm is a bit tricky here, LLVM will allocate
                    // both r0 and r1 when we specify a 64-bit value for {r0}.
                    asm!("bl __aeabi_uldivmod"
                         : "={r0}" (q), "={r2}" (r)
                         : "{r0}" (n), "{r2}" (d)
                         : "r12", "lr", "flags");
                }
                TestResult::from_bool(q == n / d && r == n % d)
            }
        }

        fn uidivmod(n: U32, d: U32) -> TestResult {
            let (n, d) = (n.0, d.0);
            if d == 0 {
                TestResult::discard()
            } else {
                let q: u32;
                let r: u32;
                unsafe {
                    asm!("bl __aeabi_uidivmod"
                         : "={r0}" (q), "={r1}" (r)
                         : "{r0}" (n), "{r1}" (d)
                         : "r2", "r3", "r12", "lr", "flags");
                }
                TestResult::from_bool(q == n / d && r == n % d)
            }
        }

        fn ldivmod(n: U64, d: U64) -> TestResult {
            let (n, d) = (n.0 as i64, d.0 as i64);
            if d == 0 {
                TestResult::discard()
            } else {
                let q: i64;
                let r: i64;
                unsafe {
                    // The inline asm is a bit tricky here, LLVM will allocate
                    // both r0 and r1 when we specify a 64-bit value for {r0}.
                    asm!("bl __aeabi_ldivmod"
                         : "={r0}" (q), "={r2}" (r)
                         : "{r0}" (n), "{r2}" (d)
                         : "r12", "lr", "flags");
                }
                TestResult::from_bool(q == n / d && r == n % d)
            }
        }

        fn idivmod(n: U32, d: U32) -> TestResult {
            let (n, d) = (n.0 as i32, d.0 as i32);
            if d == 0 || (n == i32::min_value() && d == -1) {
                TestResult::discard()
            } else {
                let q: i32;
                let r: i32;
                unsafe {
                    asm!("bl __aeabi_idivmod"
                         : "={r0}" (q), "={r1}" (r)
                         : "{r0}" (n), "{r1}" (d)
                         : "r2", "r3", "r12", "lr", "flags");
                }
                TestResult::from_bool(q == n / d && r == n % d)
            }
        }
    }
}
<|endoftext|>