<commit_before>#![feature(convert)]
#![feature(slice_patterns)]
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

type Expr = i64;

struct VM<'a> {
  stack: Vec<Expr>,
  instructions: Vec<&'a str>,
  locals: HashMap<&'a str, Expr>,
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      stack: Vec::new(),
      instructions: instructions,
      locals: HashMap::new(),
    }
  }

  /*urgh rust. can't borrow self as mut more than once, heh...
  fn unsafe_pop(&mut self) -> Expr {
    match self.stack.pop() {
      Some(expr) => expr,
      None => panic!("VM error: can't pop stack!")
    }
  }*/

  pub fn run(&mut self) {
    // just some aliases for brevity
    let ref mut stack = self.stack;
    let ref mut locals = self.locals;
    let len = self.instructions.len();

    // VM variables (might be moved back to the struct itself)
    let mut ip = 0; // instruction pointer
    let mut carry = false;

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        ["push", n] => stack.push(n.parse::<i64>().unwrap()),
        ["add"] => if let (Some(arg1), Some(arg2)) = (stack.pop(), stack.pop()) {
          stack.push(arg1 + arg2);
        } else {
          println!("VM error: not enough arguments to `add`");
        },

        ["say"] => if let Some(arg) = stack.pop() {
          println!("hey {}", arg);
        } else {
          println!("VM error: not enough arguments to `say`");
        },

        //["cmp", "<"] =>

        // how = "carry" | "always"
        ["jump", how, n] => {
          let new_ip = n.parse::<usize>().unwrap();

          if new_ip < len {
            // only check carry if we're not conditionally jumping
            if how != "carry" || carry {
              ip = new_ip;
            }
            // only reset carry if it was used
            if how == "carry" {
              carry = false;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        ["carry", "set", val] => carry = val == "true",
        ["carry", "invert"] => carry = !carry,

        // NOTE: it's stack[*-1] OP stack[*-2]
        // which means if have stack=[1, 2]
        // you'll have 2 OP 1
        ["cmp", op] => if let (Some(arg1), Some(arg2)) = (stack.pop(), stack.pop()) {
          carry = match op {
            "<" => arg1 < arg2,
            ">" => arg1 > arg2,
            "<=" => arg1 <= arg2,
            ">=" => arg1 >= arg2,
            "=" => arg1 == arg2,
            _ => panic!("VM error: unrecognized `cmp` operator: {}", op),
          };
        } else {
          panic!("VM error: not enough arguments to `cmp`");
        },

        ["local", "load", name] => match locals.get(name) {
          Some(expr) => stack.push(expr.clone()),
          None       => panic!("VM error: unknown local variable {}", name),
        },

        ["local", "store", name] => if let Some(arg) = stack.pop() {
          let _ = locals.insert(name, arg);
        } else {
          panic!("VM error: not enough arguments for `local store`");
        },

        [instr, ..] => panic!("VM error: no such instruction {}", instr),
        [..] => panic!("VM error: Unrecognized instruction!"), // todo err!
      }
    }
  }
}

fn main() {
	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

    match File::open(&path) {
      Ok(mut file) => {
        let mut content = String::new();
        if let Ok(_) = file.read_to_string(&mut content) {
          // remove trailing newlines, split by line
          let instructions = content.trim_matches('\n').split('\n').collect();
          let mut vm = VM::new(instructions);
          vm.run();
        }
      },
      Err(err) => {
        println!("Can't read file {} (error: {})", path, err);
      }
    }
	} else {
    println!("Please give a file argument");
  }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<commit_msg>Remove local variable aliases, fixes #3<commit_after>#![feature(convert)]
#![feature(slice_patterns)]
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

type Expr = i64;

struct VM<'a> {
  stack: Vec<Expr>,
  instructions: Vec<&'a str>,
  locals: HashMap<&'a str, Expr>,
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      stack: Vec::new(),
      instructions: instructions,
      locals: HashMap::new(),
    }
  }

  pub fn run(&mut self) {
    // just some aliases for brevity
    let len = self.instructions.len();

    // VM variables (might be moved back to the struct itself)
    let mut ip = 0; // instruction pointer
    let mut carry = false;

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        ["push", n] => self.stack.push(n.parse::<i64>().unwrap()),
        ["add"] => if let (Some(arg1), Some(arg2)) = (self.stack.pop(), self.stack.pop()) {
          self.stack.push(arg1 + arg2);
        } else {
          println!("VM error: not enough arguments to `add`");
        },

        ["say"] => if let Some(arg) = self.stack.pop() {
          println!("hey {}", arg);
        } else {
          println!("VM error: not enough arguments to `say`");
        },

        //["cmp", "<"] =>

        // how = "carry" | "always"
        ["jump", how, n] => {
          let new_ip = n.parse::<usize>().unwrap();

          if new_ip < len {
            // only check carry if we're not conditionally jumping
            if how != "carry" || carry {
              ip = new_ip;
            }
            // only reset carry if it was used
            if how == "carry" {
              carry = false;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        ["carry", "set", val] => carry = val == "true",
        ["carry", "invert"] => carry = !carry,

        // NOTE: it's stack[*-1] OP stack[*-2]
        // which means if have stack=[1, 2]
        // you'll have 2 OP 1
        ["cmp", op] => if let (Some(arg1), Some(arg2)) = (self.stack.pop(), self.stack.pop()) {
          carry = match op {
            "<" => arg1 < arg2,
            ">" => arg1 > arg2,
            "<=" => arg1 <= arg2,
            ">=" => arg1 >= arg2,
            "=" => arg1 == arg2,
            _ => panic!("VM error: unrecognized `cmp` operator: {}", op),
          };
        } else {
          panic!("VM error: not enough arguments to `cmp`");
        },

        ["local", "load", name] => match self.locals.get(name) {
          Some(expr) => self.stack.push(expr.clone()),
          None       => panic!("VM error: unknown local variable {}", name),
        },

        ["local", "store", name] => if let Some(arg) = self.stack.pop() {
          let _ = self.locals.insert(name, arg);
        } else {
          panic!("VM error: not enough arguments for `local store`");
        },

        [instr, ..] => panic!("VM error: no such instruction {}", instr),
        [..] => panic!("VM error: Unrecognized instruction!"), // todo err!
      }
    }
  }
}

fn main() {
	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

    match File::open(&path) {
      Ok(mut file) => {
        let mut content = String::new();
        if let Ok(_) = file.read_to_string(&mut content) {
          // remove trailing newlines, split by line
          let instructions = content.trim_matches('\n').split('\n').collect();
          let mut vm = VM::new(instructions);
          vm.run();
        }
      },
      Err(err) => {
        println!("Can't read file {} (error: {})", path, err);
      }
    }
	} else {
    println!("Please give a file argument");
  }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<|endoftext|>


<commit_before>use std::{mem, ptr};
use libc::{c_char, c_void, c_int, size_t, pid_t, off_t};
use fcntl::{fcntl, Fd, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC};
use fcntl::FcntlArg::{F_SETFD, F_SETFL};

use errno::{SysResult, SysError, from_ffi};
use core::raw::Slice as RawSlice;
use utils::ToCStr;
use std::ffi::CString;

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

mod ffi {
    use super::{IovecR,IovecW};
    use libc::{c_char, c_int, size_t, ssize_t};
    pub use libc::{close, read, write, pipe, ftruncate};
    pub use libc::funcs::posix88::unistd::fork;
    use fcntl::Fd;

    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;

        // 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;

        // vectorized version of write
        // doc: http://man7.org/linux/man-pages/man2/writev.2.html
        pub fn writev(fd: Fd, iov: *const IovecW, iovcnt: c_int) -> ssize_t;

        // vectorized version of read
        // doc: http://man7.org/linux/man-pages/man2/readv.2.html
        pub fn readv(fd: Fd, iov: *const IovecR, iovcnt: c_int) -> ssize_t;
    }
}

#[derive(Copy)]
pub enum Fork {
    Parent(pid_t),
    Child
}

impl Fork {
    pub fn is_child(&self) -> bool {
        match *self {
            Fork::Child => true,
            _ => false
        }
    }

    pub fn is_parent(&self) -> bool {
        match *self {
            Fork::Parent(_) => true,
            _ => false
        }
    }
}

pub fn fork() -> SysResult<Fork> {
    use self::Fork::*;

    let res = unsafe { ffi::fork() };

    if res < 0 {
        return Err(SysError::last());
    } else if res == 0 {
        Ok(Child)
    } else {
        Ok(Parent(res))
    }
}

// We use phantom types to maintain memory safety.
// If readv/writev were using simple &[Iovec] we could initialize
// Iovec with immutable slice and then pass it to readv, overwriting content
// we dont have write access to:
// let mut v = Vec::new();
// let iov = Iovec::from_slice(immutable_vec.as_slice());
// v.push(iov);
// let _:SysResult<usize> = readv(fd, v.as_slice());

// We do not want <T> to appear in ffi functions, so we provide this aliases.
type IovecR = Iovec<ToRead>;
type IovecW = Iovec<ToWrite>;

#[derive(Copy)]
pub struct ToRead;
#[derive(Copy)]
pub struct ToWrite;

#[repr(C)]
pub struct Iovec<T> {
    iov_base: *mut c_void,
    iov_len: size_t,
}

impl <T> Iovec<T> {
    #[inline]
    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
        unsafe { mem::transmute(RawSlice { data: self.iov_base as *const u8, len: self.iov_len as usize }) }
    }
}

