<commit_before>#![allow(dead_code)]

extern crate walkdir;

use std::env;
use std::path::Path;
use std::process::Command;
use std::u32;

use self::walkdir::DirEntry;

macro_rules! errorf {
    ($($tt:tt)*) => {
        {
            use ::std::io::Write;
            write!(::std::io::stderr(), $($tt)*).unwrap();
        }
    };
}

pub mod parse;
pub mod respan;

pub fn check_min_stack() {
    let min_stack_value = env::var("RUST_MIN_STACK")
        .expect("RUST_MIN_STACK env var should be set since some tests require it.");
    let min_stack_value: usize = min_stack_value.parse()
        .expect("RUST_MIN_STACK env var should be set since some tests require it.");
    assert!(min_stack_value >= 16000000);
}

/// Read the `ABORT_AFTER_FAILURE` environment variable, and parse it.
pub fn abort_after() -> u32 {
    if let Ok(s) = env::var("ABORT_AFTER_FAILURE") {
        if let Ok(n) = s.parse::<u32>() {
            return n;
        }
    }
    u32::MAX
}

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail") ||
       path_string.starts_with("tests/rust/src/test/compile-fail") {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // TODO better support for attributes
        //
        //      let a = A { #[a] b: c };
        "tests/rust/src/librustc_data_structures/blake2b.rs" |
        // TODO better support for attributes
        //
        //      enum A { B = #[a] 2 }
        "tests/rust/src/test/incremental/hashes/enum_defs.rs" |
        // TODO better support for attributes
        //
        //      { #![foo] }
        "tests/rust/src/test/pretty/stmt_expr_attributes.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/cfg_stmt_expr.rs" |
        // TODO weird glob import
        //
        //      use ::*;
        "tests/rust/src/test/run-pass/import-glob-crate.rs" |
        // TODO better support for attributes
        //
        //      impl Foo { #![a] }
        "tests/rust/src/test/run-pass/inner-attrs-on-impl.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/item-attributes.rs" |
        // not actually a test case
        "tests/rust/src/test/run-pass/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    if Path::new("tests/rust").is_dir() {
        return
    }

    println!("cloning rust-lang/rust");
    let result = Command::new("git")
                    .arg("clone")
                    .arg("https://github.com/rust-lang/rust")
                    .arg("tests/rust")
                    .status()
                    .unwrap();
    println!("result: {}", result);
    assert!(result.success());

    println!("reset to known-good rev");
    let result = Command::new("git")
                    .arg("reset")
                    .arg("--hard")
                    .arg("ddc5d7bd4b9ea3e8a8ccf82cb443e950be311d61")
                    .current_dir("tests/rust")
                    .status()
                    .unwrap();
    println!("result: {}", result);
    assert!(result.success());
}
<commit_msg>Update rust submodule, add some new whitelisted failures<commit_after>#![allow(dead_code)]

extern crate walkdir;

use std::env;
use std::path::Path;
use std::process::Command;
use std::u32;

use self::walkdir::DirEntry;

macro_rules! errorf {
    ($($tt:tt)*) => {
        {
            use ::std::io::Write;
            write!(::std::io::stderr(), $($tt)*).unwrap();
        }
    };
}

pub mod parse;
pub mod respan;

pub fn check_min_stack() {
    let min_stack_value = env::var("RUST_MIN_STACK")
        .expect("RUST_MIN_STACK env var should be set since some tests require it.");
    let min_stack_value: usize = min_stack_value.parse()
        .expect("RUST_MIN_STACK env var should be set since some tests require it.");
    assert!(min_stack_value >= 16000000);
}

/// Read the `ABORT_AFTER_FAILURE` environment variable, and parse it.
pub fn abort_after() -> u32 {
    if let Ok(s) = env::var("ABORT_AFTER_FAILURE") {
        if let Ok(n) = s.parse::<u32>() {
            return n;
        }
    }
    u32::MAX
}

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail") ||
       path_string.starts_with("tests/rust/src/test/compile-fail") {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    // TODO: support `macro` definitions
    if path_string.starts_with("tests/rust/src/test/run-pass/hygiene") {
        return false;
    }

    match path_string.as_ref() {
        // TODO better support for attributes
        //
        //      let a = A { #[a] b: c };
        "tests/rust/src/librustc_data_structures/blake2b.rs" |
        // TODO better support for attributes
        //
        //      enum A { B = #[a] 2 }
        "tests/rust/src/test/incremental/hashes/enum_defs.rs" |
        // TODO better support for attributes
        //
        //      { #![foo] }
        "tests/rust/src/test/pretty/stmt_expr_attributes.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/cfg_stmt_expr.rs" |
        // TODO weird glob import
        //
        //      use ::*;
        "tests/rust/src/test/run-pass/import-glob-crate.rs" |
        // TODO better support for attributes
        //
        //      impl Foo { #![a] }
        "tests/rust/src/test/run-pass/inner-attrs-on-impl.rs" |
        // TODO better support for attributes
        "tests/rust/src/test/run-pass/item-attributes.rs" |
        // TODO support lifetimes before traits
        //
        //      Box<'foo + Bar>
        "tests/rust/src/test/run-pass/trait-object-lifetime-first.rs" |
        // not actually a test case
        "tests/rust/src/test/run-pass/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    if Path::new("tests/rust").is_dir() {
        return
    }

    println!("cloning rust-lang/rust");
    let result = Command::new("git")
                    .arg("clone")
                    .arg("https://github.com/rust-lang/rust")
                    .arg("tests/rust")
                    .status()
                    .unwrap();
    println!("result: {}", result);
    assert!(result.success());

    println!("reset to known-good rev");
    let result = Command::new("git")
                    .arg("reset")
                    .arg("--hard")
                    .arg("eb8f2586ebd842dec49d3d7f50e49a985ab31493")
                    .current_dir("tests/rust")
                    .status()
                    .unwrap();
    println!("result: {}", result);
    assert!(result.success());
}
<|endoftext|>


<commit_before>use mio::{Evented,Poll,PollOpt,Ready,Token};
use mio_uds::UnixStream;
use std::fmt::Debug;
use std::iter::Iterator;
use std::str::from_utf8;
use std::marker::PhantomData;
use std::io::{self,Read,Write,ErrorKind};
use std::os::unix::net;
use std::os::unix::io::{AsRawFd,FromRawFd,IntoRawFd};
use std::cmp::min;
use log;
use serde_json;
use serde::ser::Serialize;
use serde::de::Deserialize;

use network::buffer::Buffer;

#[derive(Debug,PartialEq)]
pub enum ConnError {
  Continue,
  ParseError,
  SocketError,
}

pub struct CommandChannel<Tx,Rx> {
  pub sock:        UnixStream,
  front_buf:       Buffer,
  back_buf:        Buffer,
  max_buffer_size: usize,
  pub readiness:   Ready,
  pub interest:    Ready,
  blocking:        bool,
  phantom_tx:      PhantomData<Tx>,
  phantom_rx:      PhantomData<Rx>,
}

impl<Tx: Debug+Serialize, Rx: Debug+Deserialize> CommandChannel<Tx,Rx> {
  pub fn new(sock: UnixStream, buffer_size: usize, max_buffer_size: usize) -> CommandChannel<Tx,Rx> {
    CommandChannel {
      sock:            sock,
      front_buf:       Buffer::with_capacity(buffer_size),
      back_buf:        Buffer::with_capacity(buffer_size),
      max_buffer_size: max_buffer_size,
      readiness:       Ready::none(),
      interest:        Ready::readable(),
      blocking:        false,
      phantom_tx:      PhantomData,
      phantom_rx:      PhantomData,
    }
  }

  pub fn set_nonblocking(&mut self, nonblocking: bool) {
    unsafe {
      let fd = self.sock.as_raw_fd();
      let mut stream = net::UnixStream::from_raw_fd(fd);
      stream.set_nonblocking(nonblocking);
      let fd = stream.into_raw_fd();
    }
    self.blocking = !nonblocking;
  }

  pub fn handle_events(&mut self, events: Ready) {
    self.readiness = self.readiness | events;
  }

  pub fn run(&mut self) {
    let interest = self.interest & self.readiness;

    if interest.is_readable() {
      self.readable();
    }

    if interest.is_writable() {
      self.writable();
    }
  }

  pub fn readable(&mut self) -> Result<usize,ConnError> {
    if !(self.interest & self.readiness).is_readable() {
      return Err(ConnError::Continue);
    }

    let mut count = 0usize;
    loop {
      let size = self.front_buf.available_space();
      if size == 0 {
        self.interest.remove(Ready::readable());
        break;
      }

      match self.sock.read(self.front_buf.space()) {
        Ok(0) => {
          break;
        },
        Err(e) => {
          match e.kind() {
            ErrorKind::WouldBlock => {
              self.readiness.remove(Ready::readable());
              break;
            },
            code => {
              //log!(log::LogLevel::Error, "UNIX CLIENT[{}] read error (kind: {:?}): {:?}", tok.0, code, e);
              self.interest  = Ready::none();
              self.readiness = Ready::none();
              return Err(ConnError::SocketError);
            }
          }
        },
        Ok(r) => {
          count += r;
          self.front_buf.fill(r);
          //debug!("UNIX CLIENT[{}] sent {} bytes: {:?}", tok.0, r, from_utf8(self.buf.data()));
        },
      };
    }

    Ok(count)
  }

  pub fn writable(&mut self) -> Result<usize,ConnError> {
    if !(self.interest & self.readiness).is_writable() {
      return Err(ConnError::Continue);
    }

    let mut count = 0usize;
    loop {
      let size = self.back_buf.available_data();
      if size == 0 {
        self.interest.remove(Ready::writable());
        break;
      }

      match self.sock.write(self.back_buf.data()) {
        Ok(0) => {
          break;
        },
        Ok(r) => {
          count += r;
          self.back_buf.consume(r);
        },
        Err(e) => {
          match e.kind() {
            ErrorKind::WouldBlock => {
              self.interest.remove(Ready::writable());
              break;
            },
            code => {
              self.interest  = Ready::none();
              self.readiness = Ready::none();
              return Err(ConnError::SocketError);
            }
          }
        }
      }
    }

    Ok(count)
  }

  pub fn read_message(&mut self) -> Option<Rx> {
    if self.blocking {
      self.read_message_blocking()
    } else {
      self.read_message_nonblocking()
    }
  }

