<commit_before>use bytecode::{Chunk, Inst};
use std::mem;
use value::{GC, Ref};

pub struct Thread<'chunk, 'gc, GetChunk> {
  gc: &'gc GC,
  get_chunk: GetChunk,
  call_stack: Vec<StackFrame<'chunk, 'gc>>,
  eval_stack: Vec<Ref<'gc>>,
}

struct StackFrame<'chunk, 'gc> {
  bytecode: &'chunk [Inst],
  pcounter: usize,
  locals: Vec<Option<Ref<'gc>>>,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Status {
  Paused,
  Finished,
}

impl<'chunk, 'gc, GetChunk> Thread<'chunk, 'gc, GetChunk>
  where GetChunk: Fn(usize) -> &'chunk Chunk {
  pub fn new(
    gc: &'gc GC,
    get_chunk: GetChunk,
    bytecode: &'chunk [Inst],
    locals: usize,
  ) -> Self {
    let stack_frame = StackFrame{
      bytecode: bytecode,
      pcounter: 0,
      locals: {
        let mut locals_vec = vec![];
        locals_vec.resize(locals, None);
        locals_vec
      },
    };
    Thread{
      gc: gc,
      get_chunk: get_chunk,
      call_stack: vec![stack_frame],
      eval_stack: vec![],
    }
  }

  pub fn resume(&mut self) -> Status {
    let mut pop_call_stack = false;
    let mut push_call_stack: Option<(Ref<'gc>, Ref<'gc>)> = None;
    loop {
      if pop_call_stack {
        self.call_stack.pop();
        pop_call_stack = false;
      }
      if let Some((callee, argument)) = push_call_stack {
        let chunk = (self.get_chunk)(*callee.aux_usize());
        self.call_stack.push(StackFrame{
          bytecode: &chunk.insts,
          pcounter: 0,
          locals: {
            let mut locals_vec = vec![];
            locals_vec.resize(chunk.locals + chunk.captures, None);
            locals_vec[0] = Some(argument);
            for offset in 0 .. chunk.captures {
              locals_vec[offset + 1] = callee.get_ptr(offset);
            }
            locals_vec
          },
        });
        push_call_stack = None;
      }
      match self.call_stack.last_mut() {
        None => return Status::Finished,
        Some(stack_frame) => {
          match stack_frame.bytecode[stack_frame.pcounter] {
            Inst::NoOp =>
              stack_frame.pcounter += 1,

            Inst::Call => {
              let argument = self.eval_stack.pop().unwrap();
              let callee = self.eval_stack.pop().unwrap();
              stack_frame.pcounter += 1;
              push_call_stack = Some((callee, argument));
            },
            Inst::Return =>
              pop_call_stack = true,

            Inst::Pop => {
              self.eval_stack.pop().unwrap();
              stack_frame.pcounter += 1;
            },

            Inst::GetLocal(offset) => {
              let value = stack_frame.locals[offset].clone().unwrap();
              self.eval_stack.push(value);
              stack_frame.pcounter += 1;
            },

            Inst::New(ptr_count, aux_count) => {
              let new = self.gc.alloc(ptr_count, aux_count);
              for offset in (0 .. ptr_count).rev() {
                let ptr = self.eval_stack.pop().unwrap();
                new.set_ptr(offset, &ptr);
              }
              self.eval_stack.push(new);
              stack_frame.pcounter += 1;
            },
            Inst::NewBool(value) => {
              let new = self.gc.alloc(0, 1);
              new.aux()[0] = value as u8;
              self.eval_stack.push(new);
              stack_frame.pcounter += 1;
            },
            Inst::NewFunc(chunk_id) => {
              let chunk = (self.get_chunk)(chunk_id);
              let aux_count = mem::size_of::<usize>();
              let new = self.gc.alloc(chunk.captures, aux_count);
              for offset in (0 .. chunk.captures).rev() {
                let ptr = self.eval_stack.pop().unwrap();
                new.set_ptr(offset, &ptr);
              }
              *new.aux_usize() = chunk_id;
              self.eval_stack.push(new);
              stack_frame.pcounter += 1;
            },
          }
        },
      }
    }
  }
}

#[cfg(test)]
mod test {
  use super::*;

  #[test]
  fn test_call() {
    let chunk = Chunk{
      insts: vec![
        Inst::GetLocal(1),
        Inst::GetLocal(0),
        Inst::New(2, 0),
        Inst::Return,
      ],
      locals: 1,
      captures: 1,
    };
    let gc = GC::new();
    let bytecode = [
      Inst::NewBool(true),
      Inst::NewFunc(0),
      Inst::NewBool(false),
      Inst::Call,
      Inst::Return,
    ];
    let get_chunk = |_| &chunk;
    let mut thread = Thread::new(&gc, get_chunk, &bytecode, 0);
    assert_eq!(thread.resume(), Status::Finished);
    assert_eq!(thread.call_stack.len(), 0);
    assert_eq!(thread.eval_stack.len(), 1);
    assert_eq!(thread.eval_stack[0].ptr_count(), 2);
    assert_eq!(thread.eval_stack[0].aux_count(), 0);
    assert_eq!(thread.eval_stack[0].get_ptr(0).unwrap().ptr_count(), 0);
    assert_eq!(thread.eval_stack[0].get_ptr(0).unwrap().aux_count(), 1);
    assert_eq!(thread.eval_stack[0].get_ptr(0).unwrap().aux(), &[1]);
    assert_eq!(thread.eval_stack[0].get_ptr(1).unwrap().ptr_count(), 0);
    assert_eq!(thread.eval_stack[0].get_ptr(1).unwrap().aux_count(), 1);
    assert_eq!(thread.eval_stack[0].get_ptr(1).unwrap().aux(), &[0]);
  }

  #[test]
  fn test_new() {
    let gc = GC::new();
    let bytecode = [
      Inst::NewBool(true),
      Inst::NewBool(false),
      Inst::New(2, 0),
      Inst::Return,
    ];
    let get_chunk = |_| panic!();
    let mut thread = Thread::new(&gc, get_chunk, &bytecode, 0);
    assert_eq!(thread.resume(), Status::Finished);
    assert_eq!(thread.call_stack.len(), 0);
    assert_eq!(thread.eval_stack.len(), 1);
    assert_eq!(thread.eval_stack[0].ptr_count(), 2);
    assert_eq!(thread.eval_stack[0].aux_count(), 0);
    assert_eq!(thread.eval_stack[0].get_ptr(0).unwrap().ptr_count(), 0);
    assert_eq!(thread.eval_stack[0].get_ptr(0).unwrap().aux_count(), 1);
    assert_eq!(thread.eval_stack[0].get_ptr(0).unwrap().aux(), &[1]);
    assert_eq!(thread.eval_stack[0].get_ptr(1).unwrap().ptr_count(), 0);
    assert_eq!(thread.eval_stack[0].get_ptr(1).unwrap().aux_count(), 1);
    assert_eq!(thread.eval_stack[0].get_ptr(1).unwrap().aux(), &[0]);
  }
}
<commit_msg>Include captures in locals<commit_after>use bytecode::{Chunk, Inst};
use std::mem;
use value::{GC, Ref};

pub struct Thread<'chunk, 'gc, GetChunk> {
  gc: &'gc GC,
  get_chunk: GetChunk,
  call_stack: Vec<StackFrame<'chunk, 'gc>>,
  eval_stack: Vec<Ref<'gc>>,
}

struct StackFrame<'chunk, 'gc> {
  bytecode: &'chunk [Inst],
  pcounter: usize,
  locals: Vec<Option<Ref<'gc>>>,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Status {
  Paused,
  Finished,
}

impl<'chunk, 'gc, GetChunk> Thread<'chunk, 'gc, GetChunk>
  where GetChunk: Fn(usize) -> &'chunk Chunk {
  pub fn new(
    gc: &'gc GC,
    get_chunk: GetChunk,
    bytecode: &'chunk [Inst],
    locals: usize,
  ) -> Self {
    let stack_frame = StackFrame{
      bytecode: bytecode,
      pcounter: 0,
      locals: {
        let mut locals_vec = vec![];
        locals_vec.resize(locals, None);
        locals_vec
      },
    };
    Thread{
      gc: gc,
      get_chunk: get_chunk,
      call_stack: vec![stack_frame],
      eval_stack: vec![],
    }
  }

  pub fn resume(&mut self) -> Status {
    let mut pop_call_stack = false;
    let mut push_call_stack: Option<(Ref<'gc>, Ref<'gc>)> = None;
    loop {
      if pop_call_stack {
        self.call_stack.pop();
        pop_call_stack = false;
      }
      if let Some((callee, argument)) = push_call_stack {
        let chunk = (self.get_chunk)(*callee.aux_usize());
        self.call_stack.push(StackFrame{
          bytecode: &chunk.insts,
          pcounter: 0,
          locals: {
            let mut locals_vec = vec![];
            locals_vec.resize(chunk.locals, None);
            locals_vec[0] = Some(argument);
            for offset in 0 .. chunk.captures {
              locals_vec[offset + 1] = callee.get_ptr(offset);
            }
            locals_vec
          },
        });
        push_call_stack = None;
      }
      match self.call_stack.last_mut() {
        None => return Status::Finished,
        Some(stack_frame) => {
          match stack_frame.bytecode[stack_frame.pcounter] {
            Inst::NoOp =>
              stack_frame.pcounter += 1,

            Inst::Call => {
              let argument = self.eval_stack.pop().unwrap();
              let callee = self.eval_stack.pop().unwrap();
              stack_frame.pcounter += 1;
              push_call_stack = Some((callee, argument));
            },
            Inst::Return =>
              pop_call_stack = true,

            Inst::Pop => {
              self.eval_stack.pop().unwrap();
              stack_frame.pcounter += 1;
            },

            Inst::GetLocal(offset) => {
              let value = stack_frame.locals[offset].clone().unwrap();
              self.eval_stack.push(value);
              stack_frame.pcounter += 1;
            },

            Inst::New(ptr_count, aux_count) => {
              let new = self.gc.alloc(ptr_count, aux_count);
              for offset in (0 .. ptr_count).rev() {
                let ptr = self.eval_stack.pop().unwrap();
                new.set_ptr(offset, &ptr);
              }
              self.eval_stack.push(new);
              stack_frame.pcounter += 1;
            },
            Inst::NewBool(value) => {
              let new = self.gc.alloc(0, 1);
              new.aux()[0] = value as u8;
              self.eval_stack.push(new);
              stack_frame.pcounter += 1;
            },
            Inst::NewFunc(chunk_id) => {
              let chunk = (self.get_chunk)(chunk_id);
              let aux_count = mem::size_of::<usize>();
              let new = self.gc.alloc(chunk.captures, aux_count);
              for offset in (0 .. chunk.captures).rev() {
                let ptr = self.eval_stack.pop().unwrap();
                new.set_ptr(offset, &ptr);
              }
              *new.aux_usize() = chunk_id;
              self.eval_stack.push(new);
              stack_frame.pcounter += 1;
            },
          }
        },
      }
    }
  }
}