impl Iovec<ToWrite> {
    #[inline]
    pub fn from_slice(buf: &[u8]) -> Iovec<ToWrite> {
        Iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t
        }
    }
}

impl Iovec<ToRead> {
    #[inline]
    pub fn from_mut_slice(buf: &mut [u8]) -> Iovec<ToRead> {
        Iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t
        }
    }
}

#[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)
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub fn dup3(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    type F = unsafe extern "C" fn(c_int, c_int, c_int) -> c_int;

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

    if !dup3.is_null() {
        let res = unsafe {
            mem::transmute::<*const (), F>(dup3)(
                oldfd, newfd, flags.bits())
        };

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

        Ok(res)
    } else {
        dup3_polyfill(oldfd, newfd, flags)
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn dup3(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    dup3_polyfill(oldfd, newfd, flags)
}

#[inline]
fn dup3_polyfill(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    use errno::EINVAL;

    if oldfd == newfd {
        return Err(SysError { kind: EINVAL });
    }

    let fd = try!(dup2(oldfd, newfd));

    if flags.contains(O_CLOEXEC) {
        if let Err(e) = fcntl(fd, F_SETFD(FD_CLOEXEC)) {
            let _ = close(fd);
            return Err(e);
        }
    }

    Ok(fd)
}

#[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());
    }

    unreachable!()
}

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 size_t;

    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 size_t;

    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<usize> {
    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 usize)
}

pub fn write(fd: Fd, buf: &[u8]) -> SysResult<usize> {
    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 usize)
}

pub fn writev(fd: Fd, iov: &[Iovec<ToWrite>]) -> SysResult<usize> {
    let res = unsafe { ffi::writev(fd, iov.as_ptr(), iov.len() as c_int) };
    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as usize)
}

pub fn readv(fd: Fd, iov: &mut [Iovec<ToRead>]) -> SysResult<usize> {
    let res = unsafe { ffi::readv(fd, iov.as_ptr(), iov.len() as c_int) };
    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as usize)
}

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(any(target_os = "macos", 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);
        }
    }
}

pub fn ftruncate(fd: Fd, len: off_t) -> SysResult<()> {
    if unsafe { ffi::ftruncate(fd, len) } < 0 {
        Err(SysError::last())
    } else {
        Ok(())
    }
}

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

    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>Add a safe wrapper for `libc::isatty`.<commit_after>use std::{mem, ptr};
use libc::{c_char, c_void, c_int, size_t, pid_t, off_t};
use fcntl::{fcntl, Fd, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC};
use fcntl::FcntlArg::{F_SETFD, F_SETFL};

use errno::{SysResult, SysError, from_ffi};
use core::raw::Slice as RawSlice;
use utils::ToCStr;
use std::ffi::CString;

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

mod ffi {
    use super::{IovecR,IovecW};
    use libc::{c_char, c_int, size_t, ssize_t};
    pub use libc::{close, read, write, pipe, ftruncate};
    pub use libc::funcs::posix88::unistd::fork;
    use fcntl::Fd;

    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;

        // 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;

        // vectorized version of write
        // doc: http://man7.org/linux/man-pages/man2/writev.2.html
        pub fn writev(fd: Fd, iov: *const IovecW, iovcnt: c_int) -> ssize_t;

        // vectorized version of read
        // doc: http://man7.org/linux/man-pages/man2/readv.2.html
        pub fn readv(fd: Fd, iov: *const IovecR, iovcnt: c_int) -> ssize_t;
    }
}

#[derive(Copy)]
pub enum Fork {
    Parent(pid_t),
    Child
}

impl Fork {
    pub fn is_child(&self) -> bool {
        match *self {
            Fork::Child => true,
            _ => false
        }
    }

    pub fn is_parent(&self) -> bool {
        match *self {
            Fork::Parent(_) => true,
            _ => false
        }
    }
}

pub fn fork() -> SysResult<Fork> {
    use self::Fork::*;

    let res = unsafe { ffi::fork() };

    if res < 0 {
        return Err(SysError::last());
    } else if res == 0 {
        Ok(Child)
    } else {
        Ok(Parent(res))
    }
}

// We use phantom types to maintain memory safety.
// If readv/writev were using simple &[Iovec] we could initialize
// Iovec with immutable slice and then pass it to readv, overwriting content
// we dont have write access to:
// let mut v = Vec::new();
// let iov = Iovec::from_slice(immutable_vec.as_slice());
// v.push(iov);
// let _:SysResult<usize> = readv(fd, v.as_slice());

// We do not want <T> to appear in ffi functions, so we provide this aliases.
type IovecR = Iovec<ToRead>;
type IovecW = Iovec<ToWrite>;

#[derive(Copy)]
pub struct ToRead;
#[derive(Copy)]
pub struct ToWrite;

#[repr(C)]
pub struct Iovec<T> {
    iov_base: *mut c_void,
    iov_len: size_t,
}

impl <T> Iovec<T> {
    #[inline]
    pub fn as_slice<'a>(&'a self) -> &'a [u8] {
        unsafe { mem::transmute(RawSlice { data: self.iov_base as *const u8, len: self.iov_len as usize }) }
    }
}

impl Iovec<ToWrite> {
    #[inline]
    pub fn from_slice(buf: &[u8]) -> Iovec<ToWrite> {
        Iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t
        }
    }
}

impl Iovec<ToRead> {
    #[inline]
    pub fn from_mut_slice(buf: &mut [u8]) -> Iovec<ToRead> {
        Iovec {
            iov_base: buf.as_ptr() as *mut c_void,
            iov_len: buf.len() as size_t
        }
    }
}

#[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)
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub fn dup3(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    type F = unsafe extern "C" fn(c_int, c_int, c_int) -> c_int;

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

    if !dup3.is_null() {
        let res = unsafe {
            mem::transmute::<*const (), F>(dup3)(
                oldfd, newfd, flags.bits())
        };

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

        Ok(res)
    } else {
        dup3_polyfill(oldfd, newfd, flags)
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn dup3(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    dup3_polyfill(oldfd, newfd, flags)
}

#[inline]
fn dup3_polyfill(oldfd: Fd, newfd: Fd, flags: OFlag) -> SysResult<Fd> {
    use errno::EINVAL;

    if oldfd == newfd {
        return Err(SysError { kind: EINVAL });
    }

    let fd = try!(dup2(oldfd, newfd));

    if flags.contains(O_CLOEXEC) {
        if let Err(e) = fcntl(fd, F_SETFD(FD_CLOEXEC)) {
            let _ = close(fd);
            return Err(e);
        }
    }

    Ok(fd)
}

#[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());
    }

    unreachable!()
}

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 size_t;

    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 size_t;

    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<usize> {
    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 usize)
}

pub fn write(fd: Fd, buf: &[u8]) -> SysResult<usize> {
    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 usize)
}

pub fn writev(fd: Fd, iov: &[Iovec<ToWrite>]) -> SysResult<usize> {
    let res = unsafe { ffi::writev(fd, iov.as_ptr(), iov.len() as c_int) };
    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as usize)
}

pub fn readv(fd: Fd, iov: &mut [Iovec<ToRead>]) -> SysResult<usize> {
    let res = unsafe { ffi::readv(fd, iov.as_ptr(), iov.len() as c_int) };
    if res < 0 {
        return Err(SysError::last());
    }

    return Ok(res as usize)
}

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(any(target_os = "macos", 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);
        }
    }
}

pub fn ftruncate(fd: Fd, len: off_t) -> SysResult<()> {
    if unsafe { ffi::ftruncate(fd, len) } < 0 {
        Err(SysError::last())
    } else {
        Ok(())
    }
}

pub fn isatty(fd: Fd) -> SysResult<bool> {
    use {errno, libc};

    if unsafe { libc::isatty(fd) } == 1 {
        Ok(true)
    } else {
        match SysError::last() {
            // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so
            // we return `Ok(false)`
            SysError { kind: errno::ENOTTY } => Ok(false),
            err => Err(err)
        }
    }
}

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

    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>// Copyright 2021-2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing permissions and
// limitations under the License.

use core::borrow::Borrow;
use core::cmp::Ordering;
use core::hash::Hash;
use core::hash::Hasher;
use core::iter;
use core::ops::Range;
use std::rc::Rc;

use crate::offsets::*;

/// An immutable [str] wrapper that re-uses its underlying buffer when taking slices of itself so
/// that cloning is cheap enough that, for most use cases where a `&str` would be preferred over a
/// `String`, this [UiString] can simply be copied instead.
///
/// Unlike [String] and [std::borrow::Cow], [UiString] does _not_ implement [core::ops::Deref]. It does,
/// however, implement [core::borrow::Borrow] and [AsRef] for the underlying [str].
#[derive(Clone, Debug)]
pub struct UiString<B: Borrow<str> = Rc<str>> {
    buffer: B,
    byte_range: Range<usize>,
    len_chars: Char,
    len_graphemes: Grapheme,
}

impl<B: Borrow<str>> UiString<B> {
    pub fn new(buffer: B) -> Self {
        use unicode_segmentation::UnicodeSegmentation;
        let byte_range = 0..buffer.borrow().len();
        let len_chars = buffer.borrow().chars().count().into();
        let len_graphemes = buffer.borrow().graphemes(true).count().into();
        Self {
            buffer,
            byte_range,
            len_chars,
            len_graphemes,
        }
    }