  pub fn read_message_nonblocking(&mut self) -> Option<Rx> {
    let mut offset = 0usize;
    let mut grow   = false;

    if let Some(pos) = self.front_buf.data().iter().position(|&x| x == 0) {
      let mut res = None;

      if let Ok(s) = from_utf8(&self.front_buf.data()[..pos]) {
        if let Ok(message) = serde_json::from_str(s) {
          res = Some(message);
        } else {
          error!("could not parse message, ignoring:\n{}", s);
        }
      } else {
        error!("invalid utf-8 encoding in command message, ignoring");
      }

      self.front_buf.consume(pos+1);
      res
    } else {
      if self.front_buf.available_space() == 0 {
        if self.front_buf.capacity() == self.max_buffer_size {
          error!("command buffer full, cannot grow more, ignoring");
        } else {
          let new_size = min(self.front_buf.capacity()+5000, self.max_buffer_size);
          self.front_buf.grow(new_size);
        }
      }

      self.interest.insert(Ready::readable());
      None
    }
  }

  pub fn read_message_blocking(&mut self) -> Option<Rx> {
    let mut offset = 0usize;
    let mut grow   = false;

    loop {
      if let Some(pos) = self.front_buf.data().iter().position(|&x| x == 0) {
        let mut res = None;

        if let Ok(s) = from_utf8(&self.front_buf.data()[..pos]) {
          if let Ok(message) = serde_json::from_str(s) {
            res = Some(message);
          } else {
            error!("could not parse message, ignoring:\n{}", s);
          }
        } else {
          error!("invalid utf-8 encoding in command message, ignoring");
        }

        self.front_buf.consume(pos+1);
        return res;
      } else {
        if self.front_buf.available_space() == 0 {
          if self.front_buf.capacity() == self.max_buffer_size {
            error!("command buffer full, cannot grow more, ignoring");
            return None;
          } else {
            let new_size = min(self.front_buf.capacity()+5000, self.max_buffer_size);
            self.front_buf.grow(new_size);
          }
        }

        match self.sock.read(self.front_buf.space()) {
          Ok(0) => {
          },
          Err(e) => { return None; },
          Ok(r) => {
            self.front_buf.fill(r);
          },
        };
      }
    }
  }

  pub fn write_message(&mut self, message: Tx) -> bool {
    if self.blocking {
      self.write_message_blocking(message)
    } else {
      self.write_message_nonblocking(message)
    }
  }

  pub fn write_message_nonblocking(&mut self, message: Tx) -> bool {
    let message = &serde_json::to_string(&message).map(|s| s.into_bytes()).unwrap_or(vec!());

    let msg_len = message.len() + 1;
    if msg_len > self.back_buf.available_space() {
      self.back_buf.shift();
    }

    if msg_len > self.back_buf.available_space() {
      if msg_len - self.back_buf.available_space() + self.back_buf.capacity() > self.max_buffer_size {
        error!("message is too large to write to back buffer");
        return false;
      }

      let new_len = msg_len - self.back_buf.available_space() + self.back_buf.capacity();
      self.back_buf.grow( new_len );
    }

    self.back_buf.write(message);
    self.back_buf.write(&b"\0"[..]);
    self.interest.insert(Ready::writable());

    true
  }

  pub fn write_message_blocking(&mut self, message: Tx) -> bool {
    let message = &serde_json::to_string(&message).map(|s| s.into_bytes()).unwrap_or(vec!());

    let msg_len = message.len() + 1;
    if msg_len > self.back_buf.available_space() {
      self.back_buf.shift();
    }

    if msg_len > self.back_buf.available_space() {
      if msg_len - self.back_buf.available_space() + self.back_buf.capacity() > self.max_buffer_size {
        error!("message is too large to write to back buffer");
        return false;
      }

      let new_len = msg_len - self.back_buf.available_space() + self.back_buf.capacity();
      self.back_buf.grow( new_len );
    }

    self.back_buf.write(message);
    self.back_buf.write(&b"\0"[..]);

    loop {
      let size = self.back_buf.available_data();
      if size == 0 {
        break;
      }

      match self.sock.write(self.back_buf.data()) {
        Ok(r) => {
          self.back_buf.consume(r);
        },
        Err(e) => {
          return true;
        }
      }
    }
    true
  }
}

impl<Tx: Debug+Serialize, Rx: Debug+Deserialize> Iterator for CommandChannel<Tx,Rx> {
  type Item = Rx;
  fn next(&mut self) -> Option<Self::Item> {
    self.read_message()
  }
}

impl<Tx,Rx> Evented for CommandChannel<Tx,Rx> {
  fn register(&self,
              poll: &Poll,
              token: Token,
              interest: Ready,
              opts: PollOpt)
              -> io::Result<()> {
    self.sock.register(poll, token, interest, opts)
  }

  fn reregister(&self,
                poll: &Poll,
                token: Token,
                interest: Ready,
                opts: PollOpt)
                -> io::Result<()> {
    self.sock.reregister(poll, token, interest, opts)
  }

  fn deregister(&self, poll: &Poll) -> io::Result<()> {
    self.sock.deregister(poll)
  }
}
<commit_msg>easier generation of command channels<commit_after>use mio::{Evented,Poll,PollOpt,Ready,Token};
use mio_uds::UnixStream;
use std::fmt::Debug;
use std::iter::Iterator;
use std::str::from_utf8;
use std::marker::PhantomData;
use std::io::{self,Read,Write,ErrorKind};
use std::os::unix::net;
use std::os::unix::io::{AsRawFd,FromRawFd,IntoRawFd};
use std::cmp::min;
use log;
use serde_json;
use serde::ser::Serialize;
use serde::de::Deserialize;

use network::buffer::Buffer;

#[derive(Debug,PartialEq)]
pub enum ConnError {
  Continue,
  ParseError,
  SocketError,
}

pub struct CommandChannel<Tx,Rx> {
  pub sock:        UnixStream,
  front_buf:       Buffer,
  back_buf:        Buffer,
  max_buffer_size: usize,
  pub readiness:   Ready,
  pub interest:    Ready,
  blocking:        bool,
  phantom_tx:      PhantomData<Tx>,
  phantom_rx:      PhantomData<Rx>,
}

impl<Tx: Debug+Serialize, Rx: Debug+Deserialize> CommandChannel<Tx,Rx> {
  pub fn new(sock: UnixStream, buffer_size: usize, max_buffer_size: usize) -> CommandChannel<Tx,Rx> {
    CommandChannel {
      sock:            sock,
      front_buf:       Buffer::with_capacity(buffer_size),
      back_buf:        Buffer::with_capacity(buffer_size),
      max_buffer_size: max_buffer_size,
      readiness:       Ready::none(),
      interest:        Ready::readable(),
      blocking:        false,
      phantom_tx:      PhantomData,
      phantom_rx:      PhantomData,
    }
  }

  pub fn set_nonblocking(&mut self, nonblocking: bool) {
    unsafe {
      let fd = self.sock.as_raw_fd();
      let mut stream = net::UnixStream::from_raw_fd(fd);
      stream.set_nonblocking(nonblocking);
      let fd = stream.into_raw_fd();
    }
    self.blocking = !nonblocking;
  }

  pub fn handle_events(&mut self, events: Ready) {
    self.readiness = self.readiness | events;
  }

  pub fn run(&mut self) {
    let interest = self.interest & self.readiness;

    if interest.is_readable() {
      self.readable();
    }

    if interest.is_writable() {
      self.writable();
    }
  }

  pub fn readable(&mut self) -> Result<usize,ConnError> {
    if !(self.interest & self.readiness).is_readable() {
      return Err(ConnError::Continue);
    }

    let mut count = 0usize;
    loop {
      let size = self.front_buf.available_space();
      if size == 0 {
        self.interest.remove(Ready::readable());
        break;
      }

      match self.sock.read(self.front_buf.space()) {
        Ok(0) => {
          break;
        },
        Err(e) => {
          match e.kind() {
            ErrorKind::WouldBlock => {
              self.readiness.remove(Ready::readable());
              break;
            },
            code => {
              //log!(log::LogLevel::Error, "UNIX CLIENT[{}] read error (kind: {:?}): {:?}", tok.0, code, e);
              self.interest  = Ready::none();
              self.readiness = Ready::none();
              return Err(ConnError::SocketError);
            }
          }
        },
        Ok(r) => {
          count += r;
          self.front_buf.fill(r);
          //debug!("UNIX CLIENT[{}] sent {} bytes: {:?}", tok.0, r, from_utf8(self.buf.data()));
        },
      };
    }

    Ok(count)
  }

  pub fn writable(&mut self) -> Result<usize,ConnError> {
    if !(self.interest & self.readiness).is_writable() {
      return Err(ConnError::Continue);
    }

    let mut count = 0usize;
    loop {
      let size = self.back_buf.available_data();
      if size == 0 {
        self.interest.remove(Ready::writable());
        break;
      }

      match self.sock.write(self.back_buf.data()) {
        Ok(0) => {
          break;
        },
        Ok(r) => {
          count += r;
          self.back_buf.consume(r);
        },
        Err(e) => {
          match e.kind() {
            ErrorKind::WouldBlock => {
              self.interest.remove(Ready::writable());
              break;
            },
            code => {
              self.interest  = Ready::none();
              self.readiness = Ready::none();
              return Err(ConnError::SocketError);
            }
          }
        }
      }
    }

    Ok(count)
  }

  pub fn read_message(&mut self) -> Option<Rx> {
    if self.blocking {
      self.read_message_blocking()
    } else {
      self.read_message_nonblocking()
    }
  }

  pub fn read_message_nonblocking(&mut self) -> Option<Rx> {
    let mut offset = 0usize;
    let mut grow   = false;

    if let Some(pos) = self.front_buf.data().iter().position(|&x| x == 0) {
      let mut res = None;

      if let Ok(s) = from_utf8(&self.front_buf.data()[..pos]) {
        if let Ok(message) = serde_json::from_str(s) {
          res = Some(message);
        } else {
          error!("could not parse message, ignoring:\n{}", s);
        }
      } else {
        error!("invalid utf-8 encoding in command message, ignoring");
      }

      self.front_buf.consume(pos+1);
      res
    } else {
      if self.front_buf.available_space() == 0 {
        if self.front_buf.capacity() == self.max_buffer_size {
          error!("command buffer full, cannot grow more, ignoring");
        } else {
          let new_size = min(self.front_buf.capacity()+5000, self.max_buffer_size);
          self.front_buf.grow(new_size);
        }
      }

      self.interest.insert(Ready::readable());
      None
    }
  }

  pub fn read_message_blocking(&mut self) -> Option<Rx> {
    let mut offset = 0usize;
    let mut grow   = false;

    loop {
      if let Some(pos) = self.front_buf.data().iter().position(|&x| x == 0) {
        let mut res = None;

        if let Ok(s) = from_utf8(&self.front_buf.data()[..pos]) {
          if let Ok(message) = serde_json::from_str(s) {
            res = Some(message);
          } else {
            error!("could not parse message, ignoring:\n{}", s);
          }
        } else {
          error!("invalid utf-8 encoding in command message, ignoring");
        }

        self.front_buf.consume(pos+1);
        return res;
      } else {
        if self.front_buf.available_space() == 0 {
          if self.front_buf.capacity() == self.max_buffer_size {
            error!("command buffer full, cannot grow more, ignoring");
            return None;
          } else {
            let new_size = min(self.front_buf.capacity()+5000, self.max_buffer_size);
            self.front_buf.grow(new_size);
          }
        }

        match self.sock.read(self.front_buf.space()) {
          Ok(0) => {
          },
          Err(e) => { return None; },
          Ok(r) => {
            self.front_buf.fill(r);
          },
        };
      }
    }
  }