#[cfg(test)]
mod test {
  use super::*;

  #[test]
  fn test_call() {
    let chunk = Chunk{
      insts: vec![
        Inst::GetLocal(1),
        Inst::GetLocal(0),
        Inst::New(2, 0),
        Inst::Return,
      ],
      locals: 2,
      captures: 1,
    };
    let gc = GC::new();
    let bytecode = [
      Inst::NewBool(true),
      Inst::NewFunc(0),
      Inst::NewBool(false),
      Inst::Call,
      Inst::Return,
    ];
    let get_chunk = |_| &chunk;
    let mut thread = Thread::new(&gc, get_chunk, &bytecode, 0);
    assert_eq!(thread.resume(), Status::Finished);
    assert_eq!(thread.call_stack.len(), 0);
    assert_eq!(thread.eval_stack.len(), 1);
    assert_eq!(thread.eval_stack[0].ptr_count(), 2);
    assert_eq!(thread.eval_stack[0].aux_count(), 0);
    assert_eq!(thread.eval_stack[0].get_ptr(0).unwrap().ptr_count(), 0);
    assert_eq!(thread.eval_stack[0].get_ptr(0).unwrap().aux_count(), 1);
    assert_eq!(thread.eval_stack[0].get_ptr(0).unwrap().aux(), &[1]);
    assert_eq!(thread.eval_stack[0].get_ptr(1).unwrap().ptr_count(), 0);
    assert_eq!(thread.eval_stack[0].get_ptr(1).unwrap().aux_count(), 1);
    assert_eq!(thread.eval_stack[0].get_ptr(1).unwrap().aux(), &[0]);
  }

  #[test]
  fn test_new() {
    let gc = GC::new();
    let bytecode = [
      Inst::NewBool(true),
      Inst::NewBool(false),
      Inst::New(2, 0),
      Inst::Return,
    ];
    let get_chunk = |_| panic!();
    let mut thread = Thread::new(&gc, get_chunk, &bytecode, 0);
    assert_eq!(thread.resume(), Status::Finished);
    assert_eq!(thread.call_stack.len(), 0);
    assert_eq!(thread.eval_stack.len(), 1);
    assert_eq!(thread.eval_stack[0].ptr_count(), 2);
    assert_eq!(thread.eval_stack[0].aux_count(), 0);
    assert_eq!(thread.eval_stack[0].get_ptr(0).unwrap().ptr_count(), 0);
    assert_eq!(thread.eval_stack[0].get_ptr(0).unwrap().aux_count(), 1);
    assert_eq!(thread.eval_stack[0].get_ptr(0).unwrap().aux(), &[1]);
    assert_eq!(thread.eval_stack[0].get_ptr(1).unwrap().ptr_count(), 0);
    assert_eq!(thread.eval_stack[0].get_ptr(1).unwrap().aux_count(), 1);
    assert_eq!(thread.eval_stack[0].get_ptr(1).unwrap().aux(), &[0]);
  }
}
<|endoftext|>


<commit_before>use std::ptr;
use std::c_str::{CString, ToCStr};
use libc::{c_char, c_void, c_int, size_t};
use fcntl::{Fd, OFlag};
use errno::{SysResult, SysError, from_ffi};

#[cfg(target_os = "linux")]
pub use self::linux::*;

mod ffi {
    use libc::{c_char, c_int, size_t};
    pub use libc::{close, read, write};

    extern {
        // duplicate a file descriptor
        // doc: http://man7.org/linux/man-pages/man2/dup.2.html
        pub fn dup(oldfd: c_int) -> c_int;
        pub fn dup2(oldfd: c_int, newfd: c_int) -> c_int;
        pub fn dup3(oldfd: c_int, newfd: c_int, flags: c_int) -> c_int;

        // change working directory
        // doc: http://man7.org/linux/man-pages/man2/chdir.2.html
        pub fn chdir(path: *const c_char) -> c_int;

        // execute program
        // doc: http://man7.org/linux/man-pages/man2/execve.2.html
        pub fn execve(filename: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> c_int;

        // run the current process in the background
        // doc: http://man7.org/linux/man-pages/man3/daemon.3.html
        pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int;

        // sets the hostname to the value given
        // doc: http://man7.org/linux/man-pages/man2/gethostname.2.html
        pub fn gethostname(name: *mut c_char, len: size_t) -> c_int;

        // gets the hostname
        // doc: http://man7.org/linux/man-pages/man2/gethostname.2.html
        pub fn sethostname(name: *const c_char, len: size_t) -> c_int;
    }
}

#[inline]
pub fn dup(oldfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::dup(oldfd) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[inline]
pub fn dup2(oldfd: Fd, newfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::dup2(oldfd, newfd) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[inline]
pub fn dup3(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    let res = unsafe { ffi::dup3(oldfd, newfd, flags.bits()) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[inline]
pub fn chdir<S: ToCStr>(path: S) -> SysResult<()> {
    let path = path.to_c_str();
    let res = unsafe { ffi::chdir(path.as_ptr()) };

    if res != 0 {
        return Err(SysError::last());
    }

    return Ok(())
}

#[inline]
pub fn execve(filename: CString, args: &[CString], env: &[CString]) -> SysResult<()> {
    let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
    args_p.push(ptr::null());

    let mut env_p: Vec<*const c_char> = env.iter().map(|s| s.as_ptr()).collect();
    env_p.push(ptr::null());

    let res = unsafe {
        ffi::execve(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
    };

    if res != 0 {
        return Err(SysError::last());
    }

    // Should never reach here
    Ok(())
}

pub fn daemon(nochdir: bool, noclose: bool) -> SysResult<()> {
    let res = unsafe { ffi::daemon(nochdir as c_int, noclose as c_int) };
    from_ffi(res)
}

pub fn sethostname(name: &[u8]) -> SysResult<()> {
    let ptr = name.as_ptr() as *const c_char;
    let len = name.len() as u64;

    let res = unsafe { ffi::sethostname(ptr, len) };
    from_ffi(res)
}

pub fn gethostname(name: &mut [u8]) -> SysResult<()> {
    let ptr = name.as_mut_ptr() as *mut c_char;
    let len = name.len() as u64;

    let res = unsafe { ffi::gethostname(ptr, len) };
    from_ffi(res)
}

pub fn close(fd: Fd) -> SysResult<()> {
    let res = unsafe { ffi::close(fd) };
    from_ffi(res)
}

pub fn read(fd: Fd, buf: &mut [u8]) -> SysResult<uint> {
    let res = unsafe { ffi::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) };

    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as uint)
}

pub fn write(fd: Fd, buf: &[u8]) -> SysResult<uint> {
    let res = unsafe { ffi::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) };

    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as uint)
}

#[cfg(target_os = "linux")]
mod linux {
    use std::path::Path;
    use syscall::{syscall, SysPivotRoot};
    use errno::{SysResult, SysError};

    pub fn pivot_root(new_root: &Path, put_old: &Path) -> SysResult<()> {
        let new_root = new_root.to_c_str();
        let put_old = put_old.to_c_str();

        let res = unsafe {
            syscall(SysPivotRoot, new_root.as_ptr(), put_old.as_ptr())
        };

        if res != 0 {
            return Err(SysError::last());
        }

        Ok(())
    }
}
<commit_msg>Expose pipe and pipe2<commit_after>use std::{mem, ptr};
use std::c_str::{CString, ToCStr};
use libc::{c_char, c_void, c_int, size_t};
use fcntl::{fcntl, Fd, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC, F_SETFD, F_SETFL};
use errno::{SysResult, SysError, from_ffi};

#[cfg(target_os = "linux")]
pub use self::linux::*;

mod ffi {
    use libc::{c_char, c_int, size_t};
    pub use libc::{close, read, write, pipe};

    extern {
        // duplicate a file descriptor
        // doc: http://man7.org/linux/man-pages/man2/dup.2.html
        pub fn dup(oldfd: c_int) -> c_int;
        pub fn dup2(oldfd: c_int, newfd: c_int) -> c_int;
        pub fn dup3(oldfd: c_int, newfd: c_int, flags: c_int) -> c_int;

        // change working directory
        // doc: http://man7.org/linux/man-pages/man2/chdir.2.html
        pub fn chdir(path: *const c_char) -> c_int;

        // execute program
        // doc: http://man7.org/linux/man-pages/man2/execve.2.html
        pub fn execve(filename: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> c_int;

        // run the current process in the background
        // doc: http://man7.org/linux/man-pages/man3/daemon.3.html
        pub fn daemon(nochdir: c_int, noclose: c_int) -> c_int;

        // sets the hostname to the value given
        // doc: http://man7.org/linux/man-pages/man2/gethostname.2.html
        pub fn gethostname(name: *mut c_char, len: size_t) -> c_int;

        // gets the hostname
        // doc: http://man7.org/linux/man-pages/man2/gethostname.2.html
        pub fn sethostname(name: *const c_char, len: size_t) -> c_int;
    }
}

#[inline]
pub fn dup(oldfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::dup(oldfd) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[inline]
pub fn dup2(oldfd: Fd, newfd: Fd) -> SysResult<Fd> {
    let res = unsafe { ffi::dup2(oldfd, newfd) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[inline]
pub fn dup3(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    let res = unsafe { ffi::dup3(oldfd, newfd, flags.bits()) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(res)
}

#[inline]
pub fn chdir<S: ToCStr>(path: S) -> SysResult<()> {
    let path = path.to_c_str();
    let res = unsafe { ffi::chdir(path.as_ptr()) };

    if res != 0 {
        return Err(SysError::last());
    }

    return Ok(())
}

#[inline]
pub fn execve(filename: CString, args: &[CString], env: &[CString]) -> SysResult<()> {
    let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
    args_p.push(ptr::null());

    let mut env_p: Vec<*const c_char> = env.iter().map(|s| s.as_ptr()).collect();
    env_p.push(ptr::null());

    let res = unsafe {
        ffi::execve(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
    };

    if res != 0 {
        return Err(SysError::last());
    }

    // Should never reach here
    Ok(())
}

pub fn daemon(nochdir: bool, noclose: bool) -> SysResult<()> {
    let res = unsafe { ffi::daemon(nochdir as c_int, noclose as c_int) };
    from_ffi(res)
}

pub fn sethostname(name: &[u8]) -> SysResult<()> {
    let ptr = name.as_ptr() as *const c_char;
    let len = name.len() as u64;

    let res = unsafe { ffi::sethostname(ptr, len) };
    from_ffi(res)
}

pub fn gethostname(name: &mut [u8]) -> SysResult<()> {
    let ptr = name.as_mut_ptr() as *mut c_char;
    let len = name.len() as u64;

    let res = unsafe { ffi::gethostname(ptr, len) };
    from_ffi(res)
}

pub fn close(fd: Fd) -> SysResult<()> {
    let res = unsafe { ffi::close(fd) };
    from_ffi(res)
}

pub fn read(fd: Fd, buf: &mut [u8]) -> SysResult<uint> {
    let res = unsafe { ffi::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) };

    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as uint)
}

pub fn write(fd: Fd, buf: &[u8]) -> SysResult<uint> {
    let res = unsafe { ffi::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) };

    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as uint)
}

pub fn pipe() -> SysResult<(Fd, Fd)> {
    unsafe {
        let mut res;
        let mut fds: [c_int, ..2] = mem::uninitialized();

        res = ffi::pipe(fds.as_mut_ptr());

        if res < 0 {
            return Err(SysError::last());
        }

        Ok((fds[0], fds[1]))
    }
}

#[cfg(target_os = "linux")]
pub fn pipe2(flags: OFlag) -> SysResult<(Fd, Fd)> {
    type F = unsafe extern "C" fn(fds: *mut c_int, flags: c_int) -> c_int;

    extern {
        #[linkage = "extern_weak"]
        static pipe2: *const ();
    }

    let feat_atomic = !pipe2.is_null();

    unsafe {
        let mut res;
        let mut fds: [c_int, ..2] = mem::uninitialized();

        if feat_atomic {
            res = mem::transmute::<*const (), F>(pipe2)(
                fds.as_mut_ptr(), flags.bits());
        } else {
            res = ffi::pipe(fds.as_mut_ptr());
        }

        if res < 0 {
            return Err(SysError::last());
        }

        if !feat_atomic {
            try!(pipe2_setflags(fds[0], fds[1], flags));
        }

        Ok((fds[0], fds[1]))
    }
}

#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
pub fn pipe2(flags: OFlag) -> SysResult<(Fd, Fd)> {
    unsafe {
        let mut res;
        let mut fds: [c_int, ..2] = mem::uninitialized();

        res = ffi::pipe(fds.as_mut_ptr());

        if res < 0 {
            return Err(SysError::last());
        }

        try!(pipe2_setflags(fds[0], fds[1], flags));

        Ok((fds[0], fds[1]))
    }
}

fn pipe2_setflags(fd1: Fd, fd2: Fd, flags: OFlag) -> SysResult<()> {
    let mut res = Ok(());

    if flags.contains(O_CLOEXEC) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFD(FD_CLOEXEC)))
            .and_then(|_| fcntl(fd2, F_SETFD(FD_CLOEXEC)));
    }

    if flags.contains(O_NONBLOCK) {
        res = res
            .and_then(|_| fcntl(fd1, F_SETFL(O_NONBLOCK)))
            .and_then(|_| fcntl(fd2, F_SETFL(O_NONBLOCK)));
    }

    match res {
        Ok(_) => Ok(()),
        Err(e) => {
            let _ = close(fd1);
            let _ = close(fd2);
            return Err(e);
        }
    }
}

#[cfg(target_os = "linux")]
mod linux {
    use std::path::Path;
    use syscall::{syscall, SysPivotRoot};
    use errno::{SysResult, SysError};

