<commit_before>use byteorder::{ByteOrder, NativeEndian};

pub struct GlulxStack {
    frame_ptr: u32,
    stack: Vec<u8>,
}

impl GlulxStack {
    pub fn new(size: u32) -> GlulxStack {
        GlulxStack {
            frame_ptr: 0x0,
            stack: vec![0x0; size as usize],
        }
    }

    pub fn push_call_stub(&mut self,
            dest_type: u32,
            dest_addr: u32,
            program_counter: u32) {
        self.push(dest_type);
        self.push(dest_addr);
        self.push(program_counter);
        let frame_ptr = self.frame_ptr;
        self.push(frame_ptr);
    }

    pub fn pop_call_stub(&mut self) -> (u32, u32, u32) {
        self.frame_ptr = self.pop();

        let (
            program_counter,
            dest_addr,
            dest_type,
        ) = (self.pop(), self.pop(), self.pop());

        (dest_type, dest_addr, program_counter)
    }

    pub fn pop_call_frame(&mut self) {
        let frame_ptr = self.frame_ptr;
        self.stack.resize(frame_ptr as usize, 0x0);
    }

    pub fn push_call_frame_c0(&mut self,
            locals: Vec<u8>,
            args: Vec<u32>) {
        self.frame_ptr = self.stack.len() as u32;

        let locals_len: u32 = locals.chunks(0x2)
            .map(|pair| pair.into_iter()
                .map(|&val| val as u32)
                .product::<u32>())
            .sum();

        let mut locals = locals;
        if locals.len() & 0x3 != 0 {
            locals.push(0x0);
            locals.push(0x0);
        }
        let locals = locals;

        let local_pos = locals.len() as u32;
        let frame_len = local_pos + locals_len;

        self.push(frame_len);
        self.push(local_pos);
        self.stack.extend(locals);

        for arg in args.into_iter().rev() {
            self.push(arg);
        }
    }

    pub fn push_call_frame_c1(&mut self,
            locals: Vec<u8>,
            args: Vec<u32>) {
        self.frame_ptr = self.stack.len() as u32;

        /// placeholder values
        self.push(0x0u32);
        self.push(0x0u32);

        self.stack.extend(locals.clone());

        while self.stack.len() & 0x3 != 0 {
            self.stack.push(0x0);
        }

        let local_pos = self.stack.len() as u32;
        NativeEndian::write_u32(
            &mut self.stack[self.frame_ptr as usize + 0x4..],
            local_pos);

        let mut args = args;
        for pair in locals.chunks(0x2) {
            let (local_type, local_count) = (pair[0], pair[1]);

            match local_type {
                1 => {
                    for _ in 0x0..local_count {
                        if args.len() != 0 {
                            self.push(args.pop().unwrap() as u8);
                        } else {
                            self.push(0x0u8);
                        }
                    }
                },
                2 => {
                    if self.stack.len() & 0x1  != 0 { self.stack.push(0x0) };
                    for _ in 0x0..local_count {
                        if args.len() != 0 {
                            self.push(args.pop().unwrap() as u16);
                        } else {
                            self.push(0x0u16);
                        }
                    }
                }
                4 => {
                    while self.stack.len() & 0x3  != 0x0 {
                        self.push(0x0);
                    };
                    for _ in 0x0..local_count {
                        if args.len() != 0 {
                            self.push(args.pop().unwrap());
                        } else {
                            self.push(0x0u32);
                        }
                    }
                },
                _ => {},
            }
        }
        let args = args;

        while self.stack.len() & 0x3 != 0x0 { self.push(0x0) };

        let frame_len = self.stack.len() as u32;
        NativeEndian::write_u32(
            &mut self.stack[self.frame_ptr as usize..],
            frame_len);
    }

    pub fn pop_args(&mut self, nargs: u32) -> Vec<u32> {
        let mut vec = Vec::new();
        for x in 0x0..nargs {
            vec.push(self.pop());
        }
        vec
    }
}

pub trait Stack<T> {
    fn push(&mut self, val: T);
    fn pop(&mut self) -> T;
    fn peek(&self) -> T;
    fn read(& self, offset: u32) -> T;
    fn write(&mut self, offset: u32,  val: T);
}

impl Stack<u8> for GlulxStack {

    /// take a `u8` and push onto the stack.
    fn push(&mut self, val: u8) {
        self.stack.push(val);
    }

    /// pop a `u8` from the stack.
    fn pop(&mut self) -> u8 {
        self.stack.pop().unwrap()
    }

    fn peek(&self) -> u8 {
        let pos = self.stack.len() - 0x4;
        NativeEndian::read_u32(&self.stack[pos..]) as u8
    }

    fn read(&self, offset: u32) -> u8 {
        0
    }

    // Writes a u8 as normal
    fn write(&mut self, offset: u32, val: u8) {
    }
}

impl Stack<u16> for GlulxStack {

    /// take a `u16` and push onto the stack.
    fn push(&mut self, val: u16) {
        let pos = self.stack.len();
        for _ in 0x0..0x4 { self.stack.push(0) };
        NativeEndian::write_u16(&mut self.stack[pos..], val);
    }

    /// pop a `u16` from the stack.
    fn pop(&mut self) -> u16 {
        let pos = self.stack.len() - 0x2;
        let ret = NativeEndian::read_u16(&self.stack[pos..]);
        for _ in 0x0..0x2 { self.stack.pop(); };
        ret
    }

    fn peek(&self) -> u16 {
        let pos = self.stack.len() - 0x2;
        NativeEndian::read_u16(&self.stack[pos..])
    }

    fn read(&self, offset: u32) -> u16 {
        0
    }

    // Writes a u16 as normal
    fn write(&mut self, offset: u32, val: u16) {
    }
}

impl Stack<i32> for GlulxStack {
    fn push(&mut self, val: i32) {
        let pos = self.stack.len();
        for _ in 0x0..0x4 { self.stack.push(0) };
        NativeEndian::write_i32(&mut self.stack[pos..], val);
    }

    fn pop(&mut self) -> i32 {
        let pos = self.stack.len() - 0x4;
        let ret = NativeEndian::read_i32(&self.stack[pos..]);
        for _ in 0x0..0x4 { self.stack.pop(); };
        ret
    }

    fn peek(&self) -> i32 {
        let pos = self.stack.len() - 0x4;
        NativeEndian::read_i32(&self.stack[pos..])
    }

    fn read(&self, offset: u32) -> i32 {
        0
    }

    fn write(&mut self, offset: u32, val: i32) {
    }
}

impl Stack<u32> for GlulxStack {
    fn push(&mut self, val: u32) {
        let pos = self.stack.len();
        for _ in 0x0..0x4 { self.stack.push(0) };
        NativeEndian::write_u32(&mut self.stack[pos..], val);
    }

    fn pop(&mut self) -> u32 {
        let pos = self.stack.len() - 0x4;
        let ret = NativeEndian::read_u32(&self.stack[pos..]);
        for _ in 0x0..0x4 { self.stack.pop(); };
        ret
    }

    fn peek(&self) -> u32 {
        let pos = self.stack.len() - 0x4;
        NativeEndian::read_u32(&self.stack[pos..])
    }

    fn read(&self, offset: u32) -> u32 {
        0
    }

    fn write(&mut self, offset: u32, val: u32) {
    }
}

impl Stack<f32> for GlulxStack {
    /// push a `f32` onto the stack.
    fn push(&mut self, val: f32) {
        let pos = self.stack.len();
        for _ in 0x0..0x4 { self.stack.push(0) };
        NativeEndian::write_f32(&mut self.stack[pos..], val);
    }

    /// pop a `f32` off the stack.
    fn pop(&mut self) -> f32 {
        let pos = self.stack.len() - 0x4;
        let ret = NativeEndian::read_f32(&self.stack[pos..]);
        for _ in 0x0..0x4 { self.stack.pop(); };
        ret
    }

    fn peek(&self) -> f32 {
        let pos = self.stack.len() - 0x4;
        NativeEndian::read_f32(&self.stack[pos..])
    }

    fn read(&self, offset: u32) -> f32 {
        0.
    }

    fn write(&mut self, offset: u32, val: f32) {
    }
}
<commit_msg>replaced unimplemented read and write functions in the stack with a call to unimplemented so that progress through games would not appear deceptive<commit_after>use byteorder::{ByteOrder, NativeEndian};

pub struct GlulxStack {
    frame_ptr: u32,
    stack: Vec<u8>,
}

impl GlulxStack {
    pub fn new(size: u32) -> GlulxStack {
        GlulxStack {
            frame_ptr: 0x0,
            stack: vec![0x0; size as usize],
        }
    }

    pub fn push_call_stub(&mut self,
            dest_type: u32,
            dest_addr: u32,
            program_counter: u32) {
        self.push(dest_type);
        self.push(dest_addr);
        self.push(program_counter);
        let frame_ptr = self.frame_ptr;
        self.push(frame_ptr);
    }

    pub fn pop_call_stub(&mut self) -> (u32, u32, u32) {
        self.frame_ptr = self.pop();

        let (
            program_counter,
            dest_addr,
            dest_type,
        ) = (self.pop(), self.pop(), self.pop());

        (dest_type, dest_addr, program_counter)
    }

    pub fn pop_call_frame(&mut self) {
        let frame_ptr = self.frame_ptr;
        self.stack.resize(frame_ptr as usize, 0x0);
    }

    pub fn push_call_frame_c0(&mut self,
            locals: Vec<u8>,
            args: Vec<u32>) {
        self.frame_ptr = self.stack.len() as u32;

        let locals_len: u32 = locals.chunks(0x2)
            .map(|pair| pair.into_iter()
                .map(|&val| val as u32)
                .product::<u32>())
            .sum();

        let mut locals = locals;
        if locals.len() & 0x3 != 0 {
            locals.push(0x0);
            locals.push(0x0);
        }
        let locals = locals;

        let local_pos = locals.len() as u32;
        let frame_len = local_pos + locals_len;

        self.push(frame_len);
        self.push(local_pos);
        self.stack.extend(locals);

        for arg in args.into_iter().rev() {
            self.push(arg);
        }
    }