  pub fn write_message(&mut self, message: Tx) -> bool {
    if self.blocking {
      self.write_message_blocking(message)
    } else {
      self.write_message_nonblocking(message)
    }
  }

  pub fn write_message_nonblocking(&mut self, message: Tx) -> bool {
    let message = &serde_json::to_string(&message).map(|s| s.into_bytes()).unwrap_or(vec!());

    let msg_len = message.len() + 1;
    if msg_len > self.back_buf.available_space() {
      self.back_buf.shift();
    }

    if msg_len > self.back_buf.available_space() {
      if msg_len - self.back_buf.available_space() + self.back_buf.capacity() > self.max_buffer_size {
        error!("message is too large to write to back buffer");
        return false;
      }

      let new_len = msg_len - self.back_buf.available_space() + self.back_buf.capacity();
      self.back_buf.grow( new_len );
    }

    self.back_buf.write(message);
    self.back_buf.write(&b"\0"[..]);
    self.interest.insert(Ready::writable());

    true
  }

  pub fn write_message_blocking(&mut self, message: Tx) -> bool {
    let message = &serde_json::to_string(&message).map(|s| s.into_bytes()).unwrap_or(vec!());

    let msg_len = message.len() + 1;
    if msg_len > self.back_buf.available_space() {
      self.back_buf.shift();
    }

    if msg_len > self.back_buf.available_space() {
      if msg_len - self.back_buf.available_space() + self.back_buf.capacity() > self.max_buffer_size {
        error!("message is too large to write to back buffer");
        return false;
      }

      let new_len = msg_len - self.back_buf.available_space() + self.back_buf.capacity();
      self.back_buf.grow( new_len );
    }

    self.back_buf.write(message);
    self.back_buf.write(&b"\0"[..]);

    loop {
      let size = self.back_buf.available_data();
      if size == 0 {
        break;
      }

      match self.sock.write(self.back_buf.data()) {
        Ok(r) => {
          self.back_buf.consume(r);
        },
        Err(e) => {
          return true;
        }
      }
    }
    true
  }
}

impl<Tx: Debug+Deserialize+Serialize, Rx: Debug+Deserialize+Serialize> CommandChannel<Tx,Rx> {
  pub fn generate(buffer_size: usize, max_buffer_size: usize) -> io::Result<(CommandChannel<Tx,Rx>, CommandChannel<Rx,Tx>)> {
    let     (command,proxy) = try!(UnixStream::pair());
    let     proxy_channel   = CommandChannel::new(proxy, buffer_size, max_buffer_size);
    let mut command_channel = CommandChannel::new(command, buffer_size, max_buffer_size);
    command_channel.set_nonblocking(false);
    Ok((command_channel, proxy_channel))
  }
}

impl<Tx: Debug+Serialize, Rx: Debug+Deserialize> Iterator for CommandChannel<Tx,Rx> {
  type Item = Rx;
  fn next(&mut self) -> Option<Self::Item> {
    self.read_message()
  }
}

impl<Tx,Rx> Evented for CommandChannel<Tx,Rx> {
  fn register(&self,
              poll: &Poll,
              token: Token,
              interest: Ready,
              opts: PollOpt)
              -> io::Result<()> {
    self.sock.register(poll, token, interest, opts)
  }

  fn reregister(&self,
                poll: &Poll,
                token: Token,
                interest: Ready,
                opts: PollOpt)
                -> io::Result<()> {
    self.sock.reregister(poll, token, interest, opts)
  }

  fn deregister(&self, poll: &Poll) -> io::Result<()> {
    self.sock.deregister(poll)
  }
}
<|endoftext|>


<commit_before>extern crate rsoundio;

use std::os::raw::c_int;
use std::f32::consts;
use std::thread;
use std::time::Duration;

#[test]
fn test_outstream() {
    println!("test: OutStream");
    let sio = rsoundio::SoundIo::new();
    assert!(sio.connect_backend(rsoundio::ffi::SioBackend::Dummy).is_none());
    println!("current backend: {}", sio.current_backend().unwrap());
    sio.flush_events();
    let fmt;
    let dev_idx = sio.default_output_device_index().unwrap();
    let mut frames: Vec<Vec<f32>> = vec![vec![], vec![]];
    let dev = sio.get_output_device(dev_idx).unwrap();
    println!("device: {}, ref_count: {}", dev, dev.ref_count());
    let mut stream = dev.create_outstream().unwrap();
    assert!(stream.open().is_none());
    fmt = stream.current_format().unwrap();
    println!("current format: {}", fmt);
    let f = 4400f32;
    let sr = stream.get_sample_rate();
    let layout = stream.get_layout();
    let channels = layout.channel_count();
    let phi = 2.0 * f * consts::PI / (sr as f32);
    let l: Vec<f32> = (0..4096).map(|i| f32::sin(i as f32 * phi)).collect();
    let r = l.clone();
    frames = vec![l, r];
    let cb = |out: rsoundio::OutStream, min_frame_count: i32, max_frame_count: i32| {
        let frames_written = out.write_stream_f32(min_frame_count, &frames).unwrap();
        assert!(frames_written > 0);
        out.get_latency().map(|latency| assert!(latency >= 0.0));
    };
    stream.register_write_callback(Box::new(cb));
    let ucb = |out: rsoundio::OutStream| println!("Underflow!");
    stream.register_underflow_callback(Box::new(ucb));
    let ecb = |out: rsoundio::OutStream, err: rsoundio::ffi::SioError| println!("Error: {}", err);
    stream.register_error_callback(Box::new(ecb));
    assert!(stream.start().is_none());
    //sio.wait_events();
    thread::sleep(Duration::new(1,0));
    assert!(stream.pause(true).is_none());
    thread::sleep(Duration::new(1,0));
    assert!(stream.pause(false).is_none());
    assert!(stream.clear_buffer().is_none());
    thread::sleep(Duration::new(1,0));
    stream.destroy();
}
<commit_msg>Unref device (not really needed)<commit_after>extern crate rsoundio;

use std::os::raw::c_int;
use std::f32::consts;
use std::thread;
use std::time::Duration;

#[test]
fn test_outstream() {
    println!("test: OutStream");
    let sio = rsoundio::SoundIo::new();
    assert!(sio.connect_backend(rsoundio::ffi::SioBackend::Dummy).is_none());
    println!("current backend: {}", sio.current_backend().unwrap());
    sio.flush_events();
    let fmt;
    let dev_idx = sio.default_output_device_index().unwrap();
    let mut frames: Vec<Vec<f32>> = vec![vec![], vec![]];
    let dev = sio.get_output_device(dev_idx).unwrap();
    println!("device: {}, ref_count: {}", dev, dev.ref_count());
    let mut stream = dev.create_outstream().unwrap();
    assert!(stream.open().is_none());
    fmt = stream.current_format().unwrap();
    println!("current format: {}", fmt);
    let f = 4400f32;
    let sr = stream.get_sample_rate();
    let layout = stream.get_layout();
    let channels = layout.channel_count();
    let phi = 2.0 * f * consts::PI / (sr as f32);
    let l: Vec<f32> = (0..4096).map(|i| f32::sin(i as f32 * phi)).collect();
    let r = l.clone();
    frames = vec![l, r];
    let cb = |out: rsoundio::OutStream, min_frame_count: i32, max_frame_count: i32| {
        let frames_written = out.write_stream_f32(min_frame_count, &frames).unwrap();
        assert!(frames_written > 0);
        out.get_latency().map(|latency| assert!(latency >= 0.0));
    };
    stream.register_write_callback(Box::new(cb));
    let ucb = |out: rsoundio::OutStream| println!("Underflow!");
    stream.register_underflow_callback(Box::new(ucb));
    let ecb = |out: rsoundio::OutStream, err: rsoundio::ffi::SioError| println!("Error: {}", err);
    stream.register_error_callback(Box::new(ecb));
    assert!(stream.start().is_none());
    //sio.wait_events();
    thread::sleep(Duration::new(1,0));
    assert!(stream.pause(true).is_none());
    thread::sleep(Duration::new(1,0));
    assert!(stream.pause(false).is_none());
    assert!(stream.clear_buffer().is_none());
    thread::sleep(Duration::new(1,0));
    stream.destroy();
    dev.dec_ref();
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate time;
use std::{ptr};
use std::mem::{transmute};

struct File {
    data: *u8,
    header: *Header,
    nodetable: *NodeData,
    stringtable: *u64,
}
impl File {
    #[cfg(target_os = "win32")]
    fn open(name: &Path) -> Option<File> {
        use libc::funcs::extra::kernel32::{CreateFileW, CreateFileMappingW,
                                           MapViewOfFile};
        use libc::consts::os::extra::{GENERIC_READ, FILE_SHARE_READ,
                                      OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS,
                                      INVALID_HANDLE_VALUE, PAGE_READONLY,
                                      FILE_MAP_READ};
        use libc::types::os::arch::extra::LPSECURITY_ATTRIBUTES;
        unsafe {
            let sname = name.as_str().unwrap().to_utf16();
            let handle =
                CreateFileW(sname.as_ptr(), GENERIC_READ, FILE_SHARE_READ,
                            ptr::mut_null(), OPEN_EXISTING,
                            FILE_FLAG_RANDOM_ACCESS, ptr::mut_null());
            if handle == transmute(INVALID_HANDLE_VALUE) { return None; }
            let map =
                CreateFileMappingW(handle, ptr::mut_null(), PAGE_READONLY, 0,
                                   0, ptr::null());
            if map.is_null() { return None; }
            let data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
            if data.is_null() { return None; }
            let header: *Header = transmute(data);
            if (*header).magic != 0x34474B50 { return None; }
            let file =
                File{data: transmute(data),
                     header: header,
                     nodetable:
                         transmute(data.offset((*header).nodeoffset as int)),
                     stringtable:
                         transmute(data.offset((*header).stringoffset as
                                                   int)),};
            Some(file)
        }
    }
    #[cfg(target_os = "linux")]
    fn open(name: &Path) -> Option<File> {
        unsafe {
            //Someone fill this in please
        }
    }
    fn get_header(&self) -> &Header { unsafe { transmute(self.header) } }
    fn root<'a>(&'a self) -> Node<'a> {
        unsafe { Node{data: &*self.nodetable, file: self,} }
    }
    fn get_str<'a>(&'a self, index: u32) -> Option<&'a str> {
        unsafe {
            let off = *self.stringtable.offset(index as int);
            let ptr = self.data.offset(off as int);
            let size: *u16 = transmute(ptr);
            let func = |buf: &[u8]| -> Option<&'a str> {
                let bytes: &'a [u8] = transmute(buf);
                std::str::from_utf8(bytes) };
            std::slice::raw::buf_as_slice(ptr.offset(2), (*size) as uint,
                                          func)
        }
    }
}
#[packed]
struct Header {
    magic: u32,
    nodecount: u32,
    nodeoffset: u64,
    stringcount: u32,
    stringoffset: u64,
    bitmapcount: u32,
    bitmapoffset: u64,
    audiocount: u32,
    audiooffset: u64,
}
#[packed]
struct String {
    length: u16,
}
struct Node<'a> {
    data: &'a NodeData,
    file: &'a File,
}
impl <'a> Node<'a> {
    fn iter(&self) -> NodeIterator<'a> {
        unsafe {
            let data = self.file.nodetable.offset(self.data.children as int);
            NodeIterator{data: data, count: self.data.count, file: self.file,}
        }
    }
    fn name(&self) -> Option<&'a str> { self.file.get_str(self.data.name) }
    fn empty(&self) -> bool { self.data.count == 0 }
}
struct NodeIterator<'a> {
    data: *NodeData,
    count: u16,
    file: &'a File,
}
impl <'a> Iterator<Node<'a>> for NodeIterator<'a> {
    fn next(&mut self) -> Option<Node<'a>> {
        match self.count {
            0 => None,
            _ => {
                unsafe {
                    self.count -= 1;
                    let node = Node{data: &*self.data, file: self.file,};
                    self.data = self.data.offset(1);
                    Some(node)
                }
            }
        }
    }
}
#[packed]
struct NodeData {
    name: u32,
    children: u32,
    count: u16,
    dtype: u16,
    data: u64,
}
#[packed]
struct NodeInteger {
    value: i64,
}
#[packed]
struct NodeFloat {
    value: f64,
}
#[packed]
struct NodeString {
    index: u32,
    unused: u32,
}
#[packed]
struct NodeVector {
    x: i32,
    y: i32,
}
#[packed]
struct NodeBitmap {
    index: u32,
    width: u16,
    height: u16,
}
#[packed]
struct NodeAudio {
    index: u32,
    length: u32,
}
fn recurse(node: Node) -> int { node.iter().fold(1, |a, b| a + recurse(b)) }
fn test(name: &str, func: |Node| -> int, node: Node) {
    for i in range(0, 10) {
        let begin = time::precise_time_ns();
        let answer = recurse(node);
        let end = time::precise_time_ns();
        println!("{}\t{}\t{}" , name , ( end - begin ) / 1000 , answer);
    }
}
fn main() {
    unsafe { ::std::rt::stack::record_sp_limit(0); }
    let file = File::open(&Path::new("Data.nx")).unwrap();
    test("Re", recurse, file.root());
}
<commit_msg>Preliminary *nix implementation<commit_after>extern crate libc;
extern crate time;
use std::{ptr};
use std::mem::{transmute};