    pub fn pivot_root(new_root: &Path, put_old: &Path) -> SysResult<()> {
        let new_root = new_root.to_c_str();
        let put_old = put_old.to_c_str();

        let res = unsafe {
            syscall(SysPivotRoot, new_root.as_ptr(), put_old.as_ptr())
        };

        if res != 0 {
            return Err(SysError::last());
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Handle_a_signal
//
// Note that this solution only works on Unix.
#![cfg_attr(unix, feature(std_misc))]

extern crate libc;
extern crate time;

#[cfg(all(unix, not(test)))]
fn main()
{
    use libc::consts::os::posix88::SIGINT;
    use libc::funcs::posix01::signal;
    use std::mem;
    use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
    use time::duration::Duration;

    // The time between ticks of our counter.
    let duration = 500u32; //Duration::seconds(1) / 2;
    // "SIGINT received" global variable.
    static mut GOT_SIGINT: AtomicBool = ATOMIC_BOOL_INIT;
    unsafe {
        // Initially, "SIGINT received" is false.
        GOT_SIGINT.store(false, Ordering::Release);
        // Interrupt handler that handles the SIGINT signal
        unsafe fn handle_sigint() {
            // It is dangerous to perform any system calls in interrupts, so just set the atomic
            // "SIGINT received" global to true when it arrives.
            GOT_SIGINT.store(true, Ordering::Release);
        }
        // Make handle_sigint the signal handler for SIGINT.
        signal::signal(SIGINT, mem::transmute(handle_sigint));
    }
    // Get the start time...
    let start = time::precise_time_ns();
    // Integer counter
    let mut i = 0u32;
    // Every `duration`...
    loop {
        std::thread::sleep_ms(duration);
        // Break if SIGINT was handled
        if unsafe { GOT_SIGINT.load(Ordering::Acquire) } { break }
        // Otherwise, increment and display the integer and continue the loop.
        i += 1;
        println!("{}", i);
    }
    // Get the end time.
    let end = time::precise_time_ns();
    // Compute the difference
    let diff = Duration::nanoseconds((end - start) as i64);
    // Print the difference and exit
    println!("Program has run for {} seconds", diff);
}

#[cfg(not(unix))]
fn main()
{
    println!("Not supported on this platform");
}
<commit_msg>time::duration::Duration -> time::Duration<commit_after>// Implements http://rosettacode.org/wiki/Handle_a_signal
//
// Note that this solution only works on Unix.
#![cfg_attr(unix, feature(std_misc))]

extern crate libc;
extern crate time;

#[cfg(all(unix, not(test)))]
fn main()
{
    use libc::consts::os::posix88::SIGINT;
    use libc::funcs::posix01::signal;
    use std::mem;
    use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
    use time::Duration;

    // The time between ticks of our counter.
    let duration = 500u32; //Duration::seconds(1) / 2;
    // "SIGINT received" global variable.
    static mut GOT_SIGINT: AtomicBool = ATOMIC_BOOL_INIT;
    unsafe {
        // Initially, "SIGINT received" is false.
        GOT_SIGINT.store(false, Ordering::Release);
        // Interrupt handler that handles the SIGINT signal
        unsafe fn handle_sigint() {
            // It is dangerous to perform any system calls in interrupts, so just set the atomic
            // "SIGINT received" global to true when it arrives.
            GOT_SIGINT.store(true, Ordering::Release);
        }
        // Make handle_sigint the signal handler for SIGINT.
        signal::signal(SIGINT, mem::transmute(handle_sigint));
    }
    // Get the start time...
    let start = time::precise_time_ns();
    // Integer counter
    let mut i = 0u32;
    // Every `duration`...
    loop {
        std::thread::sleep_ms(duration);
        // Break if SIGINT was handled
        if unsafe { GOT_SIGINT.load(Ordering::Acquire) } { break }
        // Otherwise, increment and display the integer and continue the loop.
        i += 1;
        println!("{}", i);
    }
    // Get the end time.
    let end = time::precise_time_ns();
    // Compute the difference
    let diff = Duration::nanoseconds((end - start) as i64);
    // Print the difference and exit
    println!("Program has run for {} seconds", diff);
}

#[cfg(not(unix))]
fn main()
{
    println!("Not supported on this platform");
}
<|endoftext|>


<commit_before>use std::libc::*;
use std::ptr;
use std::num::Zero;

use internal::bitmap_like::*;
use internal::core_drawing::*;
use internal::color::*;

use ffi::*;

pub mod external
{
	pub use super::BitmapOptions;
	pub use super::Bitmap;
	pub use super::SubBitmap;
}

pub struct BitmapOptions
{
	format: PixelFormat,
	flags: BitmapFlags
}

impl BitmapOptions
{
	pub fn new() -> BitmapOptions
	{
		BitmapOptions{ format: PixelFormatAny, flags: Zero::zero() }
	}
}

pub struct Bitmap
{
	priv allegro_bitmap: *mut ALLEGRO_BITMAP,
	priv is_ref: bool
}

impl Bitmap
{
	pub fn new(w: i32, h: i32) -> Option<Bitmap>
	{
		unsafe
		{
			let b = al_create_bitmap(w as c_int, h as c_int);
			if ptr::is_null(b)
			{
				None
			}
			else
			{
				Some(Bitmap{allegro_bitmap: b, is_ref: false})
			}
		}
	}

	pub fn new_with_options(w: i32, h: i32, opt: &BitmapOptions) -> Option<Bitmap>
	{
		unsafe
		{
			al_set_new_bitmap_flags(opt.flags.get() as c_int);
			al_set_new_bitmap_format(opt.format as c_int);
		}
		Bitmap::new(w, h)
	}

	pub fn create_sub_bitmap<'l>(&'l self, x: i32, y: i32, w: i32, h: i32) -> Option<SubBitmap<'l>>
	{
		unsafe
		{
			let b = al_create_sub_bitmap(self.allegro_bitmap, x as c_int, y as c_int, w as c_int, h as c_int);
			if ptr::is_null(b)
			{
				None
			}
			else
			{
				Some(SubBitmap{allegro_bitmap: b, parent: self})
			}
		}
	}

	pub fn maybe_clone(&self) -> Option<Bitmap>
	{
		clone_bitmap(self.allegro_bitmap)
	}
}

impl Drop for Bitmap
{
	fn drop(&mut self)
	{
		unsafe
		{
			if !self.is_ref
			{
				al_destroy_bitmap(self.allegro_bitmap);
			}
		}
	}
}

impl DrawTarget for Bitmap
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl CoreDrawing for Bitmap {}

impl BitmapLike for Bitmap
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl Clone for Bitmap
{
	fn clone(&self) -> Bitmap
	{
		self.maybe_clone().unwrap()
	}
}

pub struct SubBitmap<'m>
{
	priv allegro_bitmap: *mut ALLEGRO_BITMAP,
	priv parent: &'m Bitmap
}

impl<'m> SubBitmap<'m>
{
	pub fn create_sub_bitmap<'l>(&'l self, x: i32, y: i32, w: i32, h: i32) -> Option<SubBitmap<'l>>
	{
		unsafe
		{
			let b = al_create_sub_bitmap(self.allegro_bitmap, x as c_int, y as c_int, w as c_int, h as c_int);
			if ptr::is_null(b)
			{
				None
			}
			else
			{
				Some(SubBitmap{allegro_bitmap: b, parent: self.parent})
			}
		}
	}

	pub fn get_parent<'l>(&'l self) -> &'l Bitmap
	{
		self.parent
	}