    pub fn push_call_frame_c1(&mut self,
            locals: Vec<u8>,
            args: Vec<u32>) {
        self.frame_ptr = self.stack.len() as u32;

        /// placeholder values
        self.push(0x0u32);
        self.push(0x0u32);

        self.stack.extend(locals.clone());

        while self.stack.len() & 0x3 != 0 {
            self.stack.push(0x0);
        }

        let local_pos = self.stack.len() as u32;
        NativeEndian::write_u32(
            &mut self.stack[self.frame_ptr as usize + 0x4..],
            local_pos);

        let mut args = args;
        for pair in locals.chunks(0x2) {
            let (local_type, local_count) = (pair[0], pair[1]);

            match local_type {
                1 => {
                    for _ in 0x0..local_count {
                        if args.len() != 0 {
                            self.push(args.pop().unwrap() as u8);
                        } else {
                            self.push(0x0u8);
                        }
                    }
                },
                2 => {
                    if self.stack.len() & 0x1  != 0 { self.stack.push(0x0) };
                    for _ in 0x0..local_count {
                        if args.len() != 0 {
                            self.push(args.pop().unwrap() as u16);
                        } else {
                            self.push(0x0u16);
                        }
                    }
                }
                4 => {
                    while self.stack.len() & 0x3  != 0x0 {
                        self.push(0x0);
                    };
                    for _ in 0x0..local_count {
                        if args.len() != 0 {
                            self.push(args.pop().unwrap());
                        } else {
                            self.push(0x0u32);
                        }
                    }
                },
                _ => {},
            }
        }
        let args = args;

        while self.stack.len() & 0x3 != 0x0 { self.push(0x0) };

        let frame_len = self.stack.len() as u32;
        NativeEndian::write_u32(
            &mut self.stack[self.frame_ptr as usize..],
            frame_len);
    }

    pub fn pop_args(&mut self, nargs: u32) -> Vec<u32> {
        let mut vec = Vec::new();
        for x in 0x0..nargs {
            vec.push(self.pop());
        }
        vec
    }
}

pub trait Stack<T> {
    fn push(&mut self, val: T);
    fn pop(&mut self) -> T;
    fn peek(&self) -> T;
    fn read(& self, offset: u32) -> T;
    fn write(&mut self, offset: u32,  val: T);
}

impl Stack<u8> for GlulxStack {

    /// take a `u8` and push onto the stack.
    fn push(&mut self, val: u8) {
        self.stack.push(val);
    }

    /// pop a `u8` from the stack.
    fn pop(&mut self) -> u8 {
        self.stack.pop().unwrap()
    }

    fn peek(&self) -> u8 {
        let pos = self.stack.len() - 0x4;
        NativeEndian::read_u32(&self.stack[pos..]) as u8
    }

    fn read(&self, offset: u32) -> u8 {
        unimplemented!()
    }

    // Writes a u8 as normal
    fn write(&mut self, offset: u32, val: u8) {
        unimplemented!()
    }
}

impl Stack<u16> for GlulxStack {

    /// take a `u16` and push onto the stack.
    fn push(&mut self, val: u16) {
        let pos = self.stack.len();
        for _ in 0x0..0x4 { self.stack.push(0) };
        NativeEndian::write_u16(&mut self.stack[pos..], val);
    }

    /// pop a `u16` from the stack.
    fn pop(&mut self) -> u16 {
        let pos = self.stack.len() - 0x2;
        let ret = NativeEndian::read_u16(&self.stack[pos..]);
        for _ in 0x0..0x2 { self.stack.pop(); };
        ret
    }

    fn peek(&self) -> u16 {
        let pos = self.stack.len() - 0x2;
        NativeEndian::read_u16(&self.stack[pos..])
    }

    fn read(&self, offset: u32) -> u16 {
        unimplemented!()
    }

    // Writes a u16 as normal
    fn write(&mut self, offset: u32, val: u16) {
        unimplemented!()
    }
}

impl Stack<i32> for GlulxStack {
    fn push(&mut self, val: i32) {
        let pos = self.stack.len();
        for _ in 0x0..0x4 { self.stack.push(0) };
        NativeEndian::write_i32(&mut self.stack[pos..], val);
    }

    fn pop(&mut self) -> i32 {
        let pos = self.stack.len() - 0x4;
        let ret = NativeEndian::read_i32(&self.stack[pos..]);
        for _ in 0x0..0x4 { self.stack.pop(); };
        ret
    }

    fn peek(&self) -> i32 {
        let pos = self.stack.len() - 0x4;
        NativeEndian::read_i32(&self.stack[pos..])
    }

    fn read(&self, offset: u32) -> i32 {
        unimplemented!()
    }

    fn write(&mut self, offset: u32, val: i32) {
        unimplemented!()
    }
}

impl Stack<u32> for GlulxStack {
    fn push(&mut self, val: u32) {
        let pos = self.stack.len();
        for _ in 0x0..0x4 { self.stack.push(0) };
        NativeEndian::write_u32(&mut self.stack[pos..], val);
    }

    fn pop(&mut self) -> u32 {
        let pos = self.stack.len() - 0x4;
        let ret = NativeEndian::read_u32(&self.stack[pos..]);
        for _ in 0x0..0x4 { self.stack.pop(); };
        ret
    }

    fn peek(&self) -> u32 {
        let pos = self.stack.len() - 0x4;
        NativeEndian::read_u32(&self.stack[pos..])
    }

    fn read(&self, offset: u32) -> u32 {
        unimplemented!()
    }

    fn write(&mut self, offset: u32, val: u32) {
        unimplemented!()
    }
}

impl Stack<f32> for GlulxStack {
    /// push a `f32` onto the stack.
    fn push(&mut self, val: f32) {
        let pos = self.stack.len();
        for _ in 0x0..0x4 { self.stack.push(0) };
        NativeEndian::write_f32(&mut self.stack[pos..], val);
    }

    /// pop a `f32` off the stack.
    fn pop(&mut self) -> f32 {
        let pos = self.stack.len() - 0x4;
        let ret = NativeEndian::read_f32(&self.stack[pos..]);
        for _ in 0x0..0x4 { self.stack.pop(); };
        ret
    }

    fn peek(&self) -> f32 {
        let pos = self.stack.len() - 0x4;
        NativeEndian::read_f32(&self.stack[pos..])
    }

    fn read(&self, offset: u32) -> f32 {
        unimplemented!()
    }