struct File {
    data: *u8,
    header: *Header,
    nodetable: *NodeData,
    stringtable: *u64,
}
impl File {
    #[cfg(windows)]
    fn open(path: &Path) -> Option<File> {
        use libc::funcs::extra::kernel32::{CreateFileW, CreateFileMappingW,
                                           MapViewOfFile};
        use libc::consts::os::extra::{GENERIC_READ, FILE_SHARE_READ,
                                      OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS,
                                      INVALID_HANDLE_VALUE, PAGE_READONLY,
                                      FILE_MAP_READ};
        use libc::types::os::arch::extra::LPSECURITY_ATTRIBUTES;
        unsafe {
            let mut name = path.as_str().unwrap().to_utf16();
            name.push(0);
            let handle =
                CreateFileW(name.as_ptr(), GENERIC_READ, FILE_SHARE_READ,
                            ptr::mut_null(), OPEN_EXISTING,
                            FILE_FLAG_RANDOM_ACCESS, ptr::mut_null());
            if handle == transmute(INVALID_HANDLE_VALUE) { return None; }
            let map =
                CreateFileMappingW(handle, ptr::mut_null(), PAGE_READONLY, 0,
                                   0, ptr::null());
            if map.is_null() { return None; }
            let data = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
            if data.is_null() { return None; }
            let header: *Header = transmute(data);
            if (*header).magic != 0x34474B50 { return None; }
            let file =
                File{data: transmute(data),
                     header: header,
                     nodetable:
                         transmute(data.offset((*header).nodeoffset as int)),
                     stringtable:
                         transmute(data.offset((*header).stringoffset as
                                                   int)),};
            Some(file)
        }
    }
    #[cfg(unix)]
    fn open(path: &Path) -> Option<File> {
        use libc::funcs::posix88::fcntl::open;
        use libc::funcs::posix88::stat_::fstat;
        use libc::funcs::posix88::mman::mmap;
        use libc::consts::os::posix88::{O_RDONLY, PROT_READ, MAP_SHARED};
        use libc::types::os::arch::posix01::stat;
        unsafe {
            let name = name.to_c_str();
            let handle = open(name.as_bytes().as_ptr(), O_RDONLY);
            if (handle == -1) { return None; }
            let finfo: stat;
            if (fstat(handle, &finfo) == -1) { return None; }
            let size = finfo.st_size;
            let data =
                mmap(ptr::null(), size, PROT_READ, MAP_SHARED, handle, 0);
            if (data == -1) { return None; }
            let header: *Header = transmute(data);
            if (*header).magic != 0x34474B50 { return None; }
            let file =
                File{data: transmute(data),
                     header: header,
                     nodetable:
                         transmute(data.offset((*header).nodeoffset as int)),
                     stringtable:
                         transmute(data.offset((*header).stringoffset as
                                                   int)),};
            Some(file)
        }
    }
    fn get_header(&self) -> &Header { unsafe { transmute(self.header) } }
    fn root<'a>(&'a self) -> Node<'a> {
        unsafe { Node{data: &*self.nodetable, file: self,} }
    }
    fn get_str<'a>(&'a self, index: u32) -> Option<&'a str> {
        unsafe {
            let off = *self.stringtable.offset(index as int);
            let ptr = self.data.offset(off as int);
            let size: *u16 = transmute(ptr);
            let func = |buf: &[u8]| -> Option<&'a str> {
                let bytes: &'a [u8] = transmute(buf);
                std::str::from_utf8(bytes) };
            std::slice::raw::buf_as_slice(ptr.offset(2), (*size) as uint,
                                          func)
        }
    }
}
#[packed]
struct Header {
    magic: u32,
    nodecount: u32,
    nodeoffset: u64,
    stringcount: u32,
    stringoffset: u64,
    bitmapcount: u32,
    bitmapoffset: u64,
    audiocount: u32,
    audiooffset: u64,
}
#[packed]
struct String {
    length: u16,
}
struct Node<'a> {
    data: &'a NodeData,
    file: &'a File,
}
impl <'a> Node<'a> {
    fn iter(&self) -> NodeIterator<'a> {
        unsafe {
            let data = self.file.nodetable.offset(self.data.children as int);
            NodeIterator{data: data, count: self.data.count, file: self.file,}
        }
    }
    fn name(&self) -> Option<&'a str> { self.file.get_str(self.data.name) }
    fn empty(&self) -> bool { self.data.count == 0 }
}
struct NodeIterator<'a> {
    data: *NodeData,
    count: u16,
    file: &'a File,
}
impl <'a> Iterator<Node<'a>> for NodeIterator<'a> {
    fn next(&mut self) -> Option<Node<'a>> {
        match self.count {
            0 => None,
            _ => {
                unsafe {
                    self.count -= 1;
                    let node = Node{data: &*self.data, file: self.file,};
                    self.data = self.data.offset(1);
                    Some(node)
                }
            }
        }
    }
}
#[packed]
struct NodeData {
    name: u32,
    children: u32,
    count: u16,
    dtype: u16,
    data: u64,
}
#[packed]
struct NodeInteger {
    value: i64,
}
#[packed]
struct NodeFloat {
    value: f64,
}
#[packed]
struct NodeString {
    index: u32,
    unused: u32,
}
#[packed]
struct NodeVector {
    x: i32,
    y: i32,
}
#[packed]
struct NodeBitmap {
    index: u32,
    width: u16,
    height: u16,
}
#[packed]
struct NodeAudio {
    index: u32,
    length: u32,
}
fn recurse(node: Node) -> int { node.iter().fold(1, |a, b| a + recurse(b)) }
fn test(name: &str, func: |Node| -> int, node: Node) {
    for i in range(0, 10) {
        let begin = time::precise_time_ns();
        let answer = recurse(node);
        let end = time::precise_time_ns();
        println!("{}\t{}\t{}" , name , ( end - begin ) / 1000 , answer);
    }
}
fn main() {
    unsafe { ::std::rt::stack::record_sp_limit(0); }
    let file = File::open(&Path::new("Data.nx")).unwrap();
    test("Re", recurse, file.root());
}
<|endoftext|>


<commit_before>use crate::{
    attrs::{Attrs, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
    derives::{from_arg_matches, into_app},
    dummies,
    utils::{is_simple_ty, subty_if_name, Sp},
};

use proc_macro2::{Ident, Span, TokenStream};
use proc_macro_error::{abort, abort_call_site};
use quote::{quote, quote_spanned};
use syn::{
    punctuated::Punctuated, spanned::Spanned, Attribute, Data, DataEnum, DeriveInput,
    FieldsUnnamed, Token, Variant,
};

pub fn derive_subcommand(input: &DeriveInput) -> TokenStream {
    let ident = &input.ident;

    dummies::subcommand(ident);

    match input.data {
        Data::Enum(ref e) => gen_for_enum(ident, &input.attrs, e),
        _ => abort_call_site!("`#[derive(Subcommand)]` only supports enums"),
    }
}

pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStream {
    let attrs = Attrs::from_struct(
        Span::call_site(),
        attrs,
        Name::Derived(name.clone()),
        Sp::call_site(DEFAULT_CASING),
        Sp::call_site(DEFAULT_ENV_CASING),
    );

    let from_subcommand = gen_from_subcommand(name, &e.variants, &attrs);
    let augment_subcommands = gen_augment_subcommands(&e.variants, &attrs);
    let augment_update_subcommands = gen_augment_update_subcommands(&e.variants, &attrs);
    let update_from_subcommand = gen_update_from_subcommand(name, &e.variants, &attrs);

    quote! {
        #[allow(dead_code, unreachable_code, unused_variables)]
        #[allow(
            clippy::style,
            clippy::complexity,
            clippy::pedantic,
            clippy::restriction,
            clippy::perf,
            clippy::deprecated,
            clippy::nursery,
            clippy::cargo
        )]
        #[deny(clippy::correctness)]
        impl ::clap::Subcommand for #name {
            #augment_subcommands
            #from_subcommand
            #augment_update_subcommands
            #update_from_subcommand
        }
    }
}