    #[must_use]
    pub fn slice(&self, r: Range<Grapheme>) -> Self
    where
        B: Clone,
    {
        use unicode_segmentation::UnicodeSegmentation;
        let mut graphemes = self
            .as_str()
            .grapheme_indices(true)
            .map(|t| t.0)
            .chain(iter::once(self.as_str().len()));
        let start = self.byte_range.start
            + graphemes
                .by_ref()
                .nth(*r.start.as_ref())
                .expect("range starts within bounds of this piece");
        let end = if r.is_empty() {
            start
        } else {
            self.byte_range.start
                + graphemes
                    .by_ref()
                    .nth(*r.end.as_ref() - 1 - *r.start.as_ref())
                    .expect("range ends within bounds of piece")
        };
        Self {
            buffer: self.buffer.clone(),
            byte_range: start..end,
            len_chars: (&self.buffer.borrow()[start..end]).chars().count().into(),
            len_graphemes: r.end - r.start,
        }
    }

    /// Returns the total length of the underlying text in `U` elements.
    pub fn len<U>(&self) -> U
    where
        U: Clone,
        Locus: AsRef<U>,
    {
        Locus(
            Byte(self.byte_range.len()),
            self.len_chars,
            self.len_graphemes,
        )
        .as_ref()
        .clone()
    }

    pub fn as_str(&self) -> &str {
        &self.buffer.borrow()[self.byte_range.clone()]
    }

    pub fn split<I: IntoIterator<Item = Grapheme>>(&self, at: I) -> impl Iterator<Item = Self>
    where
        B: Clone,
    {
        let mut start = Grapheme(0);
        at.into_iter()
            .map_while(|end| {
                let split = self.slice(start..end);
                start = end;
                Some(split)
            })
            .collect::<Vec<_>>()
            .into_iter()
    }

    pub fn graphemes(&self) -> impl Iterator<Item = Self>
    where
        B: Clone,
    {
        self.split(Grapheme(1)..=self.len_graphemes)
    }

    /// Returns the location of `offset` in this [UiString] as a [Byte] offset into the string
    /// returned by [UiString::as_str].
    ///
    /// If `offset` is out of bounds, returns the bounds of this piece.
    pub fn locate(&self, offset: Grapheme) -> Result<Locus, Locus> {
        Unit::nth_byte_offset(self.as_str(), offset)
            .map(|byte| Locus::from_grapheme_byte(byte, offset, self.as_str()))
            .map_err(|_| self.len())
    }
}

impl<S: Borrow<str>> Default for UiString<S>
where
    S: Default,
{
    fn default() -> Self {
        Self::new(Default::default())
    }
}

impl<'a, S: Borrow<str>> From<&'a str> for UiString<S>
where
    S: From<&'a str>,
{
    fn from(s: &'a str) -> Self {
        Self::new(s.into())
    }
}

impl<S: Borrow<str>> Borrow<str> for UiString<S> {
    fn borrow(&self) -> &str {
        self.as_str()
    }
}

impl<S: Borrow<str>> AsRef<str> for UiString<S> {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl<S: Borrow<str>> Hash for UiString<S> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.as_str().hash(state)
    }
}

impl<S: Borrow<str>> PartialEq for UiString<S> {
    fn eq(&self, other: &Self) -> bool {
        self.as_str() == other.as_str()
    }
}

impl<S: Borrow<str>> Eq for UiString<S> {}

impl<S: Borrow<str>> PartialOrd for UiString<S> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.as_str().partial_cmp(other.as_str())
    }
}

impl<S: Borrow<str>> Ord for UiString<S> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.as_str().cmp(other.as_str())
    }
}
#[cfg(test)]
mod a_str {
    use crate::offsets::*;
    use crate::*;
    use std::rc::Rc;

    #[test]
    fn can_slice() {
        let piece: UiString<Rc<str>> = UiString::from("a̐éö̲\r\n");
        assert_eq!(piece.slice(Grapheme(1)..Grapheme(2)).as_str(), "é");
    }

    #[test]
    fn can_slice_of_slice() {
        let piece: UiString = "a̐éö̲\r\n".into();
        assert_eq!(
            piece
                .slice(Grapheme(1)..Grapheme(4))
                .slice(Grapheme(1)..Grapheme(2))
                .as_str(),
            "ö̲",
        );
    }

    #[test]
    fn can_split_into_graphemes() {
        let piece: UiString<Rc<str>> = UiString::from("a̐éö̲\r\n");
        assert_eq!(
            piece
                .graphemes()
                .map(|s| s.as_str().to_string())
                .collect::<Vec<_>>(),
            ["a̐", "é", "ö̲", "\r\n",]
        );
    }

    #[test]
    fn can_slice_and_split_into_graphemes() {
        let piece: UiString<Rc<str>> = UiString::from("a̐éö̲\r\n");
        let slice = piece.slice(Grapheme(1)..Grapheme(4));
        assert_eq!(
            slice
                .graphemes()
                .map(|s| s.as_str().to_string())
                .collect::<Vec<_>>(),
            ["é", "ö̲", "\r\n",]
        );
    }

    #[test]
    fn can_report_its_length_in_different_units() {
        let piece: UiString<Rc<str>> = UiString::from("a̐éö̲\r\n");
        assert_eq!(Byte(13), piece.len());
        assert_eq!(Char(9), piece.len());
        assert_eq!(Grapheme(4), piece.len());
    }
}
<commit_msg>rust/notemaps_text: experiments, probably no good<commit_after>// Copyright 2021-2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing permissions and
// limitations under the License.

use core::borrow::Borrow;
use core::cmp::Ordering;
use core::hash::Hash;
use core::hash::Hasher;
use core::iter;
use core::ops::Range;
use std::rc::Rc;

use crate::offsets::*;

/*
pub trait Locii<U: Unit> {
    fn locus_at(&self, offset: U) -> Result<Locus, Locus>;
}

impl<'a> Locii<Grapheme> for &'a str {
    fn locus_at(&self, offset: Grapheme) -> Result<Locus, Locus> {
        Grapheme::nth_byte_offset(self, offset)
            .map(|ok| Locus::from_grapheme_byte(ok, offset, self))
            .map_err(|_| Locus::from_len(self))
    }
}

use std::fmt;

pub trait Cursor<U:Unit>{
    fn move(self, at:U)->Cursor{
    }
}

/// Types that implement [Text] support a minimal set of string operations that work as though the
/// [Unit] type `U` defines the boundaries between the smallest non-divisible atoms of a string.
///
/// [Text] requires implementors to implement [fmt::Display] because this eases generic testing and
/// debugging for [Text] implementations. This should be trivial anyway since every implementor of
/// [Text] represents a string-like data.
///
/// [Text] requires implementors to implement [Clone] because all intended use cases of [Text] will
/// require implementors to support cloning anyway. In addition to implementing [Clone],
/// implementors are expected to clone in O(1) constant-time.
///
/// # Example
///
/// ```rust
/// use notemaps_text::Text;
/// use notemaps_text::offsets::Grapheme;
///
/// fn take_five_graphemes(string: Text<Grapheme>) -> Text<Grapheme> {
///     string
///         .slice(Grapheme(0)..Grapheme(5))
///         .expect("string is at least 5 graphemes long")
///         .to_string()
/// }
/// ```
/// smallest indivi
/// `U`, where type `U` might be [Grapheme].
pub trait Text<U: Unit>: Clone+fmt::Display {
    type Slice: Text<U>;

    fn slice(&self, r: Range<U>) -> Result<Self::Slice, Self::Slice>;

    fn len(&self) -> U;
}

use std::borrow::Cow;

pub struct Split<'a,T:Text<U>+Clone,U:Unit, I:Iterator<Item=U>>(Cow<'a,T>, I );

pub fn atomize<'a,T:Text<U>,U:Unit>(text:&'a T)->Split<'a,T,U,_>{
    Split( Cow::from(text), U::from(0)..)
}

impl<'a,T:Text<U>,U:Unit, I:Iterator<Item=U>> Iterator for Split<'a,T,U,I>{
    type Item=T::Slice;
    fn next(&mut self)->Option<Self::Item>{
        self.1.next().map(|i| self.0.slice(i..i+1))
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub(crate) struct Slow<'a>(pub &'a str);

impl<'a, U: Unit> Text<U> for Slow<'a> {
    type Slice = Self;

    fn slice(&self, r: Range<U>) -> Result<Self::Slice, Self::Slice> {
        let (start, err) = U::nth_byte_offset(self.0, r.start)
            .map_or_else( |err| (err, true), |ok| (ok, false));
        let (end, err) = if err {
            (start, err)
        } else {
                U::nth_byte_offset(&self.0[start.0..], r.end - r.start)
            .map_or_else( |err| (start+err, true), |ok| (start+ok, false))
        };
        let slice = &self.0[start.0..end.0];
        if err {
            Err(Self(slice))
        } else {
            Ok(Self(slice))
        }
    }

    /*
    fn prefix(&self, end: U) -> Result<Self::Slice, Self::Slice> {
        U::nth_byte_offset(self.0, end)
            .map(|end| Self(&self.0[..end.0]))
            .map_err(|_| self.clone())
    }

    fn suffix(&self, start: U) -> Result<Self::Slice, Self::Slice> {
        U::nth_byte_offset(self.0, start)
            .map(|ok| Self(&self.0[ok.0..]))
            .map_err(|err| Self(&self.0[err.0..]))
    }
    */

    //fn locus<U:Unit>(&self, offset: U)->Result<Locus, Locus> where Locus:AsRef<U>{ U::nth_byte_offset(self.0, offset) .map(|ok| Locus::from_grapheme_byte(ok, offset, self.0)) .map_err(|_| Locus::from_len( self.0))?; }
    //fn len<U:Unit>(&self)->U where Locus:AsRef<U>{todo!("");}
    fn len(&self) -> U {
        U::offset_len(self.0)
    }
}