	pub fn to_bitmap(&self) -> Option<Bitmap>
	{
		clone_bitmap(self.allegro_bitmap)
	}
}

impl<'m> DrawTarget for SubBitmap<'m>
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
	self.allegro_bitmap
	}
}

impl<'m> BitmapLike for SubBitmap<'m>
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl<'m> CoreDrawing for SubBitmap<'m> {}

/* Should be safe as Bitmap does not reference a SubBitmap*/
#[unsafe_destructor]
impl<'m> Drop for SubBitmap<'m>
{
	fn drop(&mut self)
	{
		unsafe
		{
			al_destroy_bitmap(self.allegro_bitmap);
		}
	}
}

pub fn new_bitmap_ref(bmp: *mut ALLEGRO_BITMAP) -> Bitmap
{
	Bitmap{ allegro_bitmap: bmp, is_ref: true }
}

pub fn clone_bitmap(bmp: *mut ALLEGRO_BITMAP) -> Option<Bitmap>
{
	unsafe
	{
		if al_get_target_bitmap() != bmp
		{
			al_set_target_bitmap(bmp)
		}
		let b = al_clone_bitmap(bmp);
		if ptr::is_null(b)
		{
			None
		}
		else
		{
			Some(Bitmap{ allegro_bitmap: b, is_ref: false })
		}
	}
}

impl ::internal::core::Core
{
	pub fn create_bitmap(&self, w: i32, h: i32) -> Option<Bitmap>
	{
		Bitmap::new(w, h)
	}

	pub fn create_bitmap_with_options(&self, w: i32, h: i32, opt: &BitmapOptions) -> Option<Bitmap>
	{
		Bitmap::new_with_options(w, h, opt)
	}
}
<commit_msg>clone_bitmap does not need to set the target<commit_after>use std::libc::*;
use std::ptr;
use std::num::Zero;

use internal::bitmap_like::*;
use internal::core_drawing::*;
use internal::color::*;

use ffi::*;

pub mod external
{
	pub use super::BitmapOptions;
	pub use super::Bitmap;
	pub use super::SubBitmap;
}

pub struct BitmapOptions
{
	format: PixelFormat,
	flags: BitmapFlags
}

impl BitmapOptions
{
	pub fn new() -> BitmapOptions
	{
		BitmapOptions{ format: PixelFormatAny, flags: Zero::zero() }
	}
}

pub struct Bitmap
{
	priv allegro_bitmap: *mut ALLEGRO_BITMAP,
	priv is_ref: bool
}

impl Bitmap
{
	pub fn new(w: i32, h: i32) -> Option<Bitmap>
	{
		unsafe
		{
			let b = al_create_bitmap(w as c_int, h as c_int);
			if ptr::is_null(b)
			{
				None
			}
			else
			{
				Some(Bitmap{allegro_bitmap: b, is_ref: false})
			}
		}
	}

	pub fn new_with_options(w: i32, h: i32, opt: &BitmapOptions) -> Option<Bitmap>
	{
		unsafe
		{
			al_set_new_bitmap_flags(opt.flags.get() as c_int);
			al_set_new_bitmap_format(opt.format as c_int);
		}
		Bitmap::new(w, h)
	}

	pub fn create_sub_bitmap<'l>(&'l self, x: i32, y: i32, w: i32, h: i32) -> Option<SubBitmap<'l>>
	{
		unsafe
		{
			let b = al_create_sub_bitmap(self.allegro_bitmap, x as c_int, y as c_int, w as c_int, h as c_int);
			if ptr::is_null(b)
			{
				None
			}
			else
			{
				Some(SubBitmap{allegro_bitmap: b, parent: self})
			}
		}
	}

	pub fn maybe_clone(&self) -> Option<Bitmap>
	{
		clone_bitmap(self.allegro_bitmap)
	}
}

impl Drop for Bitmap
{
	fn drop(&mut self)
	{
		unsafe
		{
			if !self.is_ref
			{
				al_destroy_bitmap(self.allegro_bitmap);
			}
		}
	}
}

impl DrawTarget for Bitmap
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl CoreDrawing for Bitmap {}

impl BitmapLike for Bitmap
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl Clone for Bitmap
{
	fn clone(&self) -> Bitmap
	{
		self.maybe_clone().unwrap()
	}
}

pub struct SubBitmap<'m>
{
	priv allegro_bitmap: *mut ALLEGRO_BITMAP,
	priv parent: &'m Bitmap
}

impl<'m> SubBitmap<'m>
{
	pub fn create_sub_bitmap<'l>(&'l self, x: i32, y: i32, w: i32, h: i32) -> Option<SubBitmap<'l>>
	{
		unsafe
		{
			let b = al_create_sub_bitmap(self.allegro_bitmap, x as c_int, y as c_int, w as c_int, h as c_int);
			if ptr::is_null(b)
			{
				None
			}
			else
			{
				Some(SubBitmap{allegro_bitmap: b, parent: self.parent})
			}
		}
	}

	pub fn get_parent<'l>(&'l self) -> &'l Bitmap
	{
		self.parent
	}

	pub fn to_bitmap(&self) -> Option<Bitmap>
	{
		clone_bitmap(self.allegro_bitmap)
	}
}

impl<'m> DrawTarget for SubBitmap<'m>
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
	self.allegro_bitmap
	}
}

impl<'m> BitmapLike for SubBitmap<'m>
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl<'m> CoreDrawing for SubBitmap<'m> {}

/* Should be safe as Bitmap does not reference a SubBitmap*/
#[unsafe_destructor]
impl<'m> Drop for SubBitmap<'m>
{
	fn drop(&mut self)
	{
		unsafe
		{
			al_destroy_bitmap(self.allegro_bitmap);
		}
	}
}

pub fn new_bitmap_ref(bmp: *mut ALLEGRO_BITMAP) -> Bitmap
{
	Bitmap{ allegro_bitmap: bmp, is_ref: true }
}

pub fn clone_bitmap(bmp: *mut ALLEGRO_BITMAP) -> Option<Bitmap>
{
	unsafe
	{
		let b = al_clone_bitmap(bmp);
		if ptr::is_null(b)
		{
			None
		}
		else
		{
			Some(Bitmap{ allegro_bitmap: b, is_ref: false })
		}
	}
}

impl ::internal::core::Core
{
	pub fn create_bitmap(&self, w: i32, h: i32) -> Option<Bitmap>
	{
		Bitmap::new(w, h)
	}

	pub fn create_bitmap_with_options(&self, w: i32, h: i32, opt: &BitmapOptions) -> Option<Bitmap>
	{
		Bitmap::new_with_options(w, h, opt)
	}
}
<|endoftext|>


<commit_before>use std::fmt;

pub mod lexer;
pub mod expr;

#[deriving(Clone)]
pub struct SourcePos {
    pub line: uint,
    pub col: uint,
}

impl fmt::Show for SourcePos {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{}:{}", self.line, self.col)
	}
}

pub struct CompileError {
	pub msg: String,
    pub pos: SourcePos,
}

impl fmt::Show for CompileError {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "@{}\n\t{}", self.pos, self.msg)
	}
}
<commit_msg>fix some spaces -> tabs<commit_after>use std::fmt;

pub mod lexer;
pub mod expr;

#[deriving(Clone)]
pub struct SourcePos {
	pub line: uint,
	pub col: uint,
}

impl fmt::Show for SourcePos {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{}:{}", self.line, self.col)
	}
}

pub struct CompileError {
	pub msg: String,
	pub pos: SourcePos,
}

impl fmt::Show for CompileError {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "@{}\n\t{}", self.pos, self.msg)
	}
}
<|endoftext|>


<commit_before>//! A module to handle `Writer`

use std::io::Write;

use errors::{Error, Result};
use events::Event;

/// XML writer.
///
/// Writes XML `Event`s to a `Write` implementor.
///
/// # Examples
///
/// ```rust
/// # extern crate quick_xml;
/// # fn main() {
/// use quick_xml::{Reader, Writer};
/// use quick_xml::events::{Event, BytesEnd, BytesStart};
/// use std::io::Cursor;
///
/// let xml = r#"<this_tag k1="v1" k2="v2"><child>text</child></this_tag>"#;
/// let mut reader = Reader::from_str(xml);
/// reader.trim_text(true);
/// let mut writer = Writer::new(Cursor::new(Vec::new()));
/// let mut buf = Vec::new();
/// loop {
///     match reader.read_event(&mut buf) {
///         Ok(Event::Start(ref e)) if e.name() == b"this_tag" => {
///
///             // crates a new element ... alternatively we could reuse `e` by calling
///             // `e.into_owned()`
///             let mut elem = BytesStart::owned(b"my_elem".to_vec(), "my_elem".len());
///
///             // collect existing attributes
///             elem.extend_attributes(e.attributes().map(|attr| attr.unwrap()));
///
///             // copy existing attributes, adds a new my-key="some value" attribute
///             elem.push_attribute(("my-key", "some value"));
///
///             // writes the event to the writer
///             assert!(writer.write_event(Event::Start(elem)).is_ok());
///         },
///         Ok(Event::End(ref e)) if e.name() == b"this_tag" => {
///             assert!(writer.write_event(Event::End(BytesEnd::borrowed(b"my_elem"))).is_ok());
///         },
///         Ok(Event::Eof) => break,
///         // we can either move or borrow the event to write, depending on your use-case
///         Ok(e) => assert!(writer.write_event(&e).is_ok()),
///         Err(e) => panic!("{}", e),
///     }
///     buf.clear();
/// }
///
/// let result = writer.into_inner().into_inner();
/// let expected = r#"<my_elem k1="v1" k2="v2" my-key="some value"><child>text</child></my_elem>"#;
/// assert_eq!(result, expected.as_bytes());
/// # }
/// ```
#[derive(Clone)]
pub struct Writer<W: Write> {
    /// underlying writer
    writer: W,
    indent: Option<Indentation>,
}