fn gen_augment_subcommands(
    variants: &Punctuated<Variant, Token![,]>,
    parent_attribute: &Attrs,
) -> TokenStream {
    gen_augment("augment_subcommands", variants, parent_attribute, false)
}

fn gen_augment_update_subcommands(
    variants: &Punctuated<Variant, Token![,]>,
    parent_attribute: &Attrs,
) -> TokenStream {
    gen_augment(
        "augment_update_subcommands",
        variants,
        parent_attribute,
        true,
    )
}

fn gen_augment(
    fn_name: &str,
    variants: &Punctuated<Variant, Token![,]>,
    parent_attribute: &Attrs,
    override_required: bool,
) -> TokenStream {
    use syn::Fields::*;

    let subcommands: Vec<_> = variants
        .iter()
        .map(|variant| {
            let attrs = Attrs::from_struct(
                variant.span(),
                &variant.attrs,
                Name::Derived(variant.ident.clone()),
                parent_attribute.casing(),
                parent_attribute.env_casing(),
            );
            let kind = attrs.kind();

            match &*kind {
                Kind::ExternalSubcommand => {
                    quote_spanned! { kind.span()=>
                        let app = app.setting(::clap::AppSettings::AllowExternalSubcommands);
                    }
                }

                Kind::Flatten => match variant.fields {
                    Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
                        let ty = &unnamed[0];
                        quote! {
                            let app = <#ty as ::clap::Subcommand>::augment_subcommands(app);
                        }
                    }
                    _ => abort!(
                        variant,
                        "`flatten` is usable only with single-typed tuple variants"
                    ),
                },

                _ => {
                    let app_var = Ident::new("subcommand", Span::call_site());
                    let arg_block = match variant.fields {
                        Named(ref fields) => into_app::gen_app_augmentation(
                            &fields.named,
                            &app_var,
                            &attrs,
                            override_required,
                        ),
                        Unit => quote!( #app_var ),
                        Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
                            let ty = &unnamed[0];
                            quote_spanned! { ty.span()=>
                                {
                                    <#ty as ::clap::IntoApp>::augment_clap(#app_var)
                                }
                            }
                        }
                        Unnamed(..) => {
                            abort!(variant, "non single-typed tuple enums are not supported")
                        }
                    };

                    let name = attrs.cased_name();
                    let from_attrs = attrs.top_level_methods();
                    let version = attrs.version();
                    quote! {
                        let app = app.subcommand({
                            let #app_var = ::clap::App::new(#name);
                            let #app_var = #arg_block;
                            #app_var#from_attrs#version
                        });
                    }
                }
            }
        })
        .collect();

    let app_methods = parent_attribute.top_level_methods();
    let version = parent_attribute.version();
    let fn_name = Ident::new(fn_name, Span::call_site());
    quote! {
        fn #fn_name <'b>(app: ::clap::App<'b>) -> ::clap::App<'b> {
            let app = app #app_methods;
            #( #subcommands )*;
            app #version
        }
    }
}