impl<'a> fmt::Display for Slow<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

pub trait Cursor {
    type Item;
    type Index: Sized;
    fn move_next(&mut self);
    fn move_prev(&mut self);
    fn current(&self) -> Option<Self::Item>;
    fn index(&self) -> Self::Index;
}

pub struct IterCursor<I: Iterator + Clone> {
    current: usize,
    iter: I,
}

impl<I: Iterator + Clone> Cursor for IterCursor<I> {
    type Item = I::Item;
    type Index = usize;
    fn move_next(&mut self) {
        if self.current < usize::MAX - 1 && self.iter.clone().advance_by(self.current + 1).is_ok() {
            self.current += 1
        }
    }
    fn move_prev(&mut self) {
        if self.current > 0 && self.iter.clone().advance_by(self.current - 1).is_ok() {
            self.current -= 1
        }
    }
    fn current(&self) -> Option<Self::Item> {
        self.iter.clone().nth(self.current)
    }
    fn index(&self) -> Self::Index {
        self.current
    }
}

pub struct NestedCursor<I: Iterator<Item: Into<C>> + Clone, C: Cursor> {
    mine: IterCursor<I>,
    wrapped: Option<C>,
}

pub trait Slicer<U: Unit> {
    type Slice;
    fn slice_nth_next(&mut self, n: U) -> Result<Self::Slice, U>;
    fn slice_nth_prev(&mut self, n: U) -> Result<Self::Slice, U>;
    fn offset(&self) -> U;
}

pub struct StrByteSlicer<'a>(&'a str, Byte);
impl<'a> Slicer<Byte> for StrByteSlicer<'a> {
    type Slice = &'a str;
    fn slice_nth_next(&mut self, n: U) -> Result<Self::Slice, U>;
    fn slice_nth_prev(&mut self, n: U) -> Result<Self::Slice, U>;
    fn offset(&self) -> U;
}

pub struct StrGraphemeCursor<'a> {
    string: &'a str,
    wrapped: unicode_segmentation::GraphemeCursor,
    current: Grapheme,
}

impl<'a> StrGraphemeCursor<'a> {
    fn new(string: &'a str) -> Self {
        Self {
            string,
            wrapped: unicode_segmentation::GraphemeCursor::new(0, string.len(), true),
            current: Grapheme(0),
        }
    }
}

impl<'a> Slicer<Grapheme> for StrGraphemeCursor<'a> {
    type Slice = &'a str;

    fn slice_nth_next(&mut self, n: Grapheme) -> Result<Self::Slice, Grapheme> {
        let start = self.wrapped.cur_cursor();
        let available: Grapheme = (0..n.0)
            .map_while(|_| self.wrapped.next_boundary(self.string, 0).unwrap_or(None))
            .count()
            .into();
        if available < n {
            self.wrapped.set_cursor(start);
            Err(available.into())
        } else {
            self.current += available;
            Ok(&self.string[start..self.wrapped.cur_cursor()])
        }
    }

    fn slice_nth_prev(&mut self, n: Grapheme) -> Result<Self::Slice, Grapheme> {
        let start = self.wrapped.cur_cursor();
        let available: Grapheme = (0..n.0)
            .map_while(|_| self.wrapped.prev_boundary(self.string, 0).unwrap_or(None))
            .count()
            .into();
        if available < n {
            self.wrapped.set_cursor(start);
            Err(available.into())
        } else {
            self.current += available;
            Ok(&self.string[start..self.wrapped.cur_cursor()])
        }
    }

    fn offset(&self) -> Grapheme {
        self.current
    }
}

pub struct Splits<C: Slicer<I::Item>, I: Iterator<Item: Unit>> {
    cursor: C,
    iter: I,
}

impl<C: Slicer<I::Item>, I: Iterator<Item: Unit>> Splits<C, I> {
    pub fn new(cursor: C, iter: I) -> Self {
        Self { cursor, iter }
    }
}

impl<C: Slicer<I::Item>, I: Iterator<Item: Unit>> Iterator for Splits<C, I> {
    type Item = C::Slice;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter
            .next()
            .and_then(|o| self.cursor.slice_nth_next(o - self.cursor.offset()).ok())
    }
}

struct StrTextCursor<'a>(&'a str, Locus);

impl<'a> TextCursor<Grapheme> for StrTextCursor<'a>{
    type Slice= iter::Once<&'a str>;
    fn slice<T:Into<Byte>>(&self, end: T)->Self::Slice{
        iter::once(&self.0[self.index().byte().0..end.into().0])
    }
    fn move_nth_next(&mut self, n: Grapheme)->Result<Locus, Locus>{
        self.1 = Unit::nth_byte_offset(&self.0[self.1.byte().0..], n)
            .map(|byte| Locus::from_grapheme_byte(byte, n, self.0))
            .map_err(|_| self.1)?;
        Ok(self.1)
    }
    fn index(&self)->Locus{ self.1 }
}

pub trait Text {
    type Slice: Text;
    type Split: Iterator<Item = Self::Slice>;

    fn slice(&self, r: Range<Grapheme>) -> Self::Slice;

    fn len<U>(&self) -> U
    where
        U: Clone,
        Locus: AsRef<U>;

    fn split<I: IntoIterator<Item = Grapheme>>(&self, at: I) -> Self::Split;

    fn graphemes(&self) -> Self::Split;
}

impl<S: Borrow<str>> Text for UiString<S> {
    type Slice = Self;
    type Split= Split<UiString<S>>;

    fn slice(&self, r: Range<Grapheme>) -> Self::Slice{todo!(""); }

    fn len<U>(&self) -> U
    where
        U: Clone,
        Locus: AsRef<U>{
        todo!("");
        }

    fn split<I: IntoIterator<Item = Grapheme>>(&self, at: I) -> Self::Split{
        todo!("");
    }

    fn graphemes(&self) -> Self::Split{
        todo!("");
    }
}

struct Split<T:Text, >{
    text: T,
          start: Grapheme,
          at: Box<dyn Iterator<Item= Grapheme>>,
}

impl<T:Text> Iterator for Split<T>{
type Item=T::Slice;
fn next(&mut self)->Option<Self::Item>{
    self.at.next() .map(|end| {
                let split = self.slice(self.start..end);
                self.start = end;
                Some(split)
            })
}
}
*/

/// An immutable [str] wrapper that re-uses its underlying buffer when taking slices of itself so
/// that cloning is cheap enough that, for most use cases where a `&str` would be preferred over a
/// `String`, this [UiString] can simply be copied instead.
///
/// Unlike [String] and [std::borrow::Cow], [UiString] does _not_ implement [core::ops::Deref]. It does,
/// however, implement [core::borrow::Borrow] and [AsRef] for the underlying [str].
#[derive(Clone, Debug)]
pub struct UiString<B: Borrow<str> = Rc<str>> {
    buffer: B,
    byte_range: Range<usize>,
    len_chars: Char,
    len_graphemes: Grapheme,
}

impl<B: Borrow<str>> UiString<B> {
    pub fn new(buffer: B) -> Self {
        use unicode_segmentation::UnicodeSegmentation;
        let byte_range = 0..buffer.borrow().len();
        let len_chars = buffer.borrow().chars().count().into();
        let len_graphemes = buffer.borrow().graphemes(true).count().into();
        Self {
            buffer,
            byte_range,
            len_chars,
            len_graphemes,
        }
    }

    #[must_use]
    pub fn slice(&self, r: Range<Grapheme>) -> Self
    where
        B: Clone,
    {
        use unicode_segmentation::UnicodeSegmentation;
        let mut graphemes = self
            .as_str()
            .grapheme_indices(true)
            .map(|t| t.0)
            .chain(iter::once(self.as_str().len()));
        let start = self.byte_range.start
            + graphemes
                .by_ref()
                .nth(*r.start.as_ref())
                .expect("range starts within bounds of this piece");
        let end = if r.is_empty() {
            start
        } else {
            self.byte_range.start
                + graphemes
                    .by_ref()
                    .nth(*r.end.as_ref() - 1 - *r.start.as_ref())
                    .expect("range ends within bounds of piece")
        };
        Self {
            buffer: self.buffer.clone(),
            byte_range: start..end,
            len_chars: (&self.buffer.borrow()[start..end]).chars().count().into(),
            len_graphemes: r.end - r.start,
        }
    }

    /// Returns the total length of the underlying text in `U` elements.
    pub fn len<U>(&self) -> U
    where
        U: Clone,
        Locus: AsRef<U>,
    {
        Locus(
            Byte(self.byte_range.len()),
            self.len_chars,
            self.len_graphemes,
        )
        .as_ref()
        .clone()
    }

    pub fn as_str(&self) -> &str {
        &self.buffer.borrow()[self.byte_range.clone()]
    }

    pub fn split<I: IntoIterator<Item = Grapheme>>(&self, at: I) -> impl Iterator<Item = Self>
    where
        B: Clone,
    {
        Splits::new(StrGraphemeCursor::new(self.as_str()), at.into_iter())
    }

    pub fn graphemes(&self) -> impl Iterator<Item = Self>
    where
        B: Clone,
    {
        self.split(Grapheme(1)..=self.len_graphemes)
    }