    fn write(&mut self, offset: u32, val: f32) {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>use expr::*;
use std::collections::HashMap;
use runtime_error::RuntimeError;

#[derive(Clone, Debug)]
pub struct State {
  pub mem: Vec<HashMap<String, Binding>>,
}

#[derive(Clone, Debug)]
pub enum Binding {
  Var(Box<Expr>),
  Const(Box<Expr>),
}

impl State {
  pub fn new() -> State {
    return State {
      mem: vec!(HashMap::new()),
    }
  }

  fn first_map_for(&mut self, x: String) -> Option<&mut HashMap<String, Binding>> {
    self.mem.iter_mut().rev().find(|map| map.contains_key(&x))
  }

  pub fn alloc(&mut self, x: String, v1: Expr) -> Result<(), RuntimeError> {
    let binding = Binding::Var(Box::new(v1));

    match self.mem.last_mut() {
      Some(map) => {
        map.insert(x, binding);
        Ok(())
      },
      None => Err(RuntimeError::InvalidMemoryState("no memory frame for var allocation".to_string())),
    }
  }

  pub fn alloc_const(&mut self, x: String, v1: Expr) ->Result<(), RuntimeError> {
    let binding = Binding::Const(Box::new(v1));

    match self.mem.last_mut() {
      Some(map) => {
        map.insert(x, binding);
        Ok(())
      },
      None => return Err(RuntimeError::InvalidMemoryState("no memory frame for const allocation".to_string())),
    }
  }

  pub fn assign(&mut self, x: String, v1: Expr) -> Result<(), RuntimeError> {
    let mut map_option = self.first_map_for(x.clone());

    let map = match map_option.as_mut() {
      Some(m) => m,
      None => return Err(RuntimeError::InvalidConstAssignment(v1, x)),
    };

    let binding = match map.get_mut(&x) {
      Some(b) => b.clone(),
      None => return Err(RuntimeError::InvalidConstAssignment(v1, x)),
    };

    match binding {
      Binding::Var(_) => map.insert(x, Binding::Var(Box::new(v1))),
      Binding::Const(_) => return Err(RuntimeError::InvalidConstAssignment(v1, x)),
    };
    Ok(())
  }

  pub fn get(&mut self, x: String) -> Option<Expr> {
    match self.first_map_for(x.clone()) {
      Some(map) => match map.get(&x).clone() {
        Some(&Binding::Var(ref e)) => Some(*e.clone()),
        Some(&Binding::Const(ref e)) => Some(*e.clone()),
        _ => None,
      },
      None => None,
    }
  }

  pub fn begin_scope(&mut self) {
    self.mem.push(HashMap::new());
  }

  pub fn end_scope(&mut self) {
    self.mem.pop();
  }
}
<commit_msg>tighten unused import<commit_after>use expr::Expr;
use std::collections::HashMap;
use runtime_error::RuntimeError;

#[derive(Clone, Debug)]
pub struct State {
  pub mem: Vec<HashMap<String, Binding>>,
}

#[derive(Clone, Debug)]
pub enum Binding {
  Var(Box<Expr>),
  Const(Box<Expr>),
}

impl State {
  pub fn new() -> State {
    return State {
      mem: vec!(HashMap::new()),
    }
  }

  fn first_map_for(&mut self, x: String) -> Option<&mut HashMap<String, Binding>> {
    self.mem.iter_mut().rev().find(|map| map.contains_key(&x))
  }

  pub fn alloc(&mut self, x: String, v1: Expr) -> Result<(), RuntimeError> {
    let binding = Binding::Var(Box::new(v1));

    match self.mem.last_mut() {
      Some(map) => {
        map.insert(x, binding);
        Ok(())
      },
      None => Err(RuntimeError::InvalidMemoryState("no memory frame for var allocation".to_string())),
    }
  }

  pub fn alloc_const(&mut self, x: String, v1: Expr) ->Result<(), RuntimeError> {
    let binding = Binding::Const(Box::new(v1));

    match self.mem.last_mut() {
      Some(map) => {
        map.insert(x, binding);
        Ok(())
      },
      None => return Err(RuntimeError::InvalidMemoryState("no memory frame for const allocation".to_string())),
    }
  }

  pub fn assign(&mut self, x: String, v1: Expr) -> Result<(), RuntimeError> {
    let mut map_option = self.first_map_for(x.clone());

    let map = match map_option.as_mut() {
      Some(m) => m,
      None => return Err(RuntimeError::InvalidConstAssignment(v1, x)),
    };

    let binding = match map.get_mut(&x) {
      Some(b) => b.clone(),
      None => return Err(RuntimeError::InvalidConstAssignment(v1, x)),
    };

    match binding {
      Binding::Var(_) => map.insert(x, Binding::Var(Box::new(v1))),
      Binding::Const(_) => return Err(RuntimeError::InvalidConstAssignment(v1, x)),
    };
    Ok(())
  }

  pub fn get(&mut self, x: String) -> Option<Expr> {
    match self.first_map_for(x.clone()) {
      Some(map) => match map.get(&x).clone() {
        Some(&Binding::Var(ref e)) => Some(*e.clone()),
        Some(&Binding::Const(ref e)) => Some(*e.clone()),
        _ => None,
      },
      None => None,
    }
  }

  pub fn begin_scope(&mut self) {
    self.mem.push(HashMap::new());
  }

  pub fn end_scope(&mut self) {
    self.mem.pop();
  }
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

#![allow(unused_must_use)]

include!("bindings.rs");

use std::os::raw::c_char;
use std::io::Write;
use std::os::unix::io::FromRawFd;
use std::os::unix::io::IntoRawFd;
use std::io::Read;

#[derive(PartialEq)]
enum PrintState {
    OUT,
    IN,
    DISPLAY
}

fn print_ptr_rec<W: Write>(port: &mut W, p: ptr, state: PrintState) {
    let x = p as u32;
    if  (x & fx_mask) == fx_tag {
        write!(port, "{}", (x as i32) >> fx_shift);
    } else if x == bool_f {
        write!(port, "#f");
    } else if x == bool_t {
        write!(port, "#t");
    } else if x == list_nil {
        write!(port, "()");
    } else if x == eof_obj {
        write!(port, "#!eof");
    } else if (x & char_mask) == char_tag {
        let c = std::char::from_u32(x >> char_shift).
            expect("a char");
        if state == PrintState::DISPLAY {
            write!(port, "{}", c);
        } else {
            if      c == '\t' { write!(port, "#\\tab"); }
            else if c == '\n' { write!(port, "#\\newline"); }
            else if c == '\r' { write!(port, "#\\return"); }
            else if c == ' '  { write!(port, "#\\space"); }
            else              { write!(port, "#\\{}", c); }
        }
    } else if (x & obj_mask) == pair_tag {
        if state == PrintState::OUT { write!(port, "("); }
        let cell = unsafe { *((x-pair_tag) as *const cell) };
        let car = cell.car;
        print_ptr_rec(port, car, PrintState::OUT);
        let cdr = cell.cdr;
        if cdr != list_nil {
            if (cdr & obj_mask) != pair_tag {
                write!(port, " . ");
                print_ptr_rec(port, cdr, PrintState::OUT);
            } else {
                write!(port, " ");
                print_ptr_rec(port, cdr, PrintState::IN);
            }
        }
        if state == PrintState::OUT { write!(port, ")"); }
    } else if (x & obj_mask) == vector_tag {
        write!(port, "#(");
        unsafe {
        let p = &*((x-vector_tag) as *const vector);
        let n = (p.length as i32) >> fx_shift;
        for i in 0..n {
            if i > 0 { write!(port, " "); }
            print_ptr_rec(port,
                *((p.buf.as_ptr()).add(i as usize)),
                PrintState::OUT)
        }}
        write!(port, ")");
    } else if (x & obj_mask) == string_tag {
        if state == PrintState::OUT { write!(port, "\""); }
        unsafe {
        let p = &*((x-string_tag) as *const string);
        let n = (p.length as i32) >> fx_shift;
        for i in 0..n {
            let c = std::char::from_u32(*((p.buf.as_ptr()).add(i as usize)) as u32)
                .expect("char");
            if c == '"'       { write!(port, "\\\""); }
            else if c == '\\' { write!(port, "\\\\"); }
            else              { write!(port, "{}", c); }
        }}
        if state == PrintState::OUT { write!(port, "\""); }
    } else if (x & obj_mask) == symbol_tag {
        print_ptr_rec(port, (x - symbol_tag) | string_tag, PrintState::IN);
    } else if (x & obj_mask) == closure_tag {
        write!(port, "#<procedure>");
    } else {
        write!(port, "#<unknown 0x{:x}>", x);
    }
}
fn print_ptr(x: ptr) {
    print_ptr_rec(&mut std::io::stdout(), x, PrintState::OUT);
    println!();
}

fn eprint_ptr(msg: ptr, state: PrintState) {
    print_ptr_rec(&mut std::io::stderr(), msg, state);
}

#[no_mangle]
pub extern "C" fn ik_log(msg: ptr) -> ptr {
    eprint!("log: ");
    eprint_ptr(msg, PrintState::IN);
    eprintln!();
    0
}
#[no_mangle]
pub extern "C" fn ik_error(x: ptr) {
    eprint!("Exception");
    if (x & obj_mask) == pair_tag {
        let cell = unsafe { *((x-pair_tag) as *const cell) };
        let caller = cell.car;
        let msg = cell.cdr;
        if caller != bool_f {
            eprint!(" in ");
            eprint_ptr(caller, PrintState::OUT);
        }
        eprint!(": ");
        eprint_ptr(msg, PrintState::IN);
    }
    eprintln!();
    std::process::exit(0);
}

fn unshift(x: ptr) -> i32 {
    (x as i32) >> fx_shift
}
fn shift(x: i32) -> ptr {
    (x << fx_shift) as u32
}
fn ptr_string_to_str(x: ptr) -> String {
    unsafe {
        let p = &*((x-string_tag) as *const string);
        let n = unshift(p.length) as usize;
        let mut v = Vec::with_capacity(n);
        for i in 0..n {
            v.push(*(p.buf.as_ptr().add(i as usize)) as u8);
        }
        std::ffi::CString::from_vec_unchecked(v).into_string().expect("string")
    }
}
#[no_mangle]
pub extern "C" fn s_write(fd: ptr, str: ptr, len: ptr) -> ptr {
    let s = ptr_string_to_str(str);
    let len = unshift(len) as usize;
    let s: String = s.chars().take(len).collect();
    let ufd = unshift(fd) as i32;
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    write!(w, "{}", s);
    w.flush();
    w.into_raw_fd();
    shift(s.len() as i32)
}
#[no_mangle]
pub extern "C" fn s_open_write(fname: ptr) -> ptr {
    let s_fname = ptr_string_to_str(fname);
    let port = std::fs::File::create(s_fname).expect("created");
    let fd = port.into_raw_fd();
    shift(fd)
}
#[no_mangle]
pub extern "C" fn s_fflush(fd: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    w.flush();
    w.into_raw_fd();
    0
}
#[no_mangle]
pub extern "C" fn scheme_write(fd: ptr, x: ptr, opt: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let state = unshift(opt);
    let state =
        if state == 0 { PrintState::OUT }
    else if state == 1 { PrintState::IN }
    else { PrintState :: DISPLAY };
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    print_ptr_rec(&mut w, x, state);
    w.flush();
    w.into_raw_fd();
    0
}
#[no_mangle]
pub extern "C" fn s_open_read(fname: ptr) -> ptr {
    let s_fname = ptr_string_to_str(fname);
    let port = std::fs::File::open(s_fname).expect("opened");
    let fd = port.into_raw_fd();
    shift(fd)
}
#[no_mangle]
pub extern "C" fn s_read_char(fd: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    let mut b = [0; 1];
    w.read_exact(&mut b);
    let v = if b[0] == 0 { eof_obj }
        else { ((b[0] as u32) << char_shift) | char_tag };
    w.into_raw_fd();
    v
}
#[no_mangle]
pub extern "C" fn s_close(fd: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let w = unsafe { std::fs::File::from_raw_fd(ufd) };
    std::mem::drop(w);
    shift(0)
}

#[no_mangle]
pub extern "C" fn heap_alloc(mem: *mut memory, _stack: *mut c_char, size: usize) -> *mut c_char {
    let heap_next = unsafe {*mem}.heap_next;
    let heap_new = unsafe { heap_next.add(size) };
    if heap_new >= unsafe {*mem}.heap_top {
        eprintln!("Exception: overflow");
        std::process::exit(0);
    }
    unsafe {(*mem).heap_next = heap_new};
    return heap_next;
}

fn allocate_protected_space(size: usize) -> *mut c_char {
    let mut v = Vec::with_capacity(size);
    let ptr = v.as_mut_ptr();
    std::mem::forget(v);
    ptr
}

fn deallocate_protected_space(p: *mut c_char, size: usize) {
    unsafe { std::mem::drop(Vec::from_raw_parts(p, 0, size)) };
}

fn main() {
    let stack_size = 16 * 4096;
    let heap_size = 4 * 16 * 4096;
    let global_size = 16 * 4096;
    let scratch_size = 16 * 4096;

    let stack_top = allocate_protected_space(stack_size);
    let stack_base = unsafe { stack_top.add(stack_size) };

    let heap = allocate_protected_space(heap_size);
    let global = allocate_protected_space(global_size);
    let scratch = allocate_protected_space(scratch_size);

    let uninit = 0 as (*mut std::os::raw::c_void);

    let mut ctxt = context {
        eax : uninit,
        ebx : uninit,
        ecx : uninit,
        edx : uninit,
        esi : uninit,
        edi : uninit,
        ebp : uninit,
        esp : uninit,
    };

    let heap_top = unsafe { heap.add(heap_size/2) };
    let mut mem = memory {
        heap_next : heap,
        global_next : global,
        heap_base : heap,
        heap_top : heap_top,
        heap_base_alt : heap_top,
        heap_top_alt : unsafe { heap.add(heap_size) },
        global_base : global,
        stack_base : stack_base,
        scratch_base : scratch,
        edi : 0
    };

    let r = unsafe {
        scheme_entry(&mut ctxt, stack_base, &mut mem)
    };
    print_ptr(r);

    deallocate_protected_space(stack_top, stack_size);
    deallocate_protected_space(heap, stack_size);
}
<commit_msg>first stab at gc in rust<commit_after>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

#![allow(unused_must_use)]
#![allow(unused_variables)]

include!("bindings.rs");

use std::os::raw::c_char;
use std::io::Write;
use std::os::unix::io::FromRawFd;
use std::os::unix::io::IntoRawFd;
use std::io::Read;

#[derive(PartialEq)]
enum PrintState {
    OUT,
    IN,
    DISPLAY
}

fn print_ptr_rec<W: Write>(port: &mut W, p: ptr, state: PrintState) {
    let x = p as u32;
    if  (x & fx_mask) == fx_tag {
        write!(port, "{}", (x as i32) >> fx_shift);
    } else if x == bool_f {
        write!(port, "#f");
    } else if x == bool_t {
        write!(port, "#t");
    } else if x == list_nil {
        write!(port, "()");
    } else if x == eof_obj {
        write!(port, "#!eof");
    } else if (x & char_mask) == char_tag {
        let c = std::char::from_u32(x >> char_shift).
            expect("a char");
        if state == PrintState::DISPLAY {
            write!(port, "{}", c);
        } else {
            if      c == '\t' { write!(port, "#\\tab"); }
            else if c == '\n' { write!(port, "#\\newline"); }
            else if c == '\r' { write!(port, "#\\return"); }
            else if c == ' '  { write!(port, "#\\space"); }
            else              { write!(port, "#\\{}", c); }
        }
    } else if (x & obj_mask) == pair_tag {
        if state == PrintState::OUT { write!(port, "("); }
        let cell = unsafe { *((x-pair_tag) as *const cell) };
        let car = cell.car;
        print_ptr_rec(port, car, PrintState::OUT);
        let cdr = cell.cdr;
        if cdr != list_nil {
            if (cdr & obj_mask) != pair_tag {
                write!(port, " . ");
                print_ptr_rec(port, cdr, PrintState::OUT);
            } else {
                write!(port, " ");
                print_ptr_rec(port, cdr, PrintState::IN);
            }
        }
        if state == PrintState::OUT { write!(port, ")"); }
    } else if (x & obj_mask) == vector_tag {
        write!(port, "#(");
        unsafe {
        let p = &*((x-vector_tag) as *const vector);
        let n = (p.length as i32) >> fx_shift;
        for i in 0..n {
            if i > 0 { write!(port, " "); }
            print_ptr_rec(port,
                *((p.buf.as_ptr()).add(i as usize)),
                PrintState::OUT)
        }}
        write!(port, ")");
    } else if (x & obj_mask) == string_tag {
        if state == PrintState::OUT { write!(port, "\""); }
        unsafe {
        let p = &*((x-string_tag) as *const string);
        let n = (p.length as i32) >> fx_shift;
        for i in 0..n {
            let c = std::char::from_u32(*((p.buf.as_ptr()).add(i as usize)) as u32)
                .expect("char");
            if c == '"'       { write!(port, "\\\""); }
            else if c == '\\' { write!(port, "\\\\"); }
            else              { write!(port, "{}", c); }
        }}
        if state == PrintState::OUT { write!(port, "\""); }
    } else if (x & obj_mask) == symbol_tag {
        print_ptr_rec(port, (x - symbol_tag) | string_tag, PrintState::IN);
    } else if (x & obj_mask) == closure_tag {
        write!(port, "#<procedure>");
    } else {
        write!(port, "#<unknown 0x{:x}>", x);
    }
}
fn print_ptr(x: ptr) {
    print_ptr_rec(&mut std::io::stdout(), x, PrintState::OUT);
    println!();
}

fn eprint_ptr(msg: ptr, state: PrintState) {
    print_ptr_rec(&mut std::io::stderr(), msg, state);
}

#[no_mangle]
pub extern "C" fn ik_log(msg: ptr) -> ptr {
    eprint!("log: ");
    eprint_ptr(msg, PrintState::IN);
    eprintln!();
    0
}
#[no_mangle]
pub extern "C" fn ik_error(x: ptr) {
    eprint!("Exception");
    if (x & obj_mask) == pair_tag {
        let cell = unsafe { *((x-pair_tag) as *const cell) };
        let caller = cell.car;
        let msg = cell.cdr;
        if caller != bool_f {
            eprint!(" in ");
            eprint_ptr(caller, PrintState::OUT);
        }
        eprint!(": ");
        eprint_ptr(msg, PrintState::IN);
    }
    eprintln!();
    std::process::exit(0);
}

fn unshift(x: ptr) -> i32 {
    (x as i32) >> fx_shift
}
fn shift(x: i32) -> ptr {
    (x << fx_shift) as u32
}
fn ptr_string_to_str(x: ptr) -> String {
    unsafe {
        let p = &*((x-string_tag) as *const string);
        let n = unshift(p.length) as usize;
        let mut v = Vec::with_capacity(n);
        for i in 0..n {
            v.push(*(p.buf.as_ptr().add(i as usize)) as u8);
        }
        std::ffi::CString::from_vec_unchecked(v).into_string().expect("string")
    }
}
#[no_mangle]
pub extern "C" fn s_write(fd: ptr, str: ptr, len: ptr) -> ptr {
    let s = ptr_string_to_str(str);
    let len = unshift(len) as usize;
    let s: String = s.chars().take(len).collect();
    let ufd = unshift(fd) as i32;
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    write!(w, "{}", s);
    w.flush();
    w.into_raw_fd();
    shift(s.len() as i32)
}
#[no_mangle]
pub extern "C" fn s_open_write(fname: ptr) -> ptr {
    let s_fname = ptr_string_to_str(fname);
    let port = std::fs::File::create(s_fname).expect("created");
    let fd = port.into_raw_fd();
    shift(fd)
}
#[no_mangle]
pub extern "C" fn s_fflush(fd: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    w.flush();
    w.into_raw_fd();
    0
}
#[no_mangle]
pub extern "C" fn scheme_write(fd: ptr, x: ptr, opt: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let state = unshift(opt);
    let state =
        if state == 0 { PrintState::OUT }
    else if state == 1 { PrintState::IN }
    else { PrintState :: DISPLAY };
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    print_ptr_rec(&mut w, x, state);
    w.flush();
    w.into_raw_fd();
    0
}
#[no_mangle]
pub extern "C" fn s_open_read(fname: ptr) -> ptr {
    let s_fname = ptr_string_to_str(fname);
    let port = std::fs::File::open(s_fname).expect("opened");
    let fd = port.into_raw_fd();
    shift(fd)
}
#[no_mangle]
pub extern "C" fn s_read_char(fd: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let mut w = unsafe { std::fs::File::from_raw_fd(ufd) };
    let mut b = [0; 1];
    w.read_exact(&mut b);
    let v = if b[0] == 0 { eof_obj }
        else { ((b[0] as u32) << char_shift) | char_tag };
    w.into_raw_fd();
    v
}
#[no_mangle]
pub extern "C" fn s_close(fd: ptr) -> ptr {
    let ufd = unshift(fd) as i32;
    let w = unsafe { std::fs::File::from_raw_fd(ufd) };
    std::mem::drop(w);
    shift(0)
}

fn gc_align(n: usize) -> usize {
  let cell = 1 << obj_shift;
  (((n + cell - 1)/cell) * cell) as usize
}

fn gc_ptr_object(x: ptr) -> bool {
    let tag = x & obj_mask;
    match tag {
        pair_tag |
        vector_tag |
        symbol_tag |
        string_tag |
        closure_tag => true,
        _ => false
    }
}
fn gc_size(x: ptr) -> usize {
    let tag = x & obj_mask;
    let p = x-tag;
    match tag {
        pair_tag => 2 << word_shift,
        vector_tag => {
            let n = shift(unsafe{(&*(p as *const vector)).length} as i32) + 1;
            (n as usize) << word_shift
        },
        symbol_tag | string_tag =>
            (shift(unsafe{(&*(p as *const string)).length} as i32) + word_size) as usize,
        closure_tag => {
            let n = shift(unsafe{(&*(p as *const closure)).length} as i32) + 2;
            (n as usize) << word_shift
        },
        _ => 0
    }
}

static mut gc_new_heap_base: *mut c_char = 0 as *mut c_char;
static mut gc_new_heap_top: *mut c_char = 0 as *mut c_char;
static mut gc_next: *mut c_char = 0 as *mut c_char;
static mut gc_queue: *mut ptr = 0 as *mut ptr;

fn gc_get_forward_pointer(p: *mut c_char) -> *mut c_char {
    let x = unsafe{*p as ptr};
    if x != gc_forward_mark { return 0 as *mut c_char; }
    let q = unsafe{*((p as *mut ptr).add(1)) as *mut c_char};
    q
}

fn gc_set_forward_pointer(p: *mut c_char, q: *mut c_char) {
    unsafe {
        *p = gc_forward_mark as c_char;
        *((p as *mut ptr).add(1)) = q as ptr;
    }
}

fn gc_forward(x: ptr) -> ptr {
    if !gc_ptr_object(x) {
        return x;
    }

    let tag = x & obj_mask;
    let p = (x-tag) as *mut c_char;
    let mut q = gc_get_forward_pointer(p);
    if q != (0 as *mut c_char) {
        return (q as ptr) | tag;
    }

    unsafe {
    q = gc_next;
    let n = gc_size(x);
    for i in 0..n {
        *gc_next.add(i) = *p.add(i);
    }
    gc_next = gc_next.add(gc_align(n));
    gc_set_forward_pointer(p, q);
    let f = ((q as ptr) | tag) as ptr;
    *gc_queue = f;
    gc_queue = gc_queue.add(1);
    f
    }
}

fn gc(mem: *mut memory, stack: *mut c_char) {
    unsafe {
    gc_new_heap_base = (*mem).heap_base_alt as *mut c_char;
    gc_new_heap_top = (*mem).heap_top_alt as *mut c_char;

    gc_next = (*mem).heap_base_alt as *mut c_char;
    gc_queue = (*mem).scratch_base as *mut ptr;
    }

    let scan = unsafe{gc_queue};
    let mut root = unsafe{*mem}.global_base as *mut ptr;
    while unsafe { (root as *mut c_char) < (*mem).global_next } {
        unsafe {
            *root = gc_forward(*root);
            root = root.add(1);
        }
    }

    root = unsafe{*mem}.stack_base as *mut ptr;
    unsafe {
    root.offset(-1);
    root.offset(-1);
        while root > (stack as *mut ptr) {
            if *root == return_addr {
                root.offset(-1);
            } else {
                *root = gc_forward(*root);
            }
        }
        root.offset(-1);
    }

    unsafe {
        (*mem).edi = gc_forward((*mem).edi);
    }

    while scan < unsafe{gc_queue} {
        let x = unsafe { *(scan.add(1)) };
        let tag = x & obj_mask;

        if tag == pair_tag {
            unsafe {
                let p = (x-tag) as *mut cell;
                (*p).car = gc_forward((*p).car);
                (*p).cdr = gc_forward((*p).cdr);
            }
        } else if tag == vector_tag {
            unsafe {
                let p = (x-tag) as *mut vector;
                let len = unshift((*p).length) as usize;
                let b = (*p).buf.as_mut_ptr();
                for i in 0..len {
                    *(b.add(i)) = gc_forward(*(b.add(i)));
                }
            }
        } else if tag == closure_tag {
            unsafe {
                let p = (x-tag) as *mut closure;
                let len = unshift((*p).length) as usize;
                let b = (*p).fvs.as_mut_ptr();
                for i in 0..len {
                    *(b.add(i)) = gc_forward(*(b.add(i)));
                }
            }
        }
    }

    unsafe {
        (*mem).heap_next = gc_next;
        (*mem).heap_base_alt = (*mem).heap_base;
        (*mem).heap_top_alt = (*mem).heap_top;
        (*mem).heap_base = gc_new_heap_base;
        (*mem).heap_top = gc_new_heap_top;
    }
}

#[no_mangle]
pub extern "C" fn heap_alloc(mem: *mut memory, stack: *mut c_char, size: usize) -> *mut c_char {
    let mut heap_next = unsafe {*mem}.heap_next;
    let mut heap_new = unsafe { heap_next.add(size) };
    if unsafe { heap_new >= (*mem).heap_top } {
        gc(mem, stack);
        heap_next = unsafe{*mem}.heap_next;
        heap_new = unsafe { heap_next.add(size) };
        if unsafe { heap_new >= (*mem).heap_top } {
            eprintln!("Exception: overflow");
            std::process::exit(0);
        }
    }
    unsafe {(*mem).heap_next = heap_new};
    return heap_next;
}

fn allocate_protected_space(size: usize) -> *mut c_char {
    let mut v = Vec::with_capacity(size);
    let ptr = v.as_mut_ptr();
    std::mem::forget(v);
    ptr
}

fn deallocate_protected_space(p: *mut c_char, size: usize) {
    unsafe { std::mem::drop(Vec::from_raw_parts(p, 0, size)) };
}

fn main() {
    let stack_size = 16 * 4096;
    let heap_size = 4 * 16 * 4096;
    let global_size = 16 * 4096;
    let scratch_size = 16 * 4096;

    let stack_top = allocate_protected_space(stack_size);
    let stack_base = unsafe { stack_top.add(stack_size) };

    let heap = allocate_protected_space(heap_size);
    let global = allocate_protected_space(global_size);
    let scratch = allocate_protected_space(scratch_size);

    let uninit = 0 as (*mut std::os::raw::c_void);

    let mut ctxt = context {
        eax : uninit,
        ebx : uninit,
        ecx : uninit,
        edx : uninit,
        esi : uninit,
        edi : uninit,
        ebp : uninit,
        esp : uninit,
    };

    let heap_top = unsafe { heap.add(heap_size/2) };
    let mut mem = memory {
        heap_next : heap,
        global_next : global,
        heap_base : heap,
        heap_top : heap_top,
        heap_base_alt : heap_top,
        heap_top_alt : unsafe { heap.add(heap_size) },
        global_base : global,
        stack_base : stack_base,
        scratch_base : scratch,
        edi : 0
    };

    let r = unsafe {
        scheme_entry(&mut ctxt, stack_base, &mut mem)
    };
    print_ptr(r);

    deallocate_protected_space(stack_top, stack_size);
    deallocate_protected_space(heap, stack_size);
}
<|endoftext|>


<commit_before>#![crate_name = "uu_rm"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Alex Lyon <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate remove_dir_all;
extern crate walkdir;

#[macro_use]
extern crate uucore;

use std::collections::VecDeque;
use std::fs;
use std::io::{stderr, stdin, BufRead, Write};
use std::ops::BitOr;
use std::path::Path;
use remove_dir_all::remove_dir_all;
use walkdir::{DirEntry, WalkDir};

#[derive(Eq, PartialEq, Clone, Copy)]
enum InteractiveMode {
    InteractiveNone,
    InteractiveOnce,
    InteractiveAlways,
}

struct Options {
    force: bool,
    interactive: InteractiveMode,
    #[allow(dead_code)]
    one_fs: bool,
    preserve_root: bool,
    recursive: bool,
    dir: bool,
    verbose: bool,
}

static NAME: &str = "rm";
static VERSION: &str = env!("CARGO_PKG_VERSION");

pub fn uumain(args: Vec<String>) -> i32 {
    // TODO: make getopts support -R in addition to -r
    let mut opts = getopts::Options::new();

    opts.optflag(
        "f",
        "force",
        "ignore nonexistent files and arguments, never prompt",
    );
    opts.optflag("i", "", "prompt before every removal");
    opts.optflag("I", "", "prompt once before removing more than three files, or when removing recursively.  Less intrusive than -i, while still giving some protection against most mistakes");
    opts.optflagopt(
        "",
        "interactive",
        "prompt according to WHEN: never, once (-I), or always (-i).  Without WHEN, prompts always",
        "WHEN",
    );
    opts.optflag("", "one-file-system", "when removing a hierarchy recursively, skip any directory that is on a file system different from that of the corresponding command line argument (NOT IMPLEMENTED)");
    opts.optflag("", "no-preserve-root", "do not treat '/' specially");
    opts.optflag("", "preserve-root", "do not remove '/' (default)");
    opts.optflag(
        "r",
        "recursive",
        "remove directories and their contents recursively",
    );
    opts.optflag("d", "dir", "remove empty directories");
    opts.optflag("v", "verbose", "explain what is being done");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f),
    };

    let force = matches.opt_present("force");

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {0} [OPTION]... [FILE]...", NAME);
        println!("");
        println!("{}", opts.usage("Remove (unlink) the FILE(s)."));
        println!("By default, rm does not remove directories.  Use the --recursive (-r)");
        println!("option to remove each listed directory, too, along with all of its contents");
        println!("");
        println!("To remove a file whose name starts with a '-', for example '-foo',");
        println!("use one of these commands:");
        println!("rm -- -foo");
        println!("");
        println!("rm ./-foo");
        println!("");
        println!("Note that if you use rm to remove a file, it might be possible to recover");
        println!("some of its contents, given sufficient expertise and/or time.  For greater");
        println!("assurance that the contents are truly unrecoverable, consider using shred.");
    } else if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
    } else if matches.free.is_empty() && !force {
        show_error!("missing an argument");
        show_error!("for help, try '{0} --help'", NAME);
        return 1;
    } else {
        let options = Options {
            force: force,
            interactive: {
                if matches.opt_present("i") {
                    InteractiveMode::InteractiveAlways
                } else if matches.opt_present("I") {
                    InteractiveMode::InteractiveOnce
                } else if matches.opt_present("interactive") {
                    match &matches.opt_str("interactive").unwrap()[..] {
                        "none" => InteractiveMode::InteractiveNone,
                        "once" => InteractiveMode::InteractiveOnce,
                        "always" => InteractiveMode::InteractiveAlways,
                        val => crash!(1, "Invalid argument to interactive ({})", val),
                    }
                } else {
                    InteractiveMode::InteractiveNone
                }
            },
            one_fs: matches.opt_present("one-file-system"),
            preserve_root: !matches.opt_present("no-preserve-root"),
            recursive: matches.opt_present("recursive"),
            dir: matches.opt_present("dir"),
            verbose: matches.opt_present("verbose"),
        };
        if options.interactive == InteractiveMode::InteractiveOnce
            && (options.recursive || matches.free.len() > 3)
        {
            let msg = if options.recursive {
                "Remove all arguments recursively? "
            } else {
                "Remove all arguments? "
            };
            if !prompt(msg) {
                return 0;
            }
        }

        if remove(matches.free, options) {
            return 1;
        }
    }

    0
}