impl<W: Write> Writer<W> {
    /// Creates a Writer from a generic Write
    pub fn new(inner: W) -> Writer<W> {
        Writer {
            writer: inner,
            indent: None,
        }
    }

    /// Creates a Writer with configured whitespace indents from a generic Write
    pub fn new_with_indent(inner: W, indent_char: u8, indent_size: usize) -> Writer<W> {
        Writer {
            writer: inner,
            indent: Some(Indentation::new(indent_char, indent_size)),
        }
    }

    /// Consumes this `Writer`, returning the underlying writer.
    pub fn into_inner(self) -> W {
        self.writer
    }

    /// Get inner writer, keeping ownership
    pub fn inner(&mut self) -> &mut W {
        &mut self.writer
    }

    /// Writes the given event to the underlying writer.
    pub fn write_event<'a, E: AsRef<Event<'a>>>(&mut self, event: E) -> Result<usize> {
        let mut next_should_line_break = true;
        let result = match *event.as_ref() {
            Event::Start(ref e) => {
                let result = self.write_wrapped(b"<", e, b">");
                if let Some(i) = self.indent.as_mut() {
                    i.grow();
                }
                result
            }
            Event::End(ref e) => {
                if let Some(i) = self.indent.as_mut() {
                    i.shrink();
                }
                self.write_wrapped(b"</", e, b">")
            }
            Event::Empty(ref e) => self.write_wrapped(b"<", e, b"/>"),
            Event::Text(ref e) => {
                next_should_line_break = false;
                self.write(&e.escaped())
            }
            Event::Comment(ref e) => self.write_wrapped(b"<!--", e, b"-->"),
            Event::CData(ref e) => self.write_wrapped(b"<![CDATA[", e, b"]]>"),
            Event::Decl(ref e) => self.write_wrapped(b"<?", e, b"?>"),
            Event::PI(ref e) => self.write_wrapped(b"<?", e, b"?>"),
            Event::DocType(ref e) => self.write_wrapped(b"<!DOCTYPE", e, b">"),
            Event::Eof => Ok(0),
        };
        if let Some(i) = self.indent.as_mut() {
            i.should_line_break = next_should_line_break;
        }
        result
    }

    /// Writes bytes
    #[inline]
    pub fn write(&mut self, value: &[u8]) -> Result<usize> {
        self.writer.write(value).map_err(Error::Io)
    }

    #[inline]
    fn write_wrapped(&mut self, before: &[u8], value: &[u8], after: &[u8]) -> Result<usize> {
        let mut wrote = 0;
        if let Some(ref i) = self.indent {
            if i.should_line_break {
                wrote = self.writer.write(b"\n").map_err(Error::Io)?
                    + self
                        .writer
                        .write(&i.indents[..i.indents_len])
                        .map_err(Error::Io)?;
            }
        }
        Ok(wrote + self.write(before)? + self.write(value)? + self.write(after)?)
    }

    /// Manually write a newline and indentation at the proper level.
    ///
    /// This can be used when the heuristic to line break and indent after any [Event] apart
    /// from [Text] fails such as when a [Start] occurs directly after [Text].
    /// This method will do nothing if `Writer` was not constructed with `new_with_indent`.
    ///
    /// [Event]: events/enum.Event.html
    /// [Text]: events/enum.Event.html#variant.Text
    /// [Start]: events/enum.Event.html#variant.Start
    pub fn write_indent(&mut self) -> Result<usize> {
        let mut wrote = 0;
        if let Some(ref i) = self.indent {
            wrote = self.writer.write(b"\n").map_err(Error::Io)?
                + self
                    .writer
                    .write(&i.indents[..i.indents_len])
                    .map_err(Error::Io)?;
        }
        Ok(wrote)
    }

}

#[derive(Clone)]
struct Indentation {
    should_line_break: bool,
    indent_char: u8,
    indent_size: usize,
    indents: Vec<u8>,
    indents_len: usize,
}

impl Indentation {
    fn new(indent_char: u8, indent_size: usize) -> Indentation {
        Indentation {
            should_line_break: false,
            indent_char,
            indent_size,
            indents: vec![indent_char; 128],
            indents_len: 0,
        }
    }

    fn grow(&mut self) {
        self.indents_len = self.indents_len + self.indent_size;
        if self.indents_len > self.indents.len() {
            self.indents.resize(self.indents_len, self.indent_char);
        }
    }

    fn shrink(&mut self) {
        self.indents_len = self.indents_len - self.indent_size;
    }
}
<commit_msg>Fix underflow on shrink<commit_after>//! A module to handle `Writer`

use std::io::Write;

use errors::{Error, Result};
use events::Event;

/// XML writer.
///
/// Writes XML `Event`s to a `Write` implementor.
///
/// # Examples
///
/// ```rust
/// # extern crate quick_xml;
/// # fn main() {
/// use quick_xml::{Reader, Writer};
/// use quick_xml::events::{Event, BytesEnd, BytesStart};
/// use std::io::Cursor;
///
/// let xml = r#"<this_tag k1="v1" k2="v2"><child>text</child></this_tag>"#;
/// let mut reader = Reader::from_str(xml);
/// reader.trim_text(true);
/// let mut writer = Writer::new(Cursor::new(Vec::new()));
/// let mut buf = Vec::new();
/// loop {
///     match reader.read_event(&mut buf) {
///         Ok(Event::Start(ref e)) if e.name() == b"this_tag" => {
///
///             // crates a new element ... alternatively we could reuse `e` by calling
///             // `e.into_owned()`
///             let mut elem = BytesStart::owned(b"my_elem".to_vec(), "my_elem".len());
///
///             // collect existing attributes
///             elem.extend_attributes(e.attributes().map(|attr| attr.unwrap()));
///
///             // copy existing attributes, adds a new my-key="some value" attribute
///             elem.push_attribute(("my-key", "some value"));
///
///             // writes the event to the writer
///             assert!(writer.write_event(Event::Start(elem)).is_ok());
///         },
///         Ok(Event::End(ref e)) if e.name() == b"this_tag" => {
///             assert!(writer.write_event(Event::End(BytesEnd::borrowed(b"my_elem"))).is_ok());
///         },
///         Ok(Event::Eof) => break,
///         // we can either move or borrow the event to write, depending on your use-case
///         Ok(e) => assert!(writer.write_event(&e).is_ok()),
///         Err(e) => panic!("{}", e),
///     }
///     buf.clear();
/// }
///
/// let result = writer.into_inner().into_inner();
/// let expected = r#"<my_elem k1="v1" k2="v2" my-key="some value"><child>text</child></my_elem>"#;
/// assert_eq!(result, expected.as_bytes());
/// # }
/// ```
#[derive(Clone)]
pub struct Writer<W: Write> {
    /// underlying writer
    writer: W,
    indent: Option<Indentation>,
}

impl<W: Write> Writer<W> {
    /// Creates a Writer from a generic Write
    pub fn new(inner: W) -> Writer<W> {
        Writer {
            writer: inner,
            indent: None,
        }
    }

    /// Creates a Writer with configured whitespace indents from a generic Write
    pub fn new_with_indent(inner: W, indent_char: u8, indent_size: usize) -> Writer<W> {
        Writer {
            writer: inner,
            indent: Some(Indentation::new(indent_char, indent_size)),
        }
    }

    /// Consumes this `Writer`, returning the underlying writer.
    pub fn into_inner(self) -> W {
        self.writer
    }

    /// Get inner writer, keeping ownership
    pub fn inner(&mut self) -> &mut W {
        &mut self.writer
    }

    /// Writes the given event to the underlying writer.
    pub fn write_event<'a, E: AsRef<Event<'a>>>(&mut self, event: E) -> Result<usize> {
        let mut next_should_line_break = true;
        let result = match *event.as_ref() {
            Event::Start(ref e) => {
                let result = self.write_wrapped(b"<", e, b">");
                if let Some(i) = self.indent.as_mut() {
                    i.grow();
                }
                result
            }
            Event::End(ref e) => {
                if let Some(i) = self.indent.as_mut() {
                    i.shrink();
                }
                self.write_wrapped(b"</", e, b">")
            }
            Event::Empty(ref e) => self.write_wrapped(b"<", e, b"/>"),
            Event::Text(ref e) => {
                next_should_line_break = false;
                self.write(&e.escaped())
            }
            Event::Comment(ref e) => self.write_wrapped(b"<!--", e, b"-->"),
            Event::CData(ref e) => self.write_wrapped(b"<![CDATA[", e, b"]]>"),
            Event::Decl(ref e) => self.write_wrapped(b"<?", e, b"?>"),
            Event::PI(ref e) => self.write_wrapped(b"<?", e, b"?>"),
            Event::DocType(ref e) => self.write_wrapped(b"<!DOCTYPE", e, b">"),
            Event::Eof => Ok(0),
        };
        if let Some(i) = self.indent.as_mut() {
            i.should_line_break = next_should_line_break;
        }
        result
    }

    /// Writes bytes
    #[inline]
    pub fn write(&mut self, value: &[u8]) -> Result<usize> {
        self.writer.write(value).map_err(Error::Io)
    }

    #[inline]
    fn write_wrapped(&mut self, before: &[u8], value: &[u8], after: &[u8]) -> Result<usize> {
        let mut wrote = 0;
        if let Some(ref i) = self.indent {
            if i.should_line_break {
                wrote = self.writer.write(b"\n").map_err(Error::Io)?
                    + self
                        .writer
                        .write(&i.indents[..i.indents_len])
                        .map_err(Error::Io)?;
            }
        }
        Ok(wrote + self.write(before)? + self.write(value)? + self.write(after)?)
    }