    /// Returns the location of `offset` in this [UiString] as a [Byte] offset into the string
    /// returned by [UiString::as_str].
    ///
    /// If `offset` is out of bounds, returns the bounds of this piece.
    pub fn locate(&self, offset: Grapheme) -> Result<Locus, Locus> {
        Unit::nth_byte_offset(self.as_str(), offset)
            .map(|byte| Locus::from_grapheme_byte(byte, offset, self.as_str()))
            .map_err(|_| self.len())
    }
}

impl<S: Borrow<str>> Default for UiString<S>
where
    S: Default,
{
    fn default() -> Self {
        Self::new(Default::default())
    }
}

impl<'a, S: Borrow<str>> From<&'a str> for UiString<S>
where
    S: From<&'a str>,
{
    fn from(s: &'a str) -> Self {
        Self::new(s.into())
    }
}

impl<S: Borrow<str>> Borrow<str> for UiString<S> {
    fn borrow(&self) -> &str {
        self.as_str()
    }
}

impl<S: Borrow<str>> AsRef<str> for UiString<S> {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl<S: Borrow<str>> Hash for UiString<S> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.as_str().hash(state)
    }
}

impl<S: Borrow<str>> PartialEq for UiString<S> {
    fn eq(&self, other: &Self) -> bool {
        self.as_str() == other.as_str()
    }
}

impl<S: Borrow<str>> Eq for UiString<S> {}

impl<S: Borrow<str>> PartialOrd for UiString<S> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.as_str().partial_cmp(other.as_str())
    }
}

impl<S: Borrow<str>> Ord for UiString<S> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.as_str().cmp(other.as_str())
    }
}
#[cfg(test)]
mod a_str {
    use crate::offsets::*;
    use crate::*;
    use std::rc::Rc;

    #[test]
    fn can_slice() {
        let piece: UiString<Rc<str>> = UiString::from("a̐éö̲\r\n");
        assert_eq!(piece.slice(Grapheme(1)..Grapheme(2)).as_str(), "é");
    }

    #[test]
    fn can_slice_of_slice() {
        let piece: UiString = "a̐éö̲\r\n".into();
        assert_eq!(
            piece
                .slice(Grapheme(1)..Grapheme(4))
                .slice(Grapheme(1)..Grapheme(2))
                .as_str(),
            "ö̲",
        );
    }

    #[test]
    fn can_split_into_graphemes() {
        let piece: UiString<Rc<str>> = UiString::from("a̐éö̲\r\n");
        assert_eq!(
            piece
                .graphemes()
                .map(|s| s.as_str().to_string())
                .collect::<Vec<_>>(),
            ["a̐", "é", "ö̲", "\r\n",]
        );
    }

    #[test]
    fn can_slice_and_split_into_graphemes() {
        let piece: UiString<Rc<str>> = UiString::from("a̐éö̲\r\n");
        let slice = piece.slice(Grapheme(1)..Grapheme(4));
        assert_eq!(
            slice
                .graphemes()
                .map(|s| s.as_str().to_string())
                .collect::<Vec<_>>(),
            ["é", "ö̲", "\r\n",]
        );
    }

    #[test]
    fn can_report_its_length_in_different_units() {
        let piece: UiString<Rc<str>> = UiString::from("a̐éö̲\r\n");
        assert_eq!(Byte(13), piece.len());
        assert_eq!(Char(9), piece.len());
        assert_eq!(Grapheme(4), piece.len());
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;

use libimagstore::store::Result as StoreResult;
use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreId;

/// A tag for time-tracking. This is not a normal `libimagentrytag` tag, because we want the user
/// give the possibility to use the tagging functionality without interfering with this functionality.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TimeTrackingTag(String);

impl TimeTrackingTag {
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl Into<String> for TimeTrackingTag {
    fn into(self) -> String {
        self.0
    }
}

impl From<String> for TimeTrackingTag {
    fn from(s: String) -> TimeTrackingTag {
        TimeTrackingTag(s)
    }
}

impl<'a> From<&'a String> for TimeTrackingTag {
    fn from(s: &'a String) -> TimeTrackingTag {
        TimeTrackingTag(s.clone())
    }
}

impl IntoStoreId for TimeTrackingTag {
    fn into_storeid(self) -> StoreResult<StoreId> {
        StoreId::new_baseless(PathBuf::from(self.0))
    }
}

<commit_msg>Impl Display for TimeTrackingTag<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::fmt::Display;
use std::fmt::Error as FmtError;
use std::fmt::Formatter;
use std::path::PathBuf;

use libimagstore::store::Result as StoreResult;
use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreId;

/// A tag for time-tracking. This is not a normal `libimagentrytag` tag, because we want the user
/// give the possibility to use the tagging functionality without interfering with this functionality.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TimeTrackingTag(String);

impl TimeTrackingTag {
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl Display for TimeTrackingTag {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        self.0.fmt(f)
    }
}

impl Into<String> for TimeTrackingTag {
    fn into(self) -> String {
        self.0
    }
}

impl From<String> for TimeTrackingTag {
    fn from(s: String) -> TimeTrackingTag {
        TimeTrackingTag(s)
    }
}

impl<'a> From<&'a String> for TimeTrackingTag {
    fn from(s: &'a String) -> TimeTrackingTag {
        TimeTrackingTag(s.clone())
    }
}

impl IntoStoreId for TimeTrackingTag {
    fn into_storeid(self) -> StoreResult<StoreId> {
        StoreId::new_baseless(PathBuf::from(self.0))
    }
}

<|endoftext|>


<commit_before>use std::{net, time};
use std::rc::Rc;
use std::cell::{Cell, RefCell, RefMut};
use futures::Future;
use futures::unsync::oneshot;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Handle;
use net2::TcpStreamExt;

#[cfg(feature="tls")]
use futures::future;
#[cfg(feature="tls")]
use native_tls::TlsAcceptor;
#[cfg(feature="tls")]
use tokio_tls::TlsAcceptorExt;

#[cfg(feature="alpn")]
use futures::future;
#[cfg(feature="alpn")]
use openssl::ssl::SslAcceptor;
#[cfg(feature="alpn")]
use tokio_openssl::SslAcceptorExt;

use actix::*;
use actix::msgs::StopArbiter;

use helpers;
use channel::{HttpChannel, HttpHandler, Node};

#[derive(Message)]
pub(crate) struct Conn<T> {
    pub io: T,
    pub peer: Option<net::SocketAddr>,
    pub http2: bool,
}

/// Stop worker message. Returns `true` on successful shutdown
/// and `false` if some connections still alive.
#[derive(Message)]
#[rtype(bool)]
pub(crate) struct StopWorker {
    pub graceful: Option<time::Duration>,
}

pub(crate) struct WorkerSettings<H> {
    h: RefCell<Vec<H>>,
    enabled: bool,
    keep_alive: u64,
    bytes: Rc<helpers::SharedBytesPool>,
    messages: Rc<helpers::SharedMessagePool>,
    channels: Cell<usize>,
    node: Node<()>,
}

impl<H> WorkerSettings<H> {
    pub(crate) fn new(h: Vec<H>, keep_alive: Option<u64>) -> WorkerSettings<H> {
        WorkerSettings {
            h: RefCell::new(h),
            enabled: if let Some(ka) = keep_alive { ka > 0 } else { false },
            keep_alive: keep_alive.unwrap_or(0),
            bytes: Rc::new(helpers::SharedBytesPool::new()),
            messages: Rc::new(helpers::SharedMessagePool::new()),
            channels: Cell::new(0),
            node: Node::head(),
        }
    }

    pub fn head(&self) -> &Node<()> {
        &self.node
    }
    pub fn handlers(&self) -> RefMut<Vec<H>> {
        self.h.borrow_mut()
    }
    pub fn keep_alive(&self) -> u64 {
        self.keep_alive
    }
    pub fn keep_alive_enabled(&self) -> bool {
        self.enabled
    }
    pub fn get_shared_bytes(&self) -> helpers::SharedBytes {
        helpers::SharedBytes::new(self.bytes.get_bytes(), Rc::clone(&self.bytes))
    }
    pub fn get_http_message(&self) -> helpers::SharedHttpMessage {
        helpers::SharedHttpMessage::new(self.messages.get(), Rc::clone(&self.messages))
    }
    pub fn add_channel(&self) {
        self.channels.set(self.channels.get()+1);
    }
    pub fn remove_channel(&self) {
        let num = self.channels.get();
        if num > 0 {
            self.channels.set(num-1);
        } else {
            error!("Number of removed channels is bigger than added channel. Bug in actix-web");
        }
    }
}

/// Http worker
///
/// Worker accepts Socket objects via unbounded channel and start requests processing.
pub(crate) struct Worker<H> where H: HttpHandler + 'static {
    settings: Rc<WorkerSettings<H>>,
    hnd: Handle,
    handler: StreamHandlerType,
}

impl<H: HttpHandler + 'static> Worker<H> {

    pub(crate) fn new(h: Vec<H>, handler: StreamHandlerType, keep_alive: Option<u64>)
                      -> Worker<H>
    {
        Worker {
            settings: Rc::new(WorkerSettings::new(h, keep_alive)),
            hnd: Arbiter::handle().clone(),
            handler: handler,
        }
    }

    fn update_time(&self, ctx: &mut Context<Self>) {
        helpers::update_date();
        ctx.run_later(time::Duration::new(1, 0), |slf, ctx| slf.update_time(ctx));
    }

    fn shutdown_timeout(&self, ctx: &mut Context<Self>,
                        tx: oneshot::Sender<bool>, dur: time::Duration) {
        // sleep for 1 second and then check again
        ctx.run_later(time::Duration::new(1, 0), move |slf, ctx| {
            let num = slf.settings.channels.get();
            if num == 0 {
                let _ = tx.send(true);
                Arbiter::arbiter().send(StopArbiter(0));
            } else if let Some(d) = dur.checked_sub(time::Duration::new(1, 0)) {
                slf.shutdown_timeout(ctx, tx, d);
            } else {
                info!("Force shutdown http worker, {} connections", num);
                slf.settings.head().traverse::<TcpStream, H>();
                let _ = tx.send(false);
                Arbiter::arbiter().send(StopArbiter(0));
            }
        });
    }
}

impl<H: 'static> Actor for Worker<H> where H: HttpHandler + 'static {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        self.update_time(ctx);
    }
}