// TODO: implement one-file-system (this may get partially implemented in walkdir)
fn remove(files: Vec<String>, options: Options) -> bool {
    let mut had_err = false;

    for filename in &files {
        let file = Path::new(filename);
        had_err = match file.symlink_metadata() {
            Ok(metadata) => {
                if metadata.is_dir() {
                    handle_dir(file, &options)
                } else {
                    remove_file(file, &options)
                }
            }
            Err(_e) => {
                // TODO: actually print out the specific error
                // TODO: When the error is not about missing files
                // (e.g., permission), even rm -f should fail with
                // outputting the error, but there's no easy eay.
                if !options.force {
                    show_error!("no such file or directory '{}'", filename);
                    true
                } else {
                    false
                }
            }
        }.bitor(had_err);
    }

    had_err
}

fn handle_dir(path: &Path, options: &Options) -> bool {
    let mut had_err = false;

    let is_root = path.has_root() && path.parent().is_none();
    if options.recursive && (!is_root || !options.preserve_root) {
        if options.interactive != InteractiveMode::InteractiveAlways {
            // we need the extra crate because apparently fs::remove_dir_all() does not function
            // correctly on Windows
            if let Err(e) = remove_dir_all(path) {
                had_err = true;
                show_error!("could not remove '{}': {}", path.display(), e);
            }
        } else {
            let mut dirs: VecDeque<DirEntry> = VecDeque::new();

            for entry in WalkDir::new(path) {
                match entry {
                    Ok(entry) => {
                        let file_type = entry.file_type();
                        if file_type.is_dir() {
                            dirs.push_back(entry);
                        } else {
                            had_err = remove_file(entry.path(), options).bitor(had_err);
                        }
                    }
                    Err(e) => {
                        had_err = true;
                        show_error!("recursing in '{}': {}", path.display(), e);
                    }
                }
            }

            for dir in dirs.iter().rev() {
                had_err = remove_dir(dir.path(), options).bitor(had_err);
            }
        }
    } else if options.dir && (!is_root || !options.preserve_root) {
        had_err = remove_dir(path, options).bitor(had_err);
    } else {
        if options.recursive {
            show_error!("could not remove directory '{}'", path.display());
            had_err = true;
        } else {
            show_error!(
                "could not remove directory '{}' (did you mean to pass '-r'?)",
                path.display()
            );
            had_err = true;
        }
    }

    had_err
}