    /// Manually write a newline and indentation at the proper level.
    ///
    /// This can be used when the heuristic to line break and indent after any [Event] apart
    /// from [Text] fails such as when a [Start] occurs directly after [Text].
    /// This method will do nothing if `Writer` was not constructed with `new_with_indent`.
    ///
    /// [Event]: events/enum.Event.html
    /// [Text]: events/enum.Event.html#variant.Text
    /// [Start]: events/enum.Event.html#variant.Start
    pub fn write_indent(&mut self) -> Result<usize> {
        let mut wrote = 0;
        if let Some(ref i) = self.indent {
            wrote = self.writer.write(b"\n").map_err(Error::Io)?
                + self
                    .writer
                    .write(&i.indents[..i.indents_len])
                    .map_err(Error::Io)?;
        }
        Ok(wrote)
    }

}

#[derive(Clone)]
struct Indentation {
    should_line_break: bool,
    indent_char: u8,
    indent_size: usize,
    indents: Vec<u8>,
    indents_len: usize,
}

impl Indentation {
    fn new(indent_char: u8, indent_size: usize) -> Indentation {
        Indentation {
            should_line_break: false,
            indent_char,
            indent_size,
            indents: vec![indent_char; 128],
            indents_len: 0,
        }
    }

    fn grow(&mut self) {
        self.indents_len = self.indents_len + self.indent_size;
        if self.indents_len > self.indents.len() {
            self.indents.resize(self.indents_len, self.indent_char);
        }
    }

    fn shrink(&mut self) {
        self.indents_len = match self.indents_len.checked_sub(self.indent_size) {
            Some(result) => result,
            None => 0,
        };
    }
}
<|endoftext|>


<commit_before>use assembler::Assemble;
use disassembler::Disassemble;
use native::{Arch, Instruction};
//use definitions::{RegDefinition, SubRegDefinition, Definition, GenDefinition};

//use std::collections::HashMap;

#[allow(non_camel_case_types)]
pub struct X86_64;

impl X86_64 {
    fn get_opnd_width(opnd: &str) -> u32 {
        let definition = Self::gen_definition();
        if definition.has_reg(opnd) {
            definition.get_reg_width(opnd)
        } else {
            // Parse it, it's (probably?) a memory pointer
            if opnd.starts_with("dword ptr") {
                32
            } else if opnd.starts_with("qword ptr") {
                64
            } else if opnd.starts_with("byte ptr") {
                8
            } else {
                panic!(format!("opnd: `{}` not supported", opnd))
            }
        }
    }
}

impl Assemble for X86_64 {
    fn assemble(text: &str) -> Option<Vec<u8>> {
        Self::assemble_text(Arch::X86_64, text)
    }
}

impl Disassemble for X86_64 {
    // XXX_ this could be improved, making Instruction a better
    // representation of the operands in a generic way so it's parsed
    // once by `disassemble` instead of every time it's needed by some
    // other function.
    fn get_registers(ins: &Instruction) -> Vec<&'static str> {
        let mut res = Vec::new();
        let def = Self::gen_definition();
        for opnd in &ins.opnds {
            let t = opnd.text().to_uppercase();
            // Try to match Reg or SubReg
            for &reg_name in def.regs.keys().chain(def.sub_regs.keys()) {
                // XXX_ contains can match name parts (AX in EAX)
                // if t.contains(reg_name) {
                if t == reg_name {
                    res.push(reg_name);
                }
            }
        }
        res
    }

    fn disassemble(bytes: &[u8], address: u64) -> Option<Instruction> {
        let (mnemonic, op_str) =
            Self::disassemble_arch(Arch::X86_64, bytes, address).unwrap();
        let opnds: Vec<(&str, u32)> =
            op_str.split(',')
            .map(|s| s.trim())
            .map(|s| (s, Self::get_opnd_width(s)))
            .collect();
        Some(Instruction::new(&mnemonic,
                              &opnds))

    }
}

include!("x86_64_gen.rs");

#[test]
fn test_disassemble() {
    let out = X86_64::disassemble(&[0xff, 0x25, 0x42, 0x7e, 0x21, 0x00], 0x1000);
    println!("{:?}", out);
    let out = X86_64::disassemble(&[0x48, 0x89, 0xE0], 0x1000);
    println!("{:?}", out);
    let out = X86_64::disassemble(&[0x89, 0xC0], 0x1000);
    println!("{:?}", out);
    let out = X86_64::disassemble(&[0xAA], 0x1000);
    println!("{:?}", out);
    let out = X86_64::disassemble(&[0x48, 0xA3, 0x00, 0x90, 0x9A,
                                    0x93, 0xE6, 0x7F, 0x00, 0x00], 0x1000);
    println!("{:?}", out);

}

#[test]
fn test_assemble() {
    let out = X86_64::assemble("mov eax, 0x10");
    //println!("{:?}", out);
    assert_eq!(true, out.is_some());
    // Test the pre defined code
    let def = X86_64::gen_definition();
    // Epilogue
    let epilogue = def.epilogue;
    let parsed_epilogue = epilogue.replace("%0", "0x40ffff");
    let asm_epilogue = X86_64::assemble(&parsed_epilogue);
    //println!("{:?}", asm_epilogue);
    assert_eq!(true, asm_epilogue.is_some());
    // Prologue
    let prologue = def.prologue;
    let parsed_prologue = prologue.replace("%0", "0x40ffff");
    let asm_prologue = X86_64::assemble(&parsed_prologue);
    //println!("{:?}", asm_prologue);
    assert_eq!(true, asm_prologue.is_some());
}
<commit_msg>x86_64::disassemble now can deal with instructions without operands<commit_after>use assembler::Assemble;
use disassembler::Disassemble;
use native::{Arch, Instruction};
//use definitions::{RegDefinition, SubRegDefinition, Definition, GenDefinition};

//use std::collections::HashMap;

#[allow(non_camel_case_types)]
pub struct X86_64;

impl X86_64 {
    fn get_opnd_width(opnd: &str) -> u32 {
        let definition = Self::gen_definition();
        if definition.has_reg(opnd) {
            definition.get_reg_width(opnd)
        } else {
            // Parse it, it's (probably?) a memory pointer
            if opnd.starts_with("dword ptr") {
                32
            } else if opnd.starts_with("qword ptr") {
                64
            } else if opnd.starts_with("byte ptr") {
                8
            } else {
                panic!(format!("opnd: `{}` not supported", opnd))
            }
        }
    }
}

impl Assemble for X86_64 {
    fn assemble(text: &str) -> Option<Vec<u8>> {
        Self::assemble_text(Arch::X86_64, text)
    }
}

impl Disassemble for X86_64 {
    // XXX_ this could be improved, making Instruction a better
    // representation of the operands in a generic way so it's parsed
    // once by `disassemble` instead of every time it's needed by some
    // other function.
    fn get_registers(ins: &Instruction) -> Vec<&'static str> {
        let mut res = Vec::new();
        let def = Self::gen_definition();
        for opnd in &ins.opnds {
            let t = opnd.text().to_uppercase();
            // Try to match Reg or SubReg
            for &reg_name in def.regs.keys().chain(def.sub_regs.keys()) {
                // XXX_ contains can match name parts (AX in EAX)
                // if t.contains(reg_name) {
                if t == reg_name {
                    res.push(reg_name);
                }
            }
        }
        res
    }

    fn disassemble(bytes: &[u8], address: u64) -> Option<Instruction> {
        let (mnemonic, op_str) =
            Self::disassemble_arch(Arch::X86_64, bytes, address).unwrap();

        let opnds: Vec<(&str, u32)> =
            if op_str.trim().is_empty() {
                Vec::new()
            } else {
                op_str.split(',')
                    .map(|s| s.trim())
                    .map(|s| (s, Self::get_opnd_width(s)))
                    .collect()
            };
        Some(Instruction::new(&mnemonic,
                              &opnds))

    }
}

include!("x86_64_gen.rs");

#[test]
fn test_disassemble() {
    let out = X86_64::disassemble(&[0xff, 0x25, 0x42, 0x7e, 0x21, 0x00], 0x1000);
    println!("{:?}", out);
    let out = X86_64::disassemble(&[0x48, 0x89, 0xE0], 0x1000);
    println!("{:?}", out);
    let out = X86_64::disassemble(&[0x89, 0xC0], 0x1000);
    println!("{:?}", out);
    let out = X86_64::disassemble(&[0xAA], 0x1000);
    println!("{:?}", out);
    let out = X86_64::disassemble(&[0x48, 0xA3, 0x00, 0x90, 0x9A,
                                    0x93, 0xE6, 0x7F, 0x00, 0x00], 0x1000);
    println!("{:?}", out);

}