impl<H> StreamHandler<Conn<net::TcpStream>> for Worker<H>
    where H: HttpHandler + 'static {}

impl<H> Handler<Conn<net::TcpStream>> for Worker<H>
    where H: HttpHandler + 'static,
{
    fn handle(&mut self, msg: Conn<net::TcpStream>, _: &mut Context<Self>)
              -> Response<Self, Conn<net::TcpStream>>
    {
        if !self.settings.keep_alive_enabled() &&
            msg.io.set_keepalive(Some(time::Duration::new(75, 0))).is_err()
        {
            error!("Can not set socket keep-alive option");
        }
        self.handler.handle(Rc::clone(&self.settings), &self.hnd, msg);
        Self::empty()
    }
}

/// `StopWorker` message handler
impl<H> Handler<StopWorker> for Worker<H>
    where H: HttpHandler + 'static,
{
    fn handle(&mut self, msg: StopWorker, ctx: &mut Context<Self>) -> Response<Self, StopWorker>
    {
        let num = self.settings.channels.get();
        if num == 0 {
            info!("Shutting down http worker, 0 connections");
            Self::reply(true)
        } else if let Some(dur) = msg.graceful {
            info!("Graceful http worker shutdown, {} connections", num);
            let (tx, rx) = oneshot::channel();
            self.shutdown_timeout(ctx, tx, dur);
            Self::async_reply(rx.map_err(|_| ()).actfuture())
        } else {
            info!("Force shutdown http worker, {} connections", num);
            self.settings.head().traverse::<TcpStream, H>();
            Self::reply(false)
        }
    }
}

#[derive(Clone)]
pub(crate) enum StreamHandlerType {
    Normal,
    #[cfg(feature="tls")]
    Tls(TlsAcceptor),
    #[cfg(feature="alpn")]
    Alpn(SslAcceptor),
}

impl StreamHandlerType {

    fn handle<H: HttpHandler>(&mut self,
                              h: Rc<WorkerSettings<H>>,
                              hnd: &Handle, msg: Conn<net::TcpStream>) {
        match *self {
            StreamHandlerType::Normal => {
                let io = TcpStream::from_stream(msg.io, hnd)
                    .expect("failed to associate TCP stream");

                hnd.spawn(HttpChannel::new(h, io, msg.peer, msg.http2));
            }
            #[cfg(feature="tls")]
            StreamHandlerType::Tls(ref acceptor) => {
                let Conn { io, peer, http2 } = msg;
                let io = TcpStream::from_stream(io, hnd)
                    .expect("failed to associate TCP stream");

                hnd.spawn(
                    TlsAcceptorExt::accept_async(acceptor, io).then(move |res| {
                        match res {
                            Ok(io) => Arbiter::handle().spawn(
                                HttpChannel::new(h, io, peer, http2)),
                            Err(err) =>
                                trace!("Error during handling tls connection: {}", err),
                        };
                        future::result(Ok(()))
                    })
                );
            }
            #[cfg(feature="alpn")]
            StreamHandlerType::Alpn(ref acceptor) => {
                let Conn { io, peer, .. } = msg;
                let io = TcpStream::from_stream(io, hnd)
                    .expect("failed to associate TCP stream");

                hnd.spawn(
                    SslAcceptorExt::accept_async(acceptor, io).then(move |res| {
                        match res {
                            Ok(io) => {
                                let http2 = if let Some(p) = io.get_ref().ssl().selected_alpn_protocol()
                                {
                                    p.len() == 2 && &p == b"h2"
                                } else {
                                    false
                                };
                                Arbiter::handle().spawn(HttpChannel::new(h, io, peer, http2));
                            },
                            Err(err) =>
                                trace!("Error during handling tls connection: {}", err),
                        };
                        future::result(Ok(()))
                    })
                );
            }
        }
    }
}
<commit_msg>set nodelay for streams<commit_after>use std::{net, time};
use std::rc::Rc;
use std::cell::{Cell, RefCell, RefMut};
use futures::Future;
use futures::unsync::oneshot;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Handle;
use net2::TcpStreamExt;

#[cfg(feature="tls")]
use futures::future;
#[cfg(feature="tls")]
use native_tls::TlsAcceptor;
#[cfg(feature="tls")]
use tokio_tls::TlsAcceptorExt;

#[cfg(feature="alpn")]
use futures::future;
#[cfg(feature="alpn")]
use openssl::ssl::SslAcceptor;
#[cfg(feature="alpn")]
use tokio_openssl::SslAcceptorExt;

use actix::*;
use actix::msgs::StopArbiter;

use helpers;
use channel::{HttpChannel, HttpHandler, Node};

#[derive(Message)]
pub(crate) struct Conn<T> {
    pub io: T,
    pub peer: Option<net::SocketAddr>,
    pub http2: bool,
}

/// Stop worker message. Returns `true` on successful shutdown
/// and `false` if some connections still alive.
#[derive(Message)]
#[rtype(bool)]
pub(crate) struct StopWorker {
    pub graceful: Option<time::Duration>,
}

pub(crate) struct WorkerSettings<H> {
    h: RefCell<Vec<H>>,
    enabled: bool,
    keep_alive: u64,
    bytes: Rc<helpers::SharedBytesPool>,
    messages: Rc<helpers::SharedMessagePool>,
    channels: Cell<usize>,
    node: Node<()>,
}

impl<H> WorkerSettings<H> {
    pub(crate) fn new(h: Vec<H>, keep_alive: Option<u64>) -> WorkerSettings<H> {
        WorkerSettings {
            h: RefCell::new(h),
            enabled: if let Some(ka) = keep_alive { ka > 0 } else { false },
            keep_alive: keep_alive.unwrap_or(0),
            bytes: Rc::new(helpers::SharedBytesPool::new()),
            messages: Rc::new(helpers::SharedMessagePool::new()),
            channels: Cell::new(0),
            node: Node::head(),
        }
    }

    pub fn head(&self) -> &Node<()> {
        &self.node
    }
    pub fn handlers(&self) -> RefMut<Vec<H>> {
        self.h.borrow_mut()
    }
    pub fn keep_alive(&self) -> u64 {
        self.keep_alive
    }
    pub fn keep_alive_enabled(&self) -> bool {
        self.enabled
    }
    pub fn get_shared_bytes(&self) -> helpers::SharedBytes {
        helpers::SharedBytes::new(self.bytes.get_bytes(), Rc::clone(&self.bytes))
    }
    pub fn get_http_message(&self) -> helpers::SharedHttpMessage {
        helpers::SharedHttpMessage::new(self.messages.get(), Rc::clone(&self.messages))
    }
    pub fn add_channel(&self) {
        self.channels.set(self.channels.get()+1);
    }
    pub fn remove_channel(&self) {
        let num = self.channels.get();
        if num > 0 {
            self.channels.set(num-1);
        } else {
            error!("Number of removed channels is bigger than added channel. Bug in actix-web");
        }
    }
}

/// Http worker
///
/// Worker accepts Socket objects via unbounded channel and start requests processing.
pub(crate) struct Worker<H> where H: HttpHandler + 'static {
    settings: Rc<WorkerSettings<H>>,
    hnd: Handle,
    handler: StreamHandlerType,
}

impl<H: HttpHandler + 'static> Worker<H> {

    pub(crate) fn new(h: Vec<H>, handler: StreamHandlerType, keep_alive: Option<u64>)
                      -> Worker<H>
    {
        Worker {
            settings: Rc::new(WorkerSettings::new(h, keep_alive)),
            hnd: Arbiter::handle().clone(),
            handler: handler,
        }
    }

    fn update_time(&self, ctx: &mut Context<Self>) {
        helpers::update_date();
        ctx.run_later(time::Duration::new(1, 0), |slf, ctx| slf.update_time(ctx));
    }

    fn shutdown_timeout(&self, ctx: &mut Context<Self>,
                        tx: oneshot::Sender<bool>, dur: time::Duration) {
        // sleep for 1 second and then check again
        ctx.run_later(time::Duration::new(1, 0), move |slf, ctx| {
            let num = slf.settings.channels.get();
            if num == 0 {
                let _ = tx.send(true);
                Arbiter::arbiter().send(StopArbiter(0));
            } else if let Some(d) = dur.checked_sub(time::Duration::new(1, 0)) {
                slf.shutdown_timeout(ctx, tx, d);
            } else {
                info!("Force shutdown http worker, {} connections", num);
                slf.settings.head().traverse::<TcpStream, H>();
                let _ = tx.send(false);
                Arbiter::arbiter().send(StopArbiter(0));
            }
        });
    }
}