fn remove_dir(path: &Path, options: &Options) -> bool {
    let response = if options.interactive == InteractiveMode::InteractiveAlways {
        prompt_file(path, true)
    } else {
        true
    };
    if response {
        match fs::remove_dir(path) {
            Ok(_) => if options.verbose {
                println!("removed '{}'", path.display());
            },
            Err(e) => {
                show_error!("removing '{}': {}", path.display(), e);
                return true;
            }
        }
    }

    false
}

fn remove_file(path: &Path, options: &Options) -> bool {
    let response = if options.interactive == InteractiveMode::InteractiveAlways {
        prompt_file(path, false)
    } else {
        true
    };
    if response {
        match fs::remove_file(path) {
            Ok(_) => if options.verbose {
                println!("removed '{}'", path.display());
            },
            Err(e) => {
                show_error!("removing '{}': {}", path.display(), e);
                return true;
            }
        }
    }

    false
}

fn prompt_file(path: &Path, is_dir: bool) -> bool {
    if is_dir {
        prompt(&(format!("rm: remove directory '{}'? ", path.display())))
    } else {
        prompt(&(format!("rm: remove file '{}'? ", path.display())))
    }
}

fn prompt(msg: &str) -> bool {
    let _ = stderr().write_all(msg.as_bytes());
    let _ = stderr().flush();

    let mut buf = Vec::new();
    let stdin = stdin();
    let mut stdin = stdin.lock();

    match stdin.read_until('\n' as u8, &mut buf) {
        Ok(x) if x > 0 => match buf[0] {
            b'y' | b'Y' => true,
            _ => false,
        },
        _ => false,
    }
}
<commit_msg>rm: fix dir-type symlink removal on windows<commit_after>#![crate_name = "uu_rm"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Alex Lyon <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate remove_dir_all;
extern crate walkdir;

#[macro_use]
extern crate uucore;

use std::collections::VecDeque;
use std::fs;
use std::io::{stderr, stdin, BufRead, Write};
use std::ops::BitOr;
use std::path::Path;
use remove_dir_all::remove_dir_all;
use walkdir::{DirEntry, WalkDir};

#[derive(Eq, PartialEq, Clone, Copy)]
enum InteractiveMode {
    InteractiveNone,
    InteractiveOnce,
    InteractiveAlways,
}

struct Options {
    force: bool,
    interactive: InteractiveMode,
    #[allow(dead_code)]
    one_fs: bool,
    preserve_root: bool,
    recursive: bool,
    dir: bool,
    verbose: bool,
}

static NAME: &str = "rm";
static VERSION: &str = env!("CARGO_PKG_VERSION");