fn gen_from_subcommand(
    name: &Ident,
    variants: &Punctuated<Variant, Token![,]>,
    parent_attribute: &Attrs,
) -> TokenStream {
    use syn::Fields::*;

    let mut ext_subcmd = None;

    let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
        .iter()
        .filter_map(|variant| {
            let attrs = Attrs::from_struct(
                variant.span(),
                &variant.attrs,
                Name::Derived(variant.ident.clone()),
                parent_attribute.casing(),
                parent_attribute.env_casing(),
            );

            if let Kind::ExternalSubcommand = &*attrs.kind() {
                if ext_subcmd.is_some() {
                    abort!(
                        attrs.kind().span(),
                        "Only one variant can be marked with `external_subcommand`, \
                         this is the second"
                    );
                }

                let ty = match variant.fields {
                    Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty,

                    _ => abort!(
                        variant,
                        "The enum variant marked with `external_attribute` must be \
                         a single-typed tuple, and the type must be either `Vec<String>` \
                         or `Vec<OsString>`."
                    ),
                };

                let (span, str_ty, values_of) = match subty_if_name(ty, "Vec") {
                    Some(subty) => {
                        if is_simple_ty(subty, "String") {
                            (
                                subty.span(),
                                quote!(::std::string::String),
                                quote!(values_of),
                            )
                        } else if is_simple_ty(subty, "OsString") {
                            (
                                subty.span(),
                                quote!(::std::ffi::OsString),
                                quote!(values_of_os),
                            )
                        } else {
                            abort!(
                                ty.span(),
                                "The type must be either `Vec<String>` or `Vec<OsString>` \
                                 to be used with `external_subcommand`."
                            );
                        }
                    }

                    None => abort!(
                        ty.span(),
                        "The type must be either `Vec<String>` or `Vec<OsString>` \
                         to be used with `external_subcommand`."
                    ),
                };

                ext_subcmd = Some((span, &variant.ident, str_ty, values_of));
                None
            } else {
                Some((variant, attrs))
            }
        })
        .partition(|(_, attrs)| {
            let kind = attrs.kind();
            matches!(&*kind, Kind::Flatten)
        });

    let match_arms = variants.iter().map(|(variant, attrs)| {
        let sub_name = attrs.cased_name();
        let variant_name = &variant.ident;
        let constructor_block = match variant.fields {
            Named(ref fields) => from_arg_matches::gen_constructor(&fields.named, &attrs),
            Unit => quote!(),
            Unnamed(ref fields) if fields.unnamed.len() == 1 => {
                let ty = &fields.unnamed[0];
                quote!( ( <#ty as ::clap::FromArgMatches>::from_arg_matches(matches) ) )
            }
            Unnamed(..) => abort_call_site!("{}: tuple enums are not supported", variant.ident),
        };

        quote! {
            Some((#sub_name, matches)) => {
                Some(#name :: #variant_name #constructor_block)
            }
        }
    });
    let child_subcommands = flatten_variants.iter().map(|(variant, _attrs)| {
        let variant_name = &variant.ident;
        match variant.fields {
            Unnamed(ref fields) if fields.unnamed.len() == 1 => {
                let ty = &fields.unnamed[0];
                quote! {
                    if let Some(res) = <#ty as ::clap::Subcommand>::from_subcommand(other) {
                        return Some(#name :: #variant_name (res));
                    }
                }
            }
            _ => abort!(
                variant,
                "`flatten` is usable only with single-typed tuple variants"
            ),
        }
    });

    let wildcard = match ext_subcmd {
        Some((span, var_name, str_ty, values_of)) => quote_spanned! { span=>
            None => ::std::option::Option::None,

            Some((external, matches)) => {
                ::std::option::Option::Some(#name::#var_name(
                    ::std::iter::once(#str_ty::from(external))
                    .chain(
                        matches.#values_of("").into_iter().flatten().map(#str_ty::from)
                    )
                    .collect::<::std::vec::Vec<_>>()
                ))
            }
        },

        None => quote!(_ => None),
    };

    quote! {
        fn from_subcommand(subcommand: Option<(&str, &::clap::ArgMatches)>) -> Option<Self> {
            match subcommand {
                #( #match_arms, )*
                other => {
                    #( #child_subcommands )else*

                    match other {
                        #wildcard
                    }
                }
            }
        }
    }
}

fn gen_update_from_subcommand(
    name: &Ident,
    variants: &Punctuated<Variant, Token![,]>,
    parent_attribute: &Attrs,
) -> TokenStream {
    use syn::Fields::*;

    let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
        .iter()
        .filter_map(|variant| {
            let attrs = Attrs::from_struct(
                variant.span(),
                &variant.attrs,
                Name::Derived(variant.ident.clone()),
                parent_attribute.casing(),
                parent_attribute.env_casing(),
            );

            if let Kind::ExternalSubcommand = &*attrs.kind() {
                None
            } else {
                Some((variant, attrs))
            }
        })
        .partition(|(_, attrs)| {
            let kind = attrs.kind();
            match &*kind {
                Kind::Flatten => true,
                _ => false,
            }
        });

    let subcommands = variants.iter().map(|(variant, attrs)| {
        let sub_name = attrs.cased_name();
        let variant_name = &variant.ident;
        let (pattern, updater) = match variant.fields {
            Named(ref fields) => {
                let (fields, update): (Vec<_>, Vec<_>) = fields
                    .named
                    .iter()
                    .map(|field| {
                        let attrs = Attrs::from_field(
                            field,
                            parent_attribute.casing(),
                            parent_attribute.env_casing(),
                        );
                        let field_name = field.ident.as_ref().unwrap();
                        (
                            quote!( ref mut #field_name ),
                            from_arg_matches::gen_updater(&fields.named, &attrs, false),
                        )
                    })
                    .unzip();
                (quote!( { #( #fields, )* }), quote!( { #( #update )* } ))
            }
            Unit => (quote!(), quote!({})),
            Unnamed(ref fields) => {
                if fields.unnamed.len() == 1 {
                    (
                        quote!((ref mut arg)),
                        quote!(::clap::FromArgMatches::update_from_arg_matches(
                            arg, matches
                        )),
                    )
                } else {
                    abort_call_site!("{}: tuple enums are not supported", variant.ident)
                }
            }
        };

        quote! {
            (#sub_name, #name :: #variant_name #pattern) => { #updater }
        }
    });

    let child_subcommands = flatten_variants.iter().map(|(variant, attrs)| {
        let sub_name = attrs.cased_name();
        let variant_name = &variant.ident;
        let (pattern, updater) = match variant.fields {
            Unnamed(ref fields) if fields.unnamed.len() == 1 => {
                let ty = &fields.unnamed[0];
                (
                    quote!((ref mut arg)),
                    quote! {
                        <#ty as ::clap::Subcommand>::update_from_subcommand(arg, Some((name, matches)));
                    },
                )
            }
            _ => abort!(
                variant,
                "`flatten` is usable only with single-typed tuple variants"
            ),
        };
        quote! {
            (#sub_name, #name :: #variant_name #pattern) => { #updater }
        }
    });

    quote! {
        fn update_from_subcommand<'b>(
            &mut self,
            subcommand: Option<(&str, &::clap::ArgMatches)>
        ) {
            if let Some((name, matches)) = subcommand {
                match (name, self) {
                    #( #subcommands ),*
                    #( #child_subcommands ),*
                    (_, s) => if let Some(sub) = <Self as ::clap::Subcommand>::from_subcommand(Some((name, matches))) {
                        *s = sub;
                    }
                }
            }
        }
    }
}
<commit_msg>Address new clippy lints<commit_after>use crate::{
    attrs::{Attrs, Kind, Name, DEFAULT_CASING, DEFAULT_ENV_CASING},
    derives::{from_arg_matches, into_app},
    dummies,
    utils::{is_simple_ty, subty_if_name, Sp},
};

use proc_macro2::{Ident, Span, TokenStream};
use proc_macro_error::{abort, abort_call_site};
use quote::{quote, quote_spanned};
use syn::{
    punctuated::Punctuated, spanned::Spanned, Attribute, Data, DataEnum, DeriveInput,
    FieldsUnnamed, Token, Variant,
};

pub fn derive_subcommand(input: &DeriveInput) -> TokenStream {
    let ident = &input.ident;

    dummies::subcommand(ident);

    match input.data {
        Data::Enum(ref e) => gen_for_enum(ident, &input.attrs, e),
        _ => abort_call_site!("`#[derive(Subcommand)]` only supports enums"),
    }
}

pub fn gen_for_enum(name: &Ident, attrs: &[Attribute], e: &DataEnum) -> TokenStream {
    let attrs = Attrs::from_struct(
        Span::call_site(),
        attrs,
        Name::Derived(name.clone()),
        Sp::call_site(DEFAULT_CASING),
        Sp::call_site(DEFAULT_ENV_CASING),
    );

    let from_subcommand = gen_from_subcommand(name, &e.variants, &attrs);
    let augment_subcommands = gen_augment_subcommands(&e.variants, &attrs);
    let augment_update_subcommands = gen_augment_update_subcommands(&e.variants, &attrs);
    let update_from_subcommand = gen_update_from_subcommand(name, &e.variants, &attrs);

    quote! {
        #[allow(dead_code, unreachable_code, unused_variables)]
        #[allow(
            clippy::style,
            clippy::complexity,
            clippy::pedantic,
            clippy::restriction,
            clippy::perf,
            clippy::deprecated,
            clippy::nursery,
            clippy::cargo
        )]
        #[deny(clippy::correctness)]
        impl ::clap::Subcommand for #name {
            #augment_subcommands
            #from_subcommand
            #augment_update_subcommands
            #update_from_subcommand
        }
    }
}

fn gen_augment_subcommands(
    variants: &Punctuated<Variant, Token![,]>,
    parent_attribute: &Attrs,
) -> TokenStream {
    gen_augment("augment_subcommands", variants, parent_attribute, false)
}

fn gen_augment_update_subcommands(
    variants: &Punctuated<Variant, Token![,]>,
    parent_attribute: &Attrs,
) -> TokenStream {
    gen_augment(
        "augment_update_subcommands",
        variants,
        parent_attribute,
        true,
    )
}

fn gen_augment(
    fn_name: &str,
    variants: &Punctuated<Variant, Token![,]>,
    parent_attribute: &Attrs,
    override_required: bool,
) -> TokenStream {
    use syn::Fields::*;

    let subcommands: Vec<_> = variants
        .iter()
        .map(|variant| {
            let attrs = Attrs::from_struct(
                variant.span(),
                &variant.attrs,
                Name::Derived(variant.ident.clone()),
                parent_attribute.casing(),
                parent_attribute.env_casing(),
            );
            let kind = attrs.kind();

            match &*kind {
                Kind::ExternalSubcommand => {
                    quote_spanned! { kind.span()=>
                        let app = app.setting(::clap::AppSettings::AllowExternalSubcommands);
                    }
                }

                Kind::Flatten => match variant.fields {
                    Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
                        let ty = &unnamed[0];
                        quote! {
                            let app = <#ty as ::clap::Subcommand>::augment_subcommands(app);
                        }
                    }
                    _ => abort!(
                        variant,
                        "`flatten` is usable only with single-typed tuple variants"
                    ),
                },

                _ => {
                    let app_var = Ident::new("subcommand", Span::call_site());
                    let arg_block = match variant.fields {
                        Named(ref fields) => into_app::gen_app_augmentation(
                            &fields.named,
                            &app_var,
                            &attrs,
                            override_required,
                        ),
                        Unit => quote!( #app_var ),
                        Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
                            let ty = &unnamed[0];
                            quote_spanned! { ty.span()=>
                                {
                                    <#ty as ::clap::IntoApp>::augment_clap(#app_var)
                                }
                            }
                        }
                        Unnamed(..) => {
                            abort!(variant, "non single-typed tuple enums are not supported")
                        }
                    };

                    let name = attrs.cased_name();
                    let from_attrs = attrs.top_level_methods();
                    let version = attrs.version();
                    quote! {
                        let app = app.subcommand({
                            let #app_var = ::clap::App::new(#name);
                            let #app_var = #arg_block;
                            #app_var#from_attrs#version
                        });
                    }
                }
            }
        })
        .collect();

    let app_methods = parent_attribute.top_level_methods();
    let version = parent_attribute.version();
    let fn_name = Ident::new(fn_name, Span::call_site());
    quote! {
        fn #fn_name <'b>(app: ::clap::App<'b>) -> ::clap::App<'b> {
            let app = app #app_methods;
            #( #subcommands )*;
            app #version
        }
    }
}

fn gen_from_subcommand(
    name: &Ident,
    variants: &Punctuated<Variant, Token![,]>,
    parent_attribute: &Attrs,
) -> TokenStream {
    use syn::Fields::*;

    let mut ext_subcmd = None;

    let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
        .iter()
        .filter_map(|variant| {
            let attrs = Attrs::from_struct(
                variant.span(),
                &variant.attrs,
                Name::Derived(variant.ident.clone()),
                parent_attribute.casing(),
                parent_attribute.env_casing(),
            );

            if let Kind::ExternalSubcommand = &*attrs.kind() {
                if ext_subcmd.is_some() {
                    abort!(
                        attrs.kind().span(),
                        "Only one variant can be marked with `external_subcommand`, \
                         this is the second"
                    );
                }

                let ty = match variant.fields {
                    Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty,

                    _ => abort!(
                        variant,
                        "The enum variant marked with `external_attribute` must be \
                         a single-typed tuple, and the type must be either `Vec<String>` \
                         or `Vec<OsString>`."
                    ),
                };

                let (span, str_ty, values_of) = match subty_if_name(ty, "Vec") {
                    Some(subty) => {
                        if is_simple_ty(subty, "String") {
                            (
                                subty.span(),
                                quote!(::std::string::String),
                                quote!(values_of),
                            )
                        } else if is_simple_ty(subty, "OsString") {
                            (
                                subty.span(),
                                quote!(::std::ffi::OsString),
                                quote!(values_of_os),
                            )
                        } else {
                            abort!(
                                ty.span(),
                                "The type must be either `Vec<String>` or `Vec<OsString>` \
                                 to be used with `external_subcommand`."
                            );
                        }
                    }

                    None => abort!(
                        ty.span(),
                        "The type must be either `Vec<String>` or `Vec<OsString>` \
                         to be used with `external_subcommand`."
                    ),
                };

                ext_subcmd = Some((span, &variant.ident, str_ty, values_of));
                None
            } else {
                Some((variant, attrs))
            }
        })
        .partition(|(_, attrs)| {
            let kind = attrs.kind();
            matches!(&*kind, Kind::Flatten)
        });

    let match_arms = variants.iter().map(|(variant, attrs)| {
        let sub_name = attrs.cased_name();
        let variant_name = &variant.ident;
        let constructor_block = match variant.fields {
            Named(ref fields) => from_arg_matches::gen_constructor(&fields.named, &attrs),
            Unit => quote!(),
            Unnamed(ref fields) if fields.unnamed.len() == 1 => {
                let ty = &fields.unnamed[0];
                quote!( ( <#ty as ::clap::FromArgMatches>::from_arg_matches(matches) ) )
            }
            Unnamed(..) => abort_call_site!("{}: tuple enums are not supported", variant.ident),
        };

        quote! {
            Some((#sub_name, matches)) => {
                Some(#name :: #variant_name #constructor_block)
            }
        }
    });
    let child_subcommands = flatten_variants.iter().map(|(variant, _attrs)| {
        let variant_name = &variant.ident;
        match variant.fields {
            Unnamed(ref fields) if fields.unnamed.len() == 1 => {
                let ty = &fields.unnamed[0];
                quote! {
                    if let Some(res) = <#ty as ::clap::Subcommand>::from_subcommand(other) {
                        return Some(#name :: #variant_name (res));
                    }
                }
            }
            _ => abort!(
                variant,
                "`flatten` is usable only with single-typed tuple variants"
            ),
        }
    });

    let wildcard = match ext_subcmd {
        Some((span, var_name, str_ty, values_of)) => quote_spanned! { span=>
            None => ::std::option::Option::None,

            Some((external, matches)) => {
                ::std::option::Option::Some(#name::#var_name(
                    ::std::iter::once(#str_ty::from(external))
                    .chain(
                        matches.#values_of("").into_iter().flatten().map(#str_ty::from)
                    )
                    .collect::<::std::vec::Vec<_>>()
                ))
            }
        },

        None => quote!(_ => None),
    };

    quote! {
        fn from_subcommand(subcommand: Option<(&str, &::clap::ArgMatches)>) -> Option<Self> {
            match subcommand {
                #( #match_arms, )*
                other => {
                    #( #child_subcommands )else*

                    match other {
                        #wildcard
                    }
                }
            }
        }
    }
}

fn gen_update_from_subcommand(
    name: &Ident,
    variants: &Punctuated<Variant, Token![,]>,
    parent_attribute: &Attrs,
) -> TokenStream {
    use syn::Fields::*;

    let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
        .iter()
        .filter_map(|variant| {
            let attrs = Attrs::from_struct(
                variant.span(),
                &variant.attrs,
                Name::Derived(variant.ident.clone()),
                parent_attribute.casing(),
                parent_attribute.env_casing(),
            );

            if let Kind::ExternalSubcommand = &*attrs.kind() {
                None
            } else {
                Some((variant, attrs))
            }
        })
        .partition(|(_, attrs)| {
            let kind = attrs.kind();
            matches!(&*kind, Kind::Flatten)
        });

    let subcommands = variants.iter().map(|(variant, attrs)| {
        let sub_name = attrs.cased_name();
        let variant_name = &variant.ident;
        let (pattern, updater) = match variant.fields {
            Named(ref fields) => {
                let (fields, update): (Vec<_>, Vec<_>) = fields
                    .named
                    .iter()
                    .map(|field| {
                        let attrs = Attrs::from_field(
                            field,
                            parent_attribute.casing(),
                            parent_attribute.env_casing(),
                        );
                        let field_name = field.ident.as_ref().unwrap();
                        (
                            quote!( ref mut #field_name ),
                            from_arg_matches::gen_updater(&fields.named, &attrs, false),
                        )
                    })
                    .unzip();
                (quote!( { #( #fields, )* }), quote!( { #( #update )* } ))
            }
            Unit => (quote!(), quote!({})),
            Unnamed(ref fields) => {
                if fields.unnamed.len() == 1 {
                    (
                        quote!((ref mut arg)),
                        quote!(::clap::FromArgMatches::update_from_arg_matches(
                            arg, matches
                        )),
                    )
                } else {
                    abort_call_site!("{}: tuple enums are not supported", variant.ident)
                }
            }
        };

        quote! {
            (#sub_name, #name :: #variant_name #pattern) => { #updater }
        }
    });

    let child_subcommands = flatten_variants.iter().map(|(variant, attrs)| {
        let sub_name = attrs.cased_name();
        let variant_name = &variant.ident;
        let (pattern, updater) = match variant.fields {
            Unnamed(ref fields) if fields.unnamed.len() == 1 => {
                let ty = &fields.unnamed[0];
                (
                    quote!((ref mut arg)),
                    quote! {
                        <#ty as ::clap::Subcommand>::update_from_subcommand(arg, Some((name, matches)));
                    },
                )
            }
            _ => abort!(
                variant,
                "`flatten` is usable only with single-typed tuple variants"
            ),
        };
        quote! {
            (#sub_name, #name :: #variant_name #pattern) => { #updater }
        }
    });

    quote! {
        fn update_from_subcommand<'b>(
            &mut self,
            subcommand: Option<(&str, &::clap::ArgMatches)>
        ) {
            if let Some((name, matches)) = subcommand {
                match (name, self) {
                    #( #subcommands ),*
                    #( #child_subcommands ),*
                    (_, s) => if let Some(sub) = <Self as ::clap::Subcommand>::from_subcommand(Some((name, matches))) {
                        *s = sub;
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use core::ptr::Unique;

use ::memory::VAddr;
use alloc::{PAGE_SIZE, Allocator};

pub mod paddr_impls;
pub use self::paddr_impls::*;

pub mod table;
use self::table::*;

extern {
    pub static mut HEAP_BASE: u8;
    pub static mut HEAP_TOP: u8;
    pub static mut STACK_BASE: u8;
    pub static mut STACK_TOP: u8;
}

/// A physical (linear) memory address is a 64-bit unsigned integer
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct PAddr(u64);

impl PAddr {
    #[inline] pub const fn from_u64(u: u64) -> Self {
        PAddr(u)
    }
    #[inline] pub const fn as_u64(&self) -> u64 {
        self.0
    }
}

macro_rules! table_idx {
    ( $($name:ident >> $shift:expr)* ) => {$(
        pub fn $name(&self) -> usize {
            (self.number >> $shift) & 0o777
        }
    )*};
}

#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Page { pub number: usize }

impl Page {
    /// Create a new `Page` containing the given virtual address
    pub fn containing_addr(addr: VAddr) -> Page {
        assert!( addr.as_usize() < 0x0000_8000_0000_0000 ||
                 addr.as_usize() >= 0xffff_8000_0000_0000
               , "invalid address: 0x{:x}", addr );
        Page { number: (addr / PAGE_SIZE).as_usize() }
    }

    /// Return the start virtual address of this page
    pub fn start_addr(&self) -> VAddr {
        VAddr::from_usize(self.number * PAGE_SIZE)
    }

    table_idx!{
        pml4_index >> 27
        pdpt_index >> 18
        pd_index >> 9
        pt_index >> 0
    }

}

pub struct ActivePML4(Unique<Table<PML4Level>>);

impl ActivePML4 {

    pub unsafe fn new() -> Self {
        ActivePML4(Unique::new(PML4))
    }

    fn pml4(&self) -> &Table<PML4Level> {
        unsafe { self.0.get() }
    }

    fn pml4_mut(&mut self) -> &mut Table<PML4Level> {
        unsafe { self.0.get_mut() }
    }

    fn translate(&self, vaddr: VAddr) -> Option<PAddr> {
        self.translate_page(Page::containing_addr(vaddr))
            .map(|frame| {
                let offset = vaddr.as_usize() % PAGE_SIZE;
                PAddr::from_u64(frame as u64 + offset as u64)
            })
    }

    pub fn translate_page(&self, page: Page) -> Option<*mut u8> {
        let pdpt = self.pml4().next_table(page.pml4_index());

        let huge_page = || pdpt.and_then(|pdpt| {
            let pdpt_entry = &pdpt[page.pdpt_index()];

            if pdpt_entry.flags().contains(HUGE_PAGE) {
                // If the PDPT entry contains the huge page flag, and the
                // entry points to the start frame of a page, then the pointed
                // frame is a 1GB huge page
                pdpt_entry.pointed_frame()
                    .map(|start_frame| {
                        assert!( start_frame as usize % table::N_ENTRIES == 0
                               , "Start frame must be aligned on a \
                                  1GB boundary!");
                        (start_frame as usize + page.pd_index()
                                              + page.pt_index()) as *mut u8
                    })

            } else {
                pdpt.next_table(page.pdpt_index())
                    .and_then(|pd| {
                        let pd_entry = &pd[page.pd_index()];

                        if pd_entry.flags().contains(HUGE_PAGE) {
                            pd_entry.pointed_frame()
                                .map(|start_frame|{
                                    assert!( (start_frame as usize %
                                             table::N_ENTRIES) == 0
                                         , "Start frame must be aligned!");
                                    (start_frame as usize + page.pt_index())
                                        as *mut u8
                                })
                        } else {
                            None
                        }
                    })
            }
        });

        pdpt.and_then(|pdpt| pdpt.next_table(page.pdpt_index()))
            .and_then(|pd| pd.next_table(page.pd_index()))
            .and_then(|pt| pt[page.pt_index()].pointed_frame())
            .or_else(huge_page)

    }

    pub fn identity_map<A: Allocator>( &mut self
                                     , frame: *mut u8
                                     , flags: EntryFlags
                                     , allocator: &mut A) {
        self.map_to( Page::containing_addr(VAddr::from_ptr(frame))
                   , frame
                   , flags
                   , allocator )
    }

    pub fn map<A: Allocator>( &mut self
                            , page: Page
                            , flags: EntryFlags
                            , allocator: &mut A) {
        unsafe {
            self.map_to( page
                       , allocator.allocate(PAGE_SIZE, PAGE_SIZE)
                                  .expect("Couldn't map, out of frames!")
                       , flags
                       , allocator );
        }
    }

    pub fn map_to<A: Allocator>( &mut self
                               , page: Page
                               , frame: *mut u8
                               , flags: EntryFlags
                               , allocator: &mut A) {
        let mut pdpt = self.pml4_mut()
                           .create_next(page.pml4_index(), allocator);
        let mut pd   = pdpt.create_next(page.pdpt_index(), allocator);
        let mut pt   = pd.create_next(page.pd_index(), allocator);

        let idx = page.pt_index();

        assert!(pt[idx].is_unused()
               , "Could not map frame {:?}, page table entry {} is already \
                  in use!", frame, idx);
        pt[idx].set(frame, flags | PRESENT);
    }

}
<commit_msg>[x86_64] Change PAddr to match new Addr trait<commit_after>use core::ptr::Unique;
use core::convert;

use ::memory::{VAddr, Addr};
use alloc::{PAGE_SIZE, Allocator};

pub mod paddr_impls;
pub use self::paddr_impls::*;

pub mod table;
use self::table::*;

extern {
    pub static mut HEAP_BASE: u8;
    pub static mut HEAP_TOP: u8;
    pub static mut STACK_BASE: u8;
    pub static mut STACK_TOP: u8;
}

/// A physical (linear) memory address is a 64-bit unsigned integer
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct PAddr(u64);

impl Addr<u64> for PAddr { }

impl convert::Into<u64> for PAddr {
    #[inline] fn into(self) -> u64 { self.as_u64() }
}

impl convert::From<u64> for PAddr {
    #[inline] fn from(u: u64) -> Self { PAddr::from_u64(u) }
}

impl convert::From<*mut u8> for PAddr {
    #[inline] fn from(ptr: *mut u8) -> Self { PAddr::from_ptr(ptr) }
}

impl PAddr {
    #[inline] pub const fn from_ptr(ptr: *mut u8) -> Self {
        PAddr(ptr as u64)
    }
    #[inline] pub const fn from_u64(u: u64) -> Self { PAddr(u) }
    #[inline] pub const fn as_u64(&self) -> u64 { self.0 }
}

macro_rules! table_idx {
    ( $($name:ident >> $shift:expr)* ) => {$(
        pub fn $name(&self) -> usize {
            (self.number >> $shift) & 0o777
        }
    )*};
}

#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Page { pub number: usize }

impl Page {
    /// Create a new `Page` containing the given virtual address
    pub fn containing_addr(addr: VAddr) -> Page {
        assert!( addr.as_usize() < 0x0000_8000_0000_0000 ||
                 addr.as_usize() >= 0xffff_8000_0000_0000
               , "invalid address: 0x{:x}", addr );
        Page { number: (addr / PAGE_SIZE).as_usize() }
    }

    /// Return the start virtual address of this page
    pub fn start_addr(&self) -> VAddr {
        VAddr::from_usize(self.number * PAGE_SIZE)
    }

    table_idx!{
        pml4_index >> 27
        pdpt_index >> 18
        pd_index >> 9
        pt_index >> 0
    }

}

pub struct ActivePML4(Unique<Table<PML4Level>>);

impl ActivePML4 {

    pub unsafe fn new() -> Self {
        ActivePML4(Unique::new(PML4))
    }

    fn pml4(&self) -> &Table<PML4Level> {
        unsafe { self.0.get() }
    }

    fn pml4_mut(&mut self) -> &mut Table<PML4Level> {
        unsafe { self.0.get_mut() }
    }

    fn translate(&self, vaddr: VAddr) -> Option<PAddr> {
        self.translate_page(Page::containing_addr(vaddr))
            .map(|frame| {
                let offset = vaddr.as_usize() % PAGE_SIZE;
                PAddr::from(frame as u64 + offset as u64)
            })
    }

    pub fn translate_page(&self, page: Page) -> Option<*mut u8> {
        let pdpt = self.pml4().next_table(page.pml4_index());

        let huge_page = || pdpt.and_then(|pdpt| {
            let pdpt_entry = &pdpt[page.pdpt_index()];

            if pdpt_entry.flags().contains(HUGE_PAGE) {
                // If the PDPT entry contains the huge page flag, and the
                // entry points to the start frame of a page, then the pointed
                // frame is a 1GB huge page
                pdpt_entry.pointed_frame()
                    .map(|start_frame| {
                        assert!( start_frame as usize % table::N_ENTRIES == 0
                               , "Start frame must be aligned on a \
                                  1GB boundary!");
                        (start_frame as usize + page.pd_index()
                                              + page.pt_index()) as *mut u8
                    })

            } else {
                pdpt.next_table(page.pdpt_index())
                    .and_then(|pd| {
                        let pd_entry = &pd[page.pd_index()];

                        if pd_entry.flags().contains(HUGE_PAGE) {
                            pd_entry.pointed_frame()
                                .map(|start_frame|{
                                    assert!( (start_frame as usize %
                                             table::N_ENTRIES) == 0
                                         , "Start frame must be aligned!");
                                    (start_frame as usize + page.pt_index())
                                        as *mut u8
                                })
                        } else {
                            None
                        }
                    })
            }
        });

        pdpt.and_then(|pdpt| pdpt.next_table(page.pdpt_index()))
            .and_then(|pd| pd.next_table(page.pd_index()))
            .and_then(|pt| pt[page.pt_index()].pointed_frame())
            .or_else(huge_page)

    }

    pub fn identity_map<A: Allocator>( &mut self
                                     , frame: *mut u8
                                     , flags: EntryFlags
                                     , allocator: &mut A) {
        self.map_to( Page::containing_addr(VAddr::from_ptr(frame))
                   , frame
                   , flags
                   , allocator )
    }

    pub fn map<A: Allocator>( &mut self
                            , page: Page
                            , flags: EntryFlags
                            , allocator: &mut A) {
        unsafe {
            self.map_to( page
                       , allocator.allocate(PAGE_SIZE, PAGE_SIZE)
                                  .expect("Couldn't map, out of frames!")
                       , flags
                       , allocator );
        }
    }

    pub fn map_to<A: Allocator>( &mut self
                               , page: Page
                               , frame: *mut u8
                               , flags: EntryFlags
                               , allocator: &mut A) {
        let mut pdpt = self.pml4_mut()
                           .create_next(page.pml4_index(), allocator);
        let mut pd   = pdpt.create_next(page.pdpt_index(), allocator);
        let mut pt   = pd.create_next(page.pd_index(), allocator);

        let idx = page.pt_index();

        assert!(pt[idx].is_unused()
               , "Could not map frame {:?}, page table entry {} is already \
                  in use!", frame, idx);
        pt[idx].set(frame, flags | PRESENT);
    }

}
<|endoftext|>


<commit_before>use super::tokens::{get_token_table, Token, TokenType, Keyword};

use std::collections::HashMap;
use std::iter::{Iterator, IntoIterator};
use std::string::String;
use std::str;

// ------------ Lexer ----------------
pub struct Lexer {
    text: String,
    token_table: HashMap<&'static str, Keyword>
}

impl Lexer {
    pub fn new(input: String) -> Lexer {
        Lexer { text: input, token_table: get_token_table() }
    }
}

// ---------- Token Iterator --------------
pub struct TokenIterator<'a> {
    lexer: &'a Lexer,
    code: &'a[u8],
    pos: usize,

    // Line and column
    row: usize,
    column: usize
}

impl<'a> TokenIterator<'a> {
    fn advance_pos(&mut self, n: usize) {
        self.pos += n;
        self.column += n;
    }

    fn newline(&mut self) {
        self.row += 1;
        self.column = 0;
    }

    fn parse_next_token(&mut self) -> Option<Token<'a>> {

        while self.pos < self.code.len() {
            let chr = self.code[self.pos] as char;

            if chr.is_alphabetic() {
                return Some(Token::new(self.parse_identifier(), self.row, self.column))
            } else if chr.is_numeric() {
                return Some(Token::new(self.parse_number(), self.row, self.column))
            } else if chr == '\n' {
                self.newline()
            } else if chr == '"' {
                return Some(Token::new(self.parse_string(), self.row, self.column))
            } else if chr == ' ' || chr == '\t' || chr == '\n' {
                self.advance_pos(1);
            } else {
                return Some(Token::new(self.parse_operator(), self.row, self.column))
            }
        }

        return None;
    }

    fn parse_identifier(&mut self) -> TokenType<'a> {
        let allowed_chars = |a: &u8| {
            let chr = *a as char;

            return !(chr.is_alphabetic() || chr.is_numeric())
        };

        let (_, mut slice) = self.code.split_at(self.pos);

        // Get all allowed symbols for the identifier
        if let Some(index) = slice.iter().position(allowed_chars) {
            self.advance_pos(index);

            let (slice_tmp, _) = slice.split_at(index);
            slice = slice_tmp;
        } else {
            self.advance_pos(slice.len())
        }

        match str::from_utf8(slice) {
            // If keyword map contains the keyword, return Token::Keyword
            // Else return a Token::Identifier
            Ok(key) => match self.lexer.token_table.get(key) {
                Some(keyword) => return TokenType::Keyword(keyword.clone()),
                _ => return TokenType::Id(slice)
            },
            Err(why) => panic!("{:?}", why)
        }
    }

    fn parse_string(&mut self) -> TokenType<'a> {
        let string_chars = |a: &u8| {
            let chr = *a as char;

            return chr == '"'
        };

        self.advance_pos(1);
        let (_, slice) = self.code.split_at(self.pos);

        // Looking for the closing doublequote
        if let Some(index) = slice.iter().position(string_chars) {
            self.advance_pos(index);
            let (slice, _) = slice.split_at(index);

            self.advance_pos(1);
            return TokenType::String(slice);
        }
        panic!("Unmatched double quotes at {}:{}", self.row, self.column)
    }

    fn parse_number(&mut self) -> TokenType<'a> {
        let numeric_chars = |a: &u8| {
            let chr = *a as char;

            return !(chr.is_numeric() || chr == '.')
        };

        let (_, mut slice) = self.code.split_at(self.pos);

        // Looking for the end of the number
        if let Some(index) = slice.iter().position(numeric_chars) {
            self.advance_pos(index);

            let (slice_tmp, _) = slice.split_at(index);
            slice = slice_tmp;
        } else {
            // If number is in the end of the code (impossible actually)
            self.advance_pos(slice.len())
        }

        return TokenType::Number(slice)
    }

    fn parse_operator(&mut self) -> TokenType<'a> {
        return TokenType::Keyword(Keyword::AND);
    }
}

// ----- Iterator traits implementation -----
impl<'a> Iterator for TokenIterator<'a> {
    type Item = Token<'a>;

    fn next(&mut self) -> Option<Token<'a>> {
        return self.parse_next_token()
    }
}

impl<'a> IntoIterator for &'a Lexer {
    type Item = Token<'a>;
    type IntoIter = TokenIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        return TokenIterator { lexer: self, code: self.text.as_bytes(), pos: 0, row: 1, column: 1 };
    }
}
<commit_msg>Fix formatting<commit_after>use super::tokens::{get_token_table, Token, TokenType, Keyword};

use std::collections::HashMap;
use std::iter::{Iterator, IntoIterator};
use std::string::String;
use std::str;

// ------------ Lexer ----------------
pub struct Lexer {
    text: String,
    token_table: HashMap<&'static str, Keyword>,
}

impl Lexer {
    pub fn new(input: String) -> Lexer {
        Lexer {
            text: input,
            token_table: get_token_table(),
        }
    }
}

// ---------- Token Iterator --------------
pub struct TokenIterator<'a> {
    lexer: &'a Lexer,
    code: &'a [u8],
    pos: usize,

    // Line and column
    row: usize,
    column: usize,
}

impl<'a> TokenIterator<'a> {
    fn advance_pos(&mut self, n: usize) {
        self.pos += n;
        self.column += n;
    }

    fn newline(&mut self) {
        self.row += 1;
        self.column = 0;
    }

    fn parse_next_token(&mut self) -> Option<Token<'a>> {

        while self.pos < self.code.len() {
            let chr = self.code[self.pos] as char;

            if chr.is_alphabetic() {
                return Some(Token::new(self.parse_identifier(), self.row, self.column));
            } else if chr.is_numeric() {
                return Some(Token::new(self.parse_number(), self.row, self.column));
            } else if chr == '\n' {
                self.newline()
            } else if chr == '"' {
                return Some(Token::new(self.parse_string(), self.row, self.column));
            } else if chr == ' ' || chr == '\t' || chr == '\n' {
                self.advance_pos(1);
            } else {
                return Some(Token::new(self.parse_operator(), self.row, self.column));
            }
        }

        return None;
    }

    fn parse_identifier(&mut self) -> TokenType<'a> {
        let allowed_chars = |a: &u8| {
            let chr = *a as char;

            return !(chr.is_alphabetic() || chr.is_numeric());
        };

        let (_, mut slice) = self.code.split_at(self.pos);

        // Get all allowed symbols for the identifier
        if let Some(index) = slice.iter().position(allowed_chars) {
            self.advance_pos(index);

            let (slice_tmp, _) = slice.split_at(index);
            slice = slice_tmp;
        } else {
            self.advance_pos(slice.len())
        }

        match str::from_utf8(slice) {
            // If keyword map contains the keyword, return Token::Keyword
            // Else return a Token::Identifier
            Ok(key) => {
                match self.lexer.token_table.get(key) {
                    Some(keyword) => return TokenType::Keyword(keyword.clone()),
                    _ => return TokenType::Id(slice),
                }
            }
            Err(why) => panic!("{:?}", why),
        }
    }

    fn parse_string(&mut self) -> TokenType<'a> {
        let string_chars = |a: &u8| {
            let chr = *a as char;

            return chr == '"';
        };

        self.advance_pos(1);
        let (_, slice) = self.code.split_at(self.pos);

        // Looking for the closing doublequote
        if let Some(index) = slice.iter().position(string_chars) {
            self.advance_pos(index);
            let (slice, _) = slice.split_at(index);

            self.advance_pos(1);
            return TokenType::String(slice);
        }
        panic!("Unmatched double quotes at {}:{}", self.row, self.column)
    }

    fn parse_number(&mut self) -> TokenType<'a> {
        let numeric_chars = |a: &u8| {
            let chr = *a as char;

            return !(chr.is_numeric() || chr == '.');
        };

        let (_, mut slice) = self.code.split_at(self.pos);

        // Looking for the end of the number
        if let Some(index) = slice.iter().position(numeric_chars) {
            self.advance_pos(index);

            let (slice_tmp, _) = slice.split_at(index);
            slice = slice_tmp;
        } else {
            // If number is in the end of the code (impossible actually)
            self.advance_pos(slice.len())
        }

        return TokenType::Number(slice);
    }

    fn parse_operator(&mut self) -> TokenType<'a> {
        return TokenType::Keyword(Keyword::AND);
    }
}

// ----- Iterator traits implementation -----
impl<'a> Iterator for TokenIterator<'a> {
    type Item = Token<'a>;

    fn next(&mut self) -> Option<Token<'a>> {
        return self.parse_next_token();
    }
}

impl<'a> IntoIterator for &'a Lexer {
    type Item = Token<'a>;
    type IntoIter = TokenIterator<'a>;

    fn into_iter(self) -> Self::IntoIter {
        return TokenIterator {
            lexer: self,
            code: self.text.as_bytes(),
            pos: 0,
            row: 1,
            column: 1,
        };
    }
}
<|endoftext|>