impl<H: 'static> Actor for Worker<H> where H: HttpHandler + 'static {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        self.update_time(ctx);
    }
}

impl<H> StreamHandler<Conn<net::TcpStream>> for Worker<H>
    where H: HttpHandler + 'static {}

impl<H> Handler<Conn<net::TcpStream>> for Worker<H>
    where H: HttpHandler + 'static,
{
    fn handle(&mut self, msg: Conn<net::TcpStream>, _: &mut Context<Self>)
              -> Response<Self, Conn<net::TcpStream>>
    {
        if !self.settings.keep_alive_enabled() &&
            msg.io.set_keepalive(Some(time::Duration::new(75, 0))).is_err()
        {
            error!("Can not set socket keep-alive option");
        }
        self.handler.handle(Rc::clone(&self.settings), &self.hnd, msg);
        Self::empty()
    }
}

/// `StopWorker` message handler
impl<H> Handler<StopWorker> for Worker<H>
    where H: HttpHandler + 'static,
{
    fn handle(&mut self, msg: StopWorker, ctx: &mut Context<Self>) -> Response<Self, StopWorker>
    {
        let num = self.settings.channels.get();
        if num == 0 {
            info!("Shutting down http worker, 0 connections");
            Self::reply(true)
        } else if let Some(dur) = msg.graceful {
            info!("Graceful http worker shutdown, {} connections", num);
            let (tx, rx) = oneshot::channel();
            self.shutdown_timeout(ctx, tx, dur);
            Self::async_reply(rx.map_err(|_| ()).actfuture())
        } else {
            info!("Force shutdown http worker, {} connections", num);
            self.settings.head().traverse::<TcpStream, H>();
            Self::reply(false)
        }
    }
}

#[derive(Clone)]
pub(crate) enum StreamHandlerType {
    Normal,
    #[cfg(feature="tls")]
    Tls(TlsAcceptor),
    #[cfg(feature="alpn")]
    Alpn(SslAcceptor),
}

impl StreamHandlerType {

    fn handle<H: HttpHandler>(&mut self,
                              h: Rc<WorkerSettings<H>>,
                              hnd: &Handle, msg: Conn<net::TcpStream>) {
        match *self {
            StreamHandlerType::Normal => {
                let _ = msg.io.set_nodelay(true);
                let io = TcpStream::from_stream(msg.io, hnd)
                    .expect("failed to associate TCP stream");

                hnd.spawn(HttpChannel::new(h, io, msg.peer, msg.http2));
            }
            #[cfg(feature="tls")]
            StreamHandlerType::Tls(ref acceptor) => {
                let Conn { io, peer, http2 } = msg;
                let _ = io.set_nodelay(true);
                let io = TcpStream::from_stream(io, hnd)
                    .expect("failed to associate TCP stream");

                hnd.spawn(
                    TlsAcceptorExt::accept_async(acceptor, io).then(move |res| {
                        match res {
                            Ok(io) => Arbiter::handle().spawn(
                                HttpChannel::new(h, io, peer, http2)),
                            Err(err) =>
                                trace!("Error during handling tls connection: {}", err),
                        };
                        future::result(Ok(()))
                    })
                );
            }
            #[cfg(feature="alpn")]
            StreamHandlerType::Alpn(ref acceptor) => {
                let Conn { io, peer, .. } = msg;
                let _ = io.set_nodelay(true);
                let io = TcpStream::from_stream(io, hnd)
                    .expect("failed to associate TCP stream");

                hnd.spawn(
                    SslAcceptorExt::accept_async(acceptor, io).then(move |res| {
                        match res {
                            Ok(io) => {
                                let http2 = if let Some(p) = io.get_ref().ssl().selected_alpn_protocol()
                                {
                                    p.len() == 2 && &p == b"h2"
                                } else {
                                    false
                                };
                                Arbiter::handle().spawn(HttpChannel::new(h, io, peer, http2));
                            },
                            Err(err) =>
                                trace!("Error during handling tls connection: {}", err),
                        };
                        future::result(Ok(()))
                    })
                );
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Compiles the profiler part of the `compiler-rt` library.
//!
//! See the build.rs for libcompiler_builtins crate for details.

use std::env;
use std::path::Path;

fn main() {
    let target = env::var("TARGET").expect("TARGET was not set");
    let cfg = &mut cc::Build::new();

    // FIXME: `rerun-if-changed` directives are not currently emitted and the build script
    // will not rerun on changes in these source files or headers included into them.
    let mut profile_sources = vec![
        "GCDAProfiling.c",
        "InstrProfiling.c",
        "InstrProfilingBuffer.c",
        "InstrProfilingFile.c",
        "InstrProfilingMerge.c",
        "InstrProfilingMergeFile.c",
        "InstrProfilingNameVar.c",
        "InstrProfilingPlatformDarwin.c",
        "InstrProfilingPlatformLinux.c",
        "InstrProfilingPlatformOther.c",
        "InstrProfilingPlatformWindows.c",
        "InstrProfilingUtil.c",
        "InstrProfilingValue.c",
        "InstrProfilingWriter.c",
        // This file was renamed in LLVM 10.
        "InstrProfilingRuntime.cc",
        "InstrProfilingRuntime.cpp",
        // These files were added in LLVM 11.
        "InstrProfilingInternal.c",
        "InstrProfilingBiasVar.c",
    ];

    if target.contains("msvc") {
        // Don't pull in extra libraries on MSVC
        cfg.flag("/Zl");
        profile_sources.push("WindowsMMap.c");
        cfg.define("strdup", Some("_strdup"));
        cfg.define("open", Some("_open"));
        cfg.define("fdopen", Some("_fdopen"));
        cfg.define("getpid", Some("_getpid"));
        cfg.define("fileno", Some("_fileno"));
    } else {
        // Turn off various features of gcc and such, mostly copying
        // compiler-rt's build system already
        cfg.flag("-fno-builtin");
        cfg.flag("-fvisibility=hidden");
        cfg.flag("-fomit-frame-pointer");
        cfg.define("VISIBILITY_HIDDEN", None);
        if !target.contains("windows") {
            cfg.define("COMPILER_RT_HAS_UNAME", Some("1"));
        } else {
            profile_sources.push("WindowsMMap.c");
        }
    }

    // Assume that the Unixes we are building this for have fnctl() available
    if env::var_os("CARGO_CFG_UNIX").is_some() {
        cfg.define("COMPILER_RT_HAS_FCNTL_LCK", Some("1"));
    }

    // This should be a pretty good heuristic for when to set
    // COMPILER_RT_HAS_ATOMICS
    if env::var_os("CARGO_CFG_TARGET_HAS_ATOMIC")
        .map(|features| features.to_string_lossy().to_lowercase().contains("ptr"))
        .unwrap_or(false)
    {
        cfg.define("COMPILER_RT_HAS_ATOMICS", Some("1"));
    }

    // Note that this should exist if we're going to run (otherwise we just
    // don't build profiler builtins at all).
    let root = Path::new("../../src/llvm-project/compiler-rt");

    let src_root = root.join("lib").join("profile");
    for src in profile_sources {
        let path = src_root.join(src);
        if path.exists() {
            cfg.file(path);
        }
    }

    cfg.include(root.join("include"));
    cfg.warnings(false);
    cfg.compile("profiler-rt");
}
<commit_msg>Rollup merge of #75998 - richkadel:llvm-coverage-map-gen-6b.1, r=wesleywiser<commit_after>//! Compiles the profiler part of the `compiler-rt` library.
//!
//! See the build.rs for libcompiler_builtins crate for details.

use std::env;
use std::path::Path;

fn main() {
    let target = env::var("TARGET").expect("TARGET was not set");
    let cfg = &mut cc::Build::new();

    // FIXME: `rerun-if-changed` directives are not currently emitted and the build script
    // will not rerun on changes in these source files or headers included into them.
    let mut profile_sources = vec![
        "GCDAProfiling.c",
        "InstrProfiling.c",
        "InstrProfilingBuffer.c",
        "InstrProfilingFile.c",
        "InstrProfilingMerge.c",
        "InstrProfilingMergeFile.c",
        "InstrProfilingNameVar.c",
        "InstrProfilingPlatformDarwin.c",
        "InstrProfilingPlatformFuchsia.c",
        "InstrProfilingPlatformLinux.c",
        "InstrProfilingPlatformOther.c",
        "InstrProfilingPlatformWindows.c",
        "InstrProfilingUtil.c",
        "InstrProfilingValue.c",
        "InstrProfilingWriter.c",
        // This file was renamed in LLVM 10.
        "InstrProfilingRuntime.cc",
        "InstrProfilingRuntime.cpp",
        // These files were added in LLVM 11.
        "InstrProfilingInternal.c",
        "InstrProfilingBiasVar.c",
    ];

    if target.contains("msvc") {
        // Don't pull in extra libraries on MSVC
        cfg.flag("/Zl");
        profile_sources.push("WindowsMMap.c");
        cfg.define("strdup", Some("_strdup"));
        cfg.define("open", Some("_open"));
        cfg.define("fdopen", Some("_fdopen"));
        cfg.define("getpid", Some("_getpid"));
        cfg.define("fileno", Some("_fileno"));
    } else {
        // Turn off various features of gcc and such, mostly copying
        // compiler-rt's build system already
        cfg.flag("-fno-builtin");
        cfg.flag("-fvisibility=hidden");
        cfg.flag("-fomit-frame-pointer");
        cfg.define("VISIBILITY_HIDDEN", None);
        if !target.contains("windows") {
            cfg.define("COMPILER_RT_HAS_UNAME", Some("1"));
        } else {
            profile_sources.push("WindowsMMap.c");
        }
    }

    // Assume that the Unixes we are building this for have fnctl() available
    if env::var_os("CARGO_CFG_UNIX").is_some() {
        cfg.define("COMPILER_RT_HAS_FCNTL_LCK", Some("1"));
    }

    // This should be a pretty good heuristic for when to set
    // COMPILER_RT_HAS_ATOMICS
    if env::var_os("CARGO_CFG_TARGET_HAS_ATOMIC")
        .map(|features| features.to_string_lossy().to_lowercase().contains("ptr"))
        .unwrap_or(false)
    {
        cfg.define("COMPILER_RT_HAS_ATOMICS", Some("1"));
    }

    // Note that this should exist if we're going to run (otherwise we just
    // don't build profiler builtins at all).
    let root = Path::new("../../src/llvm-project/compiler-rt");

    let src_root = root.join("lib").join("profile");
    for src in profile_sources {
        let path = src_root.join(src);
        if path.exists() {
            cfg.file(path);
        }
    }

    cfg.include(root.join("include"));
    cfg.warnings(false);
    cfg.compile("profiler-rt");
}
<|endoftext|>


<commit_before>//! WASI-specific extensions to general I/O primitives

#![deny(unsafe_op_in_unsafe_fn)]
#![unstable(feature = "wasi_ext", issue = "none")]

use crate::fs;
use crate::io;
use crate::net;
use crate::sys;
use crate::sys_common::{AsInner, FromInner, IntoInner};

/// Raw file descriptors.
pub type RawFd = u32;

/// A trait to extract the raw WASI file descriptor from an underlying
/// object.
pub trait AsRawFd {
    /// Extracts the raw file descriptor.
    ///
    /// This method does **not** pass ownership of the raw file descriptor
    /// to the caller. The descriptor is only guaranteed to be valid while
    /// the original object has not yet been destroyed.
    fn as_raw_fd(&self) -> RawFd;
}

/// A trait to express the ability to construct an object from a raw file
/// descriptor.
pub trait FromRawFd {
    /// Constructs a new instance of `Self` from the given raw file
    /// descriptor.
    ///
    /// This function **consumes ownership** of the specified file
    /// descriptor. The returned object will take responsibility for closing
    /// it when the object goes out of scope.
    ///
    /// This function is also unsafe as the primitives currently returned
    /// have the contract that they are the sole owner of the file
    /// descriptor they are wrapping. Usage of this function could
    /// accidentally allow violating this contract which can cause memory
    /// unsafety in code that relies on it being true.
    unsafe fn from_raw_fd(fd: RawFd) -> Self;
}

/// A trait to express the ability to consume an object and acquire ownership of
/// its raw file descriptor.
pub trait IntoRawFd {
    /// Consumes this object, returning the raw underlying file descriptor.
    ///
    /// This function **transfers ownership** of the underlying file descriptor
    /// to the caller. Callers are then the unique owners of the file descriptor
    /// and must close the descriptor once it's no longer needed.
    fn into_raw_fd(self) -> RawFd;
}

#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
impl AsRawFd for RawFd {
    fn as_raw_fd(&self) -> RawFd {
        *self
    }
}
#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
impl IntoRawFd for RawFd {
    fn into_raw_fd(self) -> RawFd {
        self
    }
}
#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
impl FromRawFd for RawFd {
    unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
        fd
    }
}

impl AsRawFd for net::TcpStream {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().as_raw()
    }
}

impl FromRawFd for net::TcpStream {
    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
        net::TcpStream::from_inner(sys::net::TcpStream::from_inner(fd))
    }
}

impl IntoRawFd for net::TcpStream {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

impl AsRawFd for net::TcpListener {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().as_raw()
    }
}

impl FromRawFd for net::TcpListener {
    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
        net::TcpListener::from_inner(sys::net::TcpListener::from_inner(fd))
    }
}