pub fn uumain(args: Vec<String>) -> i32 {
    // TODO: make getopts support -R in addition to -r
    let mut opts = getopts::Options::new();

    opts.optflag(
        "f",
        "force",
        "ignore nonexistent files and arguments, never prompt",
    );
    opts.optflag("i", "", "prompt before every removal");
    opts.optflag("I", "", "prompt once before removing more than three files, or when removing recursively.  Less intrusive than -i, while still giving some protection against most mistakes");
    opts.optflagopt(
        "",
        "interactive",
        "prompt according to WHEN: never, once (-I), or always (-i).  Without WHEN, prompts always",
        "WHEN",
    );
    opts.optflag("", "one-file-system", "when removing a hierarchy recursively, skip any directory that is on a file system different from that of the corresponding command line argument (NOT IMPLEMENTED)");
    opts.optflag("", "no-preserve-root", "do not treat '/' specially");
    opts.optflag("", "preserve-root", "do not remove '/' (default)");
    opts.optflag(
        "r",
        "recursive",
        "remove directories and their contents recursively",
    );
    opts.optflag("d", "dir", "remove empty directories");
    opts.optflag("v", "verbose", "explain what is being done");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => crash!(1, "{}", f),
    };

    let force = matches.opt_present("force");

    if matches.opt_present("help") {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {0} [OPTION]... [FILE]...", NAME);
        println!("");
        println!("{}", opts.usage("Remove (unlink) the FILE(s)."));
        println!("By default, rm does not remove directories.  Use the --recursive (-r)");
        println!("option to remove each listed directory, too, along with all of its contents");
        println!("");
        println!("To remove a file whose name starts with a '-', for example '-foo',");
        println!("use one of these commands:");
        println!("rm -- -foo");
        println!("");
        println!("rm ./-foo");
        println!("");
        println!("Note that if you use rm to remove a file, it might be possible to recover");
        println!("some of its contents, given sufficient expertise and/or time.  For greater");
        println!("assurance that the contents are truly unrecoverable, consider using shred.");
    } else if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
    } else if matches.free.is_empty() && !force {
        show_error!("missing an argument");
        show_error!("for help, try '{0} --help'", NAME);
        return 1;
    } else {
        let options = Options {
            force: force,
            interactive: {
                if matches.opt_present("i") {
                    InteractiveMode::InteractiveAlways
                } else if matches.opt_present("I") {
                    InteractiveMode::InteractiveOnce
                } else if matches.opt_present("interactive") {
                    match &matches.opt_str("interactive").unwrap()[..] {
                        "none" => InteractiveMode::InteractiveNone,
                        "once" => InteractiveMode::InteractiveOnce,
                        "always" => InteractiveMode::InteractiveAlways,
                        val => crash!(1, "Invalid argument to interactive ({})", val),
                    }
                } else {
                    InteractiveMode::InteractiveNone
                }
            },
            one_fs: matches.opt_present("one-file-system"),
            preserve_root: !matches.opt_present("no-preserve-root"),
            recursive: matches.opt_present("recursive"),
            dir: matches.opt_present("dir"),
            verbose: matches.opt_present("verbose"),
        };
        if options.interactive == InteractiveMode::InteractiveOnce
            && (options.recursive || matches.free.len() > 3)
        {
            let msg = if options.recursive {
                "Remove all arguments recursively? "
            } else {
                "Remove all arguments? "
            };
            if !prompt(msg) {
                return 0;
            }
        }

        if remove(matches.free, options) {
            return 1;
        }
    }

    0
}

// TODO: implement one-file-system (this may get partially implemented in walkdir)
fn remove(files: Vec<String>, options: Options) -> bool {
    let mut had_err = false;

    for filename in &files {
        let file = Path::new(filename);
        had_err = match file.symlink_metadata() {
            Ok(metadata) => {
                if metadata.is_dir() {
                    handle_dir(file, &options)
                } else if is_symlink_dir(&metadata) {
                    remove_dir(file, &options)
                } else {
                    remove_file(file, &options)
                }
            }
            Err(_e) => {
                // TODO: actually print out the specific error
                // TODO: When the error is not about missing files
                // (e.g., permission), even rm -f should fail with
                // outputting the error, but there's no easy eay.
                if !options.force {
                    show_error!("no such file or directory '{}'", filename);
                    true
                } else {
                    false
                }
            }
        }.bitor(had_err);
    }

    had_err
}

fn handle_dir(path: &Path, options: &Options) -> bool {
    let mut had_err = false;

    let is_root = path.has_root() && path.parent().is_none();
    if options.recursive && (!is_root || !options.preserve_root) {
        if options.interactive != InteractiveMode::InteractiveAlways {
            // we need the extra crate because apparently fs::remove_dir_all() does not function
            // correctly on Windows
            if let Err(e) = remove_dir_all(path) {
                had_err = true;
                show_error!("could not remove '{}': {}", path.display(), e);
            }
        } else {
            let mut dirs: VecDeque<DirEntry> = VecDeque::new();

            for entry in WalkDir::new(path) {
                match entry {
                    Ok(entry) => {
                        let file_type = entry.file_type();
                        if file_type.is_dir() {
                            dirs.push_back(entry);
                        } else {
                            had_err = remove_file(entry.path(), options).bitor(had_err);
                        }
                    }
                    Err(e) => {
                        had_err = true;
                        show_error!("recursing in '{}': {}", path.display(), e);
                    }
                }
            }

            for dir in dirs.iter().rev() {
                had_err = remove_dir(dir.path(), options).bitor(had_err);
            }
        }
    } else if options.dir && (!is_root || !options.preserve_root) {
        had_err = remove_dir(path, options).bitor(had_err);
    } else {
        if options.recursive {
            show_error!("could not remove directory '{}'", path.display());
            had_err = true;
        } else {
            show_error!(
                "could not remove directory '{}' (did you mean to pass '-r'?)",
                path.display()
            );
            had_err = true;
        }
    }

    had_err
}

fn remove_dir(path: &Path, options: &Options) -> bool {
    let response = if options.interactive == InteractiveMode::InteractiveAlways {
        prompt_file(path, true)
    } else {
        true
    };
    if response {
        match fs::remove_dir(path) {
            Ok(_) => if options.verbose {
                println!("removed '{}'", path.display());
            },
            Err(e) => {
                show_error!("removing '{}': {}", path.display(), e);
                return true;
            }
        }
    }

    false
}

fn remove_file(path: &Path, options: &Options) -> bool {
    let response = if options.interactive == InteractiveMode::InteractiveAlways {
        prompt_file(path, false)
    } else {
        true
    };
    if response {
        match fs::remove_file(path) {
            Ok(_) => if options.verbose {
                println!("removed '{}'", path.display());
            },
            Err(e) => {
                show_error!("removing '{}': {}", path.display(), e);
                return true;
            }
        }
    }

    false
}

fn prompt_file(path: &Path, is_dir: bool) -> bool {
    if is_dir {
        prompt(&(format!("rm: remove directory '{}'? ", path.display())))
    } else {
        prompt(&(format!("rm: remove file '{}'? ", path.display())))
    }
}

fn prompt(msg: &str) -> bool {
    let _ = stderr().write_all(msg.as_bytes());
    let _ = stderr().flush();

    let mut buf = Vec::new();
    let stdin = stdin();
    let mut stdin = stdin.lock();

    match stdin.read_until('\n' as u8, &mut buf) {
        Ok(x) if x > 0 => match buf[0] {
            b'y' | b'Y' => true,
            _ => false,
        },
        _ => false,
    }
}

#[cfg(not(windows))]
fn is_symlink_dir(_metadata: &fs::Metadata) -> bool {
    false
}

#[cfg(windows)]
use std::os::windows::prelude::MetadataExt;

#[cfg(windows)]
fn is_symlink_dir(metadata: &fs::Metadata) -> bool {
    use std::os::raw::c_ulong;
    pub type DWORD = c_ulong;
    pub const FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x10;

    metadata.file_type().is_symlink() && ((metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY) != 0)
}
<|endoftext|>


<commit_before>//! Selection sort algorithm.
//!
//! The `selection` module contains the simple sorting algorithm "Selection Sort".
//!
//! Source: https://en.wikipedia.org/wiki/Selection_sort

use std::fmt::Debug;

/// Simple sort: selection sort.
///
/// # Details
///
/// Selection sort is one of the simplest sorting algorithm. The list to sort is split into two
/// sections; the first with the sorted element (starting empty) and the second with the remaining
/// element (starting full). At every iteration, the smallest element in the remaining list is
/// found and placed at the end of the sorted list.
///
/// This function takes an immutable reference vector of any type and returns a vector of `usize`
/// of the same length containing the indices of the initial vector sorted.
///
/// # Scaling
///
/// Selection sort in scale as O(N^2) since for all elements to sort, the algorithm will compare it
/// with every (remaining) elements.
///
/// Insertion sort is still useful as it is quite simple.
///
/// # Optimizations
///
/// None
///
/// # Notes
///
/// The type T of the vector elements to sort _must_ implement the `PartialOrd` trait so the
/// compiler knows how to compare the elements and sort them.
///
/// # Examples
///
/// ```
/// let mut data: Vec<i32> = vec![4, 2, 3, 1, 5];
/// sorting::simplesorts::selection::sort(&mut data);
/// assert_eq!(vec![1, 2, 3, 4, 5], data);
/// ```
///
pub fn sort<T: PartialOrd + Debug>(array: &mut Vec<T>) {
    println!("input array:  {:?}", array);

    if !array.is_empty() {
        // Let's loop over the input array, skipping last value (important as we want to get a
        // slice of the following values).
        let n = array.len();
        for i in 0..n-1 {
            println!("    i: {:?}", i);

            // Find index of the minimum value in the slice of values following the i^th element.
            let j = {
                let int_slice = &array[i+1..];
                println!("        array:        {:?}", array);
                println!("        int_slice:    {:?}", int_slice);
                // k now holds the index (of "array") of the minimum element of "int_slice", or the
                // value "i" of the current element of "array" (which should be the less than
                // all elements of "int_slice").
                // "k" is a tuple containing the smallest element of "int_slice" and its index.
                //     k.0: Index of "int_slice" of its smallest value.
                //     k.1: Smallest value of "int_slice".
                let k = int_slice.iter().enumerate().fold(
                    (0, int_slice.first().unwrap()), |acc, item| {
                        if acc.1 > item.1 { item } else { acc }
                });

                // Return from the block the smallest element between the one at index "i" of
                // the "array" and the smallest one from the "int_slice" array.
                // NOTE: Since "k" worked on the subarray "int_slice", it's first element is the
                //       i^th element of "array". If "k" is actually smaller than "array[i]", we
                //       need to adapt the index as stored in "k.0".
                if k.1 < &array[i] { i + k.0 + 1 } else { i }
            };
            println!("            j: {:?}   array[i]={:?}   array[j]={:?}", j, array[i], array[j]);

            array.swap(i, j);
            println!("        new array:    {:?}", array);
        }
    }

    println!("output array: {:?}", array);
}
<commit_msg>Doc comments<commit_after>//! Selection sort algorithm.
//!
//! The `selection` module contains the simple sorting algorithm "Selection Sort".
//!
//! Source: https://en.wikipedia.org/wiki/Selection_sort

use std::fmt::Debug;