#[test]
fn test_assemble() {
    let out = X86_64::assemble("mov eax, 0x10");
    //println!("{:?}", out);
    assert_eq!(true, out.is_some());
    // Test the pre defined code
    let def = X86_64::gen_definition();
    // Epilogue
    let epilogue = def.epilogue;
    let parsed_epilogue = epilogue.replace("%0", "0x40ffff");
    let asm_epilogue = X86_64::assemble(&parsed_epilogue);
    //println!("{:?}", asm_epilogue);
    assert_eq!(true, asm_epilogue.is_some());
    // Prologue
    let prologue = def.prologue;
    let parsed_prologue = prologue.replace("%0", "0x40ffff");
    let asm_prologue = X86_64::assemble(&parsed_prologue);
    //println!("{:?}", asm_prologue);
    assert_eq!(true, asm_prologue.is_some());
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use option::{Option, Some, None};
use rt::sched::Scheduler;
use rt::task::Task;
use rt::local_ptr;
use rt::rtio::{EventLoop, IoFactoryObject};
//use borrow::to_uint;
use cell::Cell;

pub trait Local {
    fn put(value: ~Self);
    fn take() -> ~Self;
    fn exists() -> bool;
    fn borrow<T>(f: &fn(&mut Self) -> T) -> T;
    unsafe fn unsafe_borrow() -> *mut Self;
    unsafe fn try_unsafe_borrow() -> Option<*mut Self>;
}

impl Local for Task {
    fn put(value: ~Task) { unsafe { local_ptr::put(value) } }
    fn take() -> ~Task { unsafe { local_ptr::take() } }
    fn exists() -> bool { local_ptr::exists() }
    fn borrow<T>(f: &fn(&mut Task) -> T) -> T {
        let mut res: Option<T> = None;
        let res_ptr: *mut Option<T> = &mut res;
        unsafe {
            do local_ptr::borrow |task| {
                let result = f(task);
                *res_ptr = Some(result);
            }
        }
        match res {
            Some(r) => { r }
            None => { rtabort!("function failed in local_borrow") }
        }
    }
    unsafe fn unsafe_borrow() -> *mut Task { local_ptr::unsafe_borrow() }
    unsafe fn try_unsafe_borrow() -> Option<*mut Task> {
        if Local::exists::<Task>() {
            Some(Local::unsafe_borrow())
        } else {
            None
        }
    }
}

impl Local for Scheduler {
    fn put(value: ~Scheduler) {
        let value = Cell::new(value);
        do Local::borrow::<Task,()> |task| {
            let task = task;
            task.sched = Some(value.take());
        };
    }
    fn take() -> ~Scheduler {
        do Local::borrow::<Task,~Scheduler> |task| {
            let sched = task.sched.take_unwrap();
            let task = task;
            task.sched = None;
            sched
        }
    }
    fn exists() -> bool {
        do Local::borrow::<Task,bool> |task| {
            match task.sched {
                Some(ref _task) => true,
                None => false
            }
        }
    }
    fn borrow<T>(f: &fn(&mut Scheduler) -> T) -> T {
        do Local::borrow::<Task, T> |task| {
            match task.sched {
                Some(~ref mut task) => {
                    f(task)
                }
                None => {
                    rtabort!("no scheduler")
                }
            }
        }
    }
    unsafe fn unsafe_borrow() -> *mut Scheduler {
        match (*Local::unsafe_borrow::<Task>()).sched {
            Some(~ref mut sched) => {
                let s: *mut Scheduler = &mut *sched;
                return s;
            }
            None => {
                rtabort!("no scheduler")
            }
        }
    }
    unsafe fn try_unsafe_borrow() -> Option<*mut Scheduler> {
        if Local::exists::<Scheduler>() {
            Some(Local::unsafe_borrow())
        } else {
            None
        }
    }
}

// XXX: This formulation won't work once ~IoFactoryObject is a real trait pointer
impl Local for IoFactoryObject {
    fn put(_value: ~IoFactoryObject) { rtabort!("unimpl") }
    fn take() -> ~IoFactoryObject { rtabort!("unimpl") }
    fn exists() -> bool { rtabort!("unimpl") }
    fn borrow<T>(_f: &fn(&mut IoFactoryObject) -> T) -> T { rtabort!("unimpl") }
    unsafe fn unsafe_borrow() -> *mut IoFactoryObject {
        let sched = Local::unsafe_borrow::<Scheduler>();
        let io: *mut IoFactoryObject = (*sched).event_loop.io().unwrap();
        return io;
    }
    unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> { rtabort!("unimpl") }
}

#[cfg(test)]
mod test {
    use rt::test::*;
    use super::*;
    use rt::task::Task;
    use rt::local_ptr;

    #[test]
    fn thread_local_task_smoke_test() {
        local_ptr::init_tls_key();
        let mut sched = ~new_test_uv_sched();
        let task = ~Task::new_root(&mut sched.stack_pool, || {});
        Local::put(task);
        let task: ~Task = Local::take();
        cleanup_task(task);
    }

    #[test]
    fn thread_local_task_two_instances() {
        local_ptr::init_tls_key();
        let mut sched = ~new_test_uv_sched();
        let task = ~Task::new_root(&mut sched.stack_pool, || {});
        Local::put(task);
        let task: ~Task = Local::take();
        cleanup_task(task);
        let task = ~Task::new_root(&mut sched.stack_pool, || {});
        Local::put(task);
        let task: ~Task = Local::take();
        cleanup_task(task);

    }

    #[test]
    fn borrow_smoke_test() {
        local_ptr::init_tls_key();
        let mut sched = ~new_test_uv_sched();
        let task = ~Task::new_root(&mut sched.stack_pool, || {});
        Local::put(task);

        unsafe {
            let _task: *mut Task = Local::unsafe_borrow();
        }
        let task: ~Task = Local::take();
        cleanup_task(task);
    }

    #[test]
    fn borrow_with_return() {
        local_ptr::init_tls_key();
        let mut sched = ~new_test_uv_sched();
        let task = ~Task::new_root(&mut sched.stack_pool, || {});
        Local::put(task);

        let res = do Local::borrow::<Task,bool> |_task| {
            true
        };
        assert!(res)
        let task: ~Task = Local::take();
        cleanup_task(task);
    }

}

<commit_msg>std::rt: Run the tests for Local in a bare thread<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use option::{Option, Some, None};
use rt::sched::Scheduler;
use rt::task::Task;
use rt::local_ptr;
use rt::rtio::{EventLoop, IoFactoryObject};
//use borrow::to_uint;
use cell::Cell;

pub trait Local {
    fn put(value: ~Self);
    fn take() -> ~Self;
    fn exists() -> bool;
    fn borrow<T>(f: &fn(&mut Self) -> T) -> T;
    unsafe fn unsafe_borrow() -> *mut Self;
    unsafe fn try_unsafe_borrow() -> Option<*mut Self>;
}

impl Local for Task {
    fn put(value: ~Task) { unsafe { local_ptr::put(value) } }
    fn take() -> ~Task { unsafe { local_ptr::take() } }
    fn exists() -> bool { local_ptr::exists() }
    fn borrow<T>(f: &fn(&mut Task) -> T) -> T {
        let mut res: Option<T> = None;
        let res_ptr: *mut Option<T> = &mut res;
        unsafe {
            do local_ptr::borrow |task| {
                let result = f(task);
                *res_ptr = Some(result);
            }
        }
        match res {
            Some(r) => { r }
            None => { rtabort!("function failed in local_borrow") }
        }
    }
    unsafe fn unsafe_borrow() -> *mut Task { local_ptr::unsafe_borrow() }
    unsafe fn try_unsafe_borrow() -> Option<*mut Task> {
        if Local::exists::<Task>() {
            Some(Local::unsafe_borrow())
        } else {
            None
        }
    }
}

impl Local for Scheduler {
    fn put(value: ~Scheduler) {
        let value = Cell::new(value);
        do Local::borrow::<Task,()> |task| {
            let task = task;
            task.sched = Some(value.take());
        };
    }
    fn take() -> ~Scheduler {
        do Local::borrow::<Task,~Scheduler> |task| {
            let sched = task.sched.take_unwrap();
            let task = task;
            task.sched = None;
            sched
        }
    }
    fn exists() -> bool {
        do Local::borrow::<Task,bool> |task| {
            match task.sched {
                Some(ref _task) => true,
                None => false
            }
        }
    }
    fn borrow<T>(f: &fn(&mut Scheduler) -> T) -> T {
        do Local::borrow::<Task, T> |task| {
            match task.sched {
                Some(~ref mut task) => {
                    f(task)
                }
                None => {
                    rtabort!("no scheduler")
                }
            }
        }
    }
    unsafe fn unsafe_borrow() -> *mut Scheduler {
        match (*Local::unsafe_borrow::<Task>()).sched {
            Some(~ref mut sched) => {
                let s: *mut Scheduler = &mut *sched;
                return s;
            }
            None => {
                rtabort!("no scheduler")
            }
        }
    }
    unsafe fn try_unsafe_borrow() -> Option<*mut Scheduler> {
        if Local::exists::<Scheduler>() {
            Some(Local::unsafe_borrow())
        } else {
            None
        }
    }
}

// XXX: This formulation won't work once ~IoFactoryObject is a real trait pointer
impl Local for IoFactoryObject {
    fn put(_value: ~IoFactoryObject) { rtabort!("unimpl") }
    fn take() -> ~IoFactoryObject { rtabort!("unimpl") }
    fn exists() -> bool { rtabort!("unimpl") }
    fn borrow<T>(_f: &fn(&mut IoFactoryObject) -> T) -> T { rtabort!("unimpl") }
    unsafe fn unsafe_borrow() -> *mut IoFactoryObject {
        let sched = Local::unsafe_borrow::<Scheduler>();
        let io: *mut IoFactoryObject = (*sched).event_loop.io().unwrap();
        return io;
    }
    unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> { rtabort!("unimpl") }
}

#[cfg(test)]
mod test {
    use unstable::run_in_bare_thread;
    use rt::test::*;
    use super::*;
    use rt::task::Task;
    use rt::local_ptr;

    #[test]
    fn thread_local_task_smoke_test() {
        do run_in_bare_thread {
            local_ptr::init_tls_key();
            let mut sched = ~new_test_uv_sched();
            let task = ~Task::new_root(&mut sched.stack_pool, || {});
            Local::put(task);
            let task: ~Task = Local::take();
            cleanup_task(task);
        }
    }

    #[test]
    fn thread_local_task_two_instances() {
        do run_in_bare_thread {
            local_ptr::init_tls_key();
            let mut sched = ~new_test_uv_sched();
            let task = ~Task::new_root(&mut sched.stack_pool, || {});
            Local::put(task);
            let task: ~Task = Local::take();
            cleanup_task(task);
            let task = ~Task::new_root(&mut sched.stack_pool, || {});
            Local::put(task);
            let task: ~Task = Local::take();
            cleanup_task(task);
        }

    }

    #[test]
    fn borrow_smoke_test() {
        do run_in_bare_thread {
            local_ptr::init_tls_key();
            let mut sched = ~new_test_uv_sched();
            let task = ~Task::new_root(&mut sched.stack_pool, || {});
            Local::put(task);

            unsafe {
                let _task: *mut Task = Local::unsafe_borrow();
            }
            let task: ~Task = Local::take();
            cleanup_task(task);
        }
    }

    #[test]
    fn borrow_with_return() {
        do run_in_bare_thread {
            local_ptr::init_tls_key();
            let mut sched = ~new_test_uv_sched();
            let task = ~Task::new_root(&mut sched.stack_pool, || {});
            Local::put(task);

            let res = do Local::borrow::<Task,bool> |_task| {
                true
            };
            assert!(res)
                let task: ~Task = Local::take();
            cleanup_task(task);
        }
    }

}

<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use ComponentExt;

use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::{metadata, read_dir, File};
use std::io::Read;
use std::path::{Path, PathBuf};

/// More information can be found at [kernel.org][k].
///
/// [k]: https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
pub struct Component {
    temperature: f32,
    max: f32,
    critical: Option<f32>,
    label: String,
    input_file: PathBuf,
}

fn get_file_line(file: &Path, capacity: usize) -> Option<String> {
    let mut reader = String::with_capacity(capacity);
    if let Ok(mut f) = File::open(file) {
        if f.read_to_string(&mut reader).is_ok() {
            Some(reader)
        } else {
            None
        }
    } else {
        None
    }
}

fn is_file<T: AsRef<Path>>(path: T) -> bool {
    metadata(path)
        .ok()
        .map(|m| m.is_file())
        .unwrap_or_else(|| false)
}

fn append_files(components: &mut Vec<Component>, folder: &Path) {
    let mut matchings: HashMap<u32, Vec<String>> = HashMap::with_capacity(10);

    if let Ok(dir) = read_dir(folder) {
        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if entry.is_dir()
                    || !entry
                        .file_name()
                        .unwrap_or_else(|| OsStr::new("/"))
                        .to_str()
                        .unwrap_or("")
                        .starts_with("temp")
                {
                    continue;
                }
                if let Some(entry) = entry.file_name() {
                    if let Some(entry) = entry.to_str() {
                        let mut parts = entry.split('_');
                        if let Some(Some(id)) = parts.next().map(|s| s[4..].parse::<u32>().ok()) {
                            matchings
                                .entry(id)
                                .or_insert_with(|| Vec::with_capacity(5))
                                .push(
                                    parts
                                        .next()
                                        .map(|s| format!("_{}", s))
                                        .unwrap_or_else(String::new),
                                );
                        }
                    }
                }
            }
        }
        for (key, val) in &matchings {
            let mut found_input = None;
            let mut found_label = None;
            for (pos, v) in val.iter().enumerate() {
                match v.as_str() {
                    // raspberry has empty string for temperature input
                    "_input" | "" => {
                        found_input = Some(pos);
                    }
                    "_label" => {
                        found_label = Some(pos);
                    }
                    _ => {}
                }
            }
            if let (Some(_), Some(found_input)) = (found_label, found_input) {
                let mut p_label = folder.to_path_buf();
                let mut p_input = folder.to_path_buf();
                let mut p_crit = folder.to_path_buf();
                let mut p_max = folder.to_path_buf();

                p_label.push(&format!("temp{}_label", key));
                p_input.push(&format!("temp{}{}", key, val[found_input]));
                p_max.push(&format!("temp{}_max", key));
                p_crit.push(&format!("temp{}_crit", key));
                if is_file(&p_input) {
                    let label = get_file_line(p_label.as_path(), 10)
                        .unwrap_or_else(|| format!("Component {}", key)) // needed for raspberry pi
                        .replace("\n", "");
                    let max = if let Some(max) = get_file_line(p_max.as_path(), 10) {
                        Some(max.replace("\n", "").parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                    } else {
                        None
                    };
                    let crit = if let Some(crit) = get_file_line(p_crit.as_path(), 10) {
                        Some(crit.replace("\n", "").parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                    } else {
                        None
                    };
                    components.push(Component::new(label, p_input.as_path(), max, crit));
                }
            }
        }
    }
}

impl Component {
    /// Creates a new component with the given information.
    pub(crate) fn new(
        label: String,
        input_path: &Path,
        max: Option<f32>,
        critical: Option<f32>,
    ) -> Component {
        let mut c = Component {
            temperature: 0f32,
            label,
            input_file: input_path.to_path_buf(),
            max: max.unwrap_or(0.0),
            critical,
        };
        c.refresh();
        c
    }
}

impl ComponentExt for Component {
    fn get_temperature(&self) -> f32 {
        self.temperature
    }

    fn get_max(&self) -> f32 {
        self.max
    }

    fn get_critical(&self) -> Option<f32> {
        self.critical
    }

    fn get_label(&self) -> &str {
        &self.label
    }

    fn refresh(&mut self) {
        if let Some(content) = get_file_line(self.input_file.as_path(), 10) {
            self.temperature = content
                .replace("\n", "")
                .parse::<f32>()
                .unwrap_or(100_000f32)
                / 1000f32;
            if self.temperature > self.max {
                self.max = self.temperature;
            }
        }
    }
}

pub fn get_components() -> Vec<Component> {
    if let Ok(dir) = read_dir(&Path::new("/sys/class/hwmon/")) {
        let mut components = Vec::with_capacity(10);

        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if !entry.is_dir()
                    || !entry
                        .file_name()
                        .unwrap_or_else(|| OsStr::new("/"))
                        .to_str()
                        .unwrap_or("")
                        .starts_with("hwmon")
                {
                    continue;
                }
                append_files(&mut components, &entry);
            }
        }
        components.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase()));
        components
    } else if is_file("/sys/class/thermal/thermal_zone0/temp") {
        // Specfic to raspberry pi.
        vec![Component::new(
            "CPU".to_owned(),
            Path::new("/sys/class/thermal/thermal_zone0/temp"),
            None,
            None,
        )]
    } else {
        Vec::new()
    }
}
<commit_msg>Add comment about virtual systems<commit_after>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use ComponentExt;