impl IntoRawFd for net::TcpListener {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

impl AsRawFd for net::UdpSocket {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().as_raw()
    }
}

impl FromRawFd for net::UdpSocket {
    unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
        net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(fd))
    }
}

impl IntoRawFd for net::UdpSocket {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

impl AsRawFd for fs::File {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().as_raw()
    }
}

impl FromRawFd for fs::File {
    unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
        fs::File::from_inner(sys::fs::File::from_inner(fd))
    }
}

impl IntoRawFd for fs::File {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

impl AsRawFd for io::Stdin {
    fn as_raw_fd(&self) -> RawFd {
        sys::stdio::Stdin.as_raw_fd()
    }
}

impl AsRawFd for io::Stdout {
    fn as_raw_fd(&self) -> RawFd {
        sys::stdio::Stdout.as_raw_fd()
    }
}

impl AsRawFd for io::Stderr {
    fn as_raw_fd(&self) -> RawFd {
        sys::stdio::Stderr.as_raw_fd()
    }
}
<commit_msg>Rollup merge of #77724 - sunfishcode:stdinlock-asrawfd, r=alexcrichton<commit_after>//! WASI-specific extensions to general I/O primitives

#![deny(unsafe_op_in_unsafe_fn)]
#![unstable(feature = "wasi_ext", issue = "none")]

use crate::fs;
use crate::io;
use crate::net;
use crate::sys;
use crate::sys_common::{AsInner, FromInner, IntoInner};

/// Raw file descriptors.
pub type RawFd = u32;

/// A trait to extract the raw WASI file descriptor from an underlying
/// object.
pub trait AsRawFd {
    /// Extracts the raw file descriptor.
    ///
    /// This method does **not** pass ownership of the raw file descriptor
    /// to the caller. The descriptor is only guaranteed to be valid while
    /// the original object has not yet been destroyed.
    fn as_raw_fd(&self) -> RawFd;
}

/// A trait to express the ability to construct an object from a raw file
/// descriptor.
pub trait FromRawFd {
    /// Constructs a new instance of `Self` from the given raw file
    /// descriptor.
    ///
    /// This function **consumes ownership** of the specified file
    /// descriptor. The returned object will take responsibility for closing
    /// it when the object goes out of scope.
    ///
    /// This function is also unsafe as the primitives currently returned
    /// have the contract that they are the sole owner of the file
    /// descriptor they are wrapping. Usage of this function could
    /// accidentally allow violating this contract which can cause memory
    /// unsafety in code that relies on it being true.
    unsafe fn from_raw_fd(fd: RawFd) -> Self;
}

/// A trait to express the ability to consume an object and acquire ownership of
/// its raw file descriptor.
pub trait IntoRawFd {
    /// Consumes this object, returning the raw underlying file descriptor.
    ///
    /// This function **transfers ownership** of the underlying file descriptor
    /// to the caller. Callers are then the unique owners of the file descriptor
    /// and must close the descriptor once it's no longer needed.
    fn into_raw_fd(self) -> RawFd;
}

#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
impl AsRawFd for RawFd {
    fn as_raw_fd(&self) -> RawFd {
        *self
    }
}
#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
impl IntoRawFd for RawFd {
    fn into_raw_fd(self) -> RawFd {
        self
    }
}
#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
impl FromRawFd for RawFd {
    unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
        fd
    }
}

impl AsRawFd for net::TcpStream {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().as_raw()
    }
}

impl FromRawFd for net::TcpStream {
    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
        net::TcpStream::from_inner(sys::net::TcpStream::from_inner(fd))
    }
}

impl IntoRawFd for net::TcpStream {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

impl AsRawFd for net::TcpListener {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().as_raw()
    }
}

impl FromRawFd for net::TcpListener {
    unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
        net::TcpListener::from_inner(sys::net::TcpListener::from_inner(fd))
    }
}

impl IntoRawFd for net::TcpListener {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

impl AsRawFd for net::UdpSocket {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().as_raw()
    }
}

impl FromRawFd for net::UdpSocket {
    unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
        net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(fd))
    }
}

impl IntoRawFd for net::UdpSocket {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

impl AsRawFd for fs::File {
    fn as_raw_fd(&self) -> RawFd {
        self.as_inner().fd().as_raw()
    }
}

impl FromRawFd for fs::File {
    unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
        fs::File::from_inner(sys::fs::File::from_inner(fd))
    }
}

impl IntoRawFd for fs::File {
    fn into_raw_fd(self) -> RawFd {
        self.into_inner().into_fd().into_raw()
    }
}

impl AsRawFd for io::Stdin {
    fn as_raw_fd(&self) -> RawFd {
        sys::stdio::Stdin.as_raw_fd()
    }
}

impl AsRawFd for io::Stdout {
    fn as_raw_fd(&self) -> RawFd {
        sys::stdio::Stdout.as_raw_fd()
    }
}

impl AsRawFd for io::Stderr {
    fn as_raw_fd(&self) -> RawFd {
        sys::stdio::Stderr.as_raw_fd()
    }
}

impl<'a> AsRawFd for io::StdinLock<'a> {
    fn as_raw_fd(&self) -> RawFd {
        sys::stdio::Stdin.as_raw_fd()
    }
}

impl<'a> AsRawFd for io::StdoutLock<'a> {
    fn as_raw_fd(&self) -> RawFd {
        sys::stdio::Stdout.as_raw_fd()
    }
}

impl<'a> AsRawFd for io::StderrLock<'a> {
    fn as_raw_fd(&self) -> RawFd {
        sys::stdio::Stderr.as_raw_fd()
    }
}
<|endoftext|>