/// Simple sort: selection sort.
///
/// # Details
///
/// Selection sort is one of the simplest sorting algorithm. It sorts a vector in place by
/// looping over all elements and swapping the smallest element of the rest of the vector.
///
/// # Scaling
///
/// Selection sort in scale as O(N^2) since for all elements to sort, the algorithm will compare it
/// with every (remaining) elements.
///
/// Insertion sort is still useful as it is quite simple.
///
/// # Optimizations
///
/// None
///
/// # Notes
///
/// The type T of the vector elements to sort _must_ implement the `PartialOrd` trait so the
/// compiler knows how to compare the elements and sort them.
///
/// # Examples
///
/// ```
/// let mut data: Vec<i32> = vec![4, 2, 3, 1, 5];
/// sorting::simplesorts::selection::sort(&mut data);
/// assert_eq!(vec![1, 2, 3, 4, 5], data);
/// ```
///
pub fn sort<T: PartialOrd + Debug>(array: &mut Vec<T>) {
    println!("input array:  {:?}", array);

    if !array.is_empty() {
        // Let's loop over the input array, skipping last value (important as we want to get a
        // slice of the following values).
        let n = array.len();
        for i in 0..n-1 {
            println!("    i: {:?}", i);

            // Find index of the minimum value in the slice of values following the i^th element.
            let j = {
                let int_slice = &array[i+1..];
                println!("        array:        {:?}", array);
                println!("        int_slice:    {:?}", int_slice);
                // k now holds the index (of "array") of the minimum element of "int_slice", or the
                // value "i" of the current element of "array" (which should be the less than
                // all elements of "int_slice").
                // "k" is a tuple containing the smallest element of "int_slice" and its index.
                //     k.0: Index of "int_slice" of its smallest value.
                //     k.1: Smallest value of "int_slice".
                let k = int_slice.iter().enumerate().fold(
                    (0, int_slice.first().unwrap()), |acc, item| {
                        if acc.1 > item.1 { item } else { acc }
                });

                // Return from the block the smallest element between the one at index "i" of
                // the "array" and the smallest one from the "int_slice" array.
                // NOTE: Since "k" worked on the subarray "int_slice", it's first element is the
                //       i^th element of "array". If "k" is actually smaller than "array[i]", we
                //       need to adapt the index as stored in "k.0".
                if k.1 < &array[i] { i + k.0 + 1 } else { i }
            };
            println!("            j: {:?}   array[i]={:?}   array[j]={:?}", j, array[i], array[j]);

            array.swap(i, j);
            println!("        new array:    {:?}", array);
        }
    }

    println!("output array: {:?}", array);
}
<|endoftext|>


<commit_before>#![feature(phase)]
#![allow(uppercase_variables)]
#![allow(unused_imports)]

extern crate test;
extern crate ndarray;

use ndarray::{Array, S, Si};
use ndarray::{arr0, arr1, arr2};
use ndarray::d2;

use test::black_box;

#[bench]
fn bench_std_add(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32>(&[&[1., 2., 2.],
                              &[3., 4., 4.],
                              &[3., 4., 4.],
                              &[3., 4., 4.],
                              &[5., 6., 6.]]);
    let b = a.clone();
    bench.iter(|| a.iadd(&b));
}

#[bench]
fn bench_std_iter_1d(bench: &mut test::Bencher)
{
    let a = arr1::<f32>([1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for elt in a.iter() { black_box(elt) })
}

#[bench]
fn bench_std_iter_1d_raw(bench: &mut test::Bencher)
{
    let a = arr1::<f32>([1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for elt in a.raw_data().iter() { black_box(elt) })
}

#[bench]
fn bench_std_iter_2d(bench: &mut test::Bencher)
{
    let a = arr2::<f32>(&[&[1., 2., 2.],
                          &[3., 4., 4.],
                          &[3., 4., 4.],
                          &[3., 4., 4.],
                          &[5., 6., 6.]]);
    bench.iter(|| for elt in a.iter() { black_box(elt) })
}

#[bench]
fn assign_scalar_2d(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32>(&[&[1., 2., 2.],
                              &[3., 4., 4.],
                              &[3., 4., 4.],
                              &[3., 4., 4.],
                              &[5., 6., 6.]]);
    a.swap_axes(0, 1);
    bench.iter(|| a.assign_scalar(&3.))
}

#[bench]
fn bench_iter_diag(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros(d2(1024, 1024));
    bench.iter(|| for elt in a.diag_iter() { black_box(elt) })
}

#[bench]
fn bench_row_iter(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros(d2(1024, 1024));
    let it = a.row_iter(17);
    bench.iter(|| for elt in it.clone() { black_box(elt) })
}

#[bench]
fn bench_col_iter(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros(d2(1024, 1024));
    bench.iter(|| for elt in a.col_iter(17) { black_box(elt) })
}

#[bench]
fn bench_mat_mul(bench: &mut test::Bencher)
{
    let a = arr2::<f32>(&[&[1., 2., 2.],
                          &[3., 4., 4.],
                          &[3., 4., 4.],
                          &[3., 4., 4.],
                          &[5., 6., 6.]]);
    let mut at = a.clone();
    at.swap_axes(0, 1);
    bench.iter(|| at.mat_mul(&a));
}

#[bench]
fn lst_squares(bench: &mut test::Bencher)
{
    let xs = arr2::<f32>(&[&[ 2.,  3.],
                           &[-2., -1.],
                           &[ 1.,  5.],
                           &[-1.,  2.]]);
    let b = arr1([1., -1., 2., 1.]);
    bench.iter(|| ndarray::linalg::least_squares(&xs, &b));
}
<commit_msg>Add more benches<commit_after>#![feature(phase)]
#![allow(uppercase_variables)]
#![allow(unused_imports)]

extern crate test;
extern crate ndarray;

use ndarray::{Array, S, Si};
use ndarray::{arr0, arr1, arr2};
use ndarray::{d1, d2};

use test::black_box;

#[bench]
fn bench_std_add(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32>(&[&[1., 2., 2.],
                              &[3., 4., 4.],
                              &[3., 4., 4.],
                              &[3., 4., 4.],
                              &[5., 6., 6.]]);
    let b = a.clone();
    bench.iter(|| a.iadd(&b));
}

#[bench]
fn bench_std_iter_1d(bench: &mut test::Bencher)
{
    let a = arr1::<f32>([1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.iter() { black_box(elt) })
}

#[bench]
fn bench_std_iter_1d_raw(bench: &mut test::Bencher)
{
    let a = arr1::<f32>([1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.raw_data().iter() { black_box(elt) })
}

#[bench]
fn bench_std_iter_2d(bench: &mut test::Bencher)
{
    let a = arr2::<f32>(&[&[1., 2., 2.],
                          &[3., 4., 4.],
                          &[3., 4., 4.],
                          &[3., 4., 4.],
                          &[5., 6., 6.]]);
    bench.iter(|| for &elt in a.iter() { black_box(elt) })
}

#[bench]
fn bench_std_iter_1d_large(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros(d1(1024));
    bench.iter(|| for &elt in a.iter() { black_box(elt) })
}

#[bench]
fn bench_std_iter_1d_raw_large(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros(d1(1024));
    bench.iter(|| for &elt in a.raw_data().iter() { black_box(elt) })
}

#[bench]
fn bench_std_iter_2d_large(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros(d2(16, 64));
    bench.iter(|| for &elt in a.iter() { black_box(elt) })
}

#[bench]
fn assign_scalar_2d(bench: &mut test::Bencher)
{
    let mut a = arr2::<f32>(&[&[1., 2., 2.],
                              &[3., 4., 4.],
                              &[3., 4., 4.],
                              &[3., 4., 4.],
                              &[5., 6., 6.]]);
    a.swap_axes(0, 1);
    bench.iter(|| a.assign_scalar(&3.))
}

#[bench]
fn bench_iter_diag(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros(d2(1024, 1024));
    bench.iter(|| for elt in a.diag_iter() { black_box(elt) })
}

#[bench]
fn bench_row_iter(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros(d2(1024, 1024));
    let it = a.row_iter(17);
    bench.iter(|| for elt in it.clone() { black_box(elt) })
}

#[bench]
fn bench_col_iter(bench: &mut test::Bencher)
{
    let a = Array::<f32, _>::zeros(d2(1024, 1024));
    bench.iter(|| for elt in a.col_iter(17) { black_box(elt) })
}

#[bench]
fn bench_mat_mul(bench: &mut test::Bencher)
{
    let a = arr2::<f32>(&[&[1., 2., 2.],
                          &[3., 4., 4.],
                          &[3., 4., 4.],
                          &[3., 4., 4.],
                          &[5., 6., 6.]]);
    let mut at = a.clone();
    at.swap_axes(0, 1);
    bench.iter(|| at.mat_mul(&a));
}

#[bench]
fn lst_squares(bench: &mut test::Bencher)
{
    let xs = arr2::<f32>(&[&[ 2.,  3.],
                           &[-2., -1.],
                           &[ 1.,  5.],
                           &[-1.,  2.]]);
    let b = arr1([1., -1., 2., 1.]);
    bench.iter(|| ndarray::linalg::least_squares(&xs, &b));
}
<|endoftext|>


<commit_before>extern crate rustc_version;

use std::ascii::AsciiExt;
use std::env;
use std::ffi::OsStr;
use std::path::{Component, PathBuf};
use std::process::Command;

use walkdir::WalkDir;

pub use self::rustc_version::{Channel, VersionMeta};

use cargo;
use errors::*;
use {CommandExt, Target};

/// The `rust-src` component within `rustc`'s sysroot
pub fn rust_src() -> Result<PathBuf> {
    for entry in WalkDir::new(try!(sysroot())) {
        let entry =
            try!(entry.chain_err(|| "error recursively walking the sysroot"));

        if entry.file_type().is_file() && entry.file_name() == "version" {
            let path = entry.path();

            if let Some(parent) = path.parent() {
                if parent.components().rev().next() ==
                   Some(Component::Normal(OsStr::new("rust"))) {
                    return Ok(parent.to_owned());
                }
            }
        }
    }

    try!(Err("`rust-src` component not found. Run `rustup component add \
              rust-src`."))
}

pub fn target_list() -> Result<Vec<String>> {
    let stdout =
        try!(rustc().args(&["--print", "target-list"]).run_and_get_stdout());

    Ok(stdout.split('\n')
        .filter_map(|s| if s.is_empty() {
            None
        } else {
            Some(s.to_owned())
        })
        .collect())
}

/// Parsed `rustc -Vv` output
pub fn meta() -> Result<VersionMeta> {
    Ok(rustc_version::version_meta_for(&try!(rustc()
        .arg("-Vv")
        .run_and_get_stdout())))
}

pub fn flags(target: &Target, tool: &str) -> Result<Vec<String>> {
    let tool = tool.to_ascii_uppercase();
    if let Ok(flags) = env::var(&tool) {
        return Ok(flags.split_whitespace().map(|s| s.to_owned()).collect());
    }

    let tool = tool.to_ascii_lowercase();
    if let Some(value) = try!(cargo::config()).and_then(|t| {
        t.lookup(&format!("target.{}.{}", target.triple(), tool))
            .or_else(|| t.lookup(&format!("build.{}", tool)))
            .cloned()
    }) {
        let mut error = false;
        let mut flags = vec![];
        if let Some(values) = value.as_slice() {
            for value in values {
                if let Some(flag) = value.as_str() {
                    flags.push(flag.to_owned());
                } else {
                    error = true;
                    break;
                }
            }
        } else {
            error = true;
        }

        if error {
            try!(Err(format!("{} in .cargo/config should be an array of \
                              string",
                             tool)))
        } else {
            Ok(flags)
        }
    } else {
        Ok(vec![])
    }

}

pub fn sysroot() -> Result<PathBuf> {
    Ok(PathBuf::from(try!(rustc()
            .arg("--print")
            .arg("sysroot")
            .run_and_get_stdout())
        .trim_right()))
}

pub fn rustc() -> Command {
    Command::new(env::var("RUSTC").as_ref().map(|s| &s[..]).unwrap_or("rustc"))
}
<commit_msg>Fix search for rustup rust-src component<commit_after>extern crate rustc_version;

use std::ascii::AsciiExt;
use std::env;
use std::ffi::OsStr;
use std::path::{Component, PathBuf};
use std::process::Command;

use walkdir::WalkDir;

pub use self::rustc_version::{Channel, VersionMeta};

use cargo;
use errors::*;
use {CommandExt, Target};

/// The `rust-src` component within `rustc`'s sysroot
pub fn rust_src() -> Result<PathBuf> {
    let src = try!(sysroot()).join("lib/rustlib/src/rust");

    if src.join("src/libstd/Cargo.toml").is_file() {
        return Ok(src.to_owned());
    }

    for entry in WalkDir::new(try!(sysroot()).join("lib/rustlib/src")) {
        let entry =
            try!(entry.chain_err(|| "error recursively walking the sysroot"));

        if entry.file_type().is_file() && entry.file_name() == "Cargo.toml" {
            let path = entry.path();

            if let Some(parent) = path.parent() {
                if parent.components().rev().next() ==
                   Some(Component::Normal(OsStr::new("libstd"))) {
                    return Ok(parent.to_owned());
                }
            }
        }
    }

    try!(Err("`rust-src` component not found. Run `rustup component add \
              rust-src`."))
}

pub fn target_list() -> Result<Vec<String>> {
    let stdout =
        try!(rustc().args(&["--print", "target-list"]).run_and_get_stdout());

    Ok(stdout.split('\n')
        .filter_map(|s| if s.is_empty() {
            None
        } else {
            Some(s.to_owned())
        })
        .collect())
}

/// Parsed `rustc -Vv` output
pub fn meta() -> Result<VersionMeta> {
    Ok(rustc_version::version_meta_for(&try!(rustc()
        .arg("-Vv")
        .run_and_get_stdout())))
}

pub fn flags(target: &Target, tool: &str) -> Result<Vec<String>> {
    let tool = tool.to_ascii_uppercase();
    if let Ok(flags) = env::var(&tool) {
        return Ok(flags.split_whitespace().map(|s| s.to_owned()).collect());
    }

    let tool = tool.to_ascii_lowercase();
    if let Some(value) = try!(cargo::config()).and_then(|t| {
        t.lookup(&format!("target.{}.{}", target.triple(), tool))
            .or_else(|| t.lookup(&format!("build.{}", tool)))
            .cloned()
    }) {
        let mut error = false;
        let mut flags = vec![];
        if let Some(values) = value.as_slice() {
            for value in values {
                if let Some(flag) = value.as_str() {
                    flags.push(flag.to_owned());
                } else {
                    error = true;
                    break;
                }
            }
        } else {
            error = true;
        }

        if error {
            try!(Err(format!("{} in .cargo/config should be an array of \
                              string",
                             tool)))
        } else {
            Ok(flags)
        }
    } else {
        Ok(vec![])
    }

}

pub fn sysroot() -> Result<PathBuf> {
    Ok(PathBuf::from(try!(rustc()
            .arg("--print")
            .arg("sysroot")
            .run_and_get_stdout())
        .trim_right()))
}

pub fn rustc() -> Command {
    Command::new(env::var("RUSTC").as_ref().map(|s| &s[..]).unwrap_or("rustc"))
}
<|endoftext|>


<commit_before>use std::mem;
use libc::{c_int, c_uint, c_void, c_ulong, pid_t};
use errno::Errno;
use {Result, Error};

pub type CloneFlags = c_uint;

pub static CLONE_VM:             CloneFlags = 0x00000100;
pub static CLONE_FS:             CloneFlags = 0x00000200;
pub static CLONE_FILES:          CloneFlags = 0x00000400;
pub static CLONE_SIGHAND:        CloneFlags = 0x00000800;
pub static CLONE_PTRACE:         CloneFlags = 0x00002000;
pub static CLONE_VFORK:          CloneFlags = 0x00004000;
pub static CLONE_PARENT:         CloneFlags = 0x00008000;
pub static CLONE_THREAD:         CloneFlags = 0x00010000;
pub static CLONE_NEWNS:          CloneFlags = 0x00020000;
pub static CLONE_SYSVSEM:        CloneFlags = 0x00040000;
pub static CLONE_SETTLS:         CloneFlags = 0x00080000;
pub static CLONE_PARENT_SETTID:  CloneFlags = 0x00100000;
pub static CLONE_CHILD_CLEARTID: CloneFlags = 0x00200000;
pub static CLONE_DETACHED:       CloneFlags = 0x00400000;
pub static CLONE_UNTRACED:       CloneFlags = 0x00800000;
pub static CLONE_CHILD_SETTID:   CloneFlags = 0x01000000;
pub static CLONE_NEWUTS:         CloneFlags = 0x04000000;
pub static CLONE_NEWIPC:         CloneFlags = 0x08000000;
pub static CLONE_NEWUSER:        CloneFlags = 0x10000000;
pub static CLONE_NEWPID:         CloneFlags = 0x20000000;
pub static CLONE_NEWNET:         CloneFlags = 0x40000000;
pub static CLONE_IO:             CloneFlags = 0x80000000;

// Support a maximum CPU set of 1024 nodes
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "x86", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    // bionic only supports up to 32 independent CPUs, instead of 1024.
    pub const CPU_SETSIZE:          usize = 32;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

// A single CPU mask word
pub type CpuMask = c_ulong;

// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet {
            cpu_mask: unsafe { mem::zeroed() }
        }
    }

    pub fn set(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
    }

    pub fn unset(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
    }
}

mod ffi {
    use libc::{c_void, c_int, pid_t, size_t};
    use super::CpuSet;

    pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(
            cb: *const CloneCb,
            child_stack: *mut c_void,
            flags: super::CloneFlags,
            arg: *mut super::CloneCb,
            ...) -> c_int;

        // disassociate parts of the process execution context
        // doc: http://man7.org/linux/man-pages/man2/unshare.2.html
        pub fn unshare(flags: super::CloneFlags) -> c_int;

        // Set the current CPU set that a task is allowed to run on
        pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    use libc::{pid_t, size_t};

    let res = unsafe {
        ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
    };

    if res != 0 {
        Err(Error::Sys(Errno::last()))
    } else {
        Ok(())
    }
}

pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags) -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback), ptr as *mut c_void, flags, &mut cb)
    };

    if res < 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::unshare(flags) };

    if res != 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(())
}
<commit_msg>setns<commit_after>use std::mem;
use std::os::unix::io::RawFd;
use libc::{c_int, c_uint, c_void, c_ulong, pid_t};
use errno::Errno;
use {Result, Error};