use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::{metadata, read_dir, File};
use std::io::Read;
use std::path::{Path, PathBuf};

/// More information can be found at [kernel.org][k].
///
/// [k]: https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
/// Note: these may not be present on virtual Linux systems, such as Docker
/// or Windows Subsystem for Linux. These hosts do not expose this information
/// and therefore Components may be missing or not as expected.
pub struct Component {
    temperature: f32,
    max: f32,
    critical: Option<f32>,
    label: String,
    input_file: PathBuf,
}

fn get_file_line(file: &Path, capacity: usize) -> Option<String> {
    let mut reader = String::with_capacity(capacity);
    if let Ok(mut f) = File::open(file) {
        if f.read_to_string(&mut reader).is_ok() {
            Some(reader)
        } else {
            None
        }
    } else {
        None
    }
}

fn is_file<T: AsRef<Path>>(path: T) -> bool {
    metadata(path)
        .ok()
        .map(|m| m.is_file())
        .unwrap_or_else(|| false)
}

fn append_files(components: &mut Vec<Component>, folder: &Path) {
    let mut matchings: HashMap<u32, Vec<String>> = HashMap::with_capacity(10);

    if let Ok(dir) = read_dir(folder) {
        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if entry.is_dir()
                    || !entry
                        .file_name()
                        .unwrap_or_else(|| OsStr::new("/"))
                        .to_str()
                        .unwrap_or("")
                        .starts_with("temp")
                {
                    continue;
                }
                if let Some(entry) = entry.file_name() {
                    if let Some(entry) = entry.to_str() {
                        let mut parts = entry.split('_');
                        if let Some(Some(id)) = parts.next().map(|s| s[4..].parse::<u32>().ok()) {
                            matchings
                                .entry(id)
                                .or_insert_with(|| Vec::with_capacity(5))
                                .push(
                                    parts
                                        .next()
                                        .map(|s| format!("_{}", s))
                                        .unwrap_or_else(String::new),
                                );
                        }
                    }
                }
            }
        }
        for (key, val) in &matchings {
            let mut found_input = None;
            let mut found_label = None;
            for (pos, v) in val.iter().enumerate() {
                match v.as_str() {
                    // raspberry has empty string for temperature input
                    "_input" | "" => {
                        found_input = Some(pos);
                    }
                    "_label" => {
                        found_label = Some(pos);
                    }
                    _ => {}
                }
            }
            if let (Some(_), Some(found_input)) = (found_label, found_input) {
                let mut p_label = folder.to_path_buf();
                let mut p_input = folder.to_path_buf();
                let mut p_crit = folder.to_path_buf();
                let mut p_max = folder.to_path_buf();

                p_label.push(&format!("temp{}_label", key));
                p_input.push(&format!("temp{}{}", key, val[found_input]));
                p_max.push(&format!("temp{}_max", key));
                p_crit.push(&format!("temp{}_crit", key));
                if is_file(&p_input) {
                    let label = get_file_line(p_label.as_path(), 10)
                        .unwrap_or_else(|| format!("Component {}", key)) // needed for raspberry pi
                        .replace("\n", "");
                    let max = if let Some(max) = get_file_line(p_max.as_path(), 10) {
                        Some(max.replace("\n", "").parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                    } else {
                        None
                    };
                    let crit = if let Some(crit) = get_file_line(p_crit.as_path(), 10) {
                        Some(crit.replace("\n", "").parse::<f32>().unwrap_or(100_000f32) / 1000f32)
                    } else {
                        None
                    };
                    components.push(Component::new(label, p_input.as_path(), max, crit));
                }
            }
        }
    }
}

impl Component {
    /// Creates a new component with the given information.
    pub(crate) fn new(
        label: String,
        input_path: &Path,
        max: Option<f32>,
        critical: Option<f32>,
    ) -> Component {
        let mut c = Component {
            temperature: 0f32,
            label,
            input_file: input_path.to_path_buf(),
            max: max.unwrap_or(0.0),
            critical,
        };
        c.refresh();
        c
    }
}

impl ComponentExt for Component {
    fn get_temperature(&self) -> f32 {
        self.temperature
    }

    fn get_max(&self) -> f32 {
        self.max
    }

    fn get_critical(&self) -> Option<f32> {
        self.critical
    }

    fn get_label(&self) -> &str {
        &self.label
    }

    fn refresh(&mut self) {
        if let Some(content) = get_file_line(self.input_file.as_path(), 10) {
            self.temperature = content
                .replace("\n", "")
                .parse::<f32>()
                .unwrap_or(100_000f32)
                / 1000f32;
            if self.temperature > self.max {
                self.max = self.temperature;
            }
        }
    }
}

pub fn get_components() -> Vec<Component> {
    if let Ok(dir) = read_dir(&Path::new("/sys/class/hwmon/")) {
        let mut components = Vec::with_capacity(10);

        for entry in dir {
            if let Ok(entry) = entry {
                let entry = entry.path();
                if !entry.is_dir()
                    || !entry
                        .file_name()
                        .unwrap_or_else(|| OsStr::new("/"))
                        .to_str()
                        .unwrap_or("")
                        .starts_with("hwmon")
                {
                    continue;
                }
                append_files(&mut components, &entry);
            }
        }
        components.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase()));
        components
    } else if is_file("/sys/class/thermal/thermal_zone0/temp") {
        // Specfic to raspberry pi.
        vec![Component::new(
            "CPU".to_owned(),
            Path::new("/sys/class/thermal/thermal_zone0/temp"),
            None,
            None,
        )]
    } else {
        Vec::new()
    }
}
<|endoftext|>