pub type CloneFlags = c_uint;

pub static CLONE_VM:             CloneFlags = 0x00000100;
pub static CLONE_FS:             CloneFlags = 0x00000200;
pub static CLONE_FILES:          CloneFlags = 0x00000400;
pub static CLONE_SIGHAND:        CloneFlags = 0x00000800;
pub static CLONE_PTRACE:         CloneFlags = 0x00002000;
pub static CLONE_VFORK:          CloneFlags = 0x00004000;
pub static CLONE_PARENT:         CloneFlags = 0x00008000;
pub static CLONE_THREAD:         CloneFlags = 0x00010000;
pub static CLONE_NEWNS:          CloneFlags = 0x00020000;
pub static CLONE_SYSVSEM:        CloneFlags = 0x00040000;
pub static CLONE_SETTLS:         CloneFlags = 0x00080000;
pub static CLONE_PARENT_SETTID:  CloneFlags = 0x00100000;
pub static CLONE_CHILD_CLEARTID: CloneFlags = 0x00200000;
pub static CLONE_DETACHED:       CloneFlags = 0x00400000;
pub static CLONE_UNTRACED:       CloneFlags = 0x00800000;
pub static CLONE_CHILD_SETTID:   CloneFlags = 0x01000000;
pub static CLONE_NEWUTS:         CloneFlags = 0x04000000;
pub static CLONE_NEWIPC:         CloneFlags = 0x08000000;
pub static CLONE_NEWUSER:        CloneFlags = 0x10000000;
pub static CLONE_NEWPID:         CloneFlags = 0x20000000;
pub static CLONE_NEWNET:         CloneFlags = 0x40000000;
pub static CLONE_IO:             CloneFlags = 0x80000000;

// Support a maximum CPU set of 1024 nodes
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "x86", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    // bionic only supports up to 32 independent CPUs, instead of 1024.
    pub const CPU_SETSIZE:          usize = 32;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

// A single CPU mask word
pub type CpuMask = c_ulong;

// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet {
            cpu_mask: unsafe { mem::zeroed() }
        }
    }

    pub fn set(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
    }

    pub fn unset(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
    }
}

mod ffi {
    use libc::{c_void, c_int, pid_t, size_t};
    use super::CpuSet;

    pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(
            cb: *const CloneCb,
            child_stack: *mut c_void,
            flags: super::CloneFlags,
            arg: *mut super::CloneCb,
            ...) -> c_int;

        // disassociate parts of the process execution context
        // doc: http://man7.org/linux/man-pages/man2/unshare.2.html
        pub fn unshare(flags: super::CloneFlags) -> c_int;

        // reassociate thread with a namespace
        // doc: http://man7.org/linux/man-pages/man2/setns.2.html
        pub fn setns(fd: c_int, nstype: super::CloneFlags) -> c_int;

        // Set the current CPU set that a task is allowed to run on
        pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    use libc::{pid_t, size_t};

    let res = unsafe {
        ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
    };

    if res != 0 {
        Err(Error::Sys(Errno::last()))
    } else {
        Ok(())
    }
}

pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags) -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback), ptr as *mut c_void, flags, &mut cb)
    };

    if res < 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::unshare(flags) };

    if res != 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(())
}

pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::setns(fd, nstype) };

    if res != 0 {
        return Err(Error::Sys(Errno::last()));
    }

    Ok(())
}
<|endoftext|>